Commit | Line | Data |
---|---|---|
685a6bf8 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
197dbaaa GZ |
2 | /* |
3 | * VMware VMCI Driver | |
4 | * | |
5 | * Copyright (C) 2012 VMware, Inc. All rights reserved. | |
197dbaaa GZ |
6 | */ |
7 | ||
8 | #include <linux/vmw_vmci_defs.h> | |
9 | #include <linux/vmw_vmci_api.h> | |
10 | #include <linux/atomic.h> | |
11 | #include <linux/kernel.h> | |
12 | #include <linux/module.h> | |
13 | #include <linux/init.h> | |
14 | ||
15 | #include "vmci_driver.h" | |
16 | #include "vmci_event.h" | |
17 | ||
18 | static bool vmci_disable_host; | |
19 | module_param_named(disable_host, vmci_disable_host, bool, 0); | |
20 | MODULE_PARM_DESC(disable_host, | |
21 | "Disable driver host personality (default=enabled)"); | |
22 | ||
23 | static bool vmci_disable_guest; | |
24 | module_param_named(disable_guest, vmci_disable_guest, bool, 0); | |
25 | MODULE_PARM_DESC(disable_guest, | |
26 | "Disable driver guest personality (default=enabled)"); | |
27 | ||
28 | static bool vmci_guest_personality_initialized; | |
29 | static bool vmci_host_personality_initialized; | |
30 | ||
b1bba80a SG |
31 | static DEFINE_MUTEX(vmci_vsock_mutex); /* protects vmci_vsock_transport_cb */ |
32 | static vmci_vsock_cb vmci_vsock_transport_cb; | |
2be8ca97 | 33 | static bool vmci_vsock_cb_host_called; |
b1bba80a | 34 | |
197dbaaa GZ |
35 | /* |
36 | * vmci_get_context_id() - Gets the current context ID. | |
37 | * | |
38 | * Returns the current context ID. Note that since this is accessed only | |
39 | * from code running in the host, this always returns the host context ID. | |
40 | */ | |
41 | u32 vmci_get_context_id(void) | |
42 | { | |
43 | if (vmci_guest_code_active()) | |
44 | return vmci_get_vm_context_id(); | |
45 | else if (vmci_host_code_active()) | |
46 | return VMCI_HOST_CONTEXT_ID; | |
47 | ||
48 | return VMCI_INVALID_ID; | |
49 | } | |
50 | EXPORT_SYMBOL_GPL(vmci_get_context_id); | |
51 | ||
b1bba80a SG |
52 | /* |
53 | * vmci_register_vsock_callback() - Register the VSOCK vmci_transport callback. | |
54 | * | |
55 | * The callback will be called when the first host or guest becomes active, | |
56 | * or if they are already active when this function is called. | |
57 | * To unregister the callback, call this function with NULL parameter. | |
58 | * | |
59 | * Returns 0 on success. -EBUSY if a callback is already registered. | |
60 | */ | |
61 | int vmci_register_vsock_callback(vmci_vsock_cb callback) | |
62 | { | |
63 | int err = 0; | |
64 | ||
65 | mutex_lock(&vmci_vsock_mutex); | |
66 | ||
67 | if (vmci_vsock_transport_cb && callback) { | |
68 | err = -EBUSY; | |
69 | goto out; | |
70 | } | |
71 | ||
72 | vmci_vsock_transport_cb = callback; | |
73 | ||
74 | if (!vmci_vsock_transport_cb) { | |
75 | vmci_vsock_cb_host_called = false; | |
76 | goto out; | |
77 | } | |
78 | ||
79 | if (vmci_guest_code_active()) | |
80 | vmci_vsock_transport_cb(false); | |
81 | ||
82 | if (vmci_host_users() > 0) { | |
83 | vmci_vsock_cb_host_called = true; | |
84 | vmci_vsock_transport_cb(true); | |
85 | } | |
86 | ||
87 | out: | |
88 | mutex_unlock(&vmci_vsock_mutex); | |
89 | return err; | |
90 | } | |
91 | EXPORT_SYMBOL_GPL(vmci_register_vsock_callback); | |
92 | ||
93 | void vmci_call_vsock_callback(bool is_host) | |
94 | { | |
95 | mutex_lock(&vmci_vsock_mutex); | |
96 | ||
97 | if (!vmci_vsock_transport_cb) | |
98 | goto out; | |
99 | ||
100 | /* In the host, this function could be called multiple times, | |
101 | * but we want to register it only once. | |
102 | */ | |
103 | if (is_host) { | |
104 | if (vmci_vsock_cb_host_called) | |
105 | goto out; | |
106 | ||
107 | vmci_vsock_cb_host_called = true; | |
108 | } | |
109 | ||
110 | vmci_vsock_transport_cb(is_host); | |
111 | out: | |
112 | mutex_unlock(&vmci_vsock_mutex); | |
113 | } | |
114 | ||
197dbaaa GZ |
115 | static int __init vmci_drv_init(void) |
116 | { | |
117 | int vmci_err; | |
118 | int error; | |
119 | ||
120 | vmci_err = vmci_event_init(); | |
121 | if (vmci_err < VMCI_SUCCESS) { | |
122 | pr_err("Failed to initialize VMCIEvent (result=%d)\n", | |
123 | vmci_err); | |
124 | return -EINVAL; | |
125 | } | |
126 | ||
127 | if (!vmci_disable_guest) { | |
128 | error = vmci_guest_init(); | |
129 | if (error) { | |
130 | pr_warn("Failed to initialize guest personality (err=%d)\n", | |
131 | error); | |
132 | } else { | |
133 | vmci_guest_personality_initialized = true; | |
134 | pr_info("Guest personality initialized and is %s\n", | |
135 | vmci_guest_code_active() ? | |
136 | "active" : "inactive"); | |
137 | } | |
138 | } | |
139 | ||
140 | if (!vmci_disable_host) { | |
141 | error = vmci_host_init(); | |
142 | if (error) { | |
143 | pr_warn("Unable to initialize host personality (err=%d)\n", | |
144 | error); | |
145 | } else { | |
146 | vmci_host_personality_initialized = true; | |
147 | pr_info("Initialized host personality\n"); | |
148 | } | |
149 | } | |
150 | ||
151 | if (!vmci_guest_personality_initialized && | |
152 | !vmci_host_personality_initialized) { | |
153 | vmci_event_exit(); | |
154 | return -ENODEV; | |
155 | } | |
156 | ||
157 | return 0; | |
158 | } | |
159 | module_init(vmci_drv_init); | |
160 | ||
161 | static void __exit vmci_drv_exit(void) | |
162 | { | |
163 | if (vmci_guest_personality_initialized) | |
164 | vmci_guest_exit(); | |
165 | ||
166 | if (vmci_host_personality_initialized) | |
167 | vmci_host_exit(); | |
168 | ||
169 | vmci_event_exit(); | |
170 | } | |
171 | module_exit(vmci_drv_exit); | |
172 | ||
173 | MODULE_AUTHOR("VMware, Inc."); | |
174 | MODULE_DESCRIPTION("VMware Virtual Machine Communication Interface."); | |
11924ba5 | 175 | MODULE_VERSION("1.1.6.0-k"); |
197dbaaa | 176 | MODULE_LICENSE("GPL v2"); |