1685a6bf8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2197dbaaaSGeorge Zhang /* 3197dbaaaSGeorge Zhang * VMware VMCI Driver 4197dbaaaSGeorge Zhang * 5197dbaaaSGeorge Zhang * Copyright (C) 2012 VMware, Inc. All rights reserved. 6197dbaaaSGeorge Zhang */ 7197dbaaaSGeorge Zhang 8197dbaaaSGeorge Zhang #include <linux/vmw_vmci_defs.h> 9197dbaaaSGeorge Zhang #include <linux/vmw_vmci_api.h> 10197dbaaaSGeorge Zhang #include <linux/atomic.h> 11197dbaaaSGeorge Zhang #include <linux/kernel.h> 12197dbaaaSGeorge Zhang #include <linux/module.h> 13197dbaaaSGeorge Zhang #include <linux/init.h> 14197dbaaaSGeorge Zhang 15197dbaaaSGeorge Zhang #include "vmci_driver.h" 16197dbaaaSGeorge Zhang #include "vmci_event.h" 17197dbaaaSGeorge Zhang 18197dbaaaSGeorge Zhang static bool vmci_disable_host; 19197dbaaaSGeorge Zhang module_param_named(disable_host, vmci_disable_host, bool, 0); 20197dbaaaSGeorge Zhang MODULE_PARM_DESC(disable_host, 21197dbaaaSGeorge Zhang "Disable driver host personality (default=enabled)"); 22197dbaaaSGeorge Zhang 23197dbaaaSGeorge Zhang static bool vmci_disable_guest; 24197dbaaaSGeorge Zhang module_param_named(disable_guest, vmci_disable_guest, bool, 0); 25197dbaaaSGeorge Zhang MODULE_PARM_DESC(disable_guest, 26197dbaaaSGeorge Zhang "Disable driver guest personality (default=enabled)"); 27197dbaaaSGeorge Zhang 28197dbaaaSGeorge Zhang static bool vmci_guest_personality_initialized; 29197dbaaaSGeorge Zhang static bool vmci_host_personality_initialized; 30197dbaaaSGeorge Zhang 31b1bba80aSStefano Garzarella static DEFINE_MUTEX(vmci_vsock_mutex); /* protects vmci_vsock_transport_cb */ 32b1bba80aSStefano Garzarella static vmci_vsock_cb vmci_vsock_transport_cb; 33b1bba80aSStefano Garzarella bool vmci_vsock_cb_host_called; 34b1bba80aSStefano Garzarella 35197dbaaaSGeorge Zhang /* 36197dbaaaSGeorge Zhang * vmci_get_context_id() - Gets the current context ID. 37197dbaaaSGeorge Zhang * 38197dbaaaSGeorge Zhang * Returns the current context ID. Note that since this is accessed only 39197dbaaaSGeorge Zhang * from code running in the host, this always returns the host context ID. 40197dbaaaSGeorge Zhang */ 41197dbaaaSGeorge Zhang u32 vmci_get_context_id(void) 42197dbaaaSGeorge Zhang { 43197dbaaaSGeorge Zhang if (vmci_guest_code_active()) 44197dbaaaSGeorge Zhang return vmci_get_vm_context_id(); 45197dbaaaSGeorge Zhang else if (vmci_host_code_active()) 46197dbaaaSGeorge Zhang return VMCI_HOST_CONTEXT_ID; 47197dbaaaSGeorge Zhang 48197dbaaaSGeorge Zhang return VMCI_INVALID_ID; 49197dbaaaSGeorge Zhang } 50197dbaaaSGeorge Zhang EXPORT_SYMBOL_GPL(vmci_get_context_id); 51197dbaaaSGeorge Zhang 52b1bba80aSStefano Garzarella /* 53b1bba80aSStefano Garzarella * vmci_register_vsock_callback() - Register the VSOCK vmci_transport callback. 54b1bba80aSStefano Garzarella * 55b1bba80aSStefano Garzarella * The callback will be called when the first host or guest becomes active, 56b1bba80aSStefano Garzarella * or if they are already active when this function is called. 57b1bba80aSStefano Garzarella * To unregister the callback, call this function with NULL parameter. 58b1bba80aSStefano Garzarella * 59b1bba80aSStefano Garzarella * Returns 0 on success. -EBUSY if a callback is already registered. 60b1bba80aSStefano Garzarella */ 61b1bba80aSStefano Garzarella int vmci_register_vsock_callback(vmci_vsock_cb callback) 62b1bba80aSStefano Garzarella { 63b1bba80aSStefano Garzarella int err = 0; 64b1bba80aSStefano Garzarella 65b1bba80aSStefano Garzarella mutex_lock(&vmci_vsock_mutex); 66b1bba80aSStefano Garzarella 67b1bba80aSStefano Garzarella if (vmci_vsock_transport_cb && callback) { 68b1bba80aSStefano Garzarella err = -EBUSY; 69b1bba80aSStefano Garzarella goto out; 70b1bba80aSStefano Garzarella } 71b1bba80aSStefano Garzarella 72b1bba80aSStefano Garzarella vmci_vsock_transport_cb = callback; 73b1bba80aSStefano Garzarella 74b1bba80aSStefano Garzarella if (!vmci_vsock_transport_cb) { 75b1bba80aSStefano Garzarella vmci_vsock_cb_host_called = false; 76b1bba80aSStefano Garzarella goto out; 77b1bba80aSStefano Garzarella } 78b1bba80aSStefano Garzarella 79b1bba80aSStefano Garzarella if (vmci_guest_code_active()) 80b1bba80aSStefano Garzarella vmci_vsock_transport_cb(false); 81b1bba80aSStefano Garzarella 82b1bba80aSStefano Garzarella if (vmci_host_users() > 0) { 83b1bba80aSStefano Garzarella vmci_vsock_cb_host_called = true; 84b1bba80aSStefano Garzarella vmci_vsock_transport_cb(true); 85b1bba80aSStefano Garzarella } 86b1bba80aSStefano Garzarella 87b1bba80aSStefano Garzarella out: 88b1bba80aSStefano Garzarella mutex_unlock(&vmci_vsock_mutex); 89b1bba80aSStefano Garzarella return err; 90b1bba80aSStefano Garzarella } 91b1bba80aSStefano Garzarella EXPORT_SYMBOL_GPL(vmci_register_vsock_callback); 92b1bba80aSStefano Garzarella 93b1bba80aSStefano Garzarella void vmci_call_vsock_callback(bool is_host) 94b1bba80aSStefano Garzarella { 95b1bba80aSStefano Garzarella mutex_lock(&vmci_vsock_mutex); 96b1bba80aSStefano Garzarella 97b1bba80aSStefano Garzarella if (!vmci_vsock_transport_cb) 98b1bba80aSStefano Garzarella goto out; 99b1bba80aSStefano Garzarella 100b1bba80aSStefano Garzarella /* In the host, this function could be called multiple times, 101b1bba80aSStefano Garzarella * but we want to register it only once. 102b1bba80aSStefano Garzarella */ 103b1bba80aSStefano Garzarella if (is_host) { 104b1bba80aSStefano Garzarella if (vmci_vsock_cb_host_called) 105b1bba80aSStefano Garzarella goto out; 106b1bba80aSStefano Garzarella 107b1bba80aSStefano Garzarella vmci_vsock_cb_host_called = true; 108b1bba80aSStefano Garzarella } 109b1bba80aSStefano Garzarella 110b1bba80aSStefano Garzarella vmci_vsock_transport_cb(is_host); 111b1bba80aSStefano Garzarella out: 112b1bba80aSStefano Garzarella mutex_unlock(&vmci_vsock_mutex); 113b1bba80aSStefano Garzarella } 114b1bba80aSStefano Garzarella 115197dbaaaSGeorge Zhang static int __init vmci_drv_init(void) 116197dbaaaSGeorge Zhang { 117197dbaaaSGeorge Zhang int vmci_err; 118197dbaaaSGeorge Zhang int error; 119197dbaaaSGeorge Zhang 120197dbaaaSGeorge Zhang vmci_err = vmci_event_init(); 121197dbaaaSGeorge Zhang if (vmci_err < VMCI_SUCCESS) { 122197dbaaaSGeorge Zhang pr_err("Failed to initialize VMCIEvent (result=%d)\n", 123197dbaaaSGeorge Zhang vmci_err); 124197dbaaaSGeorge Zhang return -EINVAL; 125197dbaaaSGeorge Zhang } 126197dbaaaSGeorge Zhang 127197dbaaaSGeorge Zhang if (!vmci_disable_guest) { 128197dbaaaSGeorge Zhang error = vmci_guest_init(); 129197dbaaaSGeorge Zhang if (error) { 130197dbaaaSGeorge Zhang pr_warn("Failed to initialize guest personality (err=%d)\n", 131197dbaaaSGeorge Zhang error); 132197dbaaaSGeorge Zhang } else { 133197dbaaaSGeorge Zhang vmci_guest_personality_initialized = true; 134197dbaaaSGeorge Zhang pr_info("Guest personality initialized and is %s\n", 135197dbaaaSGeorge Zhang vmci_guest_code_active() ? 136197dbaaaSGeorge Zhang "active" : "inactive"); 137197dbaaaSGeorge Zhang } 138197dbaaaSGeorge Zhang } 139197dbaaaSGeorge Zhang 140197dbaaaSGeorge Zhang if (!vmci_disable_host) { 141197dbaaaSGeorge Zhang error = vmci_host_init(); 142197dbaaaSGeorge Zhang if (error) { 143197dbaaaSGeorge Zhang pr_warn("Unable to initialize host personality (err=%d)\n", 144197dbaaaSGeorge Zhang error); 145197dbaaaSGeorge Zhang } else { 146197dbaaaSGeorge Zhang vmci_host_personality_initialized = true; 147197dbaaaSGeorge Zhang pr_info("Initialized host personality\n"); 148197dbaaaSGeorge Zhang } 149197dbaaaSGeorge Zhang } 150197dbaaaSGeorge Zhang 151197dbaaaSGeorge Zhang if (!vmci_guest_personality_initialized && 152197dbaaaSGeorge Zhang !vmci_host_personality_initialized) { 153197dbaaaSGeorge Zhang vmci_event_exit(); 154197dbaaaSGeorge Zhang return -ENODEV; 155197dbaaaSGeorge Zhang } 156197dbaaaSGeorge Zhang 157197dbaaaSGeorge Zhang return 0; 158197dbaaaSGeorge Zhang } 159197dbaaaSGeorge Zhang module_init(vmci_drv_init); 160197dbaaaSGeorge Zhang 161197dbaaaSGeorge Zhang static void __exit vmci_drv_exit(void) 162197dbaaaSGeorge Zhang { 163197dbaaaSGeorge Zhang if (vmci_guest_personality_initialized) 164197dbaaaSGeorge Zhang vmci_guest_exit(); 165197dbaaaSGeorge Zhang 166197dbaaaSGeorge Zhang if (vmci_host_personality_initialized) 167197dbaaaSGeorge Zhang vmci_host_exit(); 168197dbaaaSGeorge Zhang 169197dbaaaSGeorge Zhang vmci_event_exit(); 170197dbaaaSGeorge Zhang } 171197dbaaaSGeorge Zhang module_exit(vmci_drv_exit); 172197dbaaaSGeorge Zhang 173197dbaaaSGeorge Zhang MODULE_AUTHOR("VMware, Inc."); 174197dbaaaSGeorge Zhang MODULE_DESCRIPTION("VMware Virtual Machine Communication Interface."); 17511924ba5SJorgen Hansen MODULE_VERSION("1.1.6.0-k"); 176197dbaaaSGeorge Zhang MODULE_LICENSE("GPL v2"); 177