xref: /freebsd/sys/dev/vmware/vmci/vmci_driver.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
163a93856SMark Peek /*-
2*3eeb7511SMark Peek  * Copyright (c) 2018 VMware, Inc.
363a93856SMark Peek  *
48c302b2eSMark Peek  * SPDX-License-Identifier: (BSD-2-Clause OR GPL-2.0)
563a93856SMark Peek  */
663a93856SMark Peek 
763a93856SMark Peek /* VMCI initialization. */
863a93856SMark Peek 
963a93856SMark Peek #include <sys/cdefs.h>
1063a93856SMark Peek #include "vmci.h"
1163a93856SMark Peek #include "vmci_doorbell.h"
1263a93856SMark Peek #include "vmci_driver.h"
1363a93856SMark Peek #include "vmci_event.h"
1463a93856SMark Peek #include "vmci_kernel_api.h"
1563a93856SMark Peek #include "vmci_kernel_defs.h"
1663a93856SMark Peek #include "vmci_resource.h"
1763a93856SMark Peek 
1863a93856SMark Peek #define LGPFX			"vmci: "
1963a93856SMark Peek #define VMCI_UTIL_NUM_RESOURCES	1
2063a93856SMark Peek 
2163a93856SMark Peek static vmci_id ctx_update_sub_id = VMCI_INVALID_ID;
2263a93856SMark Peek static volatile int vm_context_id = VMCI_INVALID_ID;
2363a93856SMark Peek 
2463a93856SMark Peek /*
2563a93856SMark Peek  *------------------------------------------------------------------------------
2663a93856SMark Peek  *
2763a93856SMark Peek  * vmci_util_cid_update --
2863a93856SMark Peek  *
2963a93856SMark Peek  *     Gets called with the new context id if updated or resumed.
3063a93856SMark Peek  *
3163a93856SMark Peek  * Results:
3263a93856SMark Peek  *     Context id.
3363a93856SMark Peek  *
3463a93856SMark Peek  * Side effects:
3563a93856SMark Peek  *     None.
3663a93856SMark Peek  *
3763a93856SMark Peek  *------------------------------------------------------------------------------
3863a93856SMark Peek  */
3963a93856SMark Peek 
4063a93856SMark Peek static void
vmci_util_cid_update(vmci_id sub_id,struct vmci_event_data * event_data,void * client_data)4163a93856SMark Peek vmci_util_cid_update(vmci_id sub_id, struct vmci_event_data *event_data,
4263a93856SMark Peek     void *client_data)
4363a93856SMark Peek {
4463a93856SMark Peek 	struct vmci_event_payload_context *ev_payload;
4563a93856SMark Peek 
4663a93856SMark Peek 	ev_payload = vmci_event_data_payload(event_data);
4763a93856SMark Peek 
4863a93856SMark Peek 	if (sub_id != ctx_update_sub_id) {
4963a93856SMark Peek 		VMCI_LOG_DEBUG(LGPFX"Invalid subscriber (ID=0x%x).\n", sub_id);
5063a93856SMark Peek 		return;
5163a93856SMark Peek 	}
5263a93856SMark Peek 	if (event_data == NULL || ev_payload->context_id == VMCI_INVALID_ID) {
5363a93856SMark Peek 		VMCI_LOG_DEBUG(LGPFX"Invalid event data.\n");
5463a93856SMark Peek 		return;
5563a93856SMark Peek 	}
5663a93856SMark Peek 	VMCI_LOG_INFO(LGPFX"Updating context from (ID=0x%x) to (ID=0x%x) on "
5763a93856SMark Peek 	    "event (type=%d).\n", atomic_load_int(&vm_context_id),
5863a93856SMark Peek 	    ev_payload->context_id, event_data->event);
5963a93856SMark Peek 	atomic_store_int(&vm_context_id, ev_payload->context_id);
6063a93856SMark Peek }
6163a93856SMark Peek 
6263a93856SMark Peek /*
6363a93856SMark Peek  *------------------------------------------------------------------------------
6463a93856SMark Peek  *
6563a93856SMark Peek  * vmci_util_init --
6663a93856SMark Peek  *
6763a93856SMark Peek  *     Subscribe to context id update event.
6863a93856SMark Peek  *
6963a93856SMark Peek  * Results:
7063a93856SMark Peek  *     None.
7163a93856SMark Peek  *
7263a93856SMark Peek  * Side effects:
7363a93856SMark Peek  *     None.
7463a93856SMark Peek  *
7563a93856SMark Peek  *------------------------------------------------------------------------------
7663a93856SMark Peek  */
7763a93856SMark Peek 
7863a93856SMark Peek void
vmci_util_init(void)7963a93856SMark Peek vmci_util_init(void)
8063a93856SMark Peek {
8163a93856SMark Peek 
8263a93856SMark Peek 	/*
8363a93856SMark Peek 	 * We subscribe to the VMCI_EVENT_CTX_ID_UPDATE here so we can update
8463a93856SMark Peek 	 * the internal context id when needed.
8563a93856SMark Peek 	 */
8663a93856SMark Peek 	if (vmci_event_subscribe(VMCI_EVENT_CTX_ID_UPDATE,
8763a93856SMark Peek 	    vmci_util_cid_update, NULL, &ctx_update_sub_id) < VMCI_SUCCESS) {
8863a93856SMark Peek 		VMCI_LOG_WARNING(LGPFX"Failed to subscribe to event "
8963a93856SMark Peek 		    "(type=%d).\n", VMCI_EVENT_CTX_ID_UPDATE);
9063a93856SMark Peek 	}
9163a93856SMark Peek }
9263a93856SMark Peek 
9363a93856SMark Peek /*
9463a93856SMark Peek  *------------------------------------------------------------------------------
9563a93856SMark Peek  *
9663a93856SMark Peek  * vmci_util_exit --
9763a93856SMark Peek  *
9863a93856SMark Peek  *     Cleanup
9963a93856SMark Peek  *
10063a93856SMark Peek  * Results:
10163a93856SMark Peek  *     None.
10263a93856SMark Peek  *
10363a93856SMark Peek  * Side effects:
10463a93856SMark Peek  *     None.
10563a93856SMark Peek  *
10663a93856SMark Peek  *------------------------------------------------------------------------------
10763a93856SMark Peek  */
10863a93856SMark Peek 
10963a93856SMark Peek void
vmci_util_exit(void)11063a93856SMark Peek vmci_util_exit(void)
11163a93856SMark Peek {
11263a93856SMark Peek 
11363a93856SMark Peek 	if (vmci_event_unsubscribe(ctx_update_sub_id) < VMCI_SUCCESS)
11463a93856SMark Peek 		VMCI_LOG_WARNING(LGPFX"Failed to unsubscribe to event "
11563a93856SMark Peek 		    "(type=%d) with subscriber (ID=0x%x).\n",
11663a93856SMark Peek 		    VMCI_EVENT_CTX_ID_UPDATE, ctx_update_sub_id);
11763a93856SMark Peek }
11863a93856SMark Peek 
11963a93856SMark Peek /*
12063a93856SMark Peek  *------------------------------------------------------------------------------
12163a93856SMark Peek  *
12263a93856SMark Peek  * vmci_util_check_host_capabilities --
12363a93856SMark Peek  *
12463a93856SMark Peek  *     Verify that the host supports the hypercalls we need. If it does not, try
12563a93856SMark Peek  *     to find fallback hypercalls and use those instead.
12663a93856SMark Peek  *
12763a93856SMark Peek  * Results:
12863a93856SMark Peek  *     true if required hypercalls (or fallback hypercalls) are supported by the
12963a93856SMark Peek  *     host, false otherwise.
13063a93856SMark Peek  *
13163a93856SMark Peek  * Side effects:
13263a93856SMark Peek  *     None.
13363a93856SMark Peek  *
13463a93856SMark Peek  *------------------------------------------------------------------------------
13563a93856SMark Peek  */
13663a93856SMark Peek 
13763a93856SMark Peek static bool
vmci_util_check_host_capabilities(void)13863a93856SMark Peek vmci_util_check_host_capabilities(void)
13963a93856SMark Peek {
14063a93856SMark Peek 	struct vmci_resources_query_msg *msg;
14163a93856SMark Peek 	struct vmci_datagram *check_msg;
14263a93856SMark Peek 	int result;
14363a93856SMark Peek 	uint32_t msg_size;
14463a93856SMark Peek 
14563a93856SMark Peek 	msg_size = sizeof(struct vmci_resources_query_hdr) +
14663a93856SMark Peek 	    VMCI_UTIL_NUM_RESOURCES * sizeof(vmci_resource);
14763a93856SMark Peek 	check_msg = vmci_alloc_kernel_mem(msg_size, VMCI_MEMORY_NORMAL);
14863a93856SMark Peek 
14963a93856SMark Peek 	if (check_msg == NULL) {
15063a93856SMark Peek 		VMCI_LOG_WARNING(LGPFX"Check host: Insufficient memory.\n");
15163a93856SMark Peek 		return (false);
15263a93856SMark Peek 	}
15363a93856SMark Peek 
15463a93856SMark Peek 	check_msg->dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
15563a93856SMark Peek 	    VMCI_RESOURCES_QUERY);
15663a93856SMark Peek 	check_msg->src = VMCI_ANON_SRC_HANDLE;
15763a93856SMark Peek 	check_msg->payload_size = msg_size - VMCI_DG_HEADERSIZE;
15863a93856SMark Peek 	msg = (struct vmci_resources_query_msg *)VMCI_DG_PAYLOAD(check_msg);
15963a93856SMark Peek 
16063a93856SMark Peek 	msg->num_resources = VMCI_UTIL_NUM_RESOURCES;
16163a93856SMark Peek 	msg->resources[0] = VMCI_GET_CONTEXT_ID;
16263a93856SMark Peek 
16363a93856SMark Peek 	result = vmci_send_datagram(check_msg);
16463a93856SMark Peek 	vmci_free_kernel_mem(check_msg, msg_size);
16563a93856SMark Peek 
16663a93856SMark Peek 	/* We need the vector. There are no fallbacks. */
16763a93856SMark Peek 	return (result == 0x1);
16863a93856SMark Peek }
16963a93856SMark Peek 
17063a93856SMark Peek /*
17163a93856SMark Peek  *------------------------------------------------------------------------------
17263a93856SMark Peek  *
17363a93856SMark Peek  * vmci_check_host_capabilities --
17463a93856SMark Peek  *
17563a93856SMark Peek  *     Tell host which guestcalls we support and let each API check that the
17663a93856SMark Peek  *     host supports the hypercalls it needs. If a hypercall is not supported,
17763a93856SMark Peek  *     the API can check for a fallback hypercall, or fail the check.
17863a93856SMark Peek  *
17963a93856SMark Peek  * Results:
18063a93856SMark Peek  *     true if successful, false otherwise.
18163a93856SMark Peek  *
18263a93856SMark Peek  * Side effects:
18363a93856SMark Peek  *     Fallback mechanisms may be enabled in the API and vmmon.
18463a93856SMark Peek  *
18563a93856SMark Peek  *------------------------------------------------------------------------------
18663a93856SMark Peek  */
18763a93856SMark Peek 
18863a93856SMark Peek bool
vmci_check_host_capabilities(void)18963a93856SMark Peek vmci_check_host_capabilities(void)
19063a93856SMark Peek {
19163a93856SMark Peek 	bool result;
19263a93856SMark Peek 
19363a93856SMark Peek 	result = vmci_event_check_host_capabilities();
19463a93856SMark Peek 	result &= vmci_datagram_check_host_capabilities();
19563a93856SMark Peek 	result &= vmci_util_check_host_capabilities();
19663a93856SMark Peek 
19763a93856SMark Peek 	if (!result) {
19863a93856SMark Peek 		/*
19963a93856SMark Peek 		 * If it failed, then make sure this goes to the system event
20063a93856SMark Peek 		 * log.
20163a93856SMark Peek 		 */
20263a93856SMark Peek 		VMCI_LOG_WARNING(LGPFX"Host capability checked failed.\n");
20363a93856SMark Peek 	} else
20463a93856SMark Peek 		VMCI_LOG_DEBUG(LGPFX"Host capability check passed.\n");
20563a93856SMark Peek 
20663a93856SMark Peek 	return (result);
20763a93856SMark Peek }
20863a93856SMark Peek 
20963a93856SMark Peek /*
21063a93856SMark Peek  *------------------------------------------------------------------------------
21163a93856SMark Peek  *
21263a93856SMark Peek  * vmci_read_datagrams_from_port --
21363a93856SMark Peek  *
21463a93856SMark Peek  *     Reads datagrams from the data in port and dispatches them. We always
21563a93856SMark Peek  *     start reading datagrams into only the first page of the datagram buffer.
21663a93856SMark Peek  *     If the datagrams don't fit into one page, we use the maximum datagram
21763a93856SMark Peek  *     buffer size for the remainder of the  invocation. This is a simple
21863a93856SMark Peek  *     heuristic for not penalizing small datagrams.
21963a93856SMark Peek  *
22063a93856SMark Peek  *     This function assumes that it has exclusive access to the data in port
22163a93856SMark Peek  *     for the duration of the call.
22263a93856SMark Peek  *
22363a93856SMark Peek  * Results:
22463a93856SMark Peek  *     No result.
22563a93856SMark Peek  *
22663a93856SMark Peek  * Side effects:
22763a93856SMark Peek  *     Datagram handlers may be invoked.
22863a93856SMark Peek  *
22963a93856SMark Peek  *------------------------------------------------------------------------------
23063a93856SMark Peek  */
23163a93856SMark Peek 
23263a93856SMark Peek void
vmci_read_datagrams_from_port(vmci_io_handle io_handle,vmci_io_port dg_in_port,uint8_t * dg_in_buffer,size_t dg_in_buffer_size)23363a93856SMark Peek vmci_read_datagrams_from_port(vmci_io_handle io_handle, vmci_io_port dg_in_port,
23463a93856SMark Peek     uint8_t *dg_in_buffer, size_t dg_in_buffer_size)
23563a93856SMark Peek {
23663a93856SMark Peek 	struct vmci_datagram *dg;
23763a93856SMark Peek 	size_t current_dg_in_buffer_size;
23863a93856SMark Peek 	size_t remaining_bytes;
23963a93856SMark Peek 
24063a93856SMark Peek 	current_dg_in_buffer_size = PAGE_SIZE;
24163a93856SMark Peek 
24263a93856SMark Peek 	ASSERT(dg_in_buffer_size >= PAGE_SIZE);
24363a93856SMark Peek 
24463a93856SMark Peek 	vmci_read_port_bytes(io_handle, dg_in_port, dg_in_buffer,
24563a93856SMark Peek 	    current_dg_in_buffer_size);
24663a93856SMark Peek 	dg = (struct vmci_datagram *)dg_in_buffer;
24763a93856SMark Peek 	remaining_bytes = current_dg_in_buffer_size;
24863a93856SMark Peek 
24963a93856SMark Peek 	while (dg->dst.resource != VMCI_INVALID_ID ||
25063a93856SMark Peek 	    remaining_bytes > PAGE_SIZE) {
25163a93856SMark Peek 		size_t dg_in_size;
25263a93856SMark Peek 
25363a93856SMark Peek 		/*
25463a93856SMark Peek 		 * When the input buffer spans multiple pages, a datagram can
25563a93856SMark Peek 		 * start on any page boundary in the buffer.
25663a93856SMark Peek 		 */
25763a93856SMark Peek 
25863a93856SMark Peek 		if (dg->dst.resource == VMCI_INVALID_ID) {
25963a93856SMark Peek 			ASSERT(remaining_bytes > PAGE_SIZE);
26063a93856SMark Peek 			dg = (struct vmci_datagram *)ROUNDUP((uintptr_t)dg + 1,
26163a93856SMark Peek 			    PAGE_SIZE);
26263a93856SMark Peek 			ASSERT((uint8_t *)dg < dg_in_buffer +
26363a93856SMark Peek 			    current_dg_in_buffer_size);
26463a93856SMark Peek 			remaining_bytes = (size_t)(dg_in_buffer +
26563a93856SMark Peek 			    current_dg_in_buffer_size - (uint8_t *)dg);
26663a93856SMark Peek 			continue;
26763a93856SMark Peek 		}
26863a93856SMark Peek 
26963a93856SMark Peek 		dg_in_size = VMCI_DG_SIZE_ALIGNED(dg);
27063a93856SMark Peek 
27163a93856SMark Peek 		if (dg_in_size <= dg_in_buffer_size) {
27263a93856SMark Peek 			int result;
27363a93856SMark Peek 
27463a93856SMark Peek 			/*
27563a93856SMark Peek 			 * If the remaining bytes in the datagram buffer doesn't
27663a93856SMark Peek 			 * contain the complete datagram, we first make sure we
27763a93856SMark Peek 			 * have enough room for it and then we read the reminder
27863a93856SMark Peek 			 * of the datagram and possibly any following datagrams.
27963a93856SMark Peek 			 */
28063a93856SMark Peek 
28163a93856SMark Peek 			if (dg_in_size > remaining_bytes) {
28263a93856SMark Peek 				if (remaining_bytes !=
28363a93856SMark Peek 				    current_dg_in_buffer_size) {
28463a93856SMark Peek 					/*
28563a93856SMark Peek 					 * We move the partial datagram to the
28663a93856SMark Peek 					 * front and read the reminder of the
28763a93856SMark Peek 					 * datagram and possibly following calls
28863a93856SMark Peek 					 * into the following bytes.
28963a93856SMark Peek 					 */
29063a93856SMark Peek 
29163a93856SMark Peek 					memmove(dg_in_buffer, dg_in_buffer +
29263a93856SMark Peek 					    current_dg_in_buffer_size -
29363a93856SMark Peek 					    remaining_bytes,
29463a93856SMark Peek 					    remaining_bytes);
29563a93856SMark Peek 
29663a93856SMark Peek 					dg = (struct vmci_datagram *)
29763a93856SMark Peek 					    dg_in_buffer;
29863a93856SMark Peek 				}
29963a93856SMark Peek 
30063a93856SMark Peek 				if (current_dg_in_buffer_size !=
30163a93856SMark Peek 				    dg_in_buffer_size)
30263a93856SMark Peek 					current_dg_in_buffer_size =
30363a93856SMark Peek 					    dg_in_buffer_size;
30463a93856SMark Peek 
30563a93856SMark Peek 				vmci_read_port_bytes(io_handle, dg_in_port,
30663a93856SMark Peek 				    dg_in_buffer + remaining_bytes,
30763a93856SMark Peek 				    current_dg_in_buffer_size -
30863a93856SMark Peek 				    remaining_bytes);
30963a93856SMark Peek 			}
31063a93856SMark Peek 
31163a93856SMark Peek 			/*
31263a93856SMark Peek 			 * We special case event datagrams from the
31363a93856SMark Peek 			 * hypervisor.
31463a93856SMark Peek 			 */
31563a93856SMark Peek 			if (dg->src.context == VMCI_HYPERVISOR_CONTEXT_ID &&
31663a93856SMark Peek 			    dg->dst.resource == VMCI_EVENT_HANDLER)
31763a93856SMark Peek 				result = vmci_event_dispatch(dg);
31863a93856SMark Peek 			else
31963a93856SMark Peek 				result =
32063a93856SMark Peek 				    vmci_datagram_invoke_guest_handler(dg);
32163a93856SMark Peek 			if (result < VMCI_SUCCESS)
32263a93856SMark Peek 				VMCI_LOG_DEBUG(LGPFX"Datagram with resource"
32363a93856SMark Peek 				    " (ID=0x%x) failed (err=%d).\n",
32463a93856SMark Peek 				    dg->dst.resource, result);
32563a93856SMark Peek 
32663a93856SMark Peek 			/* On to the next datagram. */
32763a93856SMark Peek 			dg = (struct vmci_datagram *)((uint8_t *)dg +
32863a93856SMark Peek 			    dg_in_size);
32963a93856SMark Peek 		} else {
33063a93856SMark Peek 			size_t bytes_to_skip;
33163a93856SMark Peek 
33263a93856SMark Peek 			/*
33363a93856SMark Peek 			 * Datagram doesn't fit in datagram buffer of maximal
33463a93856SMark Peek 			 * size. We drop it.
33563a93856SMark Peek 			 */
33663a93856SMark Peek 
33763a93856SMark Peek 			VMCI_LOG_DEBUG(LGPFX"Failed to receive datagram "
33863a93856SMark Peek 			    "(size=%zu bytes).\n", dg_in_size);
33963a93856SMark Peek 
34063a93856SMark Peek 			bytes_to_skip = dg_in_size - remaining_bytes;
34163a93856SMark Peek 			if (current_dg_in_buffer_size != dg_in_buffer_size)
34263a93856SMark Peek 				current_dg_in_buffer_size = dg_in_buffer_size;
34363a93856SMark Peek 			for (;;) {
34463a93856SMark Peek 				vmci_read_port_bytes(io_handle, dg_in_port,
34563a93856SMark Peek 				    dg_in_buffer, current_dg_in_buffer_size);
34663a93856SMark Peek 				if (bytes_to_skip <=
34763a93856SMark Peek 				    current_dg_in_buffer_size)
34863a93856SMark Peek 					break;
34963a93856SMark Peek 				bytes_to_skip -= current_dg_in_buffer_size;
35063a93856SMark Peek 			}
35163a93856SMark Peek 			dg = (struct vmci_datagram *)(dg_in_buffer +
35263a93856SMark Peek 			    bytes_to_skip);
35363a93856SMark Peek 		}
35463a93856SMark Peek 
35563a93856SMark Peek 		remaining_bytes = (size_t) (dg_in_buffer +
35663a93856SMark Peek 		    current_dg_in_buffer_size - (uint8_t *)dg);
35763a93856SMark Peek 
35863a93856SMark Peek 		if (remaining_bytes < VMCI_DG_HEADERSIZE) {
35963a93856SMark Peek 			/* Get the next batch of datagrams. */
36063a93856SMark Peek 
36163a93856SMark Peek 			vmci_read_port_bytes(io_handle, dg_in_port,
36263a93856SMark Peek 			    dg_in_buffer, current_dg_in_buffer_size);
36363a93856SMark Peek 			dg = (struct vmci_datagram *)dg_in_buffer;
36463a93856SMark Peek 			remaining_bytes = current_dg_in_buffer_size;
36563a93856SMark Peek 		}
36663a93856SMark Peek 	}
36763a93856SMark Peek }
36863a93856SMark Peek 
36963a93856SMark Peek /*
37063a93856SMark Peek  *------------------------------------------------------------------------------
37163a93856SMark Peek  *
37263a93856SMark Peek  * vmci_get_context_id --
37363a93856SMark Peek  *
37463a93856SMark Peek  *     Returns the current context ID.  Note that since this is accessed only
37563a93856SMark Peek  *     from code running in the host, this always returns the host context ID.
37663a93856SMark Peek  *
37763a93856SMark Peek  * Results:
37863a93856SMark Peek  *     Context ID.
37963a93856SMark Peek  *
38063a93856SMark Peek  * Side effects:
38163a93856SMark Peek  *     None.
38263a93856SMark Peek  *
38363a93856SMark Peek  *------------------------------------------------------------------------------
38463a93856SMark Peek  */
38563a93856SMark Peek 
38663a93856SMark Peek vmci_id
vmci_get_context_id(void)38763a93856SMark Peek vmci_get_context_id(void)
38863a93856SMark Peek {
38963a93856SMark Peek 	if (atomic_load_int(&vm_context_id) == VMCI_INVALID_ID) {
39063a93856SMark Peek 		uint32_t result;
39163a93856SMark Peek 		struct vmci_datagram get_cid_msg;
39263a93856SMark Peek 		get_cid_msg.dst =  VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
39363a93856SMark Peek 		    VMCI_GET_CONTEXT_ID);
39463a93856SMark Peek 		get_cid_msg.src = VMCI_ANON_SRC_HANDLE;
39563a93856SMark Peek 		get_cid_msg.payload_size = 0;
39663a93856SMark Peek 		result = vmci_send_datagram(&get_cid_msg);
39763a93856SMark Peek 		atomic_store_int(&vm_context_id, result);
39863a93856SMark Peek 	}
39963a93856SMark Peek 	return (atomic_load_int(&vm_context_id));
40063a93856SMark Peek }
40163a93856SMark Peek 
40263a93856SMark Peek /*
40363a93856SMark Peek  *------------------------------------------------------------------------------
40463a93856SMark Peek  *
40563a93856SMark Peek  * vmci_components_init --
40663a93856SMark Peek  *
40763a93856SMark Peek  *     Initializes VMCI components and registers core hypercalls.
40863a93856SMark Peek  *
40963a93856SMark Peek  * Results:
41063a93856SMark Peek  *     VMCI_SUCCESS if successful, appropriate error code otherwise.
41163a93856SMark Peek  *
41263a93856SMark Peek  * Side effects:
41363a93856SMark Peek  *     None.
41463a93856SMark Peek  *
41563a93856SMark Peek  *------------------------------------------------------------------------------
41663a93856SMark Peek  */
41763a93856SMark Peek 
41863a93856SMark Peek int
vmci_components_init(void)41963a93856SMark Peek vmci_components_init(void)
42063a93856SMark Peek {
42163a93856SMark Peek 	int result;
42263a93856SMark Peek 
42363a93856SMark Peek 	result = vmci_resource_init();
42463a93856SMark Peek 	if (result < VMCI_SUCCESS) {
42563a93856SMark Peek 		VMCI_LOG_WARNING(LGPFX"Failed to initialize vmci_resource "
42663a93856SMark Peek 		    "(result=%d).\n", result);
42763a93856SMark Peek 		goto error_exit;
42863a93856SMark Peek 	}
42963a93856SMark Peek 
43063a93856SMark Peek 	result = vmci_event_init();
43163a93856SMark Peek 	if (result < VMCI_SUCCESS) {
43263a93856SMark Peek 		VMCI_LOG_WARNING(LGPFX"Failed to initialize vmci_event "
43363a93856SMark Peek 		    "(result=%d).\n", result);
43463a93856SMark Peek 		goto resource_exit;
43563a93856SMark Peek 	}
43663a93856SMark Peek 
43763a93856SMark Peek 	result = vmci_doorbell_init();
43863a93856SMark Peek 	if (result < VMCI_SUCCESS) {
43963a93856SMark Peek 		VMCI_LOG_WARNING(LGPFX"Failed to initialize vmci_doorbell "
44063a93856SMark Peek 		    "(result=%d).\n", result);
44163a93856SMark Peek 		goto event_exit;
44263a93856SMark Peek 	}
44363a93856SMark Peek 
44463a93856SMark Peek 	VMCI_LOG_DEBUG(LGPFX"components initialized.\n");
44563a93856SMark Peek 	return (VMCI_SUCCESS);
44663a93856SMark Peek 
44763a93856SMark Peek event_exit:
44863a93856SMark Peek 	vmci_event_exit();
44963a93856SMark Peek 
45063a93856SMark Peek resource_exit:
45163a93856SMark Peek 	vmci_resource_exit();
45263a93856SMark Peek 
45363a93856SMark Peek error_exit:
45463a93856SMark Peek 	return (result);
45563a93856SMark Peek }
45663a93856SMark Peek 
45763a93856SMark Peek /*
45863a93856SMark Peek  *------------------------------------------------------------------------------
45963a93856SMark Peek  *
46063a93856SMark Peek  * vmci_components_cleanup --
46163a93856SMark Peek  *
46263a93856SMark Peek  *     Cleans up VMCI components.
46363a93856SMark Peek  *
46463a93856SMark Peek  * Results:
46563a93856SMark Peek  *     None.
46663a93856SMark Peek  *
46763a93856SMark Peek  * Side effects:
46863a93856SMark Peek  *     None.
46963a93856SMark Peek  *
47063a93856SMark Peek  *------------------------------------------------------------------------------
47163a93856SMark Peek  */
47263a93856SMark Peek 
47363a93856SMark Peek void
vmci_components_cleanup(void)47463a93856SMark Peek vmci_components_cleanup(void)
47563a93856SMark Peek {
47663a93856SMark Peek 
47763a93856SMark Peek 	vmci_doorbell_exit();
47863a93856SMark Peek 	vmci_event_exit();
47963a93856SMark Peek 	vmci_resource_exit();
48063a93856SMark Peek }
481