18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * VMware VMCI Driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2012 VMware, Inc. All rights reserved. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/vmw_vmci_defs.h> 98c2ecf20Sopenharmony_ci#include <linux/vmw_vmci_api.h> 108c2ecf20Sopenharmony_ci#include <linux/atomic.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "vmci_driver.h" 168c2ecf20Sopenharmony_ci#include "vmci_event.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic bool vmci_disable_host; 198c2ecf20Sopenharmony_cimodule_param_named(disable_host, vmci_disable_host, bool, 0); 208c2ecf20Sopenharmony_ciMODULE_PARM_DESC(disable_host, 218c2ecf20Sopenharmony_ci "Disable driver host personality (default=enabled)"); 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic bool vmci_disable_guest; 248c2ecf20Sopenharmony_cimodule_param_named(disable_guest, vmci_disable_guest, bool, 0); 258c2ecf20Sopenharmony_ciMODULE_PARM_DESC(disable_guest, 268c2ecf20Sopenharmony_ci "Disable driver guest personality (default=enabled)"); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic bool vmci_guest_personality_initialized; 298c2ecf20Sopenharmony_cistatic bool vmci_host_personality_initialized; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(vmci_vsock_mutex); /* protects vmci_vsock_transport_cb */ 328c2ecf20Sopenharmony_cistatic vmci_vsock_cb vmci_vsock_transport_cb; 338c2ecf20Sopenharmony_cistatic bool vmci_vsock_cb_host_called; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* 368c2ecf20Sopenharmony_ci * vmci_get_context_id() - Gets the current context ID. 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * Returns the current context ID. Note that since this is accessed only 398c2ecf20Sopenharmony_ci * from code running in the host, this always returns the host context ID. 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ciu32 vmci_get_context_id(void) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci if (vmci_guest_code_active()) 448c2ecf20Sopenharmony_ci return vmci_get_vm_context_id(); 458c2ecf20Sopenharmony_ci else if (vmci_host_code_active()) 468c2ecf20Sopenharmony_ci return VMCI_HOST_CONTEXT_ID; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci return VMCI_INVALID_ID; 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vmci_get_context_id); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* 538c2ecf20Sopenharmony_ci * vmci_register_vsock_callback() - Register the VSOCK vmci_transport callback. 548c2ecf20Sopenharmony_ci * 558c2ecf20Sopenharmony_ci * The callback will be called when the first host or guest becomes active, 568c2ecf20Sopenharmony_ci * or if they are already active when this function is called. 578c2ecf20Sopenharmony_ci * To unregister the callback, call this function with NULL parameter. 588c2ecf20Sopenharmony_ci * 598c2ecf20Sopenharmony_ci * Returns 0 on success. -EBUSY if a callback is already registered. 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_ciint vmci_register_vsock_callback(vmci_vsock_cb callback) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci int err = 0; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci mutex_lock(&vmci_vsock_mutex); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (vmci_vsock_transport_cb && callback) { 688c2ecf20Sopenharmony_ci err = -EBUSY; 698c2ecf20Sopenharmony_ci goto out; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci vmci_vsock_transport_cb = callback; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (!vmci_vsock_transport_cb) { 758c2ecf20Sopenharmony_ci vmci_vsock_cb_host_called = false; 768c2ecf20Sopenharmony_ci goto out; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (vmci_guest_code_active()) 808c2ecf20Sopenharmony_ci vmci_vsock_transport_cb(false); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (vmci_host_users() > 0) { 838c2ecf20Sopenharmony_ci vmci_vsock_cb_host_called = true; 848c2ecf20Sopenharmony_ci vmci_vsock_transport_cb(true); 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ciout: 888c2ecf20Sopenharmony_ci mutex_unlock(&vmci_vsock_mutex); 898c2ecf20Sopenharmony_ci return err; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vmci_register_vsock_callback); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_civoid vmci_call_vsock_callback(bool is_host) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci mutex_lock(&vmci_vsock_mutex); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci if (!vmci_vsock_transport_cb) 988c2ecf20Sopenharmony_ci goto out; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci /* In the host, this function could be called multiple times, 1018c2ecf20Sopenharmony_ci * but we want to register it only once. 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_ci if (is_host) { 1048c2ecf20Sopenharmony_ci if (vmci_vsock_cb_host_called) 1058c2ecf20Sopenharmony_ci goto out; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci vmci_vsock_cb_host_called = true; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci vmci_vsock_transport_cb(is_host); 1118c2ecf20Sopenharmony_ciout: 1128c2ecf20Sopenharmony_ci mutex_unlock(&vmci_vsock_mutex); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic int __init vmci_drv_init(void) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci int vmci_err; 1188c2ecf20Sopenharmony_ci int error; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci vmci_err = vmci_event_init(); 1218c2ecf20Sopenharmony_ci if (vmci_err < VMCI_SUCCESS) { 1228c2ecf20Sopenharmony_ci pr_err("Failed to initialize VMCIEvent (result=%d)\n", 1238c2ecf20Sopenharmony_ci vmci_err); 1248c2ecf20Sopenharmony_ci return -EINVAL; 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (!vmci_disable_guest) { 1288c2ecf20Sopenharmony_ci error = vmci_guest_init(); 1298c2ecf20Sopenharmony_ci if (error) { 1308c2ecf20Sopenharmony_ci pr_warn("Failed to initialize guest personality (err=%d)\n", 1318c2ecf20Sopenharmony_ci error); 1328c2ecf20Sopenharmony_ci } else { 1338c2ecf20Sopenharmony_ci vmci_guest_personality_initialized = true; 1348c2ecf20Sopenharmony_ci pr_info("Guest personality initialized and is %s\n", 1358c2ecf20Sopenharmony_ci vmci_guest_code_active() ? 1368c2ecf20Sopenharmony_ci "active" : "inactive"); 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (!vmci_disable_host) { 1418c2ecf20Sopenharmony_ci error = vmci_host_init(); 1428c2ecf20Sopenharmony_ci if (error) { 1438c2ecf20Sopenharmony_ci pr_warn("Unable to initialize host personality (err=%d)\n", 1448c2ecf20Sopenharmony_ci error); 1458c2ecf20Sopenharmony_ci } else { 1468c2ecf20Sopenharmony_ci vmci_host_personality_initialized = true; 1478c2ecf20Sopenharmony_ci pr_info("Initialized host personality\n"); 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (!vmci_guest_personality_initialized && 1528c2ecf20Sopenharmony_ci !vmci_host_personality_initialized) { 1538c2ecf20Sopenharmony_ci vmci_event_exit(); 1548c2ecf20Sopenharmony_ci return -ENODEV; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci return 0; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_cimodule_init(vmci_drv_init); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic void __exit vmci_drv_exit(void) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci if (vmci_guest_personality_initialized) 1648c2ecf20Sopenharmony_ci vmci_guest_exit(); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci if (vmci_host_personality_initialized) 1678c2ecf20Sopenharmony_ci vmci_host_exit(); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci vmci_event_exit(); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_cimodule_exit(vmci_drv_exit); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ciMODULE_AUTHOR("VMware, Inc."); 1748c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("VMware Virtual Machine Communication Interface."); 1758c2ecf20Sopenharmony_ciMODULE_VERSION("1.1.6.0-k"); 1768c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 177