Skip to content

Commit 0dd0c8f

Browse files
committed
Merge tag 'hyperv-next-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux
Pull Hyper-V updates from Sasha Levin: - support for new VMBus protocols (Andrea Parri) - hibernation support (Dexuan Cui) - latency testing framework (Branden Bonaby) - decoupling Hyper-V page size from guest page size (Himadri Pandya) * tag 'hyperv-next-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux: (22 commits) Drivers: hv: vmbus: Fix crash handler reset of Hyper-V synic drivers/hv: Replace binary semaphore with mutex drivers: iommu: hyperv: Make HYPERV_IOMMU only available on x86 HID: hyperv: Add the support of hibernation hv_balloon: Add the support of hibernation x86/hyperv: Implement hv_is_hibernation_supported() Drivers: hv: balloon: Remove dependencies on guest page size Drivers: hv: vmbus: Remove dependencies on guest page size x86: hv: Add function to allocate zeroed page for Hyper-V Drivers: hv: util: Specify ring buffer size using Hyper-V page size Drivers: hv: Specify receive buffer size using Hyper-V page size tools: hv: add vmbus testing tool drivers: hv: vmbus: Introduce latency testing video: hyperv: hyperv_fb: Support deferred IO for Hyper-V frame buffer driver video: hyperv: hyperv_fb: Obtain screen resolution from Hyper-V host hv_netvsc: Add the support of hibernation hv_sock: Add the support of hibernation video: hyperv_fb: Add the support of hibernation scsi: storvsc: Add the support of hibernation Drivers: hv: vmbus: Add module parameter to cap the VMBus version ...
2 parents 8fa91bf + 7a1323b commit 0dd0c8f

File tree

27 files changed

+1386
-116
lines changed

27 files changed

+1386
-116
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
What: /sys/kernel/debug/hyperv/<UUID>/fuzz_test_state
2+
Date: October 2019
3+
KernelVersion: 5.5
4+
Contact: Branden Bonaby <[email protected]>
5+
Description: Fuzz testing status of a vmbus device, whether its in an ON
6+
state or a OFF state
7+
Users: Debugging tools
8+
9+
What: /sys/kernel/debug/hyperv/<UUID>/delay/fuzz_test_buffer_interrupt_delay
10+
Date: October 2019
11+
KernelVersion: 5.5
12+
Contact: Branden Bonaby <[email protected]>
13+
Description: Fuzz testing buffer interrupt delay value between 0 - 1000
14+
microseconds (inclusive).
15+
Users: Debugging tools
16+
17+
What: /sys/kernel/debug/hyperv/<UUID>/delay/fuzz_test_message_delay
18+
Date: October 2019
19+
KernelVersion: 5.5
20+
Contact: Branden Bonaby <[email protected]>
21+
Description: Fuzz testing message delay value between 0 - 1000 microseconds
22+
(inclusive).
23+
Users: Debugging tools

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7654,6 +7654,7 @@ F: include/uapi/linux/hyperv.h
76547654
F: include/asm-generic/mshyperv.h
76557655
F: tools/hv/
76567656
F: Documentation/ABI/stable/sysfs-bus-vmbus
7657+
F: Documentation/ABI/testing/debugfs-hyperv
76577658

76587659
HYPERBUS SUPPORT
76597660
M: Vignesh Raghavendra <[email protected]>

arch/x86/hyperv/hv_init.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* Author : K. Y. Srinivasan <[email protected]>
88
*/
99

10+
#include <linux/acpi.h>
1011
#include <linux/efi.h>
1112
#include <linux/types.h>
1213
#include <asm/apic.h>
@@ -45,6 +46,14 @@ void *hv_alloc_hyperv_page(void)
4546
}
4647
EXPORT_SYMBOL_GPL(hv_alloc_hyperv_page);
4748

49+
void *hv_alloc_hyperv_zeroed_page(void)
50+
{
51+
BUILD_BUG_ON(PAGE_SIZE != HV_HYP_PAGE_SIZE);
52+
53+
return (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
54+
}
55+
EXPORT_SYMBOL_GPL(hv_alloc_hyperv_zeroed_page);
56+
4857
void hv_free_hyperv_page(unsigned long addr)
4958
{
5059
free_page(addr);
@@ -437,3 +446,9 @@ bool hv_is_hyperv_initialized(void)
437446
return hypercall_msr.enable;
438447
}
439448
EXPORT_SYMBOL_GPL(hv_is_hyperv_initialized);
449+
450+
bool hv_is_hibernation_supported(void)
451+
{
452+
return acpi_sleep_state_supported(ACPI_STATE_S4);
453+
}
454+
EXPORT_SYMBOL_GPL(hv_is_hibernation_supported);

arch/x86/include/asm/mshyperv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ static inline struct hv_vp_assist_page *hv_get_vp_assist_page(unsigned int cpu)
219219
void __init hyperv_init(void);
220220
void hyperv_setup_mmu_ops(void);
221221
void *hv_alloc_hyperv_page(void);
222+
void *hv_alloc_hyperv_zeroed_page(void);
222223
void hv_free_hyperv_page(unsigned long addr);
223224
void hyperv_reenlightenment_intr(struct pt_regs *regs);
224225
void set_hv_tscchange_cb(void (*cb)(void));

drivers/hid/hid-hyperv.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
192192
if (desc->bLength == 0)
193193
goto cleanup;
194194

195+
/* The pointer is not NULL when we resume from hibernation */
196+
if (input_device->hid_desc != NULL)
197+
kfree(input_device->hid_desc);
195198
input_device->hid_desc = kmemdup(desc, desc->bLength, GFP_ATOMIC);
196199

197200
if (!input_device->hid_desc)
@@ -203,6 +206,9 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
203206
goto cleanup;
204207
}
205208

