162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * VMware VMCI Driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2012 VMware, Inc. All rights reserved.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/vmw_vmci_defs.h>
962306a36Sopenharmony_ci#include <linux/vmw_vmci_api.h>
1062306a36Sopenharmony_ci#include <linux/highmem.h>
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/mm.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/mutex.h>
1562306a36Sopenharmony_ci#include <linux/pagemap.h>
1662306a36Sopenharmony_ci#include <linux/pci.h>
1762306a36Sopenharmony_ci#include <linux/sched.h>
1862306a36Sopenharmony_ci#include <linux/slab.h>
1962306a36Sopenharmony_ci#include <linux/uio.h>
2062306a36Sopenharmony_ci#include <linux/wait.h>
2162306a36Sopenharmony_ci#include <linux/vmalloc.h>
2262306a36Sopenharmony_ci#include <linux/skbuff.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include "vmci_handle_array.h"
2562306a36Sopenharmony_ci#include "vmci_queue_pair.h"
2662306a36Sopenharmony_ci#include "vmci_datagram.h"
2762306a36Sopenharmony_ci#include "vmci_resource.h"
2862306a36Sopenharmony_ci#include "vmci_context.h"
2962306a36Sopenharmony_ci#include "vmci_driver.h"
3062306a36Sopenharmony_ci#include "vmci_event.h"
3162306a36Sopenharmony_ci#include "vmci_route.h"
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/*
3462306a36Sopenharmony_ci * In the following, we will distinguish between two kinds of VMX processes -
3562306a36Sopenharmony_ci * the ones with versions lower than VMCI_VERSION_NOVMVM that use specialized
3662306a36Sopenharmony_ci * VMCI page files in the VMX and supporting VM to VM communication and the
3762306a36Sopenharmony_ci * newer ones that use the guest memory directly. We will in the following
3862306a36Sopenharmony_ci * refer to the older VMX versions as old-style VMX'en, and the newer ones as
3962306a36Sopenharmony_ci * new-style VMX'en.
4062306a36Sopenharmony_ci *
4162306a36Sopenharmony_ci * The state transition datagram is as follows (the VMCIQPB_ prefix has been
4262306a36Sopenharmony_ci * removed for readability) - see below for more details on the transtions:
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci *            --------------  NEW  -------------
4562306a36Sopenharmony_ci *            |                                |
4662306a36Sopenharmony_ci *           \_/                              \_/
4762306a36Sopenharmony_ci *     CREATED_NO_MEM <-----------------> CREATED_MEM
4862306a36Sopenharmony_ci *            |    |                           |
4962306a36Sopenharmony_ci *            |    o-----------------------o   |
5062306a36Sopenharmony_ci *            |                            |   |
5162306a36Sopenharmony_ci *           \_/                          \_/ \_/
5262306a36Sopenharmony_ci *     ATTACHED_NO_MEM <----------------> ATTACHED_MEM
5362306a36Sopenharmony_ci *            |                            |   |
5462306a36Sopenharmony_ci *            |     o----------------------o   |
5562306a36Sopenharmony_ci *            |     |                          |
5662306a36Sopenharmony_ci *           \_/   \_/                        \_/
5762306a36Sopenharmony_ci *     SHUTDOWN_NO_MEM <----------------> SHUTDOWN_MEM
5862306a36Sopenharmony_ci *            |                                |
5962306a36Sopenharmony_ci *            |                                |
6062306a36Sopenharmony_ci *            -------------> gone <-------------
6162306a36Sopenharmony_ci *
6262306a36Sopenharmony_ci * In more detail. When a VMCI queue pair is first created, it will be in the
6362306a36Sopenharmony_ci * VMCIQPB_NEW state. It will then move into one of the following states:
6462306a36Sopenharmony_ci *
6562306a36Sopenharmony_ci * - VMCIQPB_CREATED_NO_MEM: this state indicates that either:
6662306a36Sopenharmony_ci *
6762306a36Sopenharmony_ci *     - the created was performed by a host endpoint, in which case there is
6862306a36Sopenharmony_ci *       no backing memory yet.
6962306a36Sopenharmony_ci *
7062306a36Sopenharmony_ci *     - the create was initiated by an old-style VMX, that uses
7162306a36Sopenharmony_ci *       vmci_qp_broker_set_page_store to specify the UVAs of the queue pair at
7262306a36Sopenharmony_ci *       a later point in time. This state can be distinguished from the one
7362306a36Sopenharmony_ci *       above by the context ID of the creator. A host side is not allowed to
7462306a36Sopenharmony_ci *       attach until the page store has been set.
7562306a36Sopenharmony_ci *
7662306a36Sopenharmony_ci * - VMCIQPB_CREATED_MEM: this state is the result when the queue pair
7762306a36Sopenharmony_ci *     is created by a VMX using the queue pair device backend that
7862306a36Sopenharmony_ci *     sets the UVAs of the queue pair immediately and stores the
7962306a36Sopenharmony_ci *     information for later attachers. At this point, it is ready for
8062306a36Sopenharmony_ci *     the host side to attach to it.
8162306a36Sopenharmony_ci *
8262306a36Sopenharmony_ci * Once the queue pair is in one of the created states (with the exception of
8362306a36Sopenharmony_ci * the case mentioned for older VMX'en above), it is possible to attach to the
8462306a36Sopenharmony_ci * queue pair. Again we have two new states possible:
8562306a36Sopenharmony_ci *
8662306a36Sopenharmony_ci * - VMCIQPB_ATTACHED_MEM: this state can be reached through the following
8762306a36Sopenharmony_ci *   paths:
8862306a36Sopenharmony_ci *
8962306a36Sopenharmony_ci *     - from VMCIQPB_CREATED_NO_MEM when a new-style VMX allocates a queue
9062306a36Sopenharmony_ci *       pair, and attaches to a queue pair previously created by the host side.
9162306a36Sopenharmony_ci *
9262306a36Sopenharmony_ci *     - from VMCIQPB_CREATED_MEM when the host side attaches to a queue pair
9362306a36Sopenharmony_ci *       already created by a guest.
9462306a36Sopenharmony_ci *
9562306a36Sopenharmony_ci *     - from VMCIQPB_ATTACHED_NO_MEM, when an old-style VMX calls
9662306a36Sopenharmony_ci *       vmci_qp_broker_set_page_store (see below).
9762306a36Sopenharmony_ci *
9862306a36Sopenharmony_ci * - VMCIQPB_ATTACHED_NO_MEM: If the queue pair already was in the
9962306a36Sopenharmony_ci *     VMCIQPB_CREATED_NO_MEM due to a host side create, an old-style VMX will
10062306a36Sopenharmony_ci *     bring the queue pair into this state. Once vmci_qp_broker_set_page_store
10162306a36Sopenharmony_ci *     is called to register the user memory, the VMCIQPB_ATTACH_MEM state
10262306a36Sopenharmony_ci *     will be entered.
10362306a36Sopenharmony_ci *
10462306a36Sopenharmony_ci * From the attached queue pair, the queue pair can enter the shutdown states
10562306a36Sopenharmony_ci * when either side of the queue pair detaches. If the guest side detaches
10662306a36Sopenharmony_ci * first, the queue pair will enter the VMCIQPB_SHUTDOWN_NO_MEM state, where
10762306a36Sopenharmony_ci * the content of the queue pair will no longer be available. If the host
10862306a36Sopenharmony_ci * side detaches first, the queue pair will either enter the
10962306a36Sopenharmony_ci * VMCIQPB_SHUTDOWN_MEM, if the guest memory is currently mapped, or
11062306a36Sopenharmony_ci * VMCIQPB_SHUTDOWN_NO_MEM, if the guest memory is not mapped
11162306a36Sopenharmony_ci * (e.g., the host detaches while a guest is stunned).
11262306a36Sopenharmony_ci *
11362306a36Sopenharmony_ci * New-style VMX'en will also unmap guest memory, if the guest is
11462306a36Sopenharmony_ci * quiesced, e.g., during a snapshot operation. In that case, the guest
11562306a36Sopenharmony_ci * memory will no longer be available, and the queue pair will transition from
11662306a36Sopenharmony_ci * *_MEM state to a *_NO_MEM state. The VMX may later map the memory once more,
11762306a36Sopenharmony_ci * in which case the queue pair will transition from the *_NO_MEM state at that
11862306a36Sopenharmony_ci * point back to the *_MEM state. Note that the *_NO_MEM state may have changed,
11962306a36Sopenharmony_ci * since the peer may have either attached or detached in the meantime. The
12062306a36Sopenharmony_ci * values are laid out such that ++ on a state will move from a *_NO_MEM to a
12162306a36Sopenharmony_ci * *_MEM state, and vice versa.
12262306a36Sopenharmony_ci */
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci/* The Kernel specific component of the struct vmci_queue structure. */
12562306a36Sopenharmony_cistruct vmci_queue_kern_if {
12662306a36Sopenharmony_ci	struct mutex __mutex;	/* Protects the queue. */
12762306a36Sopenharmony_ci	struct mutex *mutex;	/* Shared by producer and consumer queues. */
12862306a36Sopenharmony_ci	size_t num_pages;	/* Number of pages incl. header. */
12962306a36Sopenharmony_ci	bool host;		/* Host or guest? */
13062306a36Sopenharmony_ci	union {
13162306a36Sopenharmony_ci		struct {
13262306a36Sopenharmony_ci			dma_addr_t *pas;
13362306a36Sopenharmony_ci			void **vas;
13462306a36Sopenharmony_ci		} g;		/* Used by the guest. */
13562306a36Sopenharmony_ci		struct {
13662306a36Sopenharmony_ci			struct page **page;
13762306a36Sopenharmony_ci			struct page **header_page;
13862306a36Sopenharmony_ci		} h;		/* Used by the host. */
13962306a36Sopenharmony_ci	} u;
14062306a36Sopenharmony_ci};
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci/*
14362306a36Sopenharmony_ci * This structure is opaque to the clients.
14462306a36Sopenharmony_ci */
14562306a36Sopenharmony_cistruct vmci_qp {
14662306a36Sopenharmony_ci	struct vmci_handle handle;
14762306a36Sopenharmony_ci	struct vmci_queue *produce_q;
14862306a36Sopenharmony_ci	struct vmci_queue *consume_q;
14962306a36Sopenharmony_ci	u64 produce_q_size;
15062306a36Sopenharmony_ci	u64 consume_q_size;
15162306a36Sopenharmony_ci	u32 peer;
15262306a36Sopenharmony_ci	u32 flags;
15362306a36Sopenharmony_ci	u32 priv_flags;
15462306a36Sopenharmony_ci	bool guest_endpoint;
15562306a36Sopenharmony_ci	unsigned int blocked;
15662306a36Sopenharmony_ci	unsigned int generation;
15762306a36Sopenharmony_ci	wait_queue_head_t event;
15862306a36Sopenharmony_ci};
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cienum qp_broker_state {
16162306a36Sopenharmony_ci	VMCIQPB_NEW,
16262306a36Sopenharmony_ci	VMCIQPB_CREATED_NO_MEM,
16362306a36Sopenharmony_ci	VMCIQPB_CREATED_MEM,
16462306a36Sopenharmony_ci	VMCIQPB_ATTACHED_NO_MEM,
16562306a36Sopenharmony_ci	VMCIQPB_ATTACHED_MEM,
16662306a36Sopenharmony_ci	VMCIQPB_SHUTDOWN_NO_MEM,
16762306a36Sopenharmony_ci	VMCIQPB_SHUTDOWN_MEM,
16862306a36Sopenharmony_ci	VMCIQPB_GONE
16962306a36Sopenharmony_ci};
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci#define QPBROKERSTATE_HAS_MEM(_qpb) (_qpb->state == VMCIQPB_CREATED_MEM || \
17262306a36Sopenharmony_ci				     _qpb->state == VMCIQPB_ATTACHED_MEM || \
17362306a36Sopenharmony_ci				     _qpb->state == VMCIQPB_SHUTDOWN_MEM)
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci/*
17662306a36Sopenharmony_ci * In the queue pair broker, we always use the guest point of view for
17762306a36Sopenharmony_ci * the produce and consume queue values and references, e.g., the
17862306a36Sopenharmony_ci * produce queue size stored is the guests produce queue size. The
17962306a36Sopenharmony_ci * host endpoint will need to swap these around. The only exception is
18062306a36Sopenharmony_ci * the local queue pairs on the host, in which case the host endpoint
18162306a36Sopenharmony_ci * that creates the queue pair will have the right orientation, and
18262306a36Sopenharmony_ci * the attaching host endpoint will need to swap.
18362306a36Sopenharmony_ci */
18462306a36Sopenharmony_cistruct qp_entry {
18562306a36Sopenharmony_ci	struct list_head list_item;
18662306a36Sopenharmony_ci	struct vmci_handle handle;
18762306a36Sopenharmony_ci	u32 peer;
18862306a36Sopenharmony_ci	u32 flags;
18962306a36Sopenharmony_ci	u64 produce_size;
19062306a36Sopenharmony_ci	u64 consume_size;
19162306a36Sopenharmony_ci	u32 ref_count;
19262306a36Sopenharmony_ci};
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cistruct qp_broker_entry {
19562306a36Sopenharmony_ci	struct vmci_resource resource;
19662306a36Sopenharmony_ci	struct qp_entry qp;
19762306a36Sopenharmony_ci	u32 create_id;
19862306a36Sopenharmony_ci	u32 attach_id;
19962306a36Sopenharmony_ci	enum qp_broker_state state;
20062306a36Sopenharmony_ci	bool require_trusted_attach;
20162306a36Sopenharmony_ci	bool created_by_trusted;
20262306a36Sopenharmony_ci	bool vmci_page_files;	/* Created by VMX using VMCI page files */
20362306a36Sopenharmony_ci	struct vmci_queue *produce_q;
20462306a36Sopenharmony_ci	struct vmci_queue *consume_q;
20562306a36Sopenharmony_ci	struct vmci_queue_header saved_produce_q;
20662306a36Sopenharmony_ci	struct vmci_queue_header saved_consume_q;
20762306a36Sopenharmony_ci	vmci_event_release_cb wakeup_cb;
20862306a36Sopenharmony_ci	void *client_data;
20962306a36Sopenharmony_ci	void *local_mem;	/* Kernel memory for local queue pair */
21062306a36Sopenharmony_ci};
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistruct qp_guest_endpoint {
21362306a36Sopenharmony_ci	struct vmci_resource resource;
21462306a36Sopenharmony_ci	struct qp_entry qp;
21562306a36Sopenharmony_ci	u64 num_ppns;
21662306a36Sopenharmony_ci	void *produce_q;
21762306a36Sopenharmony_ci	void *consume_q;
21862306a36Sopenharmony_ci	struct ppn_set ppn_set;
21962306a36Sopenharmony_ci};
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistruct qp_list {
22262306a36Sopenharmony_ci	struct list_head head;
22362306a36Sopenharmony_ci	struct mutex mutex;	/* Protect queue list. */
22462306a36Sopenharmony_ci};
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistatic struct qp_list qp_broker_list = {
22762306a36Sopenharmony_ci	.head = LIST_HEAD_INIT(qp_broker_list.head),
22862306a36Sopenharmony_ci	.mutex = __MUTEX_INITIALIZER(qp_broker_list.mutex),
22962306a36Sopenharmony_ci};
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistatic struct qp_list qp_guest_endpoints = {
23262306a36Sopenharmony_ci	.head = LIST_HEAD_INIT(qp_guest_endpoints.head),
23362306a36Sopenharmony_ci	.mutex = __MUTEX_INITIALIZER(qp_guest_endpoints.mutex),
23462306a36Sopenharmony_ci};
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci#define INVALID_VMCI_GUEST_MEM_ID  0
23762306a36Sopenharmony_ci#define QPE_NUM_PAGES(_QPE) ((u32) \
23862306a36Sopenharmony_ci			     (DIV_ROUND_UP(_QPE.produce_size, PAGE_SIZE) + \
23962306a36Sopenharmony_ci			      DIV_ROUND_UP(_QPE.consume_size, PAGE_SIZE) + 2))
24062306a36Sopenharmony_ci#define QP_SIZES_ARE_VALID(_prod_qsize, _cons_qsize) \
24162306a36Sopenharmony_ci	((_prod_qsize) + (_cons_qsize) >= max(_prod_qsize, _cons_qsize) && \
24262306a36Sopenharmony_ci	 (_prod_qsize) + (_cons_qsize) <= VMCI_MAX_GUEST_QP_MEMORY)
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci/*
24562306a36Sopenharmony_ci * Frees kernel VA space for a given queue and its queue header, and
24662306a36Sopenharmony_ci * frees physical data pages.
24762306a36Sopenharmony_ci */
24862306a36Sopenharmony_cistatic void qp_free_queue(void *q, u64 size)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	struct vmci_queue *queue = q;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	if (queue) {
25362306a36Sopenharmony_ci		u64 i;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci		/* Given size does not include header, so add in a page here. */
25662306a36Sopenharmony_ci		for (i = 0; i < DIV_ROUND_UP(size, PAGE_SIZE) + 1; i++) {
25762306a36Sopenharmony_ci			dma_free_coherent(&vmci_pdev->dev, PAGE_SIZE,
25862306a36Sopenharmony_ci					  queue->kernel_if->u.g.vas[i],
25962306a36Sopenharmony_ci					  queue->kernel_if->u.g.pas[i]);
26062306a36Sopenharmony_ci		}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci		vfree(queue);
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci/*
26762306a36Sopenharmony_ci * Allocates kernel queue pages of specified size with IOMMU mappings,
26862306a36Sopenharmony_ci * plus space for the queue structure/kernel interface and the queue
26962306a36Sopenharmony_ci * header.
27062306a36Sopenharmony_ci */
27162306a36Sopenharmony_cistatic void *qp_alloc_queue(u64 size, u32 flags)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	u64 i;
27462306a36Sopenharmony_ci	struct vmci_queue *queue;
27562306a36Sopenharmony_ci	size_t pas_size;
27662306a36Sopenharmony_ci	size_t vas_size;
27762306a36Sopenharmony_ci	size_t queue_size = sizeof(*queue) + sizeof(*queue->kernel_if);
27862306a36Sopenharmony_ci	u64 num_pages;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	if (size > SIZE_MAX - PAGE_SIZE)
28162306a36Sopenharmony_ci		return NULL;
28262306a36Sopenharmony_ci	num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1;
28362306a36Sopenharmony_ci	if (num_pages >
28462306a36Sopenharmony_ci		 (SIZE_MAX - queue_size) /
28562306a36Sopenharmony_ci		 (sizeof(*queue->kernel_if->u.g.pas) +
28662306a36Sopenharmony_ci		  sizeof(*queue->kernel_if->u.g.vas)))
28762306a36Sopenharmony_ci		return NULL;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	pas_size = num_pages * sizeof(*queue->kernel_if->u.g.pas);
29062306a36Sopenharmony_ci	vas_size = num_pages * sizeof(*queue->kernel_if->u.g.vas);
29162306a36Sopenharmony_ci	queue_size += pas_size + vas_size;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	queue = vmalloc(queue_size);
29462306a36Sopenharmony_ci	if (!queue)
29562306a36Sopenharmony_ci		return NULL;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	queue->q_header = NULL;
29862306a36Sopenharmony_ci	queue->saved_header = NULL;
29962306a36Sopenharmony_ci	queue->kernel_if = (struct vmci_queue_kern_if *)(queue + 1);
30062306a36Sopenharmony_ci	queue->kernel_if->mutex = NULL;
30162306a36Sopenharmony_ci	queue->kernel_if->num_pages = num_pages;
30262306a36Sopenharmony_ci	queue->kernel_if->u.g.pas = (dma_addr_t *)(queue->kernel_if + 1);
30362306a36Sopenharmony_ci	queue->kernel_if->u.g.vas =
30462306a36Sopenharmony_ci		(void **)((u8 *)queue->kernel_if->u.g.pas + pas_size);
30562306a36Sopenharmony_ci	queue->kernel_if->host = false;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	for (i = 0; i < num_pages; i++) {
30862306a36Sopenharmony_ci		queue->kernel_if->u.g.vas[i] =
30962306a36Sopenharmony_ci			dma_alloc_coherent(&vmci_pdev->dev, PAGE_SIZE,
31062306a36Sopenharmony_ci					   &queue->kernel_if->u.g.pas[i],
31162306a36Sopenharmony_ci					   GFP_KERNEL);
31262306a36Sopenharmony_ci		if (!queue->kernel_if->u.g.vas[i]) {
31362306a36Sopenharmony_ci			/* Size excl. the header. */
31462306a36Sopenharmony_ci			qp_free_queue(queue, i * PAGE_SIZE);
31562306a36Sopenharmony_ci			return NULL;
31662306a36Sopenharmony_ci		}
31762306a36Sopenharmony_ci	}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	/* Queue header is the first page. */
32062306a36Sopenharmony_ci	queue->q_header = queue->kernel_if->u.g.vas[0];
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	return queue;
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci/*
32662306a36Sopenharmony_ci * Copies from a given buffer or iovector to a VMCI Queue.  Uses
32762306a36Sopenharmony_ci * kmap_local_page() to dynamically map required portions of the queue
32862306a36Sopenharmony_ci * by traversing the offset -> page translation structure for the queue.
32962306a36Sopenharmony_ci * Assumes that offset + size does not wrap around in the queue.
33062306a36Sopenharmony_ci */
33162306a36Sopenharmony_cistatic int qp_memcpy_to_queue_iter(struct vmci_queue *queue,
33262306a36Sopenharmony_ci				  u64 queue_offset,
33362306a36Sopenharmony_ci				  struct iov_iter *from,
33462306a36Sopenharmony_ci				  size_t size)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	struct vmci_queue_kern_if *kernel_if = queue->kernel_if;
33762306a36Sopenharmony_ci	size_t bytes_copied = 0;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	while (bytes_copied < size) {
34062306a36Sopenharmony_ci		const u64 page_index =
34162306a36Sopenharmony_ci			(queue_offset + bytes_copied) / PAGE_SIZE;
34262306a36Sopenharmony_ci		const size_t page_offset =
34362306a36Sopenharmony_ci		    (queue_offset + bytes_copied) & (PAGE_SIZE - 1);
34462306a36Sopenharmony_ci		void *va;
34562306a36Sopenharmony_ci		size_t to_copy;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci		if (kernel_if->host)
34862306a36Sopenharmony_ci			va = kmap_local_page(kernel_if->u.h.page[page_index]);
34962306a36Sopenharmony_ci		else
35062306a36Sopenharmony_ci			va = kernel_if->u.g.vas[page_index + 1];
35162306a36Sopenharmony_ci			/* Skip header. */
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci		if (size - bytes_copied > PAGE_SIZE - page_offset)
35462306a36Sopenharmony_ci			/* Enough payload to fill up from this page. */
35562306a36Sopenharmony_ci			to_copy = PAGE_SIZE - page_offset;
35662306a36Sopenharmony_ci		else
35762306a36Sopenharmony_ci			to_copy = size - bytes_copied;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci		if (!copy_from_iter_full((u8 *)va + page_offset, to_copy,
36062306a36Sopenharmony_ci					 from)) {
36162306a36Sopenharmony_ci			if (kernel_if->host)
36262306a36Sopenharmony_ci				kunmap_local(va);
36362306a36Sopenharmony_ci			return VMCI_ERROR_INVALID_ARGS;
36462306a36Sopenharmony_ci		}
36562306a36Sopenharmony_ci		bytes_copied += to_copy;
36662306a36Sopenharmony_ci		if (kernel_if->host)
36762306a36Sopenharmony_ci			kunmap_local(va);
36862306a36Sopenharmony_ci	}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	return VMCI_SUCCESS;
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci/*
37462306a36Sopenharmony_ci * Copies to a given buffer or iovector from a VMCI Queue.  Uses
37562306a36Sopenharmony_ci * kmap_local_page() to dynamically map required portions of the queue
37662306a36Sopenharmony_ci * by traversing the offset -> page translation structure for the queue.
37762306a36Sopenharmony_ci * Assumes that offset + size does not wrap around in the queue.
37862306a36Sopenharmony_ci */
37962306a36Sopenharmony_cistatic int qp_memcpy_from_queue_iter(struct iov_iter *to,
38062306a36Sopenharmony_ci				    const struct vmci_queue *queue,
38162306a36Sopenharmony_ci				    u64 queue_offset, size_t size)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	struct vmci_queue_kern_if *kernel_if = queue->kernel_if;
38462306a36Sopenharmony_ci	size_t bytes_copied = 0;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	while (bytes_copied < size) {
38762306a36Sopenharmony_ci		const u64 page_index =
38862306a36Sopenharmony_ci			(queue_offset + bytes_copied) / PAGE_SIZE;
38962306a36Sopenharmony_ci		const size_t page_offset =
39062306a36Sopenharmony_ci		    (queue_offset + bytes_copied) & (PAGE_SIZE - 1);
39162306a36Sopenharmony_ci		void *va;
39262306a36Sopenharmony_ci		size_t to_copy;
39362306a36Sopenharmony_ci		int err;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci		if (kernel_if->host)
39662306a36Sopenharmony_ci			va = kmap_local_page(kernel_if->u.h.page[page_index]);
39762306a36Sopenharmony_ci		else
39862306a36Sopenharmony_ci			va = kernel_if->u.g.vas[page_index + 1];
39962306a36Sopenharmony_ci			/* Skip header. */
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci		if (size - bytes_copied > PAGE_SIZE - page_offset)
40262306a36Sopenharmony_ci			/* Enough payload to fill up this page. */
40362306a36Sopenharmony_ci			to_copy = PAGE_SIZE - page_offset;
40462306a36Sopenharmony_ci		else
40562306a36Sopenharmony_ci			to_copy = size - bytes_copied;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci		err = copy_to_iter((u8 *)va + page_offset, to_copy, to);
40862306a36Sopenharmony_ci		if (err != to_copy) {
40962306a36Sopenharmony_ci			if (kernel_if->host)
41062306a36Sopenharmony_ci				kunmap_local(va);
41162306a36Sopenharmony_ci			return VMCI_ERROR_INVALID_ARGS;
41262306a36Sopenharmony_ci		}
41362306a36Sopenharmony_ci		bytes_copied += to_copy;
41462306a36Sopenharmony_ci		if (kernel_if->host)
41562306a36Sopenharmony_ci			kunmap_local(va);
41662306a36Sopenharmony_ci	}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	return VMCI_SUCCESS;
41962306a36Sopenharmony_ci}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci/*
42262306a36Sopenharmony_ci * Allocates two list of PPNs --- one for the pages in the produce queue,
42362306a36Sopenharmony_ci * and the other for the pages in the consume queue. Intializes the list
42462306a36Sopenharmony_ci * of PPNs with the page frame numbers of the KVA for the two queues (and
42562306a36Sopenharmony_ci * the queue headers).
42662306a36Sopenharmony_ci */
42762306a36Sopenharmony_cistatic int qp_alloc_ppn_set(void *prod_q,
42862306a36Sopenharmony_ci			    u64 num_produce_pages,
42962306a36Sopenharmony_ci			    void *cons_q,
43062306a36Sopenharmony_ci			    u64 num_consume_pages, struct ppn_set *ppn_set)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	u64 *produce_ppns;
43362306a36Sopenharmony_ci	u64 *consume_ppns;
43462306a36Sopenharmony_ci	struct vmci_queue *produce_q = prod_q;
43562306a36Sopenharmony_ci	struct vmci_queue *consume_q = cons_q;
43662306a36Sopenharmony_ci	u64 i;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	if (!produce_q || !num_produce_pages || !consume_q ||
43962306a36Sopenharmony_ci	    !num_consume_pages || !ppn_set)
44062306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	if (ppn_set->initialized)
44362306a36Sopenharmony_ci		return VMCI_ERROR_ALREADY_EXISTS;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	produce_ppns =
44662306a36Sopenharmony_ci	    kmalloc_array(num_produce_pages, sizeof(*produce_ppns),
44762306a36Sopenharmony_ci			  GFP_KERNEL);
44862306a36Sopenharmony_ci	if (!produce_ppns)
44962306a36Sopenharmony_ci		return VMCI_ERROR_NO_MEM;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	consume_ppns =
45262306a36Sopenharmony_ci	    kmalloc_array(num_consume_pages, sizeof(*consume_ppns),
45362306a36Sopenharmony_ci			  GFP_KERNEL);
45462306a36Sopenharmony_ci	if (!consume_ppns) {
45562306a36Sopenharmony_ci		kfree(produce_ppns);
45662306a36Sopenharmony_ci		return VMCI_ERROR_NO_MEM;
45762306a36Sopenharmony_ci	}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	for (i = 0; i < num_produce_pages; i++)
46062306a36Sopenharmony_ci		produce_ppns[i] =
46162306a36Sopenharmony_ci			produce_q->kernel_if->u.g.pas[i] >> PAGE_SHIFT;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	for (i = 0; i < num_consume_pages; i++)
46462306a36Sopenharmony_ci		consume_ppns[i] =
46562306a36Sopenharmony_ci			consume_q->kernel_if->u.g.pas[i] >> PAGE_SHIFT;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	ppn_set->num_produce_pages = num_produce_pages;
46862306a36Sopenharmony_ci	ppn_set->num_consume_pages = num_consume_pages;
46962306a36Sopenharmony_ci	ppn_set->produce_ppns = produce_ppns;
47062306a36Sopenharmony_ci	ppn_set->consume_ppns = consume_ppns;
47162306a36Sopenharmony_ci	ppn_set->initialized = true;
47262306a36Sopenharmony_ci	return VMCI_SUCCESS;
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci/*
47662306a36Sopenharmony_ci * Frees the two list of PPNs for a queue pair.
47762306a36Sopenharmony_ci */
47862306a36Sopenharmony_cistatic void qp_free_ppn_set(struct ppn_set *ppn_set)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	if (ppn_set->initialized) {
48162306a36Sopenharmony_ci		/* Do not call these functions on NULL inputs. */
48262306a36Sopenharmony_ci		kfree(ppn_set->produce_ppns);
48362306a36Sopenharmony_ci		kfree(ppn_set->consume_ppns);
48462306a36Sopenharmony_ci	}
48562306a36Sopenharmony_ci	memset(ppn_set, 0, sizeof(*ppn_set));
48662306a36Sopenharmony_ci}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci/*
48962306a36Sopenharmony_ci * Populates the list of PPNs in the hypercall structure with the PPNS
49062306a36Sopenharmony_ci * of the produce queue and the consume queue.
49162306a36Sopenharmony_ci */
49262306a36Sopenharmony_cistatic int qp_populate_ppn_set(u8 *call_buf, const struct ppn_set *ppn_set)
49362306a36Sopenharmony_ci{
49462306a36Sopenharmony_ci	if (vmci_use_ppn64()) {
49562306a36Sopenharmony_ci		memcpy(call_buf, ppn_set->produce_ppns,
49662306a36Sopenharmony_ci		       ppn_set->num_produce_pages *
49762306a36Sopenharmony_ci		       sizeof(*ppn_set->produce_ppns));
49862306a36Sopenharmony_ci		memcpy(call_buf +
49962306a36Sopenharmony_ci		       ppn_set->num_produce_pages *
50062306a36Sopenharmony_ci		       sizeof(*ppn_set->produce_ppns),
50162306a36Sopenharmony_ci		       ppn_set->consume_ppns,
50262306a36Sopenharmony_ci		       ppn_set->num_consume_pages *
50362306a36Sopenharmony_ci		       sizeof(*ppn_set->consume_ppns));
50462306a36Sopenharmony_ci	} else {
50562306a36Sopenharmony_ci		int i;
50662306a36Sopenharmony_ci		u32 *ppns = (u32 *) call_buf;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci		for (i = 0; i < ppn_set->num_produce_pages; i++)
50962306a36Sopenharmony_ci			ppns[i] = (u32) ppn_set->produce_ppns[i];
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci		ppns = &ppns[ppn_set->num_produce_pages];
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci		for (i = 0; i < ppn_set->num_consume_pages; i++)
51462306a36Sopenharmony_ci			ppns[i] = (u32) ppn_set->consume_ppns[i];
51562306a36Sopenharmony_ci	}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	return VMCI_SUCCESS;
51862306a36Sopenharmony_ci}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci/*
52162306a36Sopenharmony_ci * Allocates kernel VA space of specified size plus space for the queue
52262306a36Sopenharmony_ci * and kernel interface.  This is different from the guest queue allocator,
52362306a36Sopenharmony_ci * because we do not allocate our own queue header/data pages here but
52462306a36Sopenharmony_ci * share those of the guest.
52562306a36Sopenharmony_ci */
52662306a36Sopenharmony_cistatic struct vmci_queue *qp_host_alloc_queue(u64 size)
52762306a36Sopenharmony_ci{
52862306a36Sopenharmony_ci	struct vmci_queue *queue;
52962306a36Sopenharmony_ci	size_t queue_page_size;
53062306a36Sopenharmony_ci	u64 num_pages;
53162306a36Sopenharmony_ci	const size_t queue_size = sizeof(*queue) + sizeof(*(queue->kernel_if));
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	if (size > min_t(size_t, VMCI_MAX_GUEST_QP_MEMORY, SIZE_MAX - PAGE_SIZE))
53462306a36Sopenharmony_ci		return NULL;
53562306a36Sopenharmony_ci	num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1;
53662306a36Sopenharmony_ci	if (num_pages > (SIZE_MAX - queue_size) /
53762306a36Sopenharmony_ci		 sizeof(*queue->kernel_if->u.h.page))
53862306a36Sopenharmony_ci		return NULL;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	queue_page_size = num_pages * sizeof(*queue->kernel_if->u.h.page);
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	if (queue_size + queue_page_size > KMALLOC_MAX_SIZE)
54362306a36Sopenharmony_ci		return NULL;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	queue = kzalloc(queue_size + queue_page_size, GFP_KERNEL);
54662306a36Sopenharmony_ci	if (queue) {
54762306a36Sopenharmony_ci		queue->q_header = NULL;
54862306a36Sopenharmony_ci		queue->saved_header = NULL;
54962306a36Sopenharmony_ci		queue->kernel_if = (struct vmci_queue_kern_if *)(queue + 1);
55062306a36Sopenharmony_ci		queue->kernel_if->host = true;
55162306a36Sopenharmony_ci		queue->kernel_if->mutex = NULL;
55262306a36Sopenharmony_ci		queue->kernel_if->num_pages = num_pages;
55362306a36Sopenharmony_ci		queue->kernel_if->u.h.header_page =
55462306a36Sopenharmony_ci		    (struct page **)((u8 *)queue + queue_size);
55562306a36Sopenharmony_ci		queue->kernel_if->u.h.page =
55662306a36Sopenharmony_ci			&queue->kernel_if->u.h.header_page[1];
55762306a36Sopenharmony_ci	}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	return queue;
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci/*
56362306a36Sopenharmony_ci * Frees kernel memory for a given queue (header plus translation
56462306a36Sopenharmony_ci * structure).
56562306a36Sopenharmony_ci */
56662306a36Sopenharmony_cistatic void qp_host_free_queue(struct vmci_queue *queue, u64 queue_size)
56762306a36Sopenharmony_ci{
56862306a36Sopenharmony_ci	kfree(queue);
56962306a36Sopenharmony_ci}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci/*
57262306a36Sopenharmony_ci * Initialize the mutex for the pair of queues.  This mutex is used to
57362306a36Sopenharmony_ci * protect the q_header and the buffer from changing out from under any
57462306a36Sopenharmony_ci * users of either queue.  Of course, it's only any good if the mutexes
57562306a36Sopenharmony_ci * are actually acquired.  Queue structure must lie on non-paged memory
57662306a36Sopenharmony_ci * or we cannot guarantee access to the mutex.
57762306a36Sopenharmony_ci */
57862306a36Sopenharmony_cistatic void qp_init_queue_mutex(struct vmci_queue *produce_q,
57962306a36Sopenharmony_ci				struct vmci_queue *consume_q)
58062306a36Sopenharmony_ci{
58162306a36Sopenharmony_ci	/*
58262306a36Sopenharmony_ci	 * Only the host queue has shared state - the guest queues do not
58362306a36Sopenharmony_ci	 * need to synchronize access using a queue mutex.
58462306a36Sopenharmony_ci	 */
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	if (produce_q->kernel_if->host) {
58762306a36Sopenharmony_ci		produce_q->kernel_if->mutex = &produce_q->kernel_if->__mutex;
58862306a36Sopenharmony_ci		consume_q->kernel_if->mutex = &produce_q->kernel_if->__mutex;
58962306a36Sopenharmony_ci		mutex_init(produce_q->kernel_if->mutex);
59062306a36Sopenharmony_ci	}
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci/*
59462306a36Sopenharmony_ci * Cleans up the mutex for the pair of queues.
59562306a36Sopenharmony_ci */
59662306a36Sopenharmony_cistatic void qp_cleanup_queue_mutex(struct vmci_queue *produce_q,
59762306a36Sopenharmony_ci				   struct vmci_queue *consume_q)
59862306a36Sopenharmony_ci{
59962306a36Sopenharmony_ci	if (produce_q->kernel_if->host) {
60062306a36Sopenharmony_ci		produce_q->kernel_if->mutex = NULL;
60162306a36Sopenharmony_ci		consume_q->kernel_if->mutex = NULL;
60262306a36Sopenharmony_ci	}
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci/*
60662306a36Sopenharmony_ci * Acquire the mutex for the queue.  Note that the produce_q and
60762306a36Sopenharmony_ci * the consume_q share a mutex.  So, only one of the two need to
60862306a36Sopenharmony_ci * be passed in to this routine.  Either will work just fine.
60962306a36Sopenharmony_ci */
61062306a36Sopenharmony_cistatic void qp_acquire_queue_mutex(struct vmci_queue *queue)
61162306a36Sopenharmony_ci{
61262306a36Sopenharmony_ci	if (queue->kernel_if->host)
61362306a36Sopenharmony_ci		mutex_lock(queue->kernel_if->mutex);
61462306a36Sopenharmony_ci}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci/*
61762306a36Sopenharmony_ci * Release the mutex for the queue.  Note that the produce_q and
61862306a36Sopenharmony_ci * the consume_q share a mutex.  So, only one of the two need to
61962306a36Sopenharmony_ci * be passed in to this routine.  Either will work just fine.
62062306a36Sopenharmony_ci */
62162306a36Sopenharmony_cistatic void qp_release_queue_mutex(struct vmci_queue *queue)
62262306a36Sopenharmony_ci{
62362306a36Sopenharmony_ci	if (queue->kernel_if->host)
62462306a36Sopenharmony_ci		mutex_unlock(queue->kernel_if->mutex);
62562306a36Sopenharmony_ci}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci/*
62862306a36Sopenharmony_ci * Helper function to release pages in the PageStoreAttachInfo
62962306a36Sopenharmony_ci * previously obtained using get_user_pages.
63062306a36Sopenharmony_ci */
63162306a36Sopenharmony_cistatic void qp_release_pages(struct page **pages,
63262306a36Sopenharmony_ci			     u64 num_pages, bool dirty)
63362306a36Sopenharmony_ci{
63462306a36Sopenharmony_ci	int i;
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	for (i = 0; i < num_pages; i++) {
63762306a36Sopenharmony_ci		if (dirty)
63862306a36Sopenharmony_ci			set_page_dirty_lock(pages[i]);
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci		put_page(pages[i]);
64162306a36Sopenharmony_ci		pages[i] = NULL;
64262306a36Sopenharmony_ci	}
64362306a36Sopenharmony_ci}
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci/*
64662306a36Sopenharmony_ci * Lock the user pages referenced by the {produce,consume}Buffer
64762306a36Sopenharmony_ci * struct into memory and populate the {produce,consume}Pages
64862306a36Sopenharmony_ci * arrays in the attach structure with them.
64962306a36Sopenharmony_ci */
65062306a36Sopenharmony_cistatic int qp_host_get_user_memory(u64 produce_uva,
65162306a36Sopenharmony_ci				   u64 consume_uva,
65262306a36Sopenharmony_ci				   struct vmci_queue *produce_q,
65362306a36Sopenharmony_ci				   struct vmci_queue *consume_q)
65462306a36Sopenharmony_ci{
65562306a36Sopenharmony_ci	int retval;
65662306a36Sopenharmony_ci	int err = VMCI_SUCCESS;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	retval = get_user_pages_fast((uintptr_t) produce_uva,
65962306a36Sopenharmony_ci				     produce_q->kernel_if->num_pages,
66062306a36Sopenharmony_ci				     FOLL_WRITE,
66162306a36Sopenharmony_ci				     produce_q->kernel_if->u.h.header_page);
66262306a36Sopenharmony_ci	if (retval < (int)produce_q->kernel_if->num_pages) {
66362306a36Sopenharmony_ci		pr_debug("get_user_pages_fast(produce) failed (retval=%d)",
66462306a36Sopenharmony_ci			retval);
66562306a36Sopenharmony_ci		if (retval > 0)
66662306a36Sopenharmony_ci			qp_release_pages(produce_q->kernel_if->u.h.header_page,
66762306a36Sopenharmony_ci					retval, false);
66862306a36Sopenharmony_ci		err = VMCI_ERROR_NO_MEM;
66962306a36Sopenharmony_ci		goto out;
67062306a36Sopenharmony_ci	}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	retval = get_user_pages_fast((uintptr_t) consume_uva,
67362306a36Sopenharmony_ci				     consume_q->kernel_if->num_pages,
67462306a36Sopenharmony_ci				     FOLL_WRITE,
67562306a36Sopenharmony_ci				     consume_q->kernel_if->u.h.header_page);
67662306a36Sopenharmony_ci	if (retval < (int)consume_q->kernel_if->num_pages) {
67762306a36Sopenharmony_ci		pr_debug("get_user_pages_fast(consume) failed (retval=%d)",
67862306a36Sopenharmony_ci			retval);
67962306a36Sopenharmony_ci		if (retval > 0)
68062306a36Sopenharmony_ci			qp_release_pages(consume_q->kernel_if->u.h.header_page,
68162306a36Sopenharmony_ci					retval, false);
68262306a36Sopenharmony_ci		qp_release_pages(produce_q->kernel_if->u.h.header_page,
68362306a36Sopenharmony_ci				 produce_q->kernel_if->num_pages, false);
68462306a36Sopenharmony_ci		err = VMCI_ERROR_NO_MEM;
68562306a36Sopenharmony_ci	}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci out:
68862306a36Sopenharmony_ci	return err;
68962306a36Sopenharmony_ci}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci/*
69262306a36Sopenharmony_ci * Registers the specification of the user pages used for backing a queue
69362306a36Sopenharmony_ci * pair. Enough information to map in pages is stored in the OS specific
69462306a36Sopenharmony_ci * part of the struct vmci_queue structure.
69562306a36Sopenharmony_ci */
69662306a36Sopenharmony_cistatic int qp_host_register_user_memory(struct vmci_qp_page_store *page_store,
69762306a36Sopenharmony_ci					struct vmci_queue *produce_q,
69862306a36Sopenharmony_ci					struct vmci_queue *consume_q)
69962306a36Sopenharmony_ci{
70062306a36Sopenharmony_ci	u64 produce_uva;
70162306a36Sopenharmony_ci	u64 consume_uva;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	/*
70462306a36Sopenharmony_ci	 * The new style and the old style mapping only differs in
70562306a36Sopenharmony_ci	 * that we either get a single or two UVAs, so we split the
70662306a36Sopenharmony_ci	 * single UVA range at the appropriate spot.
70762306a36Sopenharmony_ci	 */
70862306a36Sopenharmony_ci	produce_uva = page_store->pages;
70962306a36Sopenharmony_ci	consume_uva = page_store->pages +
71062306a36Sopenharmony_ci	    produce_q->kernel_if->num_pages * PAGE_SIZE;
71162306a36Sopenharmony_ci	return qp_host_get_user_memory(produce_uva, consume_uva, produce_q,
71262306a36Sopenharmony_ci				       consume_q);
71362306a36Sopenharmony_ci}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci/*
71662306a36Sopenharmony_ci * Releases and removes the references to user pages stored in the attach
71762306a36Sopenharmony_ci * struct.  Pages are released from the page cache and may become
71862306a36Sopenharmony_ci * swappable again.
71962306a36Sopenharmony_ci */
72062306a36Sopenharmony_cistatic void qp_host_unregister_user_memory(struct vmci_queue *produce_q,
72162306a36Sopenharmony_ci					   struct vmci_queue *consume_q)
72262306a36Sopenharmony_ci{
72362306a36Sopenharmony_ci	qp_release_pages(produce_q->kernel_if->u.h.header_page,
72462306a36Sopenharmony_ci			 produce_q->kernel_if->num_pages, true);
72562306a36Sopenharmony_ci	memset(produce_q->kernel_if->u.h.header_page, 0,
72662306a36Sopenharmony_ci	       sizeof(*produce_q->kernel_if->u.h.header_page) *
72762306a36Sopenharmony_ci	       produce_q->kernel_if->num_pages);
72862306a36Sopenharmony_ci	qp_release_pages(consume_q->kernel_if->u.h.header_page,
72962306a36Sopenharmony_ci			 consume_q->kernel_if->num_pages, true);
73062306a36Sopenharmony_ci	memset(consume_q->kernel_if->u.h.header_page, 0,
73162306a36Sopenharmony_ci	       sizeof(*consume_q->kernel_if->u.h.header_page) *
73262306a36Sopenharmony_ci	       consume_q->kernel_if->num_pages);
73362306a36Sopenharmony_ci}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci/*
73662306a36Sopenharmony_ci * Once qp_host_register_user_memory has been performed on a
73762306a36Sopenharmony_ci * queue, the queue pair headers can be mapped into the
73862306a36Sopenharmony_ci * kernel. Once mapped, they must be unmapped with
73962306a36Sopenharmony_ci * qp_host_unmap_queues prior to calling
74062306a36Sopenharmony_ci * qp_host_unregister_user_memory.
74162306a36Sopenharmony_ci * Pages are pinned.
74262306a36Sopenharmony_ci */
74362306a36Sopenharmony_cistatic int qp_host_map_queues(struct vmci_queue *produce_q,
74462306a36Sopenharmony_ci			      struct vmci_queue *consume_q)
74562306a36Sopenharmony_ci{
74662306a36Sopenharmony_ci	int result;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	if (!produce_q->q_header || !consume_q->q_header) {
74962306a36Sopenharmony_ci		struct page *headers[2];
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci		if (produce_q->q_header != consume_q->q_header)
75262306a36Sopenharmony_ci			return VMCI_ERROR_QUEUEPAIR_MISMATCH;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci		if (produce_q->kernel_if->u.h.header_page == NULL ||
75562306a36Sopenharmony_ci		    *produce_q->kernel_if->u.h.header_page == NULL)
75662306a36Sopenharmony_ci			return VMCI_ERROR_UNAVAILABLE;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci		headers[0] = *produce_q->kernel_if->u.h.header_page;
75962306a36Sopenharmony_ci		headers[1] = *consume_q->kernel_if->u.h.header_page;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci		produce_q->q_header = vmap(headers, 2, VM_MAP, PAGE_KERNEL);
76262306a36Sopenharmony_ci		if (produce_q->q_header != NULL) {
76362306a36Sopenharmony_ci			consume_q->q_header =
76462306a36Sopenharmony_ci			    (struct vmci_queue_header *)((u8 *)
76562306a36Sopenharmony_ci							 produce_q->q_header +
76662306a36Sopenharmony_ci							 PAGE_SIZE);
76762306a36Sopenharmony_ci			result = VMCI_SUCCESS;
76862306a36Sopenharmony_ci		} else {
76962306a36Sopenharmony_ci			pr_warn("vmap failed\n");
77062306a36Sopenharmony_ci			result = VMCI_ERROR_NO_MEM;
77162306a36Sopenharmony_ci		}
77262306a36Sopenharmony_ci	} else {
77362306a36Sopenharmony_ci		result = VMCI_SUCCESS;
77462306a36Sopenharmony_ci	}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	return result;
77762306a36Sopenharmony_ci}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci/*
78062306a36Sopenharmony_ci * Unmaps previously mapped queue pair headers from the kernel.
78162306a36Sopenharmony_ci * Pages are unpinned.
78262306a36Sopenharmony_ci */
78362306a36Sopenharmony_cistatic int qp_host_unmap_queues(u32 gid,
78462306a36Sopenharmony_ci				struct vmci_queue *produce_q,
78562306a36Sopenharmony_ci				struct vmci_queue *consume_q)
78662306a36Sopenharmony_ci{
78762306a36Sopenharmony_ci	if (produce_q->q_header) {
78862306a36Sopenharmony_ci		if (produce_q->q_header < consume_q->q_header)
78962306a36Sopenharmony_ci			vunmap(produce_q->q_header);
79062306a36Sopenharmony_ci		else
79162306a36Sopenharmony_ci			vunmap(consume_q->q_header);
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci		produce_q->q_header = NULL;
79462306a36Sopenharmony_ci		consume_q->q_header = NULL;
79562306a36Sopenharmony_ci	}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	return VMCI_SUCCESS;
79862306a36Sopenharmony_ci}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci/*
80162306a36Sopenharmony_ci * Finds the entry in the list corresponding to a given handle. Assumes
80262306a36Sopenharmony_ci * that the list is locked.
80362306a36Sopenharmony_ci */
80462306a36Sopenharmony_cistatic struct qp_entry *qp_list_find(struct qp_list *qp_list,
80562306a36Sopenharmony_ci				     struct vmci_handle handle)
80662306a36Sopenharmony_ci{
80762306a36Sopenharmony_ci	struct qp_entry *entry;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	if (vmci_handle_is_invalid(handle))
81062306a36Sopenharmony_ci		return NULL;
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	list_for_each_entry(entry, &qp_list->head, list_item) {
81362306a36Sopenharmony_ci		if (vmci_handle_is_equal(entry->handle, handle))
81462306a36Sopenharmony_ci			return entry;
81562306a36Sopenharmony_ci	}
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	return NULL;
81862306a36Sopenharmony_ci}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci/*
82162306a36Sopenharmony_ci * Finds the entry in the list corresponding to a given handle.
82262306a36Sopenharmony_ci */
82362306a36Sopenharmony_cistatic struct qp_guest_endpoint *
82462306a36Sopenharmony_ciqp_guest_handle_to_entry(struct vmci_handle handle)
82562306a36Sopenharmony_ci{
82662306a36Sopenharmony_ci	struct qp_guest_endpoint *entry;
82762306a36Sopenharmony_ci	struct qp_entry *qp = qp_list_find(&qp_guest_endpoints, handle);
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	entry = qp ? container_of(
83062306a36Sopenharmony_ci		qp, struct qp_guest_endpoint, qp) : NULL;
83162306a36Sopenharmony_ci	return entry;
83262306a36Sopenharmony_ci}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci/*
83562306a36Sopenharmony_ci * Finds the entry in the list corresponding to a given handle.
83662306a36Sopenharmony_ci */
83762306a36Sopenharmony_cistatic struct qp_broker_entry *
83862306a36Sopenharmony_ciqp_broker_handle_to_entry(struct vmci_handle handle)
83962306a36Sopenharmony_ci{
84062306a36Sopenharmony_ci	struct qp_broker_entry *entry;
84162306a36Sopenharmony_ci	struct qp_entry *qp = qp_list_find(&qp_broker_list, handle);
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	entry = qp ? container_of(
84462306a36Sopenharmony_ci		qp, struct qp_broker_entry, qp) : NULL;
84562306a36Sopenharmony_ci	return entry;
84662306a36Sopenharmony_ci}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci/*
84962306a36Sopenharmony_ci * Dispatches a queue pair event message directly into the local event
85062306a36Sopenharmony_ci * queue.
85162306a36Sopenharmony_ci */
85262306a36Sopenharmony_cistatic int qp_notify_peer_local(bool attach, struct vmci_handle handle)
85362306a36Sopenharmony_ci{
85462306a36Sopenharmony_ci	u32 context_id = vmci_get_context_id();
85562306a36Sopenharmony_ci	struct vmci_event_qp ev;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	memset(&ev, 0, sizeof(ev));
85862306a36Sopenharmony_ci	ev.msg.hdr.dst = vmci_make_handle(context_id, VMCI_EVENT_HANDLER);
85962306a36Sopenharmony_ci	ev.msg.hdr.src = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
86062306a36Sopenharmony_ci					  VMCI_CONTEXT_RESOURCE_ID);
86162306a36Sopenharmony_ci	ev.msg.hdr.payload_size = sizeof(ev) - sizeof(ev.msg.hdr);
86262306a36Sopenharmony_ci	ev.msg.event_data.event =
86362306a36Sopenharmony_ci	    attach ? VMCI_EVENT_QP_PEER_ATTACH : VMCI_EVENT_QP_PEER_DETACH;
86462306a36Sopenharmony_ci	ev.payload.peer_id = context_id;
86562306a36Sopenharmony_ci	ev.payload.handle = handle;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	return vmci_event_dispatch(&ev.msg.hdr);
86862306a36Sopenharmony_ci}
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci/*
87162306a36Sopenharmony_ci * Allocates and initializes a qp_guest_endpoint structure.
87262306a36Sopenharmony_ci * Allocates a queue_pair rid (and handle) iff the given entry has
87362306a36Sopenharmony_ci * an invalid handle.  0 through VMCI_RESERVED_RESOURCE_ID_MAX
87462306a36Sopenharmony_ci * are reserved handles.  Assumes that the QP list mutex is held
87562306a36Sopenharmony_ci * by the caller.
87662306a36Sopenharmony_ci */
87762306a36Sopenharmony_cistatic struct qp_guest_endpoint *
87862306a36Sopenharmony_ciqp_guest_endpoint_create(struct vmci_handle handle,
87962306a36Sopenharmony_ci			 u32 peer,
88062306a36Sopenharmony_ci			 u32 flags,
88162306a36Sopenharmony_ci			 u64 produce_size,
88262306a36Sopenharmony_ci			 u64 consume_size,
88362306a36Sopenharmony_ci			 void *produce_q,
88462306a36Sopenharmony_ci			 void *consume_q)
88562306a36Sopenharmony_ci{
88662306a36Sopenharmony_ci	int result;
88762306a36Sopenharmony_ci	struct qp_guest_endpoint *entry;
88862306a36Sopenharmony_ci	/* One page each for the queue headers. */
88962306a36Sopenharmony_ci	const u64 num_ppns = DIV_ROUND_UP(produce_size, PAGE_SIZE) +
89062306a36Sopenharmony_ci	    DIV_ROUND_UP(consume_size, PAGE_SIZE) + 2;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	if (vmci_handle_is_invalid(handle)) {
89362306a36Sopenharmony_ci		u32 context_id = vmci_get_context_id();
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci		handle = vmci_make_handle(context_id, VMCI_INVALID_ID);
89662306a36Sopenharmony_ci	}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
89962306a36Sopenharmony_ci	if (entry) {
90062306a36Sopenharmony_ci		entry->qp.peer = peer;
90162306a36Sopenharmony_ci		entry->qp.flags = flags;
90262306a36Sopenharmony_ci		entry->qp.produce_size = produce_size;
90362306a36Sopenharmony_ci		entry->qp.consume_size = consume_size;
90462306a36Sopenharmony_ci		entry->qp.ref_count = 0;
90562306a36Sopenharmony_ci		entry->num_ppns = num_ppns;
90662306a36Sopenharmony_ci		entry->produce_q = produce_q;
90762306a36Sopenharmony_ci		entry->consume_q = consume_q;
90862306a36Sopenharmony_ci		INIT_LIST_HEAD(&entry->qp.list_item);
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci		/* Add resource obj */
91162306a36Sopenharmony_ci		result = vmci_resource_add(&entry->resource,
91262306a36Sopenharmony_ci					   VMCI_RESOURCE_TYPE_QPAIR_GUEST,
91362306a36Sopenharmony_ci					   handle);
91462306a36Sopenharmony_ci		entry->qp.handle = vmci_resource_handle(&entry->resource);
91562306a36Sopenharmony_ci		if ((result != VMCI_SUCCESS) ||
91662306a36Sopenharmony_ci		    qp_list_find(&qp_guest_endpoints, entry->qp.handle)) {
91762306a36Sopenharmony_ci			pr_warn("Failed to add new resource (handle=0x%x:0x%x), error: %d",
91862306a36Sopenharmony_ci				handle.context, handle.resource, result);
91962306a36Sopenharmony_ci			kfree(entry);
92062306a36Sopenharmony_ci			entry = NULL;
92162306a36Sopenharmony_ci		}
92262306a36Sopenharmony_ci	}
92362306a36Sopenharmony_ci	return entry;
92462306a36Sopenharmony_ci}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci/*
92762306a36Sopenharmony_ci * Frees a qp_guest_endpoint structure.
92862306a36Sopenharmony_ci */
92962306a36Sopenharmony_cistatic void qp_guest_endpoint_destroy(struct qp_guest_endpoint *entry)
93062306a36Sopenharmony_ci{
93162306a36Sopenharmony_ci	qp_free_ppn_set(&entry->ppn_set);
93262306a36Sopenharmony_ci	qp_cleanup_queue_mutex(entry->produce_q, entry->consume_q);
93362306a36Sopenharmony_ci	qp_free_queue(entry->produce_q, entry->qp.produce_size);
93462306a36Sopenharmony_ci	qp_free_queue(entry->consume_q, entry->qp.consume_size);
93562306a36Sopenharmony_ci	/* Unlink from resource hash table and free callback */
93662306a36Sopenharmony_ci	vmci_resource_remove(&entry->resource);
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	kfree(entry);
93962306a36Sopenharmony_ci}
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci/*
94262306a36Sopenharmony_ci * Helper to make a queue_pairAlloc hypercall when the driver is
94362306a36Sopenharmony_ci * supporting a guest device.
94462306a36Sopenharmony_ci */
94562306a36Sopenharmony_cistatic int qp_alloc_hypercall(const struct qp_guest_endpoint *entry)
94662306a36Sopenharmony_ci{
94762306a36Sopenharmony_ci	struct vmci_qp_alloc_msg *alloc_msg;
94862306a36Sopenharmony_ci	size_t msg_size;
94962306a36Sopenharmony_ci	size_t ppn_size;
95062306a36Sopenharmony_ci	int result;
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	if (!entry || entry->num_ppns <= 2)
95362306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	ppn_size = vmci_use_ppn64() ? sizeof(u64) : sizeof(u32);
95662306a36Sopenharmony_ci	msg_size = sizeof(*alloc_msg) +
95762306a36Sopenharmony_ci	    (size_t) entry->num_ppns * ppn_size;
95862306a36Sopenharmony_ci	alloc_msg = kmalloc(msg_size, GFP_KERNEL);
95962306a36Sopenharmony_ci	if (!alloc_msg)
96062306a36Sopenharmony_ci		return VMCI_ERROR_NO_MEM;
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	alloc_msg->hdr.dst = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
96362306a36Sopenharmony_ci					      VMCI_QUEUEPAIR_ALLOC);
96462306a36Sopenharmony_ci	alloc_msg->hdr.src = VMCI_ANON_SRC_HANDLE;
96562306a36Sopenharmony_ci	alloc_msg->hdr.payload_size = msg_size - VMCI_DG_HEADERSIZE;
96662306a36Sopenharmony_ci	alloc_msg->handle = entry->qp.handle;
96762306a36Sopenharmony_ci	alloc_msg->peer = entry->qp.peer;
96862306a36Sopenharmony_ci	alloc_msg->flags = entry->qp.flags;
96962306a36Sopenharmony_ci	alloc_msg->produce_size = entry->qp.produce_size;
97062306a36Sopenharmony_ci	alloc_msg->consume_size = entry->qp.consume_size;
97162306a36Sopenharmony_ci	alloc_msg->num_ppns = entry->num_ppns;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	result = qp_populate_ppn_set((u8 *)alloc_msg + sizeof(*alloc_msg),
97462306a36Sopenharmony_ci				     &entry->ppn_set);
97562306a36Sopenharmony_ci	if (result == VMCI_SUCCESS)
97662306a36Sopenharmony_ci		result = vmci_send_datagram(&alloc_msg->hdr);
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	kfree(alloc_msg);
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	return result;
98162306a36Sopenharmony_ci}
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci/*
98462306a36Sopenharmony_ci * Helper to make a queue_pairDetach hypercall when the driver is
98562306a36Sopenharmony_ci * supporting a guest device.
98662306a36Sopenharmony_ci */
98762306a36Sopenharmony_cistatic int qp_detatch_hypercall(struct vmci_handle handle)
98862306a36Sopenharmony_ci{
98962306a36Sopenharmony_ci	struct vmci_qp_detach_msg detach_msg;
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	detach_msg.hdr.dst = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
99262306a36Sopenharmony_ci					      VMCI_QUEUEPAIR_DETACH);
99362306a36Sopenharmony_ci	detach_msg.hdr.src = VMCI_ANON_SRC_HANDLE;
99462306a36Sopenharmony_ci	detach_msg.hdr.payload_size = sizeof(handle);
99562306a36Sopenharmony_ci	detach_msg.handle = handle;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	return vmci_send_datagram(&detach_msg.hdr);
99862306a36Sopenharmony_ci}
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci/*
100162306a36Sopenharmony_ci * Adds the given entry to the list. Assumes that the list is locked.
100262306a36Sopenharmony_ci */
100362306a36Sopenharmony_cistatic void qp_list_add_entry(struct qp_list *qp_list, struct qp_entry *entry)
100462306a36Sopenharmony_ci{
100562306a36Sopenharmony_ci	if (entry)
100662306a36Sopenharmony_ci		list_add(&entry->list_item, &qp_list->head);
100762306a36Sopenharmony_ci}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci/*
101062306a36Sopenharmony_ci * Removes the given entry from the list. Assumes that the list is locked.
101162306a36Sopenharmony_ci */
101262306a36Sopenharmony_cistatic void qp_list_remove_entry(struct qp_list *qp_list,
101362306a36Sopenharmony_ci				 struct qp_entry *entry)
101462306a36Sopenharmony_ci{
101562306a36Sopenharmony_ci	if (entry)
101662306a36Sopenharmony_ci		list_del(&entry->list_item);
101762306a36Sopenharmony_ci}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci/*
102062306a36Sopenharmony_ci * Helper for VMCI queue_pair detach interface. Frees the physical
102162306a36Sopenharmony_ci * pages for the queue pair.
102262306a36Sopenharmony_ci */
102362306a36Sopenharmony_cistatic int qp_detatch_guest_work(struct vmci_handle handle)
102462306a36Sopenharmony_ci{
102562306a36Sopenharmony_ci	int result;
102662306a36Sopenharmony_ci	struct qp_guest_endpoint *entry;
102762306a36Sopenharmony_ci	u32 ref_count = ~0;	/* To avoid compiler warning below */
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	mutex_lock(&qp_guest_endpoints.mutex);
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	entry = qp_guest_handle_to_entry(handle);
103262306a36Sopenharmony_ci	if (!entry) {
103362306a36Sopenharmony_ci		mutex_unlock(&qp_guest_endpoints.mutex);
103462306a36Sopenharmony_ci		return VMCI_ERROR_NOT_FOUND;
103562306a36Sopenharmony_ci	}
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	if (entry->qp.flags & VMCI_QPFLAG_LOCAL) {
103862306a36Sopenharmony_ci		result = VMCI_SUCCESS;
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci		if (entry->qp.ref_count > 1) {
104162306a36Sopenharmony_ci			result = qp_notify_peer_local(false, handle);
104262306a36Sopenharmony_ci			/*
104362306a36Sopenharmony_ci			 * We can fail to notify a local queuepair
104462306a36Sopenharmony_ci			 * because we can't allocate.  We still want
104562306a36Sopenharmony_ci			 * to release the entry if that happens, so
104662306a36Sopenharmony_ci			 * don't bail out yet.
104762306a36Sopenharmony_ci			 */
104862306a36Sopenharmony_ci		}
104962306a36Sopenharmony_ci	} else {
105062306a36Sopenharmony_ci		result = qp_detatch_hypercall(handle);
105162306a36Sopenharmony_ci		if (result < VMCI_SUCCESS) {
105262306a36Sopenharmony_ci			/*
105362306a36Sopenharmony_ci			 * We failed to notify a non-local queuepair.
105462306a36Sopenharmony_ci			 * That other queuepair might still be
105562306a36Sopenharmony_ci			 * accessing the shared memory, so don't
105662306a36Sopenharmony_ci			 * release the entry yet.  It will get cleaned
105762306a36Sopenharmony_ci			 * up by VMCIqueue_pair_Exit() if necessary
105862306a36Sopenharmony_ci			 * (assuming we are going away, otherwise why
105962306a36Sopenharmony_ci			 * did this fail?).
106062306a36Sopenharmony_ci			 */
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci			mutex_unlock(&qp_guest_endpoints.mutex);
106362306a36Sopenharmony_ci			return result;
106462306a36Sopenharmony_ci		}
106562306a36Sopenharmony_ci	}
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	/*
106862306a36Sopenharmony_ci	 * If we get here then we either failed to notify a local queuepair, or
106962306a36Sopenharmony_ci	 * we succeeded in all cases.  Release the entry if required.
107062306a36Sopenharmony_ci	 */
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	entry->qp.ref_count--;
107362306a36Sopenharmony_ci	if (entry->qp.ref_count == 0)
107462306a36Sopenharmony_ci		qp_list_remove_entry(&qp_guest_endpoints, &entry->qp);
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	/* If we didn't remove the entry, this could change once we unlock. */
107762306a36Sopenharmony_ci	if (entry)
107862306a36Sopenharmony_ci		ref_count = entry->qp.ref_count;
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	mutex_unlock(&qp_guest_endpoints.mutex);
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	if (ref_count == 0)
108362306a36Sopenharmony_ci		qp_guest_endpoint_destroy(entry);
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	return result;
108662306a36Sopenharmony_ci}
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci/*
108962306a36Sopenharmony_ci * This functions handles the actual allocation of a VMCI queue
109062306a36Sopenharmony_ci * pair guest endpoint. Allocates physical pages for the queue
109162306a36Sopenharmony_ci * pair. It makes OS dependent calls through generic wrappers.
109262306a36Sopenharmony_ci */
109362306a36Sopenharmony_cistatic int qp_alloc_guest_work(struct vmci_handle *handle,
109462306a36Sopenharmony_ci			       struct vmci_queue **produce_q,
109562306a36Sopenharmony_ci			       u64 produce_size,
109662306a36Sopenharmony_ci			       struct vmci_queue **consume_q,
109762306a36Sopenharmony_ci			       u64 consume_size,
109862306a36Sopenharmony_ci			       u32 peer,
109962306a36Sopenharmony_ci			       u32 flags,
110062306a36Sopenharmony_ci			       u32 priv_flags)
110162306a36Sopenharmony_ci{
110262306a36Sopenharmony_ci	const u64 num_produce_pages =
110362306a36Sopenharmony_ci	    DIV_ROUND_UP(produce_size, PAGE_SIZE) + 1;
110462306a36Sopenharmony_ci	const u64 num_consume_pages =
110562306a36Sopenharmony_ci	    DIV_ROUND_UP(consume_size, PAGE_SIZE) + 1;
110662306a36Sopenharmony_ci	void *my_produce_q = NULL;
110762306a36Sopenharmony_ci	void *my_consume_q = NULL;
110862306a36Sopenharmony_ci	int result;
110962306a36Sopenharmony_ci	struct qp_guest_endpoint *queue_pair_entry = NULL;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	if (priv_flags != VMCI_NO_PRIVILEGE_FLAGS)
111262306a36Sopenharmony_ci		return VMCI_ERROR_NO_ACCESS;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	mutex_lock(&qp_guest_endpoints.mutex);
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	queue_pair_entry = qp_guest_handle_to_entry(*handle);
111762306a36Sopenharmony_ci	if (queue_pair_entry) {
111862306a36Sopenharmony_ci		if (queue_pair_entry->qp.flags & VMCI_QPFLAG_LOCAL) {
111962306a36Sopenharmony_ci			/* Local attach case. */
112062306a36Sopenharmony_ci			if (queue_pair_entry->qp.ref_count > 1) {
112162306a36Sopenharmony_ci				pr_devel("Error attempting to attach more than once\n");
112262306a36Sopenharmony_ci				result = VMCI_ERROR_UNAVAILABLE;
112362306a36Sopenharmony_ci				goto error_keep_entry;
112462306a36Sopenharmony_ci			}
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci			if (queue_pair_entry->qp.produce_size != consume_size ||
112762306a36Sopenharmony_ci			    queue_pair_entry->qp.consume_size !=
112862306a36Sopenharmony_ci			    produce_size ||
112962306a36Sopenharmony_ci			    queue_pair_entry->qp.flags !=
113062306a36Sopenharmony_ci			    (flags & ~VMCI_QPFLAG_ATTACH_ONLY)) {
113162306a36Sopenharmony_ci				pr_devel("Error mismatched queue pair in local attach\n");
113262306a36Sopenharmony_ci				result = VMCI_ERROR_QUEUEPAIR_MISMATCH;
113362306a36Sopenharmony_ci				goto error_keep_entry;
113462306a36Sopenharmony_ci			}
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci			/*
113762306a36Sopenharmony_ci			 * Do a local attach.  We swap the consume and
113862306a36Sopenharmony_ci			 * produce queues for the attacher and deliver
113962306a36Sopenharmony_ci			 * an attach event.
114062306a36Sopenharmony_ci			 */
114162306a36Sopenharmony_ci			result = qp_notify_peer_local(true, *handle);
114262306a36Sopenharmony_ci			if (result < VMCI_SUCCESS)
114362306a36Sopenharmony_ci				goto error_keep_entry;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci			my_produce_q = queue_pair_entry->consume_q;
114662306a36Sopenharmony_ci			my_consume_q = queue_pair_entry->produce_q;
114762306a36Sopenharmony_ci			goto out;
114862306a36Sopenharmony_ci		}
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci		result = VMCI_ERROR_ALREADY_EXISTS;
115162306a36Sopenharmony_ci		goto error_keep_entry;
115262306a36Sopenharmony_ci	}
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	my_produce_q = qp_alloc_queue(produce_size, flags);
115562306a36Sopenharmony_ci	if (!my_produce_q) {
115662306a36Sopenharmony_ci		pr_warn("Error allocating pages for produce queue\n");
115762306a36Sopenharmony_ci		result = VMCI_ERROR_NO_MEM;
115862306a36Sopenharmony_ci		goto error;
115962306a36Sopenharmony_ci	}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	my_consume_q = qp_alloc_queue(consume_size, flags);
116262306a36Sopenharmony_ci	if (!my_consume_q) {
116362306a36Sopenharmony_ci		pr_warn("Error allocating pages for consume queue\n");
116462306a36Sopenharmony_ci		result = VMCI_ERROR_NO_MEM;
116562306a36Sopenharmony_ci		goto error;
116662306a36Sopenharmony_ci	}
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	queue_pair_entry = qp_guest_endpoint_create(*handle, peer, flags,
116962306a36Sopenharmony_ci						    produce_size, consume_size,
117062306a36Sopenharmony_ci						    my_produce_q, my_consume_q);
117162306a36Sopenharmony_ci	if (!queue_pair_entry) {
117262306a36Sopenharmony_ci		pr_warn("Error allocating memory in %s\n", __func__);
117362306a36Sopenharmony_ci		result = VMCI_ERROR_NO_MEM;
117462306a36Sopenharmony_ci		goto error;
117562306a36Sopenharmony_ci	}
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	result = qp_alloc_ppn_set(my_produce_q, num_produce_pages, my_consume_q,
117862306a36Sopenharmony_ci				  num_consume_pages,
117962306a36Sopenharmony_ci				  &queue_pair_entry->ppn_set);
118062306a36Sopenharmony_ci	if (result < VMCI_SUCCESS) {
118162306a36Sopenharmony_ci		pr_warn("qp_alloc_ppn_set failed\n");
118262306a36Sopenharmony_ci		goto error;
118362306a36Sopenharmony_ci	}
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	/*
118662306a36Sopenharmony_ci	 * It's only necessary to notify the host if this queue pair will be
118762306a36Sopenharmony_ci	 * attached to from another context.
118862306a36Sopenharmony_ci	 */
118962306a36Sopenharmony_ci	if (queue_pair_entry->qp.flags & VMCI_QPFLAG_LOCAL) {
119062306a36Sopenharmony_ci		/* Local create case. */
119162306a36Sopenharmony_ci		u32 context_id = vmci_get_context_id();
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci		/*
119462306a36Sopenharmony_ci		 * Enforce similar checks on local queue pairs as we
119562306a36Sopenharmony_ci		 * do for regular ones.  The handle's context must
119662306a36Sopenharmony_ci		 * match the creator or attacher context id (here they
119762306a36Sopenharmony_ci		 * are both the current context id) and the
119862306a36Sopenharmony_ci		 * attach-only flag cannot exist during create.  We
119962306a36Sopenharmony_ci		 * also ensure specified peer is this context or an
120062306a36Sopenharmony_ci		 * invalid one.
120162306a36Sopenharmony_ci		 */
120262306a36Sopenharmony_ci		if (queue_pair_entry->qp.handle.context != context_id ||
120362306a36Sopenharmony_ci		    (queue_pair_entry->qp.peer != VMCI_INVALID_ID &&
120462306a36Sopenharmony_ci		     queue_pair_entry->qp.peer != context_id)) {
120562306a36Sopenharmony_ci			result = VMCI_ERROR_NO_ACCESS;
120662306a36Sopenharmony_ci			goto error;
120762306a36Sopenharmony_ci		}
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci		if (queue_pair_entry->qp.flags & VMCI_QPFLAG_ATTACH_ONLY) {
121062306a36Sopenharmony_ci			result = VMCI_ERROR_NOT_FOUND;
121162306a36Sopenharmony_ci			goto error;
121262306a36Sopenharmony_ci		}
121362306a36Sopenharmony_ci	} else {
121462306a36Sopenharmony_ci		result = qp_alloc_hypercall(queue_pair_entry);
121562306a36Sopenharmony_ci		if (result < VMCI_SUCCESS) {
121662306a36Sopenharmony_ci			pr_devel("qp_alloc_hypercall result = %d\n", result);
121762306a36Sopenharmony_ci			goto error;
121862306a36Sopenharmony_ci		}
121962306a36Sopenharmony_ci	}
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	qp_init_queue_mutex((struct vmci_queue *)my_produce_q,
122262306a36Sopenharmony_ci			    (struct vmci_queue *)my_consume_q);
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	qp_list_add_entry(&qp_guest_endpoints, &queue_pair_entry->qp);
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci out:
122762306a36Sopenharmony_ci	queue_pair_entry->qp.ref_count++;
122862306a36Sopenharmony_ci	*handle = queue_pair_entry->qp.handle;
122962306a36Sopenharmony_ci	*produce_q = (struct vmci_queue *)my_produce_q;
123062306a36Sopenharmony_ci	*consume_q = (struct vmci_queue *)my_consume_q;
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	/*
123362306a36Sopenharmony_ci	 * We should initialize the queue pair header pages on a local
123462306a36Sopenharmony_ci	 * queue pair create.  For non-local queue pairs, the
123562306a36Sopenharmony_ci	 * hypervisor initializes the header pages in the create step.
123662306a36Sopenharmony_ci	 */
123762306a36Sopenharmony_ci	if ((queue_pair_entry->qp.flags & VMCI_QPFLAG_LOCAL) &&
123862306a36Sopenharmony_ci	    queue_pair_entry->qp.ref_count == 1) {
123962306a36Sopenharmony_ci		vmci_q_header_init((*produce_q)->q_header, *handle);
124062306a36Sopenharmony_ci		vmci_q_header_init((*consume_q)->q_header, *handle);
124162306a36Sopenharmony_ci	}
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	mutex_unlock(&qp_guest_endpoints.mutex);
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	return VMCI_SUCCESS;
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci error:
124862306a36Sopenharmony_ci	mutex_unlock(&qp_guest_endpoints.mutex);
124962306a36Sopenharmony_ci	if (queue_pair_entry) {
125062306a36Sopenharmony_ci		/* The queues will be freed inside the destroy routine. */
125162306a36Sopenharmony_ci		qp_guest_endpoint_destroy(queue_pair_entry);
125262306a36Sopenharmony_ci	} else {
125362306a36Sopenharmony_ci		qp_free_queue(my_produce_q, produce_size);
125462306a36Sopenharmony_ci		qp_free_queue(my_consume_q, consume_size);
125562306a36Sopenharmony_ci	}
125662306a36Sopenharmony_ci	return result;
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci error_keep_entry:
125962306a36Sopenharmony_ci	/* This path should only be used when an existing entry was found. */
126062306a36Sopenharmony_ci	mutex_unlock(&qp_guest_endpoints.mutex);
126162306a36Sopenharmony_ci	return result;
126262306a36Sopenharmony_ci}
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci/*
126562306a36Sopenharmony_ci * The first endpoint issuing a queue pair allocation will create the state
126662306a36Sopenharmony_ci * of the queue pair in the queue pair broker.
126762306a36Sopenharmony_ci *
126862306a36Sopenharmony_ci * If the creator is a guest, it will associate a VMX virtual address range
126962306a36Sopenharmony_ci * with the queue pair as specified by the page_store. For compatibility with
127062306a36Sopenharmony_ci * older VMX'en, that would use a separate step to set the VMX virtual
127162306a36Sopenharmony_ci * address range, the virtual address range can be registered later using
127262306a36Sopenharmony_ci * vmci_qp_broker_set_page_store. In that case, a page_store of NULL should be
127362306a36Sopenharmony_ci * used.
127462306a36Sopenharmony_ci *
127562306a36Sopenharmony_ci * If the creator is the host, a page_store of NULL should be used as well,
127662306a36Sopenharmony_ci * since the host is not able to supply a page store for the queue pair.
127762306a36Sopenharmony_ci *
127862306a36Sopenharmony_ci * For older VMX and host callers, the queue pair will be created in the
127962306a36Sopenharmony_ci * VMCIQPB_CREATED_NO_MEM state, and for current VMX callers, it will be
128062306a36Sopenharmony_ci * created in VMCOQPB_CREATED_MEM state.
128162306a36Sopenharmony_ci */
128262306a36Sopenharmony_cistatic int qp_broker_create(struct vmci_handle handle,
128362306a36Sopenharmony_ci			    u32 peer,
128462306a36Sopenharmony_ci			    u32 flags,
128562306a36Sopenharmony_ci			    u32 priv_flags,
128662306a36Sopenharmony_ci			    u64 produce_size,
128762306a36Sopenharmony_ci			    u64 consume_size,
128862306a36Sopenharmony_ci			    struct vmci_qp_page_store *page_store,
128962306a36Sopenharmony_ci			    struct vmci_ctx *context,
129062306a36Sopenharmony_ci			    vmci_event_release_cb wakeup_cb,
129162306a36Sopenharmony_ci			    void *client_data, struct qp_broker_entry **ent)
129262306a36Sopenharmony_ci{
129362306a36Sopenharmony_ci	struct qp_broker_entry *entry = NULL;
129462306a36Sopenharmony_ci	const u32 context_id = vmci_ctx_get_id(context);
129562306a36Sopenharmony_ci	bool is_local = flags & VMCI_QPFLAG_LOCAL;
129662306a36Sopenharmony_ci	int result;
129762306a36Sopenharmony_ci	u64 guest_produce_size;
129862306a36Sopenharmony_ci	u64 guest_consume_size;
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	/* Do not create if the caller asked not to. */
130162306a36Sopenharmony_ci	if (flags & VMCI_QPFLAG_ATTACH_ONLY)
130262306a36Sopenharmony_ci		return VMCI_ERROR_NOT_FOUND;
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	/*
130562306a36Sopenharmony_ci	 * Creator's context ID should match handle's context ID or the creator
130662306a36Sopenharmony_ci	 * must allow the context in handle's context ID as the "peer".
130762306a36Sopenharmony_ci	 */
130862306a36Sopenharmony_ci	if (handle.context != context_id && handle.context != peer)
130962306a36Sopenharmony_ci		return VMCI_ERROR_NO_ACCESS;
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	if (VMCI_CONTEXT_IS_VM(context_id) && VMCI_CONTEXT_IS_VM(peer))
131262306a36Sopenharmony_ci		return VMCI_ERROR_DST_UNREACHABLE;
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	/*
131562306a36Sopenharmony_ci	 * Creator's context ID for local queue pairs should match the
131662306a36Sopenharmony_ci	 * peer, if a peer is specified.
131762306a36Sopenharmony_ci	 */
131862306a36Sopenharmony_ci	if (is_local && peer != VMCI_INVALID_ID && context_id != peer)
131962306a36Sopenharmony_ci		return VMCI_ERROR_NO_ACCESS;
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
132262306a36Sopenharmony_ci	if (!entry)
132362306a36Sopenharmony_ci		return VMCI_ERROR_NO_MEM;
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	if (vmci_ctx_get_id(context) == VMCI_HOST_CONTEXT_ID && !is_local) {
132662306a36Sopenharmony_ci		/*
132762306a36Sopenharmony_ci		 * The queue pair broker entry stores values from the guest
132862306a36Sopenharmony_ci		 * point of view, so a creating host side endpoint should swap
132962306a36Sopenharmony_ci		 * produce and consume values -- unless it is a local queue
133062306a36Sopenharmony_ci		 * pair, in which case no swapping is necessary, since the local
133162306a36Sopenharmony_ci		 * attacher will swap queues.
133262306a36Sopenharmony_ci		 */
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci		guest_produce_size = consume_size;
133562306a36Sopenharmony_ci		guest_consume_size = produce_size;
133662306a36Sopenharmony_ci	} else {
133762306a36Sopenharmony_ci		guest_produce_size = produce_size;
133862306a36Sopenharmony_ci		guest_consume_size = consume_size;
133962306a36Sopenharmony_ci	}
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	entry->qp.handle = handle;
134262306a36Sopenharmony_ci	entry->qp.peer = peer;
134362306a36Sopenharmony_ci	entry->qp.flags = flags;
134462306a36Sopenharmony_ci	entry->qp.produce_size = guest_produce_size;
134562306a36Sopenharmony_ci	entry->qp.consume_size = guest_consume_size;
134662306a36Sopenharmony_ci	entry->qp.ref_count = 1;
134762306a36Sopenharmony_ci	entry->create_id = context_id;
134862306a36Sopenharmony_ci	entry->attach_id = VMCI_INVALID_ID;
134962306a36Sopenharmony_ci	entry->state = VMCIQPB_NEW;
135062306a36Sopenharmony_ci	entry->require_trusted_attach =
135162306a36Sopenharmony_ci	    !!(context->priv_flags & VMCI_PRIVILEGE_FLAG_RESTRICTED);
135262306a36Sopenharmony_ci	entry->created_by_trusted =
135362306a36Sopenharmony_ci	    !!(priv_flags & VMCI_PRIVILEGE_FLAG_TRUSTED);
135462306a36Sopenharmony_ci	entry->vmci_page_files = false;
135562306a36Sopenharmony_ci	entry->wakeup_cb = wakeup_cb;
135662306a36Sopenharmony_ci	entry->client_data = client_data;
135762306a36Sopenharmony_ci	entry->produce_q = qp_host_alloc_queue(guest_produce_size);
135862306a36Sopenharmony_ci	if (entry->produce_q == NULL) {
135962306a36Sopenharmony_ci		result = VMCI_ERROR_NO_MEM;
136062306a36Sopenharmony_ci		goto error;
136162306a36Sopenharmony_ci	}
136262306a36Sopenharmony_ci	entry->consume_q = qp_host_alloc_queue(guest_consume_size);
136362306a36Sopenharmony_ci	if (entry->consume_q == NULL) {
136462306a36Sopenharmony_ci		result = VMCI_ERROR_NO_MEM;
136562306a36Sopenharmony_ci		goto error;
136662306a36Sopenharmony_ci	}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	qp_init_queue_mutex(entry->produce_q, entry->consume_q);
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	INIT_LIST_HEAD(&entry->qp.list_item);
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	if (is_local) {
137362306a36Sopenharmony_ci		u8 *tmp;
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci		entry->local_mem = kcalloc(QPE_NUM_PAGES(entry->qp),
137662306a36Sopenharmony_ci					   PAGE_SIZE, GFP_KERNEL);
137762306a36Sopenharmony_ci		if (entry->local_mem == NULL) {
137862306a36Sopenharmony_ci			result = VMCI_ERROR_NO_MEM;
137962306a36Sopenharmony_ci			goto error;
138062306a36Sopenharmony_ci		}
138162306a36Sopenharmony_ci		entry->state = VMCIQPB_CREATED_MEM;
138262306a36Sopenharmony_ci		entry->produce_q->q_header = entry->local_mem;
138362306a36Sopenharmony_ci		tmp = (u8 *)entry->local_mem + PAGE_SIZE *
138462306a36Sopenharmony_ci		    (DIV_ROUND_UP(entry->qp.produce_size, PAGE_SIZE) + 1);
138562306a36Sopenharmony_ci		entry->consume_q->q_header = (struct vmci_queue_header *)tmp;
138662306a36Sopenharmony_ci	} else if (page_store) {
138762306a36Sopenharmony_ci		/*
138862306a36Sopenharmony_ci		 * The VMX already initialized the queue pair headers, so no
138962306a36Sopenharmony_ci		 * need for the kernel side to do that.
139062306a36Sopenharmony_ci		 */
139162306a36Sopenharmony_ci		result = qp_host_register_user_memory(page_store,
139262306a36Sopenharmony_ci						      entry->produce_q,
139362306a36Sopenharmony_ci						      entry->consume_q);
139462306a36Sopenharmony_ci		if (result < VMCI_SUCCESS)
139562306a36Sopenharmony_ci			goto error;
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci		entry->state = VMCIQPB_CREATED_MEM;
139862306a36Sopenharmony_ci	} else {
139962306a36Sopenharmony_ci		/*
140062306a36Sopenharmony_ci		 * A create without a page_store may be either a host
140162306a36Sopenharmony_ci		 * side create (in which case we are waiting for the
140262306a36Sopenharmony_ci		 * guest side to supply the memory) or an old style
140362306a36Sopenharmony_ci		 * queue pair create (in which case we will expect a
140462306a36Sopenharmony_ci		 * set page store call as the next step).
140562306a36Sopenharmony_ci		 */
140662306a36Sopenharmony_ci		entry->state = VMCIQPB_CREATED_NO_MEM;
140762306a36Sopenharmony_ci	}
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	qp_list_add_entry(&qp_broker_list, &entry->qp);
141062306a36Sopenharmony_ci	if (ent != NULL)
141162306a36Sopenharmony_ci		*ent = entry;
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	/* Add to resource obj */
141462306a36Sopenharmony_ci	result = vmci_resource_add(&entry->resource,
141562306a36Sopenharmony_ci				   VMCI_RESOURCE_TYPE_QPAIR_HOST,
141662306a36Sopenharmony_ci				   handle);
141762306a36Sopenharmony_ci	if (result != VMCI_SUCCESS) {
141862306a36Sopenharmony_ci		pr_warn("Failed to add new resource (handle=0x%x:0x%x), error: %d",
141962306a36Sopenharmony_ci			handle.context, handle.resource, result);
142062306a36Sopenharmony_ci		goto error;
142162306a36Sopenharmony_ci	}
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	entry->qp.handle = vmci_resource_handle(&entry->resource);
142462306a36Sopenharmony_ci	if (is_local) {
142562306a36Sopenharmony_ci		vmci_q_header_init(entry->produce_q->q_header,
142662306a36Sopenharmony_ci				   entry->qp.handle);
142762306a36Sopenharmony_ci		vmci_q_header_init(entry->consume_q->q_header,
142862306a36Sopenharmony_ci				   entry->qp.handle);
142962306a36Sopenharmony_ci	}
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	vmci_ctx_qp_create(context, entry->qp.handle);
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci	return VMCI_SUCCESS;
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci error:
143662306a36Sopenharmony_ci	if (entry != NULL) {
143762306a36Sopenharmony_ci		qp_host_free_queue(entry->produce_q, guest_produce_size);
143862306a36Sopenharmony_ci		qp_host_free_queue(entry->consume_q, guest_consume_size);
143962306a36Sopenharmony_ci		kfree(entry);
144062306a36Sopenharmony_ci	}
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	return result;
144362306a36Sopenharmony_ci}
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci/*
144662306a36Sopenharmony_ci * Enqueues an event datagram to notify the peer VM attached to
144762306a36Sopenharmony_ci * the given queue pair handle about attach/detach event by the
144862306a36Sopenharmony_ci * given VM.  Returns Payload size of datagram enqueued on
144962306a36Sopenharmony_ci * success, error code otherwise.
145062306a36Sopenharmony_ci */
145162306a36Sopenharmony_cistatic int qp_notify_peer(bool attach,
145262306a36Sopenharmony_ci			  struct vmci_handle handle,
145362306a36Sopenharmony_ci			  u32 my_id,
145462306a36Sopenharmony_ci			  u32 peer_id)
145562306a36Sopenharmony_ci{
145662306a36Sopenharmony_ci	int rv;
145762306a36Sopenharmony_ci	struct vmci_event_qp ev;
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	if (vmci_handle_is_invalid(handle) || my_id == VMCI_INVALID_ID ||
146062306a36Sopenharmony_ci	    peer_id == VMCI_INVALID_ID)
146162306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	/*
146462306a36Sopenharmony_ci	 * In vmci_ctx_enqueue_datagram() we enforce the upper limit on
146562306a36Sopenharmony_ci	 * number of pending events from the hypervisor to a given VM
146662306a36Sopenharmony_ci	 * otherwise a rogue VM could do an arbitrary number of attach
146762306a36Sopenharmony_ci	 * and detach operations causing memory pressure in the host
146862306a36Sopenharmony_ci	 * kernel.
146962306a36Sopenharmony_ci	 */
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	memset(&ev, 0, sizeof(ev));
147262306a36Sopenharmony_ci	ev.msg.hdr.dst = vmci_make_handle(peer_id, VMCI_EVENT_HANDLER);
147362306a36Sopenharmony_ci	ev.msg.hdr.src = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
147462306a36Sopenharmony_ci					  VMCI_CONTEXT_RESOURCE_ID);
147562306a36Sopenharmony_ci	ev.msg.hdr.payload_size = sizeof(ev) - sizeof(ev.msg.hdr);
147662306a36Sopenharmony_ci	ev.msg.event_data.event = attach ?
147762306a36Sopenharmony_ci	    VMCI_EVENT_QP_PEER_ATTACH : VMCI_EVENT_QP_PEER_DETACH;
147862306a36Sopenharmony_ci	ev.payload.handle = handle;
147962306a36Sopenharmony_ci	ev.payload.peer_id = my_id;
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	rv = vmci_datagram_dispatch(VMCI_HYPERVISOR_CONTEXT_ID,
148262306a36Sopenharmony_ci				    &ev.msg.hdr, false);
148362306a36Sopenharmony_ci	if (rv < VMCI_SUCCESS)
148462306a36Sopenharmony_ci		pr_warn("Failed to enqueue queue_pair %s event datagram for context (ID=0x%x)\n",
148562306a36Sopenharmony_ci			attach ? "ATTACH" : "DETACH", peer_id);
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	return rv;
148862306a36Sopenharmony_ci}
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci/*
149162306a36Sopenharmony_ci * The second endpoint issuing a queue pair allocation will attach to
149262306a36Sopenharmony_ci * the queue pair registered with the queue pair broker.
149362306a36Sopenharmony_ci *
149462306a36Sopenharmony_ci * If the attacher is a guest, it will associate a VMX virtual address
149562306a36Sopenharmony_ci * range with the queue pair as specified by the page_store. At this
149662306a36Sopenharmony_ci * point, the already attach host endpoint may start using the queue
149762306a36Sopenharmony_ci * pair, and an attach event is sent to it. For compatibility with
149862306a36Sopenharmony_ci * older VMX'en, that used a separate step to set the VMX virtual
149962306a36Sopenharmony_ci * address range, the virtual address range can be registered later
150062306a36Sopenharmony_ci * using vmci_qp_broker_set_page_store. In that case, a page_store of
150162306a36Sopenharmony_ci * NULL should be used, and the attach event will be generated once
150262306a36Sopenharmony_ci * the actual page store has been set.
150362306a36Sopenharmony_ci *
150462306a36Sopenharmony_ci * If the attacher is the host, a page_store of NULL should be used as
150562306a36Sopenharmony_ci * well, since the page store information is already set by the guest.
150662306a36Sopenharmony_ci *
150762306a36Sopenharmony_ci * For new VMX and host callers, the queue pair will be moved to the
150862306a36Sopenharmony_ci * VMCIQPB_ATTACHED_MEM state, and for older VMX callers, it will be
150962306a36Sopenharmony_ci * moved to the VMCOQPB_ATTACHED_NO_MEM state.
151062306a36Sopenharmony_ci */
151162306a36Sopenharmony_cistatic int qp_broker_attach(struct qp_broker_entry *entry,
151262306a36Sopenharmony_ci			    u32 peer,
151362306a36Sopenharmony_ci			    u32 flags,
151462306a36Sopenharmony_ci			    u32 priv_flags,
151562306a36Sopenharmony_ci			    u64 produce_size,
151662306a36Sopenharmony_ci			    u64 consume_size,
151762306a36Sopenharmony_ci			    struct vmci_qp_page_store *page_store,
151862306a36Sopenharmony_ci			    struct vmci_ctx *context,
151962306a36Sopenharmony_ci			    vmci_event_release_cb wakeup_cb,
152062306a36Sopenharmony_ci			    void *client_data,
152162306a36Sopenharmony_ci			    struct qp_broker_entry **ent)
152262306a36Sopenharmony_ci{
152362306a36Sopenharmony_ci	const u32 context_id = vmci_ctx_get_id(context);
152462306a36Sopenharmony_ci	bool is_local = flags & VMCI_QPFLAG_LOCAL;
152562306a36Sopenharmony_ci	int result;
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	if (entry->state != VMCIQPB_CREATED_NO_MEM &&
152862306a36Sopenharmony_ci	    entry->state != VMCIQPB_CREATED_MEM)
152962306a36Sopenharmony_ci		return VMCI_ERROR_UNAVAILABLE;
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	if (is_local) {
153262306a36Sopenharmony_ci		if (!(entry->qp.flags & VMCI_QPFLAG_LOCAL) ||
153362306a36Sopenharmony_ci		    context_id != entry->create_id) {
153462306a36Sopenharmony_ci			return VMCI_ERROR_INVALID_ARGS;
153562306a36Sopenharmony_ci		}
153662306a36Sopenharmony_ci	} else if (context_id == entry->create_id ||
153762306a36Sopenharmony_ci		   context_id == entry->attach_id) {
153862306a36Sopenharmony_ci		return VMCI_ERROR_ALREADY_EXISTS;
153962306a36Sopenharmony_ci	}
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	if (VMCI_CONTEXT_IS_VM(context_id) &&
154262306a36Sopenharmony_ci	    VMCI_CONTEXT_IS_VM(entry->create_id))
154362306a36Sopenharmony_ci		return VMCI_ERROR_DST_UNREACHABLE;
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	/*
154662306a36Sopenharmony_ci	 * If we are attaching from a restricted context then the queuepair
154762306a36Sopenharmony_ci	 * must have been created by a trusted endpoint.
154862306a36Sopenharmony_ci	 */
154962306a36Sopenharmony_ci	if ((context->priv_flags & VMCI_PRIVILEGE_FLAG_RESTRICTED) &&
155062306a36Sopenharmony_ci	    !entry->created_by_trusted)
155162306a36Sopenharmony_ci		return VMCI_ERROR_NO_ACCESS;
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci	/*
155462306a36Sopenharmony_ci	 * If we are attaching to a queuepair that was created by a restricted
155562306a36Sopenharmony_ci	 * context then we must be trusted.
155662306a36Sopenharmony_ci	 */
155762306a36Sopenharmony_ci	if (entry->require_trusted_attach &&
155862306a36Sopenharmony_ci	    (!(priv_flags & VMCI_PRIVILEGE_FLAG_TRUSTED)))
155962306a36Sopenharmony_ci		return VMCI_ERROR_NO_ACCESS;
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci	/*
156262306a36Sopenharmony_ci	 * If the creator specifies VMCI_INVALID_ID in "peer" field, access
156362306a36Sopenharmony_ci	 * control check is not performed.
156462306a36Sopenharmony_ci	 */
156562306a36Sopenharmony_ci	if (entry->qp.peer != VMCI_INVALID_ID && entry->qp.peer != context_id)
156662306a36Sopenharmony_ci		return VMCI_ERROR_NO_ACCESS;
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	if (entry->create_id == VMCI_HOST_CONTEXT_ID) {
156962306a36Sopenharmony_ci		/*
157062306a36Sopenharmony_ci		 * Do not attach if the caller doesn't support Host Queue Pairs
157162306a36Sopenharmony_ci		 * and a host created this queue pair.
157262306a36Sopenharmony_ci		 */
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci		if (!vmci_ctx_supports_host_qp(context))
157562306a36Sopenharmony_ci			return VMCI_ERROR_INVALID_RESOURCE;
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci	} else if (context_id == VMCI_HOST_CONTEXT_ID) {
157862306a36Sopenharmony_ci		struct vmci_ctx *create_context;
157962306a36Sopenharmony_ci		bool supports_host_qp;
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci		/*
158262306a36Sopenharmony_ci		 * Do not attach a host to a user created queue pair if that
158362306a36Sopenharmony_ci		 * user doesn't support host queue pair end points.
158462306a36Sopenharmony_ci		 */
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci		create_context = vmci_ctx_get(entry->create_id);
158762306a36Sopenharmony_ci		supports_host_qp = vmci_ctx_supports_host_qp(create_context);
158862306a36Sopenharmony_ci		vmci_ctx_put(create_context);
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci		if (!supports_host_qp)
159162306a36Sopenharmony_ci			return VMCI_ERROR_INVALID_RESOURCE;
159262306a36Sopenharmony_ci	}
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	if ((entry->qp.flags & ~VMCI_QP_ASYMM) != (flags & ~VMCI_QP_ASYMM_PEER))
159562306a36Sopenharmony_ci		return VMCI_ERROR_QUEUEPAIR_MISMATCH;
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci	if (context_id != VMCI_HOST_CONTEXT_ID) {
159862306a36Sopenharmony_ci		/*
159962306a36Sopenharmony_ci		 * The queue pair broker entry stores values from the guest
160062306a36Sopenharmony_ci		 * point of view, so an attaching guest should match the values
160162306a36Sopenharmony_ci		 * stored in the entry.
160262306a36Sopenharmony_ci		 */
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ci		if (entry->qp.produce_size != produce_size ||
160562306a36Sopenharmony_ci		    entry->qp.consume_size != consume_size) {
160662306a36Sopenharmony_ci			return VMCI_ERROR_QUEUEPAIR_MISMATCH;
160762306a36Sopenharmony_ci		}
160862306a36Sopenharmony_ci	} else if (entry->qp.produce_size != consume_size ||
160962306a36Sopenharmony_ci		   entry->qp.consume_size != produce_size) {
161062306a36Sopenharmony_ci		return VMCI_ERROR_QUEUEPAIR_MISMATCH;
161162306a36Sopenharmony_ci	}
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	if (context_id != VMCI_HOST_CONTEXT_ID) {
161462306a36Sopenharmony_ci		/*
161562306a36Sopenharmony_ci		 * If a guest attached to a queue pair, it will supply
161662306a36Sopenharmony_ci		 * the backing memory.  If this is a pre NOVMVM vmx,
161762306a36Sopenharmony_ci		 * the backing memory will be supplied by calling
161862306a36Sopenharmony_ci		 * vmci_qp_broker_set_page_store() following the
161962306a36Sopenharmony_ci		 * return of the vmci_qp_broker_alloc() call. If it is
162062306a36Sopenharmony_ci		 * a vmx of version NOVMVM or later, the page store
162162306a36Sopenharmony_ci		 * must be supplied as part of the
162262306a36Sopenharmony_ci		 * vmci_qp_broker_alloc call.  Under all circumstances
162362306a36Sopenharmony_ci		 * must the initially created queue pair not have any
162462306a36Sopenharmony_ci		 * memory associated with it already.
162562306a36Sopenharmony_ci		 */
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci		if (entry->state != VMCIQPB_CREATED_NO_MEM)
162862306a36Sopenharmony_ci			return VMCI_ERROR_INVALID_ARGS;
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci		if (page_store != NULL) {
163162306a36Sopenharmony_ci			/*
163262306a36Sopenharmony_ci			 * Patch up host state to point to guest
163362306a36Sopenharmony_ci			 * supplied memory. The VMX already
163462306a36Sopenharmony_ci			 * initialized the queue pair headers, so no
163562306a36Sopenharmony_ci			 * need for the kernel side to do that.
163662306a36Sopenharmony_ci			 */
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci			result = qp_host_register_user_memory(page_store,
163962306a36Sopenharmony_ci							      entry->produce_q,
164062306a36Sopenharmony_ci							      entry->consume_q);
164162306a36Sopenharmony_ci			if (result < VMCI_SUCCESS)
164262306a36Sopenharmony_ci				return result;
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci			entry->state = VMCIQPB_ATTACHED_MEM;
164562306a36Sopenharmony_ci		} else {
164662306a36Sopenharmony_ci			entry->state = VMCIQPB_ATTACHED_NO_MEM;
164762306a36Sopenharmony_ci		}
164862306a36Sopenharmony_ci	} else if (entry->state == VMCIQPB_CREATED_NO_MEM) {
164962306a36Sopenharmony_ci		/*
165062306a36Sopenharmony_ci		 * The host side is attempting to attach to a queue
165162306a36Sopenharmony_ci		 * pair that doesn't have any memory associated with
165262306a36Sopenharmony_ci		 * it. This must be a pre NOVMVM vmx that hasn't set
165362306a36Sopenharmony_ci		 * the page store information yet, or a quiesced VM.
165462306a36Sopenharmony_ci		 */
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci		return VMCI_ERROR_UNAVAILABLE;
165762306a36Sopenharmony_ci	} else {
165862306a36Sopenharmony_ci		/* The host side has successfully attached to a queue pair. */
165962306a36Sopenharmony_ci		entry->state = VMCIQPB_ATTACHED_MEM;
166062306a36Sopenharmony_ci	}
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci	if (entry->state == VMCIQPB_ATTACHED_MEM) {
166362306a36Sopenharmony_ci		result =
166462306a36Sopenharmony_ci		    qp_notify_peer(true, entry->qp.handle, context_id,
166562306a36Sopenharmony_ci				   entry->create_id);
166662306a36Sopenharmony_ci		if (result < VMCI_SUCCESS)
166762306a36Sopenharmony_ci			pr_warn("Failed to notify peer (ID=0x%x) of attach to queue pair (handle=0x%x:0x%x)\n",
166862306a36Sopenharmony_ci				entry->create_id, entry->qp.handle.context,
166962306a36Sopenharmony_ci				entry->qp.handle.resource);
167062306a36Sopenharmony_ci	}
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	entry->attach_id = context_id;
167362306a36Sopenharmony_ci	entry->qp.ref_count++;
167462306a36Sopenharmony_ci	if (wakeup_cb) {
167562306a36Sopenharmony_ci		entry->wakeup_cb = wakeup_cb;
167662306a36Sopenharmony_ci		entry->client_data = client_data;
167762306a36Sopenharmony_ci	}
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	/*
168062306a36Sopenharmony_ci	 * When attaching to local queue pairs, the context already has
168162306a36Sopenharmony_ci	 * an entry tracking the queue pair, so don't add another one.
168262306a36Sopenharmony_ci	 */
168362306a36Sopenharmony_ci	if (!is_local)
168462306a36Sopenharmony_ci		vmci_ctx_qp_create(context, entry->qp.handle);
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	if (ent != NULL)
168762306a36Sopenharmony_ci		*ent = entry;
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	return VMCI_SUCCESS;
169062306a36Sopenharmony_ci}
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci/*
169362306a36Sopenharmony_ci * queue_pair_Alloc for use when setting up queue pair endpoints
169462306a36Sopenharmony_ci * on the host.
169562306a36Sopenharmony_ci */
169662306a36Sopenharmony_cistatic int qp_broker_alloc(struct vmci_handle handle,
169762306a36Sopenharmony_ci			   u32 peer,
169862306a36Sopenharmony_ci			   u32 flags,
169962306a36Sopenharmony_ci			   u32 priv_flags,
170062306a36Sopenharmony_ci			   u64 produce_size,
170162306a36Sopenharmony_ci			   u64 consume_size,
170262306a36Sopenharmony_ci			   struct vmci_qp_page_store *page_store,
170362306a36Sopenharmony_ci			   struct vmci_ctx *context,
170462306a36Sopenharmony_ci			   vmci_event_release_cb wakeup_cb,
170562306a36Sopenharmony_ci			   void *client_data,
170662306a36Sopenharmony_ci			   struct qp_broker_entry **ent,
170762306a36Sopenharmony_ci			   bool *swap)
170862306a36Sopenharmony_ci{
170962306a36Sopenharmony_ci	const u32 context_id = vmci_ctx_get_id(context);
171062306a36Sopenharmony_ci	bool create;
171162306a36Sopenharmony_ci	struct qp_broker_entry *entry = NULL;
171262306a36Sopenharmony_ci	bool is_local = flags & VMCI_QPFLAG_LOCAL;
171362306a36Sopenharmony_ci	int result;
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	if (vmci_handle_is_invalid(handle) ||
171662306a36Sopenharmony_ci	    (flags & ~VMCI_QP_ALL_FLAGS) || is_local ||
171762306a36Sopenharmony_ci	    !(produce_size || consume_size) ||
171862306a36Sopenharmony_ci	    !context || context_id == VMCI_INVALID_ID ||
171962306a36Sopenharmony_ci	    handle.context == VMCI_INVALID_ID) {
172062306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
172162306a36Sopenharmony_ci	}
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	if (page_store && !VMCI_QP_PAGESTORE_IS_WELLFORMED(page_store))
172462306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	/*
172762306a36Sopenharmony_ci	 * In the initial argument check, we ensure that non-vmkernel hosts
172862306a36Sopenharmony_ci	 * are not allowed to create local queue pairs.
172962306a36Sopenharmony_ci	 */
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	mutex_lock(&qp_broker_list.mutex);
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	if (!is_local && vmci_ctx_qp_exists(context, handle)) {
173462306a36Sopenharmony_ci		pr_devel("Context (ID=0x%x) already attached to queue pair (handle=0x%x:0x%x)\n",
173562306a36Sopenharmony_ci			 context_id, handle.context, handle.resource);
173662306a36Sopenharmony_ci		mutex_unlock(&qp_broker_list.mutex);
173762306a36Sopenharmony_ci		return VMCI_ERROR_ALREADY_EXISTS;
173862306a36Sopenharmony_ci	}
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci	if (handle.resource != VMCI_INVALID_ID)
174162306a36Sopenharmony_ci		entry = qp_broker_handle_to_entry(handle);
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	if (!entry) {
174462306a36Sopenharmony_ci		create = true;
174562306a36Sopenharmony_ci		result =
174662306a36Sopenharmony_ci		    qp_broker_create(handle, peer, flags, priv_flags,
174762306a36Sopenharmony_ci				     produce_size, consume_size, page_store,
174862306a36Sopenharmony_ci				     context, wakeup_cb, client_data, ent);
174962306a36Sopenharmony_ci	} else {
175062306a36Sopenharmony_ci		create = false;
175162306a36Sopenharmony_ci		result =
175262306a36Sopenharmony_ci		    qp_broker_attach(entry, peer, flags, priv_flags,
175362306a36Sopenharmony_ci				     produce_size, consume_size, page_store,
175462306a36Sopenharmony_ci				     context, wakeup_cb, client_data, ent);
175562306a36Sopenharmony_ci	}
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	mutex_unlock(&qp_broker_list.mutex);
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci	if (swap)
176062306a36Sopenharmony_ci		*swap = (context_id == VMCI_HOST_CONTEXT_ID) &&
176162306a36Sopenharmony_ci		    !(create && is_local);
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci	return result;
176462306a36Sopenharmony_ci}
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci/*
176762306a36Sopenharmony_ci * This function implements the kernel API for allocating a queue
176862306a36Sopenharmony_ci * pair.
176962306a36Sopenharmony_ci */
177062306a36Sopenharmony_cistatic int qp_alloc_host_work(struct vmci_handle *handle,
177162306a36Sopenharmony_ci			      struct vmci_queue **produce_q,
177262306a36Sopenharmony_ci			      u64 produce_size,
177362306a36Sopenharmony_ci			      struct vmci_queue **consume_q,
177462306a36Sopenharmony_ci			      u64 consume_size,
177562306a36Sopenharmony_ci			      u32 peer,
177662306a36Sopenharmony_ci			      u32 flags,
177762306a36Sopenharmony_ci			      u32 priv_flags,
177862306a36Sopenharmony_ci			      vmci_event_release_cb wakeup_cb,
177962306a36Sopenharmony_ci			      void *client_data)
178062306a36Sopenharmony_ci{
178162306a36Sopenharmony_ci	struct vmci_handle new_handle;
178262306a36Sopenharmony_ci	struct vmci_ctx *context;
178362306a36Sopenharmony_ci	struct qp_broker_entry *entry;
178462306a36Sopenharmony_ci	int result;
178562306a36Sopenharmony_ci	bool swap;
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_ci	if (vmci_handle_is_invalid(*handle)) {
178862306a36Sopenharmony_ci		new_handle = vmci_make_handle(
178962306a36Sopenharmony_ci			VMCI_HOST_CONTEXT_ID, VMCI_INVALID_ID);
179062306a36Sopenharmony_ci	} else
179162306a36Sopenharmony_ci		new_handle = *handle;
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	context = vmci_ctx_get(VMCI_HOST_CONTEXT_ID);
179462306a36Sopenharmony_ci	entry = NULL;
179562306a36Sopenharmony_ci	result =
179662306a36Sopenharmony_ci	    qp_broker_alloc(new_handle, peer, flags, priv_flags,
179762306a36Sopenharmony_ci			    produce_size, consume_size, NULL, context,
179862306a36Sopenharmony_ci			    wakeup_cb, client_data, &entry, &swap);
179962306a36Sopenharmony_ci	if (result == VMCI_SUCCESS) {
180062306a36Sopenharmony_ci		if (swap) {
180162306a36Sopenharmony_ci			/*
180262306a36Sopenharmony_ci			 * If this is a local queue pair, the attacher
180362306a36Sopenharmony_ci			 * will swap around produce and consume
180462306a36Sopenharmony_ci			 * queues.
180562306a36Sopenharmony_ci			 */
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci			*produce_q = entry->consume_q;
180862306a36Sopenharmony_ci			*consume_q = entry->produce_q;
180962306a36Sopenharmony_ci		} else {
181062306a36Sopenharmony_ci			*produce_q = entry->produce_q;
181162306a36Sopenharmony_ci			*consume_q = entry->consume_q;
181262306a36Sopenharmony_ci		}
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci		*handle = vmci_resource_handle(&entry->resource);
181562306a36Sopenharmony_ci	} else {
181662306a36Sopenharmony_ci		*handle = VMCI_INVALID_HANDLE;
181762306a36Sopenharmony_ci		pr_devel("queue pair broker failed to alloc (result=%d)\n",
181862306a36Sopenharmony_ci			 result);
181962306a36Sopenharmony_ci	}
182062306a36Sopenharmony_ci	vmci_ctx_put(context);
182162306a36Sopenharmony_ci	return result;
182262306a36Sopenharmony_ci}
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ci/*
182562306a36Sopenharmony_ci * Allocates a VMCI queue_pair. Only checks validity of input
182662306a36Sopenharmony_ci * arguments. The real work is done in the host or guest
182762306a36Sopenharmony_ci * specific function.
182862306a36Sopenharmony_ci */
182962306a36Sopenharmony_ciint vmci_qp_alloc(struct vmci_handle *handle,
183062306a36Sopenharmony_ci		  struct vmci_queue **produce_q,
183162306a36Sopenharmony_ci		  u64 produce_size,
183262306a36Sopenharmony_ci		  struct vmci_queue **consume_q,
183362306a36Sopenharmony_ci		  u64 consume_size,
183462306a36Sopenharmony_ci		  u32 peer,
183562306a36Sopenharmony_ci		  u32 flags,
183662306a36Sopenharmony_ci		  u32 priv_flags,
183762306a36Sopenharmony_ci		  bool guest_endpoint,
183862306a36Sopenharmony_ci		  vmci_event_release_cb wakeup_cb,
183962306a36Sopenharmony_ci		  void *client_data)
184062306a36Sopenharmony_ci{
184162306a36Sopenharmony_ci	if (!handle || !produce_q || !consume_q ||
184262306a36Sopenharmony_ci	    (!produce_size && !consume_size) || (flags & ~VMCI_QP_ALL_FLAGS))
184362306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci	if (guest_endpoint) {
184662306a36Sopenharmony_ci		return qp_alloc_guest_work(handle, produce_q,
184762306a36Sopenharmony_ci					   produce_size, consume_q,
184862306a36Sopenharmony_ci					   consume_size, peer,
184962306a36Sopenharmony_ci					   flags, priv_flags);
185062306a36Sopenharmony_ci	} else {
185162306a36Sopenharmony_ci		return qp_alloc_host_work(handle, produce_q,
185262306a36Sopenharmony_ci					  produce_size, consume_q,
185362306a36Sopenharmony_ci					  consume_size, peer, flags,
185462306a36Sopenharmony_ci					  priv_flags, wakeup_cb, client_data);
185562306a36Sopenharmony_ci	}
185662306a36Sopenharmony_ci}
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci/*
185962306a36Sopenharmony_ci * This function implements the host kernel API for detaching from
186062306a36Sopenharmony_ci * a queue pair.
186162306a36Sopenharmony_ci */
186262306a36Sopenharmony_cistatic int qp_detatch_host_work(struct vmci_handle handle)
186362306a36Sopenharmony_ci{
186462306a36Sopenharmony_ci	int result;
186562306a36Sopenharmony_ci	struct vmci_ctx *context;
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	context = vmci_ctx_get(VMCI_HOST_CONTEXT_ID);
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	result = vmci_qp_broker_detach(handle, context);
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	vmci_ctx_put(context);
187262306a36Sopenharmony_ci	return result;
187362306a36Sopenharmony_ci}
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci/*
187662306a36Sopenharmony_ci * Detaches from a VMCI queue_pair. Only checks validity of input argument.
187762306a36Sopenharmony_ci * Real work is done in the host or guest specific function.
187862306a36Sopenharmony_ci */
187962306a36Sopenharmony_cistatic int qp_detatch(struct vmci_handle handle, bool guest_endpoint)
188062306a36Sopenharmony_ci{
188162306a36Sopenharmony_ci	if (vmci_handle_is_invalid(handle))
188262306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci	if (guest_endpoint)
188562306a36Sopenharmony_ci		return qp_detatch_guest_work(handle);
188662306a36Sopenharmony_ci	else
188762306a36Sopenharmony_ci		return qp_detatch_host_work(handle);
188862306a36Sopenharmony_ci}
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci/*
189162306a36Sopenharmony_ci * Returns the entry from the head of the list. Assumes that the list is
189262306a36Sopenharmony_ci * locked.
189362306a36Sopenharmony_ci */
189462306a36Sopenharmony_cistatic struct qp_entry *qp_list_get_head(struct qp_list *qp_list)
189562306a36Sopenharmony_ci{
189662306a36Sopenharmony_ci	if (!list_empty(&qp_list->head)) {
189762306a36Sopenharmony_ci		struct qp_entry *entry =
189862306a36Sopenharmony_ci		    list_first_entry(&qp_list->head, struct qp_entry,
189962306a36Sopenharmony_ci				     list_item);
190062306a36Sopenharmony_ci		return entry;
190162306a36Sopenharmony_ci	}
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci	return NULL;
190462306a36Sopenharmony_ci}
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_civoid vmci_qp_broker_exit(void)
190762306a36Sopenharmony_ci{
190862306a36Sopenharmony_ci	struct qp_entry *entry;
190962306a36Sopenharmony_ci	struct qp_broker_entry *be;
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci	mutex_lock(&qp_broker_list.mutex);
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	while ((entry = qp_list_get_head(&qp_broker_list))) {
191462306a36Sopenharmony_ci		be = (struct qp_broker_entry *)entry;
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci		qp_list_remove_entry(&qp_broker_list, entry);
191762306a36Sopenharmony_ci		kfree(be);
191862306a36Sopenharmony_ci	}
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci	mutex_unlock(&qp_broker_list.mutex);
192162306a36Sopenharmony_ci}
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_ci/*
192462306a36Sopenharmony_ci * Requests that a queue pair be allocated with the VMCI queue
192562306a36Sopenharmony_ci * pair broker. Allocates a queue pair entry if one does not
192662306a36Sopenharmony_ci * exist. Attaches to one if it exists, and retrieves the page
192762306a36Sopenharmony_ci * files backing that queue_pair.  Assumes that the queue pair
192862306a36Sopenharmony_ci * broker lock is held.
192962306a36Sopenharmony_ci */
193062306a36Sopenharmony_ciint vmci_qp_broker_alloc(struct vmci_handle handle,
193162306a36Sopenharmony_ci			 u32 peer,
193262306a36Sopenharmony_ci			 u32 flags,
193362306a36Sopenharmony_ci			 u32 priv_flags,
193462306a36Sopenharmony_ci			 u64 produce_size,
193562306a36Sopenharmony_ci			 u64 consume_size,
193662306a36Sopenharmony_ci			 struct vmci_qp_page_store *page_store,
193762306a36Sopenharmony_ci			 struct vmci_ctx *context)
193862306a36Sopenharmony_ci{
193962306a36Sopenharmony_ci	if (!QP_SIZES_ARE_VALID(produce_size, consume_size))
194062306a36Sopenharmony_ci		return VMCI_ERROR_NO_RESOURCES;
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci	return qp_broker_alloc(handle, peer, flags, priv_flags,
194362306a36Sopenharmony_ci			       produce_size, consume_size,
194462306a36Sopenharmony_ci			       page_store, context, NULL, NULL, NULL, NULL);
194562306a36Sopenharmony_ci}
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci/*
194862306a36Sopenharmony_ci * VMX'en with versions lower than VMCI_VERSION_NOVMVM use a separate
194962306a36Sopenharmony_ci * step to add the UVAs of the VMX mapping of the queue pair. This function
195062306a36Sopenharmony_ci * provides backwards compatibility with such VMX'en, and takes care of
195162306a36Sopenharmony_ci * registering the page store for a queue pair previously allocated by the
195262306a36Sopenharmony_ci * VMX during create or attach. This function will move the queue pair state
195362306a36Sopenharmony_ci * to either from VMCIQBP_CREATED_NO_MEM to VMCIQBP_CREATED_MEM or
195462306a36Sopenharmony_ci * VMCIQBP_ATTACHED_NO_MEM to VMCIQBP_ATTACHED_MEM. If moving to the
195562306a36Sopenharmony_ci * attached state with memory, the queue pair is ready to be used by the
195662306a36Sopenharmony_ci * host peer, and an attached event will be generated.
195762306a36Sopenharmony_ci *
195862306a36Sopenharmony_ci * Assumes that the queue pair broker lock is held.
195962306a36Sopenharmony_ci *
196062306a36Sopenharmony_ci * This function is only used by the hosted platform, since there is no
196162306a36Sopenharmony_ci * issue with backwards compatibility for vmkernel.
196262306a36Sopenharmony_ci */
196362306a36Sopenharmony_ciint vmci_qp_broker_set_page_store(struct vmci_handle handle,
196462306a36Sopenharmony_ci				  u64 produce_uva,
196562306a36Sopenharmony_ci				  u64 consume_uva,
196662306a36Sopenharmony_ci				  struct vmci_ctx *context)
196762306a36Sopenharmony_ci{
196862306a36Sopenharmony_ci	struct qp_broker_entry *entry;
196962306a36Sopenharmony_ci	int result;
197062306a36Sopenharmony_ci	const u32 context_id = vmci_ctx_get_id(context);
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci	if (vmci_handle_is_invalid(handle) || !context ||
197362306a36Sopenharmony_ci	    context_id == VMCI_INVALID_ID)
197462306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_ci	/*
197762306a36Sopenharmony_ci	 * We only support guest to host queue pairs, so the VMX must
197862306a36Sopenharmony_ci	 * supply UVAs for the mapped page files.
197962306a36Sopenharmony_ci	 */
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci	if (produce_uva == 0 || consume_uva == 0)
198262306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_ci	mutex_lock(&qp_broker_list.mutex);
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_ci	if (!vmci_ctx_qp_exists(context, handle)) {
198762306a36Sopenharmony_ci		pr_warn("Context (ID=0x%x) not attached to queue pair (handle=0x%x:0x%x)\n",
198862306a36Sopenharmony_ci			context_id, handle.context, handle.resource);
198962306a36Sopenharmony_ci		result = VMCI_ERROR_NOT_FOUND;
199062306a36Sopenharmony_ci		goto out;
199162306a36Sopenharmony_ci	}
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_ci	entry = qp_broker_handle_to_entry(handle);
199462306a36Sopenharmony_ci	if (!entry) {
199562306a36Sopenharmony_ci		result = VMCI_ERROR_NOT_FOUND;
199662306a36Sopenharmony_ci		goto out;
199762306a36Sopenharmony_ci	}
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	/*
200062306a36Sopenharmony_ci	 * If I'm the owner then I can set the page store.
200162306a36Sopenharmony_ci	 *
200262306a36Sopenharmony_ci	 * Or, if a host created the queue_pair and I'm the attached peer
200362306a36Sopenharmony_ci	 * then I can set the page store.
200462306a36Sopenharmony_ci	 */
200562306a36Sopenharmony_ci	if (entry->create_id != context_id &&
200662306a36Sopenharmony_ci	    (entry->create_id != VMCI_HOST_CONTEXT_ID ||
200762306a36Sopenharmony_ci	     entry->attach_id != context_id)) {
200862306a36Sopenharmony_ci		result = VMCI_ERROR_QUEUEPAIR_NOTOWNER;
200962306a36Sopenharmony_ci		goto out;
201062306a36Sopenharmony_ci	}
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_ci	if (entry->state != VMCIQPB_CREATED_NO_MEM &&
201362306a36Sopenharmony_ci	    entry->state != VMCIQPB_ATTACHED_NO_MEM) {
201462306a36Sopenharmony_ci		result = VMCI_ERROR_UNAVAILABLE;
201562306a36Sopenharmony_ci		goto out;
201662306a36Sopenharmony_ci	}
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_ci	result = qp_host_get_user_memory(produce_uva, consume_uva,
201962306a36Sopenharmony_ci					 entry->produce_q, entry->consume_q);
202062306a36Sopenharmony_ci	if (result < VMCI_SUCCESS)
202162306a36Sopenharmony_ci		goto out;
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci	result = qp_host_map_queues(entry->produce_q, entry->consume_q);
202462306a36Sopenharmony_ci	if (result < VMCI_SUCCESS) {
202562306a36Sopenharmony_ci		qp_host_unregister_user_memory(entry->produce_q,
202662306a36Sopenharmony_ci					       entry->consume_q);
202762306a36Sopenharmony_ci		goto out;
202862306a36Sopenharmony_ci	}
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci	if (entry->state == VMCIQPB_CREATED_NO_MEM)
203162306a36Sopenharmony_ci		entry->state = VMCIQPB_CREATED_MEM;
203262306a36Sopenharmony_ci	else
203362306a36Sopenharmony_ci		entry->state = VMCIQPB_ATTACHED_MEM;
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_ci	entry->vmci_page_files = true;
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	if (entry->state == VMCIQPB_ATTACHED_MEM) {
203862306a36Sopenharmony_ci		result =
203962306a36Sopenharmony_ci		    qp_notify_peer(true, handle, context_id, entry->create_id);
204062306a36Sopenharmony_ci		if (result < VMCI_SUCCESS) {
204162306a36Sopenharmony_ci			pr_warn("Failed to notify peer (ID=0x%x) of attach to queue pair (handle=0x%x:0x%x)\n",
204262306a36Sopenharmony_ci				entry->create_id, entry->qp.handle.context,
204362306a36Sopenharmony_ci				entry->qp.handle.resource);
204462306a36Sopenharmony_ci		}
204562306a36Sopenharmony_ci	}
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci	result = VMCI_SUCCESS;
204862306a36Sopenharmony_ci out:
204962306a36Sopenharmony_ci	mutex_unlock(&qp_broker_list.mutex);
205062306a36Sopenharmony_ci	return result;
205162306a36Sopenharmony_ci}
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci/*
205462306a36Sopenharmony_ci * Resets saved queue headers for the given QP broker
205562306a36Sopenharmony_ci * entry. Should be used when guest memory becomes available
205662306a36Sopenharmony_ci * again, or the guest detaches.
205762306a36Sopenharmony_ci */
205862306a36Sopenharmony_cistatic void qp_reset_saved_headers(struct qp_broker_entry *entry)
205962306a36Sopenharmony_ci{
206062306a36Sopenharmony_ci	entry->produce_q->saved_header = NULL;
206162306a36Sopenharmony_ci	entry->consume_q->saved_header = NULL;
206262306a36Sopenharmony_ci}
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci/*
206562306a36Sopenharmony_ci * The main entry point for detaching from a queue pair registered with the
206662306a36Sopenharmony_ci * queue pair broker. If more than one endpoint is attached to the queue
206762306a36Sopenharmony_ci * pair, the first endpoint will mainly decrement a reference count and
206862306a36Sopenharmony_ci * generate a notification to its peer. The last endpoint will clean up
206962306a36Sopenharmony_ci * the queue pair state registered with the broker.
207062306a36Sopenharmony_ci *
207162306a36Sopenharmony_ci * When a guest endpoint detaches, it will unmap and unregister the guest
207262306a36Sopenharmony_ci * memory backing the queue pair. If the host is still attached, it will
207362306a36Sopenharmony_ci * no longer be able to access the queue pair content.
207462306a36Sopenharmony_ci *
207562306a36Sopenharmony_ci * If the queue pair is already in a state where there is no memory
207662306a36Sopenharmony_ci * registered for the queue pair (any *_NO_MEM state), it will transition to
207762306a36Sopenharmony_ci * the VMCIQPB_SHUTDOWN_NO_MEM state. This will also happen, if a guest
207862306a36Sopenharmony_ci * endpoint is the first of two endpoints to detach. If the host endpoint is
207962306a36Sopenharmony_ci * the first out of two to detach, the queue pair will move to the
208062306a36Sopenharmony_ci * VMCIQPB_SHUTDOWN_MEM state.
208162306a36Sopenharmony_ci */
208262306a36Sopenharmony_ciint vmci_qp_broker_detach(struct vmci_handle handle, struct vmci_ctx *context)
208362306a36Sopenharmony_ci{
208462306a36Sopenharmony_ci	struct qp_broker_entry *entry;
208562306a36Sopenharmony_ci	const u32 context_id = vmci_ctx_get_id(context);
208662306a36Sopenharmony_ci	u32 peer_id;
208762306a36Sopenharmony_ci	bool is_local = false;
208862306a36Sopenharmony_ci	int result;
208962306a36Sopenharmony_ci
209062306a36Sopenharmony_ci	if (vmci_handle_is_invalid(handle) || !context ||
209162306a36Sopenharmony_ci	    context_id == VMCI_INVALID_ID) {
209262306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
209362306a36Sopenharmony_ci	}
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci	mutex_lock(&qp_broker_list.mutex);
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci	if (!vmci_ctx_qp_exists(context, handle)) {
209862306a36Sopenharmony_ci		pr_devel("Context (ID=0x%x) not attached to queue pair (handle=0x%x:0x%x)\n",
209962306a36Sopenharmony_ci			 context_id, handle.context, handle.resource);
210062306a36Sopenharmony_ci		result = VMCI_ERROR_NOT_FOUND;
210162306a36Sopenharmony_ci		goto out;
210262306a36Sopenharmony_ci	}
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_ci	entry = qp_broker_handle_to_entry(handle);
210562306a36Sopenharmony_ci	if (!entry) {
210662306a36Sopenharmony_ci		pr_devel("Context (ID=0x%x) reports being attached to queue pair(handle=0x%x:0x%x) that isn't present in broker\n",
210762306a36Sopenharmony_ci			 context_id, handle.context, handle.resource);
210862306a36Sopenharmony_ci		result = VMCI_ERROR_NOT_FOUND;
210962306a36Sopenharmony_ci		goto out;
211062306a36Sopenharmony_ci	}
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci	if (context_id != entry->create_id && context_id != entry->attach_id) {
211362306a36Sopenharmony_ci		result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
211462306a36Sopenharmony_ci		goto out;
211562306a36Sopenharmony_ci	}
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_ci	if (context_id == entry->create_id) {
211862306a36Sopenharmony_ci		peer_id = entry->attach_id;
211962306a36Sopenharmony_ci		entry->create_id = VMCI_INVALID_ID;
212062306a36Sopenharmony_ci	} else {
212162306a36Sopenharmony_ci		peer_id = entry->create_id;
212262306a36Sopenharmony_ci		entry->attach_id = VMCI_INVALID_ID;
212362306a36Sopenharmony_ci	}
212462306a36Sopenharmony_ci	entry->qp.ref_count--;
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	is_local = entry->qp.flags & VMCI_QPFLAG_LOCAL;
212762306a36Sopenharmony_ci
212862306a36Sopenharmony_ci	if (context_id != VMCI_HOST_CONTEXT_ID) {
212962306a36Sopenharmony_ci		bool headers_mapped;
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ci		/*
213262306a36Sopenharmony_ci		 * Pre NOVMVM vmx'en may detach from a queue pair
213362306a36Sopenharmony_ci		 * before setting the page store, and in that case
213462306a36Sopenharmony_ci		 * there is no user memory to detach from. Also, more
213562306a36Sopenharmony_ci		 * recent VMX'en may detach from a queue pair in the
213662306a36Sopenharmony_ci		 * quiesced state.
213762306a36Sopenharmony_ci		 */
213862306a36Sopenharmony_ci
213962306a36Sopenharmony_ci		qp_acquire_queue_mutex(entry->produce_q);
214062306a36Sopenharmony_ci		headers_mapped = entry->produce_q->q_header ||
214162306a36Sopenharmony_ci		    entry->consume_q->q_header;
214262306a36Sopenharmony_ci		if (QPBROKERSTATE_HAS_MEM(entry)) {
214362306a36Sopenharmony_ci			result =
214462306a36Sopenharmony_ci			    qp_host_unmap_queues(INVALID_VMCI_GUEST_MEM_ID,
214562306a36Sopenharmony_ci						 entry->produce_q,
214662306a36Sopenharmony_ci						 entry->consume_q);
214762306a36Sopenharmony_ci			if (result < VMCI_SUCCESS)
214862306a36Sopenharmony_ci				pr_warn("Failed to unmap queue headers for queue pair (handle=0x%x:0x%x,result=%d)\n",
214962306a36Sopenharmony_ci					handle.context, handle.resource,
215062306a36Sopenharmony_ci					result);
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_ci			qp_host_unregister_user_memory(entry->produce_q,
215362306a36Sopenharmony_ci						       entry->consume_q);
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_ci		}
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci		if (!headers_mapped)
215862306a36Sopenharmony_ci			qp_reset_saved_headers(entry);
215962306a36Sopenharmony_ci
216062306a36Sopenharmony_ci		qp_release_queue_mutex(entry->produce_q);
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_ci		if (!headers_mapped && entry->wakeup_cb)
216362306a36Sopenharmony_ci			entry->wakeup_cb(entry->client_data);
216462306a36Sopenharmony_ci
216562306a36Sopenharmony_ci	} else {
216662306a36Sopenharmony_ci		if (entry->wakeup_cb) {
216762306a36Sopenharmony_ci			entry->wakeup_cb = NULL;
216862306a36Sopenharmony_ci			entry->client_data = NULL;
216962306a36Sopenharmony_ci		}
217062306a36Sopenharmony_ci	}
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci	if (entry->qp.ref_count == 0) {
217362306a36Sopenharmony_ci		qp_list_remove_entry(&qp_broker_list, &entry->qp);
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci		if (is_local)
217662306a36Sopenharmony_ci			kfree(entry->local_mem);
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_ci		qp_cleanup_queue_mutex(entry->produce_q, entry->consume_q);
217962306a36Sopenharmony_ci		qp_host_free_queue(entry->produce_q, entry->qp.produce_size);
218062306a36Sopenharmony_ci		qp_host_free_queue(entry->consume_q, entry->qp.consume_size);
218162306a36Sopenharmony_ci		/* Unlink from resource hash table and free callback */
218262306a36Sopenharmony_ci		vmci_resource_remove(&entry->resource);
218362306a36Sopenharmony_ci
218462306a36Sopenharmony_ci		kfree(entry);
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci		vmci_ctx_qp_destroy(context, handle);
218762306a36Sopenharmony_ci	} else {
218862306a36Sopenharmony_ci		qp_notify_peer(false, handle, context_id, peer_id);
218962306a36Sopenharmony_ci		if (context_id == VMCI_HOST_CONTEXT_ID &&
219062306a36Sopenharmony_ci		    QPBROKERSTATE_HAS_MEM(entry)) {
219162306a36Sopenharmony_ci			entry->state = VMCIQPB_SHUTDOWN_MEM;
219262306a36Sopenharmony_ci		} else {
219362306a36Sopenharmony_ci			entry->state = VMCIQPB_SHUTDOWN_NO_MEM;
219462306a36Sopenharmony_ci		}
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ci		if (!is_local)
219762306a36Sopenharmony_ci			vmci_ctx_qp_destroy(context, handle);
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	}
220062306a36Sopenharmony_ci	result = VMCI_SUCCESS;
220162306a36Sopenharmony_ci out:
220262306a36Sopenharmony_ci	mutex_unlock(&qp_broker_list.mutex);
220362306a36Sopenharmony_ci	return result;
220462306a36Sopenharmony_ci}
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_ci/*
220762306a36Sopenharmony_ci * Establishes the necessary mappings for a queue pair given a
220862306a36Sopenharmony_ci * reference to the queue pair guest memory. This is usually
220962306a36Sopenharmony_ci * called when a guest is unquiesced and the VMX is allowed to
221062306a36Sopenharmony_ci * map guest memory once again.
221162306a36Sopenharmony_ci */
221262306a36Sopenharmony_ciint vmci_qp_broker_map(struct vmci_handle handle,
221362306a36Sopenharmony_ci		       struct vmci_ctx *context,
221462306a36Sopenharmony_ci		       u64 guest_mem)
221562306a36Sopenharmony_ci{
221662306a36Sopenharmony_ci	struct qp_broker_entry *entry;
221762306a36Sopenharmony_ci	const u32 context_id = vmci_ctx_get_id(context);
221862306a36Sopenharmony_ci	int result;
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_ci	if (vmci_handle_is_invalid(handle) || !context ||
222162306a36Sopenharmony_ci	    context_id == VMCI_INVALID_ID)
222262306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
222362306a36Sopenharmony_ci
222462306a36Sopenharmony_ci	mutex_lock(&qp_broker_list.mutex);
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci	if (!vmci_ctx_qp_exists(context, handle)) {
222762306a36Sopenharmony_ci		pr_devel("Context (ID=0x%x) not attached to queue pair (handle=0x%x:0x%x)\n",
222862306a36Sopenharmony_ci			 context_id, handle.context, handle.resource);
222962306a36Sopenharmony_ci		result = VMCI_ERROR_NOT_FOUND;
223062306a36Sopenharmony_ci		goto out;
223162306a36Sopenharmony_ci	}
223262306a36Sopenharmony_ci
223362306a36Sopenharmony_ci	entry = qp_broker_handle_to_entry(handle);
223462306a36Sopenharmony_ci	if (!entry) {
223562306a36Sopenharmony_ci		pr_devel("Context (ID=0x%x) reports being attached to queue pair (handle=0x%x:0x%x) that isn't present in broker\n",
223662306a36Sopenharmony_ci			 context_id, handle.context, handle.resource);
223762306a36Sopenharmony_ci		result = VMCI_ERROR_NOT_FOUND;
223862306a36Sopenharmony_ci		goto out;
223962306a36Sopenharmony_ci	}
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_ci	if (context_id != entry->create_id && context_id != entry->attach_id) {
224262306a36Sopenharmony_ci		result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
224362306a36Sopenharmony_ci		goto out;
224462306a36Sopenharmony_ci	}
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci	result = VMCI_SUCCESS;
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci	if (context_id != VMCI_HOST_CONTEXT_ID &&
224962306a36Sopenharmony_ci	    !QPBROKERSTATE_HAS_MEM(entry)) {
225062306a36Sopenharmony_ci		struct vmci_qp_page_store page_store;
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci		page_store.pages = guest_mem;
225362306a36Sopenharmony_ci		page_store.len = QPE_NUM_PAGES(entry->qp);
225462306a36Sopenharmony_ci
225562306a36Sopenharmony_ci		qp_acquire_queue_mutex(entry->produce_q);
225662306a36Sopenharmony_ci		qp_reset_saved_headers(entry);
225762306a36Sopenharmony_ci		result =
225862306a36Sopenharmony_ci		    qp_host_register_user_memory(&page_store,
225962306a36Sopenharmony_ci						 entry->produce_q,
226062306a36Sopenharmony_ci						 entry->consume_q);
226162306a36Sopenharmony_ci		qp_release_queue_mutex(entry->produce_q);
226262306a36Sopenharmony_ci		if (result == VMCI_SUCCESS) {
226362306a36Sopenharmony_ci			/* Move state from *_NO_MEM to *_MEM */
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci			entry->state++;
226662306a36Sopenharmony_ci
226762306a36Sopenharmony_ci			if (entry->wakeup_cb)
226862306a36Sopenharmony_ci				entry->wakeup_cb(entry->client_data);
226962306a36Sopenharmony_ci		}
227062306a36Sopenharmony_ci	}
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_ci out:
227362306a36Sopenharmony_ci	mutex_unlock(&qp_broker_list.mutex);
227462306a36Sopenharmony_ci	return result;
227562306a36Sopenharmony_ci}
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci/*
227862306a36Sopenharmony_ci * Saves a snapshot of the queue headers for the given QP broker
227962306a36Sopenharmony_ci * entry. Should be used when guest memory is unmapped.
228062306a36Sopenharmony_ci * Results:
228162306a36Sopenharmony_ci * VMCI_SUCCESS on success, appropriate error code if guest memory
228262306a36Sopenharmony_ci * can't be accessed..
228362306a36Sopenharmony_ci */
228462306a36Sopenharmony_cistatic int qp_save_headers(struct qp_broker_entry *entry)
228562306a36Sopenharmony_ci{
228662306a36Sopenharmony_ci	int result;
228762306a36Sopenharmony_ci
228862306a36Sopenharmony_ci	if (entry->produce_q->saved_header != NULL &&
228962306a36Sopenharmony_ci	    entry->consume_q->saved_header != NULL) {
229062306a36Sopenharmony_ci		/*
229162306a36Sopenharmony_ci		 *  If the headers have already been saved, we don't need to do
229262306a36Sopenharmony_ci		 *  it again, and we don't want to map in the headers
229362306a36Sopenharmony_ci		 *  unnecessarily.
229462306a36Sopenharmony_ci		 */
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci		return VMCI_SUCCESS;
229762306a36Sopenharmony_ci	}
229862306a36Sopenharmony_ci
229962306a36Sopenharmony_ci	if (NULL == entry->produce_q->q_header ||
230062306a36Sopenharmony_ci	    NULL == entry->consume_q->q_header) {
230162306a36Sopenharmony_ci		result = qp_host_map_queues(entry->produce_q, entry->consume_q);
230262306a36Sopenharmony_ci		if (result < VMCI_SUCCESS)
230362306a36Sopenharmony_ci			return result;
230462306a36Sopenharmony_ci	}
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_ci	memcpy(&entry->saved_produce_q, entry->produce_q->q_header,
230762306a36Sopenharmony_ci	       sizeof(entry->saved_produce_q));
230862306a36Sopenharmony_ci	entry->produce_q->saved_header = &entry->saved_produce_q;
230962306a36Sopenharmony_ci	memcpy(&entry->saved_consume_q, entry->consume_q->q_header,
231062306a36Sopenharmony_ci	       sizeof(entry->saved_consume_q));
231162306a36Sopenharmony_ci	entry->consume_q->saved_header = &entry->saved_consume_q;
231262306a36Sopenharmony_ci
231362306a36Sopenharmony_ci	return VMCI_SUCCESS;
231462306a36Sopenharmony_ci}
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci/*
231762306a36Sopenharmony_ci * Removes all references to the guest memory of a given queue pair, and
231862306a36Sopenharmony_ci * will move the queue pair from state *_MEM to *_NO_MEM. It is usually
231962306a36Sopenharmony_ci * called when a VM is being quiesced where access to guest memory should
232062306a36Sopenharmony_ci * avoided.
232162306a36Sopenharmony_ci */
232262306a36Sopenharmony_ciint vmci_qp_broker_unmap(struct vmci_handle handle,
232362306a36Sopenharmony_ci			 struct vmci_ctx *context,
232462306a36Sopenharmony_ci			 u32 gid)
232562306a36Sopenharmony_ci{
232662306a36Sopenharmony_ci	struct qp_broker_entry *entry;
232762306a36Sopenharmony_ci	const u32 context_id = vmci_ctx_get_id(context);
232862306a36Sopenharmony_ci	int result;
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci	if (vmci_handle_is_invalid(handle) || !context ||
233162306a36Sopenharmony_ci	    context_id == VMCI_INVALID_ID)
233262306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci	mutex_lock(&qp_broker_list.mutex);
233562306a36Sopenharmony_ci
233662306a36Sopenharmony_ci	if (!vmci_ctx_qp_exists(context, handle)) {
233762306a36Sopenharmony_ci		pr_devel("Context (ID=0x%x) not attached to queue pair (handle=0x%x:0x%x)\n",
233862306a36Sopenharmony_ci			 context_id, handle.context, handle.resource);
233962306a36Sopenharmony_ci		result = VMCI_ERROR_NOT_FOUND;
234062306a36Sopenharmony_ci		goto out;
234162306a36Sopenharmony_ci	}
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci	entry = qp_broker_handle_to_entry(handle);
234462306a36Sopenharmony_ci	if (!entry) {
234562306a36Sopenharmony_ci		pr_devel("Context (ID=0x%x) reports being attached to queue pair (handle=0x%x:0x%x) that isn't present in broker\n",
234662306a36Sopenharmony_ci			 context_id, handle.context, handle.resource);
234762306a36Sopenharmony_ci		result = VMCI_ERROR_NOT_FOUND;
234862306a36Sopenharmony_ci		goto out;
234962306a36Sopenharmony_ci	}
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ci	if (context_id != entry->create_id && context_id != entry->attach_id) {
235262306a36Sopenharmony_ci		result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
235362306a36Sopenharmony_ci		goto out;
235462306a36Sopenharmony_ci	}
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci	if (context_id != VMCI_HOST_CONTEXT_ID &&
235762306a36Sopenharmony_ci	    QPBROKERSTATE_HAS_MEM(entry)) {
235862306a36Sopenharmony_ci		qp_acquire_queue_mutex(entry->produce_q);
235962306a36Sopenharmony_ci		result = qp_save_headers(entry);
236062306a36Sopenharmony_ci		if (result < VMCI_SUCCESS)
236162306a36Sopenharmony_ci			pr_warn("Failed to save queue headers for queue pair (handle=0x%x:0x%x,result=%d)\n",
236262306a36Sopenharmony_ci				handle.context, handle.resource, result);
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci		qp_host_unmap_queues(gid, entry->produce_q, entry->consume_q);
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_ci		/*
236762306a36Sopenharmony_ci		 * On hosted, when we unmap queue pairs, the VMX will also
236862306a36Sopenharmony_ci		 * unmap the guest memory, so we invalidate the previously
236962306a36Sopenharmony_ci		 * registered memory. If the queue pair is mapped again at a
237062306a36Sopenharmony_ci		 * later point in time, we will need to reregister the user
237162306a36Sopenharmony_ci		 * memory with a possibly new user VA.
237262306a36Sopenharmony_ci		 */
237362306a36Sopenharmony_ci		qp_host_unregister_user_memory(entry->produce_q,
237462306a36Sopenharmony_ci					       entry->consume_q);
237562306a36Sopenharmony_ci
237662306a36Sopenharmony_ci		/*
237762306a36Sopenharmony_ci		 * Move state from *_MEM to *_NO_MEM.
237862306a36Sopenharmony_ci		 */
237962306a36Sopenharmony_ci		entry->state--;
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci		qp_release_queue_mutex(entry->produce_q);
238262306a36Sopenharmony_ci	}
238362306a36Sopenharmony_ci
238462306a36Sopenharmony_ci	result = VMCI_SUCCESS;
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci out:
238762306a36Sopenharmony_ci	mutex_unlock(&qp_broker_list.mutex);
238862306a36Sopenharmony_ci	return result;
238962306a36Sopenharmony_ci}
239062306a36Sopenharmony_ci
239162306a36Sopenharmony_ci/*
239262306a36Sopenharmony_ci * Destroys all guest queue pair endpoints. If active guest queue
239362306a36Sopenharmony_ci * pairs still exist, hypercalls to attempt detach from these
239462306a36Sopenharmony_ci * queue pairs will be made. Any failure to detach is silently
239562306a36Sopenharmony_ci * ignored.
239662306a36Sopenharmony_ci */
239762306a36Sopenharmony_civoid vmci_qp_guest_endpoints_exit(void)
239862306a36Sopenharmony_ci{
239962306a36Sopenharmony_ci	struct qp_entry *entry;
240062306a36Sopenharmony_ci	struct qp_guest_endpoint *ep;
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_ci	mutex_lock(&qp_guest_endpoints.mutex);
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci	while ((entry = qp_list_get_head(&qp_guest_endpoints))) {
240562306a36Sopenharmony_ci		ep = (struct qp_guest_endpoint *)entry;
240662306a36Sopenharmony_ci
240762306a36Sopenharmony_ci		/* Don't make a hypercall for local queue_pairs. */
240862306a36Sopenharmony_ci		if (!(entry->flags & VMCI_QPFLAG_LOCAL))
240962306a36Sopenharmony_ci			qp_detatch_hypercall(entry->handle);
241062306a36Sopenharmony_ci
241162306a36Sopenharmony_ci		/* We cannot fail the exit, so let's reset ref_count. */
241262306a36Sopenharmony_ci		entry->ref_count = 0;
241362306a36Sopenharmony_ci		qp_list_remove_entry(&qp_guest_endpoints, entry);
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_ci		qp_guest_endpoint_destroy(ep);
241662306a36Sopenharmony_ci	}
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_ci	mutex_unlock(&qp_guest_endpoints.mutex);
241962306a36Sopenharmony_ci}
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci/*
242262306a36Sopenharmony_ci * Helper routine that will lock the queue pair before subsequent
242362306a36Sopenharmony_ci * operations.
242462306a36Sopenharmony_ci * Note: Non-blocking on the host side is currently only implemented in ESX.
242562306a36Sopenharmony_ci * Since non-blocking isn't yet implemented on the host personality we
242662306a36Sopenharmony_ci * have no reason to acquire a spin lock.  So to avoid the use of an
242762306a36Sopenharmony_ci * unnecessary lock only acquire the mutex if we can block.
242862306a36Sopenharmony_ci */
242962306a36Sopenharmony_cistatic void qp_lock(const struct vmci_qp *qpair)
243062306a36Sopenharmony_ci{
243162306a36Sopenharmony_ci	qp_acquire_queue_mutex(qpair->produce_q);
243262306a36Sopenharmony_ci}
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_ci/*
243562306a36Sopenharmony_ci * Helper routine that unlocks the queue pair after calling
243662306a36Sopenharmony_ci * qp_lock.
243762306a36Sopenharmony_ci */
243862306a36Sopenharmony_cistatic void qp_unlock(const struct vmci_qp *qpair)
243962306a36Sopenharmony_ci{
244062306a36Sopenharmony_ci	qp_release_queue_mutex(qpair->produce_q);
244162306a36Sopenharmony_ci}
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_ci/*
244462306a36Sopenharmony_ci * The queue headers may not be mapped at all times. If a queue is
244562306a36Sopenharmony_ci * currently not mapped, it will be attempted to do so.
244662306a36Sopenharmony_ci */
244762306a36Sopenharmony_cistatic int qp_map_queue_headers(struct vmci_queue *produce_q,
244862306a36Sopenharmony_ci				struct vmci_queue *consume_q)
244962306a36Sopenharmony_ci{
245062306a36Sopenharmony_ci	int result;
245162306a36Sopenharmony_ci
245262306a36Sopenharmony_ci	if (NULL == produce_q->q_header || NULL == consume_q->q_header) {
245362306a36Sopenharmony_ci		result = qp_host_map_queues(produce_q, consume_q);
245462306a36Sopenharmony_ci		if (result < VMCI_SUCCESS)
245562306a36Sopenharmony_ci			return (produce_q->saved_header &&
245662306a36Sopenharmony_ci				consume_q->saved_header) ?
245762306a36Sopenharmony_ci			    VMCI_ERROR_QUEUEPAIR_NOT_READY :
245862306a36Sopenharmony_ci			    VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
245962306a36Sopenharmony_ci	}
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci	return VMCI_SUCCESS;
246262306a36Sopenharmony_ci}
246362306a36Sopenharmony_ci
246462306a36Sopenharmony_ci/*
246562306a36Sopenharmony_ci * Helper routine that will retrieve the produce and consume
246662306a36Sopenharmony_ci * headers of a given queue pair. If the guest memory of the
246762306a36Sopenharmony_ci * queue pair is currently not available, the saved queue headers
246862306a36Sopenharmony_ci * will be returned, if these are available.
246962306a36Sopenharmony_ci */
247062306a36Sopenharmony_cistatic int qp_get_queue_headers(const struct vmci_qp *qpair,
247162306a36Sopenharmony_ci				struct vmci_queue_header **produce_q_header,
247262306a36Sopenharmony_ci				struct vmci_queue_header **consume_q_header)
247362306a36Sopenharmony_ci{
247462306a36Sopenharmony_ci	int result;
247562306a36Sopenharmony_ci
247662306a36Sopenharmony_ci	result = qp_map_queue_headers(qpair->produce_q, qpair->consume_q);
247762306a36Sopenharmony_ci	if (result == VMCI_SUCCESS) {
247862306a36Sopenharmony_ci		*produce_q_header = qpair->produce_q->q_header;
247962306a36Sopenharmony_ci		*consume_q_header = qpair->consume_q->q_header;
248062306a36Sopenharmony_ci	} else if (qpair->produce_q->saved_header &&
248162306a36Sopenharmony_ci		   qpair->consume_q->saved_header) {
248262306a36Sopenharmony_ci		*produce_q_header = qpair->produce_q->saved_header;
248362306a36Sopenharmony_ci		*consume_q_header = qpair->consume_q->saved_header;
248462306a36Sopenharmony_ci		result = VMCI_SUCCESS;
248562306a36Sopenharmony_ci	}
248662306a36Sopenharmony_ci
248762306a36Sopenharmony_ci	return result;
248862306a36Sopenharmony_ci}
248962306a36Sopenharmony_ci
249062306a36Sopenharmony_ci/*
249162306a36Sopenharmony_ci * Callback from VMCI queue pair broker indicating that a queue
249262306a36Sopenharmony_ci * pair that was previously not ready, now either is ready or
249362306a36Sopenharmony_ci * gone forever.
249462306a36Sopenharmony_ci */
249562306a36Sopenharmony_cistatic int qp_wakeup_cb(void *client_data)
249662306a36Sopenharmony_ci{
249762306a36Sopenharmony_ci	struct vmci_qp *qpair = (struct vmci_qp *)client_data;
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_ci	qp_lock(qpair);
250062306a36Sopenharmony_ci	while (qpair->blocked > 0) {
250162306a36Sopenharmony_ci		qpair->blocked--;
250262306a36Sopenharmony_ci		qpair->generation++;
250362306a36Sopenharmony_ci		wake_up(&qpair->event);
250462306a36Sopenharmony_ci	}
250562306a36Sopenharmony_ci	qp_unlock(qpair);
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_ci	return VMCI_SUCCESS;
250862306a36Sopenharmony_ci}
250962306a36Sopenharmony_ci
251062306a36Sopenharmony_ci/*
251162306a36Sopenharmony_ci * Makes the calling thread wait for the queue pair to become
251262306a36Sopenharmony_ci * ready for host side access.  Returns true when thread is
251362306a36Sopenharmony_ci * woken up after queue pair state change, false otherwise.
251462306a36Sopenharmony_ci */
251562306a36Sopenharmony_cistatic bool qp_wait_for_ready_queue(struct vmci_qp *qpair)
251662306a36Sopenharmony_ci{
251762306a36Sopenharmony_ci	unsigned int generation;
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_ci	qpair->blocked++;
252062306a36Sopenharmony_ci	generation = qpair->generation;
252162306a36Sopenharmony_ci	qp_unlock(qpair);
252262306a36Sopenharmony_ci	wait_event(qpair->event, generation != qpair->generation);
252362306a36Sopenharmony_ci	qp_lock(qpair);
252462306a36Sopenharmony_ci
252562306a36Sopenharmony_ci	return true;
252662306a36Sopenharmony_ci}
252762306a36Sopenharmony_ci
252862306a36Sopenharmony_ci/*
252962306a36Sopenharmony_ci * Enqueues a given buffer to the produce queue using the provided
253062306a36Sopenharmony_ci * function. As many bytes as possible (space available in the queue)
253162306a36Sopenharmony_ci * are enqueued.  Assumes the queue->mutex has been acquired.  Returns
253262306a36Sopenharmony_ci * VMCI_ERROR_QUEUEPAIR_NOSPACE if no space was available to enqueue
253362306a36Sopenharmony_ci * data, VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the
253462306a36Sopenharmony_ci * queue (as defined by the queue size), VMCI_ERROR_INVALID_ARGS, if
253562306a36Sopenharmony_ci * an error occured when accessing the buffer,
253662306a36Sopenharmony_ci * VMCI_ERROR_QUEUEPAIR_NOTATTACHED, if the queue pair pages aren't
253762306a36Sopenharmony_ci * available.  Otherwise, the number of bytes written to the queue is
253862306a36Sopenharmony_ci * returned.  Updates the tail pointer of the produce queue.
253962306a36Sopenharmony_ci */
254062306a36Sopenharmony_cistatic ssize_t qp_enqueue_locked(struct vmci_queue *produce_q,
254162306a36Sopenharmony_ci				 struct vmci_queue *consume_q,
254262306a36Sopenharmony_ci				 const u64 produce_q_size,
254362306a36Sopenharmony_ci				 struct iov_iter *from)
254462306a36Sopenharmony_ci{
254562306a36Sopenharmony_ci	s64 free_space;
254662306a36Sopenharmony_ci	u64 tail;
254762306a36Sopenharmony_ci	size_t buf_size = iov_iter_count(from);
254862306a36Sopenharmony_ci	size_t written;
254962306a36Sopenharmony_ci	ssize_t result;
255062306a36Sopenharmony_ci
255162306a36Sopenharmony_ci	result = qp_map_queue_headers(produce_q, consume_q);
255262306a36Sopenharmony_ci	if (unlikely(result != VMCI_SUCCESS))
255362306a36Sopenharmony_ci		return result;
255462306a36Sopenharmony_ci
255562306a36Sopenharmony_ci	free_space = vmci_q_header_free_space(produce_q->q_header,
255662306a36Sopenharmony_ci					      consume_q->q_header,
255762306a36Sopenharmony_ci					      produce_q_size);
255862306a36Sopenharmony_ci	if (free_space == 0)
255962306a36Sopenharmony_ci		return VMCI_ERROR_QUEUEPAIR_NOSPACE;
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci	if (free_space < VMCI_SUCCESS)
256262306a36Sopenharmony_ci		return (ssize_t) free_space;
256362306a36Sopenharmony_ci
256462306a36Sopenharmony_ci	written = (size_t) (free_space > buf_size ? buf_size : free_space);
256562306a36Sopenharmony_ci	tail = vmci_q_header_producer_tail(produce_q->q_header);
256662306a36Sopenharmony_ci	if (likely(tail + written < produce_q_size)) {
256762306a36Sopenharmony_ci		result = qp_memcpy_to_queue_iter(produce_q, tail, from, written);
256862306a36Sopenharmony_ci	} else {
256962306a36Sopenharmony_ci		/* Tail pointer wraps around. */
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci		const size_t tmp = (size_t) (produce_q_size - tail);
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci		result = qp_memcpy_to_queue_iter(produce_q, tail, from, tmp);
257462306a36Sopenharmony_ci		if (result >= VMCI_SUCCESS)
257562306a36Sopenharmony_ci			result = qp_memcpy_to_queue_iter(produce_q, 0, from,
257662306a36Sopenharmony_ci						 written - tmp);
257762306a36Sopenharmony_ci	}
257862306a36Sopenharmony_ci
257962306a36Sopenharmony_ci	if (result < VMCI_SUCCESS)
258062306a36Sopenharmony_ci		return result;
258162306a36Sopenharmony_ci
258262306a36Sopenharmony_ci	/*
258362306a36Sopenharmony_ci	 * This virt_wmb() ensures that data written to the queue
258462306a36Sopenharmony_ci	 * is observable before the new producer_tail is.
258562306a36Sopenharmony_ci	 */
258662306a36Sopenharmony_ci	virt_wmb();
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_ci	vmci_q_header_add_producer_tail(produce_q->q_header, written,
258962306a36Sopenharmony_ci					produce_q_size);
259062306a36Sopenharmony_ci	return written;
259162306a36Sopenharmony_ci}
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ci/*
259462306a36Sopenharmony_ci * Dequeues data (if available) from the given consume queue. Writes data
259562306a36Sopenharmony_ci * to the user provided buffer using the provided function.
259662306a36Sopenharmony_ci * Assumes the queue->mutex has been acquired.
259762306a36Sopenharmony_ci * Results:
259862306a36Sopenharmony_ci * VMCI_ERROR_QUEUEPAIR_NODATA if no data was available to dequeue.
259962306a36Sopenharmony_ci * VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the queue
260062306a36Sopenharmony_ci * (as defined by the queue size).
260162306a36Sopenharmony_ci * VMCI_ERROR_INVALID_ARGS, if an error occured when accessing the buffer.
260262306a36Sopenharmony_ci * Otherwise the number of bytes dequeued is returned.
260362306a36Sopenharmony_ci * Side effects:
260462306a36Sopenharmony_ci * Updates the head pointer of the consume queue.
260562306a36Sopenharmony_ci */
260662306a36Sopenharmony_cistatic ssize_t qp_dequeue_locked(struct vmci_queue *produce_q,
260762306a36Sopenharmony_ci				 struct vmci_queue *consume_q,
260862306a36Sopenharmony_ci				 const u64 consume_q_size,
260962306a36Sopenharmony_ci				 struct iov_iter *to,
261062306a36Sopenharmony_ci				 bool update_consumer)
261162306a36Sopenharmony_ci{
261262306a36Sopenharmony_ci	size_t buf_size = iov_iter_count(to);
261362306a36Sopenharmony_ci	s64 buf_ready;
261462306a36Sopenharmony_ci	u64 head;
261562306a36Sopenharmony_ci	size_t read;
261662306a36Sopenharmony_ci	ssize_t result;
261762306a36Sopenharmony_ci
261862306a36Sopenharmony_ci	result = qp_map_queue_headers(produce_q, consume_q);
261962306a36Sopenharmony_ci	if (unlikely(result != VMCI_SUCCESS))
262062306a36Sopenharmony_ci		return result;
262162306a36Sopenharmony_ci
262262306a36Sopenharmony_ci	buf_ready = vmci_q_header_buf_ready(consume_q->q_header,
262362306a36Sopenharmony_ci					    produce_q->q_header,
262462306a36Sopenharmony_ci					    consume_q_size);
262562306a36Sopenharmony_ci	if (buf_ready == 0)
262662306a36Sopenharmony_ci		return VMCI_ERROR_QUEUEPAIR_NODATA;
262762306a36Sopenharmony_ci
262862306a36Sopenharmony_ci	if (buf_ready < VMCI_SUCCESS)
262962306a36Sopenharmony_ci		return (ssize_t) buf_ready;
263062306a36Sopenharmony_ci
263162306a36Sopenharmony_ci	/*
263262306a36Sopenharmony_ci	 * This virt_rmb() ensures that data from the queue will be read
263362306a36Sopenharmony_ci	 * after we have determined how much is ready to be consumed.
263462306a36Sopenharmony_ci	 */
263562306a36Sopenharmony_ci	virt_rmb();
263662306a36Sopenharmony_ci
263762306a36Sopenharmony_ci	read = (size_t) (buf_ready > buf_size ? buf_size : buf_ready);
263862306a36Sopenharmony_ci	head = vmci_q_header_consumer_head(produce_q->q_header);
263962306a36Sopenharmony_ci	if (likely(head + read < consume_q_size)) {
264062306a36Sopenharmony_ci		result = qp_memcpy_from_queue_iter(to, consume_q, head, read);
264162306a36Sopenharmony_ci	} else {
264262306a36Sopenharmony_ci		/* Head pointer wraps around. */
264362306a36Sopenharmony_ci
264462306a36Sopenharmony_ci		const size_t tmp = (size_t) (consume_q_size - head);
264562306a36Sopenharmony_ci
264662306a36Sopenharmony_ci		result = qp_memcpy_from_queue_iter(to, consume_q, head, tmp);
264762306a36Sopenharmony_ci		if (result >= VMCI_SUCCESS)
264862306a36Sopenharmony_ci			result = qp_memcpy_from_queue_iter(to, consume_q, 0,
264962306a36Sopenharmony_ci						   read - tmp);
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_ci	}
265262306a36Sopenharmony_ci
265362306a36Sopenharmony_ci	if (result < VMCI_SUCCESS)
265462306a36Sopenharmony_ci		return result;
265562306a36Sopenharmony_ci
265662306a36Sopenharmony_ci	if (update_consumer)
265762306a36Sopenharmony_ci		vmci_q_header_add_consumer_head(produce_q->q_header,
265862306a36Sopenharmony_ci						read, consume_q_size);
265962306a36Sopenharmony_ci
266062306a36Sopenharmony_ci	return read;
266162306a36Sopenharmony_ci}
266262306a36Sopenharmony_ci
266362306a36Sopenharmony_ci/*
266462306a36Sopenharmony_ci * vmci_qpair_alloc() - Allocates a queue pair.
266562306a36Sopenharmony_ci * @qpair:      Pointer for the new vmci_qp struct.
266662306a36Sopenharmony_ci * @handle:     Handle to track the resource.
266762306a36Sopenharmony_ci * @produce_qsize:      Desired size of the producer queue.
266862306a36Sopenharmony_ci * @consume_qsize:      Desired size of the consumer queue.
266962306a36Sopenharmony_ci * @peer:       ContextID of the peer.
267062306a36Sopenharmony_ci * @flags:      VMCI flags.
267162306a36Sopenharmony_ci * @priv_flags: VMCI priviledge flags.
267262306a36Sopenharmony_ci *
267362306a36Sopenharmony_ci * This is the client interface for allocating the memory for a
267462306a36Sopenharmony_ci * vmci_qp structure and then attaching to the underlying
267562306a36Sopenharmony_ci * queue.  If an error occurs allocating the memory for the
267662306a36Sopenharmony_ci * vmci_qp structure no attempt is made to attach.  If an
267762306a36Sopenharmony_ci * error occurs attaching, then the structure is freed.
267862306a36Sopenharmony_ci */
267962306a36Sopenharmony_ciint vmci_qpair_alloc(struct vmci_qp **qpair,
268062306a36Sopenharmony_ci		     struct vmci_handle *handle,
268162306a36Sopenharmony_ci		     u64 produce_qsize,
268262306a36Sopenharmony_ci		     u64 consume_qsize,
268362306a36Sopenharmony_ci		     u32 peer,
268462306a36Sopenharmony_ci		     u32 flags,
268562306a36Sopenharmony_ci		     u32 priv_flags)
268662306a36Sopenharmony_ci{
268762306a36Sopenharmony_ci	struct vmci_qp *my_qpair;
268862306a36Sopenharmony_ci	int retval;
268962306a36Sopenharmony_ci	struct vmci_handle src = VMCI_INVALID_HANDLE;
269062306a36Sopenharmony_ci	struct vmci_handle dst = vmci_make_handle(peer, VMCI_INVALID_ID);
269162306a36Sopenharmony_ci	enum vmci_route route;
269262306a36Sopenharmony_ci	vmci_event_release_cb wakeup_cb;
269362306a36Sopenharmony_ci	void *client_data;
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci	/*
269662306a36Sopenharmony_ci	 * Restrict the size of a queuepair.  The device already
269762306a36Sopenharmony_ci	 * enforces a limit on the total amount of memory that can be
269862306a36Sopenharmony_ci	 * allocated to queuepairs for a guest.  However, we try to
269962306a36Sopenharmony_ci	 * allocate this memory before we make the queuepair
270062306a36Sopenharmony_ci	 * allocation hypercall.  On Linux, we allocate each page
270162306a36Sopenharmony_ci	 * separately, which means rather than fail, the guest will
270262306a36Sopenharmony_ci	 * thrash while it tries to allocate, and will become
270362306a36Sopenharmony_ci	 * increasingly unresponsive to the point where it appears to
270462306a36Sopenharmony_ci	 * be hung.  So we place a limit on the size of an individual
270562306a36Sopenharmony_ci	 * queuepair here, and leave the device to enforce the
270662306a36Sopenharmony_ci	 * restriction on total queuepair memory.  (Note that this
270762306a36Sopenharmony_ci	 * doesn't prevent all cases; a user with only this much
270862306a36Sopenharmony_ci	 * physical memory could still get into trouble.)  The error
270962306a36Sopenharmony_ci	 * used by the device is NO_RESOURCES, so use that here too.
271062306a36Sopenharmony_ci	 */
271162306a36Sopenharmony_ci
271262306a36Sopenharmony_ci	if (!QP_SIZES_ARE_VALID(produce_qsize, consume_qsize))
271362306a36Sopenharmony_ci		return VMCI_ERROR_NO_RESOURCES;
271462306a36Sopenharmony_ci
271562306a36Sopenharmony_ci	retval = vmci_route(&src, &dst, false, &route);
271662306a36Sopenharmony_ci	if (retval < VMCI_SUCCESS)
271762306a36Sopenharmony_ci		route = vmci_guest_code_active() ?
271862306a36Sopenharmony_ci		    VMCI_ROUTE_AS_GUEST : VMCI_ROUTE_AS_HOST;
271962306a36Sopenharmony_ci
272062306a36Sopenharmony_ci	if (flags & (VMCI_QPFLAG_NONBLOCK | VMCI_QPFLAG_PINNED)) {
272162306a36Sopenharmony_ci		pr_devel("NONBLOCK OR PINNED set");
272262306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
272362306a36Sopenharmony_ci	}
272462306a36Sopenharmony_ci
272562306a36Sopenharmony_ci	my_qpair = kzalloc(sizeof(*my_qpair), GFP_KERNEL);
272662306a36Sopenharmony_ci	if (!my_qpair)
272762306a36Sopenharmony_ci		return VMCI_ERROR_NO_MEM;
272862306a36Sopenharmony_ci
272962306a36Sopenharmony_ci	my_qpair->produce_q_size = produce_qsize;
273062306a36Sopenharmony_ci	my_qpair->consume_q_size = consume_qsize;
273162306a36Sopenharmony_ci	my_qpair->peer = peer;
273262306a36Sopenharmony_ci	my_qpair->flags = flags;
273362306a36Sopenharmony_ci	my_qpair->priv_flags = priv_flags;
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_ci	wakeup_cb = NULL;
273662306a36Sopenharmony_ci	client_data = NULL;
273762306a36Sopenharmony_ci
273862306a36Sopenharmony_ci	if (VMCI_ROUTE_AS_HOST == route) {
273962306a36Sopenharmony_ci		my_qpair->guest_endpoint = false;
274062306a36Sopenharmony_ci		if (!(flags & VMCI_QPFLAG_LOCAL)) {
274162306a36Sopenharmony_ci			my_qpair->blocked = 0;
274262306a36Sopenharmony_ci			my_qpair->generation = 0;
274362306a36Sopenharmony_ci			init_waitqueue_head(&my_qpair->event);
274462306a36Sopenharmony_ci			wakeup_cb = qp_wakeup_cb;
274562306a36Sopenharmony_ci			client_data = (void *)my_qpair;
274662306a36Sopenharmony_ci		}
274762306a36Sopenharmony_ci	} else {
274862306a36Sopenharmony_ci		my_qpair->guest_endpoint = true;
274962306a36Sopenharmony_ci	}
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci	retval = vmci_qp_alloc(handle,
275262306a36Sopenharmony_ci			       &my_qpair->produce_q,
275362306a36Sopenharmony_ci			       my_qpair->produce_q_size,
275462306a36Sopenharmony_ci			       &my_qpair->consume_q,
275562306a36Sopenharmony_ci			       my_qpair->consume_q_size,
275662306a36Sopenharmony_ci			       my_qpair->peer,
275762306a36Sopenharmony_ci			       my_qpair->flags,
275862306a36Sopenharmony_ci			       my_qpair->priv_flags,
275962306a36Sopenharmony_ci			       my_qpair->guest_endpoint,
276062306a36Sopenharmony_ci			       wakeup_cb, client_data);
276162306a36Sopenharmony_ci
276262306a36Sopenharmony_ci	if (retval < VMCI_SUCCESS) {
276362306a36Sopenharmony_ci		kfree(my_qpair);
276462306a36Sopenharmony_ci		return retval;
276562306a36Sopenharmony_ci	}
276662306a36Sopenharmony_ci
276762306a36Sopenharmony_ci	*qpair = my_qpair;
276862306a36Sopenharmony_ci	my_qpair->handle = *handle;
276962306a36Sopenharmony_ci
277062306a36Sopenharmony_ci	return retval;
277162306a36Sopenharmony_ci}
277262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vmci_qpair_alloc);
277362306a36Sopenharmony_ci
277462306a36Sopenharmony_ci/*
277562306a36Sopenharmony_ci * vmci_qpair_detach() - Detatches the client from a queue pair.
277662306a36Sopenharmony_ci * @qpair:      Reference of a pointer to the qpair struct.
277762306a36Sopenharmony_ci *
277862306a36Sopenharmony_ci * This is the client interface for detaching from a VMCIQPair.
277962306a36Sopenharmony_ci * Note that this routine will free the memory allocated for the
278062306a36Sopenharmony_ci * vmci_qp structure too.
278162306a36Sopenharmony_ci */
278262306a36Sopenharmony_ciint vmci_qpair_detach(struct vmci_qp **qpair)
278362306a36Sopenharmony_ci{
278462306a36Sopenharmony_ci	int result;
278562306a36Sopenharmony_ci	struct vmci_qp *old_qpair;
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_ci	if (!qpair || !(*qpair))
278862306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
278962306a36Sopenharmony_ci
279062306a36Sopenharmony_ci	old_qpair = *qpair;
279162306a36Sopenharmony_ci	result = qp_detatch(old_qpair->handle, old_qpair->guest_endpoint);
279262306a36Sopenharmony_ci
279362306a36Sopenharmony_ci	/*
279462306a36Sopenharmony_ci	 * The guest can fail to detach for a number of reasons, and
279562306a36Sopenharmony_ci	 * if it does so, it will cleanup the entry (if there is one).
279662306a36Sopenharmony_ci	 * The host can fail too, but it won't cleanup the entry
279762306a36Sopenharmony_ci	 * immediately, it will do that later when the context is
279862306a36Sopenharmony_ci	 * freed.  Either way, we need to release the qpair struct
279962306a36Sopenharmony_ci	 * here; there isn't much the caller can do, and we don't want
280062306a36Sopenharmony_ci	 * to leak.
280162306a36Sopenharmony_ci	 */
280262306a36Sopenharmony_ci
280362306a36Sopenharmony_ci	memset(old_qpair, 0, sizeof(*old_qpair));
280462306a36Sopenharmony_ci	old_qpair->handle = VMCI_INVALID_HANDLE;
280562306a36Sopenharmony_ci	old_qpair->peer = VMCI_INVALID_ID;
280662306a36Sopenharmony_ci	kfree(old_qpair);
280762306a36Sopenharmony_ci	*qpair = NULL;
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_ci	return result;
281062306a36Sopenharmony_ci}
281162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vmci_qpair_detach);
281262306a36Sopenharmony_ci
281362306a36Sopenharmony_ci/*
281462306a36Sopenharmony_ci * vmci_qpair_get_produce_indexes() - Retrieves the indexes of the producer.
281562306a36Sopenharmony_ci * @qpair:      Pointer to the queue pair struct.
281662306a36Sopenharmony_ci * @producer_tail:      Reference used for storing producer tail index.
281762306a36Sopenharmony_ci * @consumer_head:      Reference used for storing the consumer head index.
281862306a36Sopenharmony_ci *
281962306a36Sopenharmony_ci * This is the client interface for getting the current indexes of the
282062306a36Sopenharmony_ci * QPair from the point of the view of the caller as the producer.
282162306a36Sopenharmony_ci */
282262306a36Sopenharmony_ciint vmci_qpair_get_produce_indexes(const struct vmci_qp *qpair,
282362306a36Sopenharmony_ci				   u64 *producer_tail,
282462306a36Sopenharmony_ci				   u64 *consumer_head)
282562306a36Sopenharmony_ci{
282662306a36Sopenharmony_ci	struct vmci_queue_header *produce_q_header;
282762306a36Sopenharmony_ci	struct vmci_queue_header *consume_q_header;
282862306a36Sopenharmony_ci	int result;
282962306a36Sopenharmony_ci
283062306a36Sopenharmony_ci	if (!qpair)
283162306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
283262306a36Sopenharmony_ci
283362306a36Sopenharmony_ci	qp_lock(qpair);
283462306a36Sopenharmony_ci	result =
283562306a36Sopenharmony_ci	    qp_get_queue_headers(qpair, &produce_q_header, &consume_q_header);
283662306a36Sopenharmony_ci	if (result == VMCI_SUCCESS)
283762306a36Sopenharmony_ci		vmci_q_header_get_pointers(produce_q_header, consume_q_header,
283862306a36Sopenharmony_ci					   producer_tail, consumer_head);
283962306a36Sopenharmony_ci	qp_unlock(qpair);
284062306a36Sopenharmony_ci
284162306a36Sopenharmony_ci	if (result == VMCI_SUCCESS &&
284262306a36Sopenharmony_ci	    ((producer_tail && *producer_tail >= qpair->produce_q_size) ||
284362306a36Sopenharmony_ci	     (consumer_head && *consumer_head >= qpair->produce_q_size)))
284462306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_SIZE;
284562306a36Sopenharmony_ci
284662306a36Sopenharmony_ci	return result;
284762306a36Sopenharmony_ci}
284862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vmci_qpair_get_produce_indexes);
284962306a36Sopenharmony_ci
285062306a36Sopenharmony_ci/*
285162306a36Sopenharmony_ci * vmci_qpair_get_consume_indexes() - Retrieves the indexes of the consumer.
285262306a36Sopenharmony_ci * @qpair:      Pointer to the queue pair struct.
285362306a36Sopenharmony_ci * @consumer_tail:      Reference used for storing consumer tail index.
285462306a36Sopenharmony_ci * @producer_head:      Reference used for storing the producer head index.
285562306a36Sopenharmony_ci *
285662306a36Sopenharmony_ci * This is the client interface for getting the current indexes of the
285762306a36Sopenharmony_ci * QPair from the point of the view of the caller as the consumer.
285862306a36Sopenharmony_ci */
285962306a36Sopenharmony_ciint vmci_qpair_get_consume_indexes(const struct vmci_qp *qpair,
286062306a36Sopenharmony_ci				   u64 *consumer_tail,
286162306a36Sopenharmony_ci				   u64 *producer_head)
286262306a36Sopenharmony_ci{
286362306a36Sopenharmony_ci	struct vmci_queue_header *produce_q_header;
286462306a36Sopenharmony_ci	struct vmci_queue_header *consume_q_header;
286562306a36Sopenharmony_ci	int result;
286662306a36Sopenharmony_ci
286762306a36Sopenharmony_ci	if (!qpair)
286862306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
286962306a36Sopenharmony_ci
287062306a36Sopenharmony_ci	qp_lock(qpair);
287162306a36Sopenharmony_ci	result =
287262306a36Sopenharmony_ci	    qp_get_queue_headers(qpair, &produce_q_header, &consume_q_header);
287362306a36Sopenharmony_ci	if (result == VMCI_SUCCESS)
287462306a36Sopenharmony_ci		vmci_q_header_get_pointers(consume_q_header, produce_q_header,
287562306a36Sopenharmony_ci					   consumer_tail, producer_head);
287662306a36Sopenharmony_ci	qp_unlock(qpair);
287762306a36Sopenharmony_ci
287862306a36Sopenharmony_ci	if (result == VMCI_SUCCESS &&
287962306a36Sopenharmony_ci	    ((consumer_tail && *consumer_tail >= qpair->consume_q_size) ||
288062306a36Sopenharmony_ci	     (producer_head && *producer_head >= qpair->consume_q_size)))
288162306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_SIZE;
288262306a36Sopenharmony_ci
288362306a36Sopenharmony_ci	return result;
288462306a36Sopenharmony_ci}
288562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vmci_qpair_get_consume_indexes);
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_ci/*
288862306a36Sopenharmony_ci * vmci_qpair_produce_free_space() - Retrieves free space in producer queue.
288962306a36Sopenharmony_ci * @qpair:      Pointer to the queue pair struct.
289062306a36Sopenharmony_ci *
289162306a36Sopenharmony_ci * This is the client interface for getting the amount of free
289262306a36Sopenharmony_ci * space in the QPair from the point of the view of the caller as
289362306a36Sopenharmony_ci * the producer which is the common case.  Returns < 0 if err, else
289462306a36Sopenharmony_ci * available bytes into which data can be enqueued if > 0.
289562306a36Sopenharmony_ci */
289662306a36Sopenharmony_cis64 vmci_qpair_produce_free_space(const struct vmci_qp *qpair)
289762306a36Sopenharmony_ci{
289862306a36Sopenharmony_ci	struct vmci_queue_header *produce_q_header;
289962306a36Sopenharmony_ci	struct vmci_queue_header *consume_q_header;
290062306a36Sopenharmony_ci	s64 result;
290162306a36Sopenharmony_ci
290262306a36Sopenharmony_ci	if (!qpair)
290362306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
290462306a36Sopenharmony_ci
290562306a36Sopenharmony_ci	qp_lock(qpair);
290662306a36Sopenharmony_ci	result =
290762306a36Sopenharmony_ci	    qp_get_queue_headers(qpair, &produce_q_header, &consume_q_header);
290862306a36Sopenharmony_ci	if (result == VMCI_SUCCESS)
290962306a36Sopenharmony_ci		result = vmci_q_header_free_space(produce_q_header,
291062306a36Sopenharmony_ci						  consume_q_header,
291162306a36Sopenharmony_ci						  qpair->produce_q_size);
291262306a36Sopenharmony_ci	else
291362306a36Sopenharmony_ci		result = 0;
291462306a36Sopenharmony_ci
291562306a36Sopenharmony_ci	qp_unlock(qpair);
291662306a36Sopenharmony_ci
291762306a36Sopenharmony_ci	return result;
291862306a36Sopenharmony_ci}
291962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vmci_qpair_produce_free_space);
292062306a36Sopenharmony_ci
292162306a36Sopenharmony_ci/*
292262306a36Sopenharmony_ci * vmci_qpair_consume_free_space() - Retrieves free space in consumer queue.
292362306a36Sopenharmony_ci * @qpair:      Pointer to the queue pair struct.
292462306a36Sopenharmony_ci *
292562306a36Sopenharmony_ci * This is the client interface for getting the amount of free
292662306a36Sopenharmony_ci * space in the QPair from the point of the view of the caller as
292762306a36Sopenharmony_ci * the consumer which is not the common case.  Returns < 0 if err, else
292862306a36Sopenharmony_ci * available bytes into which data can be enqueued if > 0.
292962306a36Sopenharmony_ci */
293062306a36Sopenharmony_cis64 vmci_qpair_consume_free_space(const struct vmci_qp *qpair)
293162306a36Sopenharmony_ci{
293262306a36Sopenharmony_ci	struct vmci_queue_header *produce_q_header;
293362306a36Sopenharmony_ci	struct vmci_queue_header *consume_q_header;
293462306a36Sopenharmony_ci	s64 result;
293562306a36Sopenharmony_ci
293662306a36Sopenharmony_ci	if (!qpair)
293762306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
293862306a36Sopenharmony_ci
293962306a36Sopenharmony_ci	qp_lock(qpair);
294062306a36Sopenharmony_ci	result =
294162306a36Sopenharmony_ci	    qp_get_queue_headers(qpair, &produce_q_header, &consume_q_header);
294262306a36Sopenharmony_ci	if (result == VMCI_SUCCESS)
294362306a36Sopenharmony_ci		result = vmci_q_header_free_space(consume_q_header,
294462306a36Sopenharmony_ci						  produce_q_header,
294562306a36Sopenharmony_ci						  qpair->consume_q_size);
294662306a36Sopenharmony_ci	else
294762306a36Sopenharmony_ci		result = 0;
294862306a36Sopenharmony_ci
294962306a36Sopenharmony_ci	qp_unlock(qpair);
295062306a36Sopenharmony_ci
295162306a36Sopenharmony_ci	return result;
295262306a36Sopenharmony_ci}
295362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vmci_qpair_consume_free_space);
295462306a36Sopenharmony_ci
295562306a36Sopenharmony_ci/*
295662306a36Sopenharmony_ci * vmci_qpair_produce_buf_ready() - Gets bytes ready to read from
295762306a36Sopenharmony_ci * producer queue.
295862306a36Sopenharmony_ci * @qpair:      Pointer to the queue pair struct.
295962306a36Sopenharmony_ci *
296062306a36Sopenharmony_ci * This is the client interface for getting the amount of
296162306a36Sopenharmony_ci * enqueued data in the QPair from the point of the view of the
296262306a36Sopenharmony_ci * caller as the producer which is not the common case.  Returns < 0 if err,
296362306a36Sopenharmony_ci * else available bytes that may be read.
296462306a36Sopenharmony_ci */
296562306a36Sopenharmony_cis64 vmci_qpair_produce_buf_ready(const struct vmci_qp *qpair)
296662306a36Sopenharmony_ci{
296762306a36Sopenharmony_ci	struct vmci_queue_header *produce_q_header;
296862306a36Sopenharmony_ci	struct vmci_queue_header *consume_q_header;
296962306a36Sopenharmony_ci	s64 result;
297062306a36Sopenharmony_ci
297162306a36Sopenharmony_ci	if (!qpair)
297262306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
297362306a36Sopenharmony_ci
297462306a36Sopenharmony_ci	qp_lock(qpair);
297562306a36Sopenharmony_ci	result =
297662306a36Sopenharmony_ci	    qp_get_queue_headers(qpair, &produce_q_header, &consume_q_header);
297762306a36Sopenharmony_ci	if (result == VMCI_SUCCESS)
297862306a36Sopenharmony_ci		result = vmci_q_header_buf_ready(produce_q_header,
297962306a36Sopenharmony_ci						 consume_q_header,
298062306a36Sopenharmony_ci						 qpair->produce_q_size);
298162306a36Sopenharmony_ci	else
298262306a36Sopenharmony_ci		result = 0;
298362306a36Sopenharmony_ci
298462306a36Sopenharmony_ci	qp_unlock(qpair);
298562306a36Sopenharmony_ci
298662306a36Sopenharmony_ci	return result;
298762306a36Sopenharmony_ci}
298862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vmci_qpair_produce_buf_ready);
298962306a36Sopenharmony_ci
299062306a36Sopenharmony_ci/*
299162306a36Sopenharmony_ci * vmci_qpair_consume_buf_ready() - Gets bytes ready to read from
299262306a36Sopenharmony_ci * consumer queue.
299362306a36Sopenharmony_ci * @qpair:      Pointer to the queue pair struct.
299462306a36Sopenharmony_ci *
299562306a36Sopenharmony_ci * This is the client interface for getting the amount of
299662306a36Sopenharmony_ci * enqueued data in the QPair from the point of the view of the
299762306a36Sopenharmony_ci * caller as the consumer which is the normal case.  Returns < 0 if err,
299862306a36Sopenharmony_ci * else available bytes that may be read.
299962306a36Sopenharmony_ci */
300062306a36Sopenharmony_cis64 vmci_qpair_consume_buf_ready(const struct vmci_qp *qpair)
300162306a36Sopenharmony_ci{
300262306a36Sopenharmony_ci	struct vmci_queue_header *produce_q_header;
300362306a36Sopenharmony_ci	struct vmci_queue_header *consume_q_header;
300462306a36Sopenharmony_ci	s64 result;
300562306a36Sopenharmony_ci
300662306a36Sopenharmony_ci	if (!qpair)
300762306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
300862306a36Sopenharmony_ci
300962306a36Sopenharmony_ci	qp_lock(qpair);
301062306a36Sopenharmony_ci	result =
301162306a36Sopenharmony_ci	    qp_get_queue_headers(qpair, &produce_q_header, &consume_q_header);
301262306a36Sopenharmony_ci	if (result == VMCI_SUCCESS)
301362306a36Sopenharmony_ci		result = vmci_q_header_buf_ready(consume_q_header,
301462306a36Sopenharmony_ci						 produce_q_header,
301562306a36Sopenharmony_ci						 qpair->consume_q_size);
301662306a36Sopenharmony_ci	else
301762306a36Sopenharmony_ci		result = 0;
301862306a36Sopenharmony_ci
301962306a36Sopenharmony_ci	qp_unlock(qpair);
302062306a36Sopenharmony_ci
302162306a36Sopenharmony_ci	return result;
302262306a36Sopenharmony_ci}
302362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vmci_qpair_consume_buf_ready);
302462306a36Sopenharmony_ci
302562306a36Sopenharmony_ci/*
302662306a36Sopenharmony_ci * vmci_qpair_enqueue() - Throw data on the queue.
302762306a36Sopenharmony_ci * @qpair:      Pointer to the queue pair struct.
302862306a36Sopenharmony_ci * @buf:        Pointer to buffer containing data
302962306a36Sopenharmony_ci * @buf_size:   Length of buffer.
303062306a36Sopenharmony_ci * @buf_type:   Buffer type (Unused).
303162306a36Sopenharmony_ci *
303262306a36Sopenharmony_ci * This is the client interface for enqueueing data into the queue.
303362306a36Sopenharmony_ci * Returns number of bytes enqueued or < 0 on error.
303462306a36Sopenharmony_ci */
303562306a36Sopenharmony_cissize_t vmci_qpair_enqueue(struct vmci_qp *qpair,
303662306a36Sopenharmony_ci			   const void *buf,
303762306a36Sopenharmony_ci			   size_t buf_size,
303862306a36Sopenharmony_ci			   int buf_type)
303962306a36Sopenharmony_ci{
304062306a36Sopenharmony_ci	ssize_t result;
304162306a36Sopenharmony_ci	struct iov_iter from;
304262306a36Sopenharmony_ci	struct kvec v = {.iov_base = (void *)buf, .iov_len = buf_size};
304362306a36Sopenharmony_ci
304462306a36Sopenharmony_ci	if (!qpair || !buf)
304562306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
304662306a36Sopenharmony_ci
304762306a36Sopenharmony_ci	iov_iter_kvec(&from, ITER_SOURCE, &v, 1, buf_size);
304862306a36Sopenharmony_ci
304962306a36Sopenharmony_ci	qp_lock(qpair);
305062306a36Sopenharmony_ci
305162306a36Sopenharmony_ci	do {
305262306a36Sopenharmony_ci		result = qp_enqueue_locked(qpair->produce_q,
305362306a36Sopenharmony_ci					   qpair->consume_q,
305462306a36Sopenharmony_ci					   qpair->produce_q_size,
305562306a36Sopenharmony_ci					   &from);
305662306a36Sopenharmony_ci
305762306a36Sopenharmony_ci		if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
305862306a36Sopenharmony_ci		    !qp_wait_for_ready_queue(qpair))
305962306a36Sopenharmony_ci			result = VMCI_ERROR_WOULD_BLOCK;
306062306a36Sopenharmony_ci
306162306a36Sopenharmony_ci	} while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY);
306262306a36Sopenharmony_ci
306362306a36Sopenharmony_ci	qp_unlock(qpair);
306462306a36Sopenharmony_ci
306562306a36Sopenharmony_ci	return result;
306662306a36Sopenharmony_ci}
306762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vmci_qpair_enqueue);
306862306a36Sopenharmony_ci
306962306a36Sopenharmony_ci/*
307062306a36Sopenharmony_ci * vmci_qpair_dequeue() - Get data from the queue.
307162306a36Sopenharmony_ci * @qpair:      Pointer to the queue pair struct.
307262306a36Sopenharmony_ci * @buf:        Pointer to buffer for the data
307362306a36Sopenharmony_ci * @buf_size:   Length of buffer.
307462306a36Sopenharmony_ci * @buf_type:   Buffer type (Unused).
307562306a36Sopenharmony_ci *
307662306a36Sopenharmony_ci * This is the client interface for dequeueing data from the queue.
307762306a36Sopenharmony_ci * Returns number of bytes dequeued or < 0 on error.
307862306a36Sopenharmony_ci */
307962306a36Sopenharmony_cissize_t vmci_qpair_dequeue(struct vmci_qp *qpair,
308062306a36Sopenharmony_ci			   void *buf,
308162306a36Sopenharmony_ci			   size_t buf_size,
308262306a36Sopenharmony_ci			   int buf_type)
308362306a36Sopenharmony_ci{
308462306a36Sopenharmony_ci	ssize_t result;
308562306a36Sopenharmony_ci	struct iov_iter to;
308662306a36Sopenharmony_ci	struct kvec v = {.iov_base = buf, .iov_len = buf_size};
308762306a36Sopenharmony_ci
308862306a36Sopenharmony_ci	if (!qpair || !buf)
308962306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
309062306a36Sopenharmony_ci
309162306a36Sopenharmony_ci	iov_iter_kvec(&to, ITER_DEST, &v, 1, buf_size);
309262306a36Sopenharmony_ci
309362306a36Sopenharmony_ci	qp_lock(qpair);
309462306a36Sopenharmony_ci
309562306a36Sopenharmony_ci	do {
309662306a36Sopenharmony_ci		result = qp_dequeue_locked(qpair->produce_q,
309762306a36Sopenharmony_ci					   qpair->consume_q,
309862306a36Sopenharmony_ci					   qpair->consume_q_size,
309962306a36Sopenharmony_ci					   &to, true);
310062306a36Sopenharmony_ci
310162306a36Sopenharmony_ci		if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
310262306a36Sopenharmony_ci		    !qp_wait_for_ready_queue(qpair))
310362306a36Sopenharmony_ci			result = VMCI_ERROR_WOULD_BLOCK;
310462306a36Sopenharmony_ci
310562306a36Sopenharmony_ci	} while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY);
310662306a36Sopenharmony_ci
310762306a36Sopenharmony_ci	qp_unlock(qpair);
310862306a36Sopenharmony_ci
310962306a36Sopenharmony_ci	return result;
311062306a36Sopenharmony_ci}
311162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vmci_qpair_dequeue);
311262306a36Sopenharmony_ci
311362306a36Sopenharmony_ci/*
311462306a36Sopenharmony_ci * vmci_qpair_peek() - Peek at the data in the queue.
311562306a36Sopenharmony_ci * @qpair:      Pointer to the queue pair struct.
311662306a36Sopenharmony_ci * @buf:        Pointer to buffer for the data
311762306a36Sopenharmony_ci * @buf_size:   Length of buffer.
311862306a36Sopenharmony_ci * @buf_type:   Buffer type (Unused on Linux).
311962306a36Sopenharmony_ci *
312062306a36Sopenharmony_ci * This is the client interface for peeking into a queue.  (I.e.,
312162306a36Sopenharmony_ci * copy data from the queue without updating the head pointer.)
312262306a36Sopenharmony_ci * Returns number of bytes dequeued or < 0 on error.
312362306a36Sopenharmony_ci */
312462306a36Sopenharmony_cissize_t vmci_qpair_peek(struct vmci_qp *qpair,
312562306a36Sopenharmony_ci			void *buf,
312662306a36Sopenharmony_ci			size_t buf_size,
312762306a36Sopenharmony_ci			int buf_type)
312862306a36Sopenharmony_ci{
312962306a36Sopenharmony_ci	struct iov_iter to;
313062306a36Sopenharmony_ci	struct kvec v = {.iov_base = buf, .iov_len = buf_size};
313162306a36Sopenharmony_ci	ssize_t result;
313262306a36Sopenharmony_ci
313362306a36Sopenharmony_ci	if (!qpair || !buf)
313462306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
313562306a36Sopenharmony_ci
313662306a36Sopenharmony_ci	iov_iter_kvec(&to, ITER_DEST, &v, 1, buf_size);
313762306a36Sopenharmony_ci
313862306a36Sopenharmony_ci	qp_lock(qpair);
313962306a36Sopenharmony_ci
314062306a36Sopenharmony_ci	do {
314162306a36Sopenharmony_ci		result = qp_dequeue_locked(qpair->produce_q,
314262306a36Sopenharmony_ci					   qpair->consume_q,
314362306a36Sopenharmony_ci					   qpair->consume_q_size,
314462306a36Sopenharmony_ci					   &to, false);
314562306a36Sopenharmony_ci
314662306a36Sopenharmony_ci		if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
314762306a36Sopenharmony_ci		    !qp_wait_for_ready_queue(qpair))
314862306a36Sopenharmony_ci			result = VMCI_ERROR_WOULD_BLOCK;
314962306a36Sopenharmony_ci
315062306a36Sopenharmony_ci	} while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY);
315162306a36Sopenharmony_ci
315262306a36Sopenharmony_ci	qp_unlock(qpair);
315362306a36Sopenharmony_ci
315462306a36Sopenharmony_ci	return result;
315562306a36Sopenharmony_ci}
315662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vmci_qpair_peek);
315762306a36Sopenharmony_ci
315862306a36Sopenharmony_ci/*
315962306a36Sopenharmony_ci * vmci_qpair_enquev() - Throw data on the queue using iov.
316062306a36Sopenharmony_ci * @qpair:      Pointer to the queue pair struct.
316162306a36Sopenharmony_ci * @iov:        Pointer to buffer containing data
316262306a36Sopenharmony_ci * @iov_size:   Length of buffer.
316362306a36Sopenharmony_ci * @buf_type:   Buffer type (Unused).
316462306a36Sopenharmony_ci *
316562306a36Sopenharmony_ci * This is the client interface for enqueueing data into the queue.
316662306a36Sopenharmony_ci * This function uses IO vectors to handle the work. Returns number
316762306a36Sopenharmony_ci * of bytes enqueued or < 0 on error.
316862306a36Sopenharmony_ci */
316962306a36Sopenharmony_cissize_t vmci_qpair_enquev(struct vmci_qp *qpair,
317062306a36Sopenharmony_ci			  struct msghdr *msg,
317162306a36Sopenharmony_ci			  size_t iov_size,
317262306a36Sopenharmony_ci			  int buf_type)
317362306a36Sopenharmony_ci{
317462306a36Sopenharmony_ci	ssize_t result;
317562306a36Sopenharmony_ci
317662306a36Sopenharmony_ci	if (!qpair)
317762306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
317862306a36Sopenharmony_ci
317962306a36Sopenharmony_ci	qp_lock(qpair);
318062306a36Sopenharmony_ci
318162306a36Sopenharmony_ci	do {
318262306a36Sopenharmony_ci		result = qp_enqueue_locked(qpair->produce_q,
318362306a36Sopenharmony_ci					   qpair->consume_q,
318462306a36Sopenharmony_ci					   qpair->produce_q_size,
318562306a36Sopenharmony_ci					   &msg->msg_iter);
318662306a36Sopenharmony_ci
318762306a36Sopenharmony_ci		if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
318862306a36Sopenharmony_ci		    !qp_wait_for_ready_queue(qpair))
318962306a36Sopenharmony_ci			result = VMCI_ERROR_WOULD_BLOCK;
319062306a36Sopenharmony_ci
319162306a36Sopenharmony_ci	} while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY);
319262306a36Sopenharmony_ci
319362306a36Sopenharmony_ci	qp_unlock(qpair);
319462306a36Sopenharmony_ci
319562306a36Sopenharmony_ci	return result;
319662306a36Sopenharmony_ci}
319762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vmci_qpair_enquev);
319862306a36Sopenharmony_ci
319962306a36Sopenharmony_ci/*
320062306a36Sopenharmony_ci * vmci_qpair_dequev() - Get data from the queue using iov.
320162306a36Sopenharmony_ci * @qpair:      Pointer to the queue pair struct.
320262306a36Sopenharmony_ci * @iov:        Pointer to buffer for the data
320362306a36Sopenharmony_ci * @iov_size:   Length of buffer.
320462306a36Sopenharmony_ci * @buf_type:   Buffer type (Unused).
320562306a36Sopenharmony_ci *
320662306a36Sopenharmony_ci * This is the client interface for dequeueing data from the queue.
320762306a36Sopenharmony_ci * This function uses IO vectors to handle the work. Returns number
320862306a36Sopenharmony_ci * of bytes dequeued or < 0 on error.
320962306a36Sopenharmony_ci */
321062306a36Sopenharmony_cissize_t vmci_qpair_dequev(struct vmci_qp *qpair,
321162306a36Sopenharmony_ci			  struct msghdr *msg,
321262306a36Sopenharmony_ci			  size_t iov_size,
321362306a36Sopenharmony_ci			  int buf_type)
321462306a36Sopenharmony_ci{
321562306a36Sopenharmony_ci	ssize_t result;
321662306a36Sopenharmony_ci
321762306a36Sopenharmony_ci	if (!qpair)
321862306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
321962306a36Sopenharmony_ci
322062306a36Sopenharmony_ci	qp_lock(qpair);
322162306a36Sopenharmony_ci
322262306a36Sopenharmony_ci	do {
322362306a36Sopenharmony_ci		result = qp_dequeue_locked(qpair->produce_q,
322462306a36Sopenharmony_ci					   qpair->consume_q,
322562306a36Sopenharmony_ci					   qpair->consume_q_size,
322662306a36Sopenharmony_ci					   &msg->msg_iter, true);
322762306a36Sopenharmony_ci
322862306a36Sopenharmony_ci		if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
322962306a36Sopenharmony_ci		    !qp_wait_for_ready_queue(qpair))
323062306a36Sopenharmony_ci			result = VMCI_ERROR_WOULD_BLOCK;
323162306a36Sopenharmony_ci
323262306a36Sopenharmony_ci	} while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY);
323362306a36Sopenharmony_ci
323462306a36Sopenharmony_ci	qp_unlock(qpair);
323562306a36Sopenharmony_ci
323662306a36Sopenharmony_ci	return result;
323762306a36Sopenharmony_ci}
323862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vmci_qpair_dequev);
323962306a36Sopenharmony_ci
324062306a36Sopenharmony_ci/*
324162306a36Sopenharmony_ci * vmci_qpair_peekv() - Peek at the data in the queue using iov.
324262306a36Sopenharmony_ci * @qpair:      Pointer to the queue pair struct.
324362306a36Sopenharmony_ci * @iov:        Pointer to buffer for the data
324462306a36Sopenharmony_ci * @iov_size:   Length of buffer.
324562306a36Sopenharmony_ci * @buf_type:   Buffer type (Unused on Linux).
324662306a36Sopenharmony_ci *
324762306a36Sopenharmony_ci * This is the client interface for peeking into a queue.  (I.e.,
324862306a36Sopenharmony_ci * copy data from the queue without updating the head pointer.)
324962306a36Sopenharmony_ci * This function uses IO vectors to handle the work. Returns number
325062306a36Sopenharmony_ci * of bytes peeked or < 0 on error.
325162306a36Sopenharmony_ci */
325262306a36Sopenharmony_cissize_t vmci_qpair_peekv(struct vmci_qp *qpair,
325362306a36Sopenharmony_ci			 struct msghdr *msg,
325462306a36Sopenharmony_ci			 size_t iov_size,
325562306a36Sopenharmony_ci			 int buf_type)
325662306a36Sopenharmony_ci{
325762306a36Sopenharmony_ci	ssize_t result;
325862306a36Sopenharmony_ci
325962306a36Sopenharmony_ci	if (!qpair)
326062306a36Sopenharmony_ci		return VMCI_ERROR_INVALID_ARGS;
326162306a36Sopenharmony_ci
326262306a36Sopenharmony_ci	qp_lock(qpair);
326362306a36Sopenharmony_ci
326462306a36Sopenharmony_ci	do {
326562306a36Sopenharmony_ci		result = qp_dequeue_locked(qpair->produce_q,
326662306a36Sopenharmony_ci					   qpair->consume_q,
326762306a36Sopenharmony_ci					   qpair->consume_q_size,
326862306a36Sopenharmony_ci					   &msg->msg_iter, false);
326962306a36Sopenharmony_ci
327062306a36Sopenharmony_ci		if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
327162306a36Sopenharmony_ci		    !qp_wait_for_ready_queue(qpair))
327262306a36Sopenharmony_ci			result = VMCI_ERROR_WOULD_BLOCK;
327362306a36Sopenharmony_ci
327462306a36Sopenharmony_ci	} while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY);
327562306a36Sopenharmony_ci
327662306a36Sopenharmony_ci	qp_unlock(qpair);
327762306a36Sopenharmony_ci	return result;
327862306a36Sopenharmony_ci}
327962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(vmci_qpair_peekv);
3280