hc
2023-12-06 08f87f769b595151be1afeff53e144f543faa614
kernel/drivers/hv/connection.c
....@@ -1,24 +1,11 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 *
34 * Copyright (c) 2009, Microsoft Corporation.
45 *
5
- * This program is free software; you can redistribute it and/or modify it
6
- * under the terms and conditions of the GNU General Public License,
7
- * version 2, as published by the Free Software Foundation.
8
- *
9
- * This program is distributed in the hope it will be useful, but WITHOUT
10
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12
- * more details.
13
- *
14
- * You should have received a copy of the GNU General Public License along with
15
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16
- * Place - Suite 330, Boston, MA 02111-1307 USA.
17
- *
186 * Authors:
197 * Haiyang Zhang <haiyangz@microsoft.com>
208 * Hank Janssen <hjanssen@microsoft.com>
21
- *
229 */
2310 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2411
....@@ -27,6 +14,7 @@
2714 #include <linux/wait.h>
2815 #include <linux/delay.h>
2916 #include <linux/mm.h>
17
+#include <linux/module.h>
3018 #include <linux/slab.h>
3119 #include <linux/vmalloc.h>
3220 #include <linux/hyperv.h>
....@@ -39,6 +27,11 @@
3927 struct vmbus_connection vmbus_connection = {
4028 .conn_state = DISCONNECTED,
4129 .next_gpadl_handle = ATOMIC_INIT(0xE1E10),
30
+
31
+ .ready_for_suspend_event= COMPLETION_INITIALIZER(
32
+ vmbus_connection.ready_for_suspend_event),
33
+ .ready_for_resume_event = COMPLETION_INITIALIZER(
34
+ vmbus_connection.ready_for_resume_event),
4235 };
4336 EXPORT_SYMBOL_GPL(vmbus_connection);
4437
....@@ -48,35 +41,34 @@
4841 __u32 vmbus_proto_version;
4942 EXPORT_SYMBOL_GPL(vmbus_proto_version);
5043
51
-static __u32 vmbus_get_next_version(__u32 current_version)
52
-{
53
- switch (current_version) {
54
- case (VERSION_WIN7):
55
- return VERSION_WS2008;
44
+/*
45
+ * Table of VMBus versions listed from newest to oldest.
46
+ */
47
+static __u32 vmbus_versions[] = {
48
+ VERSION_WIN10_V5_2,
49
+ VERSION_WIN10_V5_1,
50
+ VERSION_WIN10_V5,
51
+ VERSION_WIN10_V4_1,
52
+ VERSION_WIN10,
53
+ VERSION_WIN8_1,
54
+ VERSION_WIN8,
55
+ VERSION_WIN7,
56
+ VERSION_WS2008
57
+};
5658
57
- case (VERSION_WIN8):
58
- return VERSION_WIN7;
59
+/*
60
+ * Maximal VMBus protocol version guests can negotiate. Useful to cap the
61
+ * VMBus version for testing and debugging purpose.
62
+ */
63
+static uint max_version = VERSION_WIN10_V5_2;
5964
60
- case (VERSION_WIN8_1):
61
- return VERSION_WIN8;
65
+module_param(max_version, uint, S_IRUGO);
66
+MODULE_PARM_DESC(max_version,
67
+ "Maximal VMBus protocol version which can be negotiated");
6268
63
- case (VERSION_WIN10):
64
- return VERSION_WIN8_1;
65
-
66
- case (VERSION_WIN10_V5):
67
- return VERSION_WIN10;
68
-
69
- case (VERSION_WS2008):
70
- default:
71
- return VERSION_INVAL;
72
- }
73
-}
74
-
75
-static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
76
- __u32 version)
69
+int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
7770 {
7871 int ret = 0;
79
- unsigned int cur_cpu;
8072 struct vmbus_channel_initiate_contact *msg;
8173 unsigned long flags;
8274
....@@ -89,12 +81,12 @@
8981 msg->vmbus_version_requested = version;
9082
9183 /*
92
- * VMBus protocol 5.0 (VERSION_WIN10_V5) requires that we must use
93
- * VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate Contact Message,
84
+ * VMBus protocol 5.0 (VERSION_WIN10_V5) and higher require that we must
85
+ * use VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate Contact Message,
9486 * and for subsequent messages, we must use the Message Connection ID
9587 * field in the host-returned Version Response Message. And, with
96
- * VERSION_WIN10_V5, we don't use msg->interrupt_page, but we tell
97
- * the host explicitly that we still use VMBUS_MESSAGE_SINT(2) for
88
+ * VERSION_WIN10_V5 and higher, we don't use msg->interrupt_page, but we
89
+ * tell the host explicitly that we still use VMBUS_MESSAGE_SINT(2) for
9890 * compatibility.
9991 *
10092 * On old hosts, we should always use VMBUS_MESSAGE_CONNECTION_ID (1).
....@@ -109,24 +101,7 @@
109101
110102 msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]);
111103 msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]);
112
- /*
113
- * We want all channel messages to be delivered on CPU 0.
114
- * This has been the behavior pre-win8. This is not
115
- * perf issue and having all channel messages delivered on CPU 0
116
- * would be ok.
117
- * For post win8 hosts, we support receiving channel messagges on
118
- * all the CPUs. This is needed for kexec to work correctly where
119
- * the CPU attempting to connect may not be CPU 0.
120
- */
121
- if (version >= VERSION_WIN8_1) {
122
- cur_cpu = get_cpu();
123
- msg->target_vcpu = hv_cpu_number_to_vp_number(cur_cpu);
124
- vmbus_connection.connect_cpu = cur_cpu;
125
- put_cpu();
126
- } else {
127
- msg->target_vcpu = 0;
128
- vmbus_connection.connect_cpu = 0;
129
- }
104
+ msg->target_vcpu = hv_cpu_number_to_vp_number(VMBUS_CONNECT_CPU);
130105
131106 /*
132107 * Add to list before we send the request since we may
....@@ -178,8 +153,8 @@
178153 */
179154 int vmbus_connect(void)
180155 {
181
- int ret = 0;
182156 struct vmbus_channel_msginfo *msginfo = NULL;
157
+ int i, ret = 0;
183158 __u32 version;
184159
185160 /* Initialize the vmbus connection */
....@@ -215,7 +190,7 @@
215190 * abstraction stuff
216191 */
217192 vmbus_connection.int_page =
218
- (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, 0);
193
+ (void *)hv_alloc_hyperv_zeroed_page();
219194 if (vmbus_connection.int_page == NULL) {
220195 ret = -ENOMEM;
221196 goto cleanup;
....@@ -224,14 +199,14 @@
224199 vmbus_connection.recv_int_page = vmbus_connection.int_page;
225200 vmbus_connection.send_int_page =
226201 (void *)((unsigned long)vmbus_connection.int_page +
227
- (PAGE_SIZE >> 1));
202
+ (HV_HYP_PAGE_SIZE >> 1));
228203
229204 /*
230205 * Setup the monitor notification facility. The 1st page for
231206 * parent->child and the 2nd page for child->parent
232207 */
233
- vmbus_connection.monitor_pages[0] = (void *)__get_free_pages((GFP_KERNEL|__GFP_ZERO), 0);
234
- vmbus_connection.monitor_pages[1] = (void *)__get_free_pages((GFP_KERNEL|__GFP_ZERO), 0);
208
+ vmbus_connection.monitor_pages[0] = (void *)hv_alloc_hyperv_zeroed_page();
209
+ vmbus_connection.monitor_pages[1] = (void *)hv_alloc_hyperv_zeroed_page();
235210 if ((vmbus_connection.monitor_pages[0] == NULL) ||
236211 (vmbus_connection.monitor_pages[1] == NULL)) {
237212 ret = -ENOMEM;
....@@ -253,25 +228,35 @@
253228 * version.
254229 */
255230
256
- version = VERSION_CURRENT;
231
+ for (i = 0; ; i++) {
232
+ if (i == ARRAY_SIZE(vmbus_versions)) {
233
+ ret = -EDOM;
234
+ goto cleanup;
235
+ }
257236
258
- do {
237
+ version = vmbus_versions[i];
238
+ if (version > max_version)
239
+ continue;
240
+
259241 ret = vmbus_negotiate_version(msginfo, version);
260242 if (ret == -ETIMEDOUT)
261243 goto cleanup;
262244
263245 if (vmbus_connection.conn_state == CONNECTED)
264246 break;
265
-
266
- version = vmbus_get_next_version(version);
267
- } while (version != VERSION_INVAL);
268
-
269
- if (version == VERSION_INVAL)
270
- goto cleanup;
247
+ }
271248
272249 vmbus_proto_version = version;
273250 pr_info("Vmbus version:%d.%d\n",
274251 version >> 16, version & 0xFFFF);
252
+
253
+ vmbus_connection.channels = kcalloc(MAX_CHANNEL_RELIDS,
254
+ sizeof(struct vmbus_channel *),
255
+ GFP_KERNEL);
256
+ if (vmbus_connection.channels == NULL) {
257
+ ret = -ENOMEM;
258
+ goto cleanup;
259
+ }
275260
276261 kfree(msginfo);
277262 return 0;
....@@ -304,12 +289,12 @@
304289 destroy_workqueue(vmbus_connection.work_queue);
305290
306291 if (vmbus_connection.int_page) {
307
- free_pages((unsigned long)vmbus_connection.int_page, 0);
292
+ hv_free_hyperv_page((unsigned long)vmbus_connection.int_page);
308293 vmbus_connection.int_page = NULL;
309294 }
310295
311
- free_pages((unsigned long)vmbus_connection.monitor_pages[0], 0);
312
- free_pages((unsigned long)vmbus_connection.monitor_pages[1], 0);
296
+ hv_free_hyperv_page((unsigned long)vmbus_connection.monitor_pages[0]);
297
+ hv_free_hyperv_page((unsigned long)vmbus_connection.monitor_pages[1]);
313298 vmbus_connection.monitor_pages[0] = NULL;
314299 vmbus_connection.monitor_pages[1] = NULL;
315300 }
....@@ -320,33 +305,9 @@
320305 */
321306 struct vmbus_channel *relid2channel(u32 relid)
322307 {
323
- struct vmbus_channel *channel;
324
- struct vmbus_channel *found_channel = NULL;
325
- struct list_head *cur, *tmp;
326
- struct vmbus_channel *cur_sc;
327
-
328
- BUG_ON(!mutex_is_locked(&vmbus_connection.channel_mutex));
329
-
330
- list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
331
- if (channel->offermsg.child_relid == relid) {
332
- found_channel = channel;
333
- break;
334
- } else if (!list_empty(&channel->sc_list)) {
335
- /*
336
- * Deal with sub-channels.
337
- */
338
- list_for_each_safe(cur, tmp, &channel->sc_list) {
339
- cur_sc = list_entry(cur, struct vmbus_channel,
340
- sc_list);
341
- if (cur_sc->offermsg.child_relid == relid) {
342
- found_channel = cur_sc;
343
- break;
344
- }
345
- }
346
- }
347
- }
348
-
349
- return found_channel;
308
+ if (WARN_ON(relid >= MAX_CHANNEL_RELIDS))
309
+ return NULL;
310
+ return READ_ONCE(vmbus_connection.channels[relid]);
350311 }
351312
352313 /*
....@@ -370,6 +331,7 @@
370331
371332 trace_vmbus_on_event(channel);
372333
334
+ hv_debug_delay_test(channel, INTERRUPT_DELAY);
373335 do {
374336 void (*callback_fn)(void *);
375337
....@@ -422,7 +384,7 @@
422384 case HV_STATUS_INVALID_CONNECTION_ID:
423385 /*
424386 * See vmbus_negotiate_version(): VMBus protocol 5.0
425
- * requires that we must use
387
+ * and higher require that we must use
426388 * VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate
427389 * Contact message, but on old hosts that only
428390 * support VMBus protocol 4.0 or lower, here we get