209+
/* The pointer is not NULL when we resume from hibernation */
210+
if (input_device->report_desc != NULL)
211+
kfree(input_device->report_desc);
206212
input_device->report_desc = kzalloc(input_device->report_desc_size,
207213
GFP_ATOMIC);
208214

@@ -342,6 +348,8 @@ static int mousevsc_connect_to_vsp(struct hv_device *device)
342348
struct mousevsc_prt_msg *request;
343349
struct mousevsc_prt_msg *response;
344350

351+
reinit_completion(&input_dev->wait_event);
352+
345353
request = &input_dev->protocol_req;
346354
memset(request, 0, sizeof(struct mousevsc_prt_msg));
347355

@@ -541,6 +549,30 @@ static int mousevsc_remove(struct hv_device *dev)
541549
return 0;
542550
}
543551

552+
static int mousevsc_suspend(struct hv_device *dev)
553+
{
554+
vmbus_close(dev->channel);
555+
556+
return 0;
557+
}
558+
559+
static int mousevsc_resume(struct hv_device *dev)
560+
{
561+
int ret;
562+
563+
ret = vmbus_open(dev->channel,
564+
INPUTVSC_SEND_RING_BUFFER_SIZE,
565+
INPUTVSC_RECV_RING_BUFFER_SIZE,
566+
NULL, 0,
567+
mousevsc_on_channel_callback,
568+
dev);
569+
if (ret)
570+
return ret;
571+
572+
ret = mousevsc_connect_to_vsp(dev);
573+
return ret;
574+
}
575+
544576
static const struct hv_vmbus_device_id id_table[] = {
545577
/* Mouse guid */
546578
{ HV_MOUSE_GUID, },
@@ -554,6 +586,8 @@ static struct hv_driver mousevsc_drv = {
554586
.id_table = id_table,
555587
.probe = mousevsc_probe,
556588
.remove = mousevsc_remove,
589+
.suspend = mousevsc_suspend,
590+
.resume = mousevsc_resume,
557591
.driver = {
558592
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
559593
},

drivers/hv/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ CFLAGS_hv_balloon.o = -I$(src)
99
hv_vmbus-y := vmbus_drv.o \
1010
hv.o connection.o channel.o \
1111
channel_mgmt.o ring_buffer.o hv_trace.o
12+
hv_vmbus-$(CONFIG_HYPERV_TESTING) += hv_debugfs.o
1213
hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o hv_fcopy.o hv_utils_transport.o

drivers/hv/connection.c

Lines changed: 45 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/wait.h>
1515
#include <linux/delay.h>
1616
#include <linux/mm.h>
17+
#include <linux/module.h>
1718
#include <linux/slab.h>
1819
#include <linux/vmalloc.h>
1920
#include <linux/hyperv.h>
@@ -40,29 +41,30 @@ EXPORT_SYMBOL_GPL(vmbus_connection);
4041
__u32 vmbus_proto_version;
4142
EXPORT_SYMBOL_GPL(vmbus_proto_version);
4243

43-
static __u32 vmbus_get_next_version(__u32 current_version)
44-
{
45-
switch (current_version) {
46-
case (VERSION_WIN7):
47-
return VERSION_WS2008;
48-
49-
case (VERSION_WIN8):
50-
return VERSION_WIN7;
51-
52-
case (VERSION_WIN8_1):
53-
return VERSION_WIN8;
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+
};
5458

55-
case (VERSION_WIN10):
56-
return VERSION_WIN8_1;
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;
5764

58-
case (VERSION_WIN10_V5):
59-
return VERSION_WIN10;
60-
61-
case (VERSION_WS2008):
62-
default:
63-
return VERSION_INVAL;
64-
}
65-
}
65+
module_param(max_version, uint, S_IRUGO);
66+
MODULE_PARM_DESC(max_version,
67+
"Maximal VMBus protocol version which can be negotiated");
6668

6769
int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
6870
{
@@ -80,12 +82,12 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
8082
msg->vmbus_version_requested = version;
8183

8284
/*
83-
* VMBus protocol 5.0 (VERSION_WIN10_V5) requires that we must use
84-
* VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate Contact Message,
85+
* VMBus protocol 5.0 (VERSION_WIN10_V5) and higher require that we must
86+
* use VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate Contact Message,
8587
* and for subsequent messages, we must use the Message Connection ID
8688
* field in the host-returned Version Response Message. And, with
87-
* VERSION_WIN10_V5, we don't use msg->interrupt_page, but we tell
88-
* the host explicitly that we still use VMBUS_MESSAGE_SINT(2) for
89+
* VERSION_WIN10_V5 and higher, we don't use msg->interrupt_page, but we
90+
* tell the host explicitly that we still use VMBUS_MESSAGE_SINT(2) for
8991
* compatibility.
9092
*
9193
* On old hosts, we should always use VMBUS_MESSAGE_CONNECTION_ID (1).
@@ -169,8 +171,8 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
169171
*/
170172
int vmbus_connect(void)
171173
{
172-
int ret = 0;
173174
struct vmbus_channel_msginfo *msginfo = NULL;
175+
int i, ret = 0;
174176
__u32 version;
175177

176178
/* Initialize the vmbus connection */
@@ -206,7 +208,7 @@ int vmbus_connect(void)
206208
* abstraction stuff
207209
*/
208210
vmbus_connection.int_page =
209-
(void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, 0);
211+
(void *)hv_alloc_hyperv_zeroed_page();
210212
if (vmbus_connection.int_page == NULL) {
211213
ret = -ENOMEM;
212214
goto cleanup;
@@ -215,14 +217,14 @@ int vmbus_connect(void)
215217
vmbus_connection.recv_int_page = vmbus_connection.int_page;
216218
vmbus_connection.send_int_page =
217219
(void *)((unsigned long)vmbus_connection.int_page +
218-
(PAGE_SIZE >> 1));
220+
(HV_HYP_PAGE_SIZE >> 1));
219221

220222
/*
221223
* Setup the monitor notification facility. The 1st page for
222224
* parent->child and the 2nd page for child->parent
223225
*/
224-
vmbus_connection.monitor_pages[0] = (void *)__get_free_pages((GFP_KERNEL|__GFP_ZERO), 0);
225-
vmbus_connection.monitor_pages[1] = (void *)__get_free_pages((GFP_KERNEL|__GFP_ZERO), 0);
226+
vmbus_connection.monitor_pages[0] = (void *)hv_alloc_hyperv_zeroed_page();
227+
vmbus_connection.monitor_pages[1] = (void *)hv_alloc_hyperv_zeroed_page();
226228
if ((vmbus_connection.monitor_pages[0] == NULL) ||
227229
(vmbus_connection.monitor_pages[1] == NULL)) {
228230
ret = -ENOMEM;
@@ -244,21 +246,21 @@ int vmbus_connect(void)
244246
* version.
245247
*/
246248

247-
version = VERSION_CURRENT;
249+
for (i = 0; ; i++) {
250+
if (i == ARRAY_SIZE(vmbus_versions))
251+
goto cleanup;
252+
253+
version = vmbus_versions[i];
254+
if (version > max_version)
255+
continue;
248256

249-
do {
250257
ret = vmbus_negotiate_version(msginfo, version);
251258
if (ret == -ETIMEDOUT)
252259
goto cleanup;
253260

254261
if (vmbus_connection.conn_state == CONNECTED)
255262
break;
256-
257-
version = vmbus_get_next_version(version);
258-
} while (version != VERSION_INVAL);
259-
260-
if (version == VERSION_INVAL)
261-
goto cleanup;
263+
}
262264

263265
vmbus_proto_version = version;
264266
pr_info("Vmbus version:%d.%d\n",
@@ -295,12 +297,12 @@ void vmbus_disconnect(void)
295297
destroy_workqueue(vmbus_connection.work_queue);
296298

297299
if (vmbus_connection.int_page) {
298-
free_pages((unsigned long)vmbus_connection.int_page, 0);
300+
hv_free_hyperv_page((unsigned long)vmbus_connection.int_page);
299301
vmbus_connection.int_page = NULL;
300302
}
301303

302-
free_pages((unsigned long)vmbus_connection.monitor_pages[0], 0);
303-
free_pages((unsigned long)vmbus_connection.monitor_pages[1], 0);
304+
hv_free_hyperv_page((unsigned long)vmbus_connection.monitor_pages[0]);
305+
hv_free_hyperv_page((unsigned long)vmbus_connection.monitor_pages[1]);
304306
vmbus_connection.monitor_pages[0] = NULL;
305307
vmbus_connection.monitor_pages[1] = NULL;
306308
}
@@ -361,6 +363,7 @@ void vmbus_on_event(unsigned long data)
361363

362364
trace_vmbus_on_event(channel);
363365

366+
hv_debug_delay_test(channel, INTERRUPT_DELAY);
364367
do {
365368
void (*callback_fn)(void *);
366369

@@ -413,7 +416,7 @@ int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep)
413416
case HV_STATUS_INVALID_CONNECTION_ID:
414417
/*
415418
* See vmbus_negotiate_version(): VMBus protocol 5.0
416-
* requires that we must use
419+
* and higher require that we must use
417420
* VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate
418421
* Contact message, but on old hosts that only
419422
* support VMBus protocol 4.0 or lower, here we get

0 commit comments

Comments
 (0)