History

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 ...

Linus Torvalds committed 6 years ago

Commit 0dd0c8f2 parents 8fa91bf 7a1323b27 files · +1386 −116Browse files

Unified · Split

27 files
  1. Documentation/ABI/testing/debugfs-hyperv +23 −0
  2. MAINTAINERS +1 −0
  3. arch/x86/hyperv/hv_init.c +15 −0
  4. arch/x86/include/asm/mshyperv.h +1 −0
  5. drivers/hid/hid-hyperv.c +34 −0
  6. drivers/hv/Makefile +1 −0
  7. drivers/hv/connection.c +45 −42
  8. drivers/hv/hv_balloon.c +97 −15
  9. drivers/hv/hv_debugfs.c +178 −0
  10. drivers/hv/hv_fcopy.c +2 −1
  11. drivers/hv/hv_kvp.c +2 −1
  12. drivers/hv/hv_snapshot.c +2 −1
  13. drivers/hv/hv_util.c +7 −6
  14. drivers/hv/hyperv_vmbus.h +31 −0
  15. drivers/hv/ring_buffer.c +2 −0
  16. drivers/hv/vmbus_drv.c +16 −11
  17. drivers/iommu/Kconfig +1 −1
  18. drivers/net/hyperv/hyperv_net.h +3 −0
  19. drivers/net/hyperv/netvsc_drv.c +57 −0
  20. drivers/scsi/storvsc_drv.c +41 −0
  21. drivers/video/fbdev/Kconfig +1 −0
  22. drivers/video/fbdev/hyperv_fb.c +395 −33
  23. include/asm-generic/mshyperv.h +2 −0
  24. include/linux/hyperv.h +26 −5
  25. lib/Kconfig.debug +7 −0
  26. net/vmw_vsock/hyperv_transport.c +20 −0
  27. tools/hv/vmbus_testing +376 −0
Documentation/ABI/testing/debugfs-hyperv+23−0
@@ -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 <brandonbonaby94@gmail.com>
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 <brandonbonaby94@gmail.com>
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 <brandonbonaby94@gmail.com>
21+Description: Fuzz testing message delay value between 0 - 1000 microseconds
22+ (inclusive).
23+Users: Debugging tools
MAINTAINERS+1−0
@@ -7654,6 +7654,7 @@ F: include/uapi/linux/hyperv.h · 7653 unmodified lines
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 <vigneshr@ti.com>
arch/x86/hyperv/hv_init.c+15−0
@@ -7,6 +7,7 @@ · 6 unmodified lines
77 * Author : K. Y. Srinivasan <kys@microsoft.com>
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) · 32 unmodified lines
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) · 386 unmodified lines
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+1−0
@@ -219,6 +219,7 @@ static inline struct hv_vp_assist_page *hv_get_vp_assist_page(unsigned int cpu) · 218 unmodified lines
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+34−0
@@ -192,6 +192,9 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device, · 191 unmodified lines
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, · 5 unmodified lines
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) · 133 unmodified lines
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) · 193 unmodified lines
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 = { · 7 unmodified lines
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+1−0
@@ -9,4 +9,5 @@ CFLAGS_hv_balloon.o = -I$(src) · 8 unmodified lines
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+45−42
@@ -14,6 +14,7 @@ · 13 unmodified lines
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); · 20 unmodified lines
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) · 11 unmodified lines
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) · 77 unmodified lines
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) · 29 unmodified lines
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) · 2 unmodified lines
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) · 15 unmodified lines
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) · 30 unmodified lines
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) · 54 unmodified lines
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) · 46 unmodified lines
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
drivers/hv/hv_balloon.c+97−15
@@ -23,6 +23,9 @@ · 22 unmodified lines
2323 #include <linux/percpu_counter.h>
2424
2525 #include <linux/hyperv.h>
26+#include <asm/hyperv-tlfs.h>
27+
28+#include <asm/mshyperv.h>
2629
2730 #define CREATE_TRACE_POINTS
2831 #include "hv_trace_balloon.h"
@@ -341,8 +344,6 @@ struct dm_unballoon_response { · 312 unmodified lines
341344 *
342345 * mem_range: Memory range to hot add.
343346 *
344− * On Linux we currently don't support this since we cannot hot add
345− * arbitrary granularity of memory.
346347 */
347348
348349 struct dm_hot_add {
@@ -457,6 +458,7 @@ struct hot_add_wrk { · 108 unmodified lines
457458 struct work_struct wrk;
458459 };
459460
461+static bool allow_hibernation;
460462 static bool hot_add = true;
461463 static bool do_hot_add;
462464 /*
@@ -477,7 +479,7 @@ module_param(pressure_report_delay, uint, (S_IRUGO | S_IWUSR)); · 14 unmodified lines
477479 MODULE_PARM_DESC(pressure_report_delay, "Delay in secs in reporting pressure");
478480 static atomic_t trans_id = ATOMIC_INIT(0);
479481
480−static int dm_ring_size = (5 * PAGE_SIZE);
482+static int dm_ring_size = 20 * 1024;
481483
482484 /*
483485 * Driver specific state.
@@ -493,10 +495,10 @@ enum hv_dm_state { · 9 unmodified lines
493495 };
494496
495497
496−static __u8 recv_buffer[PAGE_SIZE];
497−static __u8 balloon_up_send_buffer[PAGE_SIZE];
498−#define PAGES_IN_2M 512
499−#define HA_CHUNK (32 * 1024)
498+static __u8 recv_buffer[HV_HYP_PAGE_SIZE];
499+static __u8 balloon_up_send_buffer[HV_HYP_PAGE_SIZE];
500+#define PAGES_IN_2M (2 * 1024 * 1024 / PAGE_SIZE)
501+#define HA_CHUNK (128 * 1024 * 1024 / PAGE_SIZE)
500502
501503 struct hv_dynmem_device {
502504 struct hv_device *dev;
@@ -1053,8 +1055,12 @@ static void hot_add_req(struct work_struct *dummy) · 550 unmodified lines
10531055 else
10541056 resp.result = 0;
10551057
1056− if (!do_hot_add || (resp.page_count == 0))
1057− pr_err("Memory hot add failed\n");
1058+ if (!do_hot_add || resp.page_count == 0) {
1059+ if (!allow_hibernation)
1060+ pr_err("Memory hot add failed\n");
1061+ else
1062+ pr_info("Ignore hot-add request!\n");
1063+ }
10581064
10591065 dm->state = DM_INITIALIZED;
10601066 resp.hdr.trans_id = atomic_inc_return(&trans_id);
@@ -1076,7 +1082,7 @@ static void process_info(struct hv_dynmem_device *dm, struct dm_info_msg *msg) · 15 unmodified lines
10761082 __u64 *max_page_count = (__u64 *)&info_hdr[1];
10771083
10781084 pr_info("Max. dynamic memory size: %llu MB\n",
1079− (*max_page_count) >> (20 - PAGE_SHIFT));
1085+ (*max_page_count) >> (20 - HV_HYP_PAGE_SHIFT));
10801086 }
10811087
10821088 break;
@@ -1218,7 +1224,7 @@ static unsigned int alloc_balloon_pages(struct hv_dynmem_device *dm, · 135 unmodified lines
12181224
12191225 for (i = 0; (i * alloc_unit) < num_pages; i++) {
12201226 if (bl_resp->hdr.size + sizeof(union dm_mem_page_range) >
1221− PAGE_SIZE)
1227+ HV_HYP_PAGE_SIZE)
12221228 return i * alloc_unit;
12231229
12241230 /*
@@ -1274,9 +1280,9 @@ static void balloon_up(struct work_struct *dummy) · 49 unmodified lines
12741280
12751281 /*
12761282 * We will attempt 2M allocations. However, if we fail to
1277− * allocate 2M chunks, we will go back to 4k allocations.
1283+ * allocate 2M chunks, we will go back to PAGE_SIZE allocations.
12781284 */
1279− alloc_unit = 512;
1285+ alloc_unit = PAGES_IN_2M;
12801286
12811287 avail_pages = si_mem_available();
12821288 floor = compute_balloon_floor();
@@ -1292,7 +1298,7 @@ static void balloon_up(struct work_struct *dummy) · 9 unmodified lines
12921298 }
12931299
12941300 while (!done) {
1295− memset(balloon_up_send_buffer, 0, PAGE_SIZE);
1301+ memset(balloon_up_send_buffer, 0, HV_HYP_PAGE_SIZE);
12961302 bl_resp = (struct dm_balloon_response *)balloon_up_send_buffer;
12971303 bl_resp->hdr.type = DM_BALLOON_RESPONSE;
12981304 bl_resp->hdr.size = sizeof(struct dm_balloon_response);
@@ -1491,7 +1497,7 @@ static void balloon_onchannelcallback(void *context) · 192 unmodified lines
14911497
14921498 memset(recv_buffer, 0, sizeof(recv_buffer));
14931499 vmbus_recvpacket(dev->channel, recv_buffer,
1494− PAGE_SIZE, &recvlen, &requestid);
1500+ HV_HYP_PAGE_SIZE, &recvlen, &requestid);
14951501
14961502 if (recvlen > 0) {
14971503 dm_msg = (struct dm_message *)recv_buffer;
@@ -1509,6 +1515,11 @@ static void balloon_onchannelcallback(void *context) · 11 unmodified lines
15091515 break;
15101516
15111517 case DM_BALLOON_REQUEST:
1518+ if (allow_hibernation) {
1519+ pr_info("Ignore balloon-up request!\n");
1520+ break;
1521+ }
1522+
15121523 if (dm->state == DM_BALLOON_UP)
15131524 pr_warn("Currently ballooning\n");
15141525 bal_msg = (struct dm_balloon *)recv_buffer;
@@ -1518,6 +1529,11 @@ static void balloon_onchannelcallback(void *context) · 3 unmodified lines
15181529 break;
15191530
15201531 case DM_UNBALLOON_REQUEST:
1532+ if (allow_hibernation) {
1533+ pr_info("Ignore balloon-down request!\n");
1534+ break;
1535+ }
1536+
15211537 dm->state = DM_BALLOON_DOWN;
15221538 balloon_down(dm,
15231539 (struct dm_unballoon_request *)recv_buffer);
@@ -1623,6 +1639,11 @@ static int balloon_connect_vsp(struct hv_device *dev) · 99 unmodified lines
16231639 cap_msg.hdr.size = sizeof(struct dm_capabilities);
16241640 cap_msg.hdr.trans_id = atomic_inc_return(&trans_id);
16251641
1642+ /*
1643+ * When hibernation (i.e. virtual ACPI S4 state) is enabled, the host
1644+ * currently still requires the bits to be set, so we have to add code
1645+ * to fail the host's hot-add and balloon up/down requests, if any.
1646+ */
16261647 cap_msg.caps.cap_bits.balloon = 1;
16271648 cap_msg.caps.cap_bits.hot_add = 1;
16281649
@@ -1672,6 +1693,10 @@ static int balloon_probe(struct hv_device *dev, · 43 unmodified lines
16721693 {
16731694 int ret;
16741695
1696+ allow_hibernation = hv_is_hibernation_supported();
1697+ if (allow_hibernation)
1698+ hot_add = false;
1699+
16751700 #ifdef CONFIG_MEMORY_HOTPLUG
16761701 do_hot_add = hot_add;
16771702 #else
@@ -1711,6 +1736,8 @@ static int balloon_probe(struct hv_device *dev, · 33 unmodified lines
17111736 return 0;
17121737
17131738 probe_error:
1739+ dm_device.state = DM_INIT_ERROR;
1740+ dm_device.thread = NULL;
17141741 vmbus_close(dev->channel);
17151742 #ifdef CONFIG_MEMORY_HOTPLUG
17161743 unregister_memory_notifier(&hv_memory_nb);
@@ -1752,6 +1779,59 @@ static int balloon_remove(struct hv_device *dev) · 35 unmodified lines
17521779 return 0;
17531780 }
17541781
1782+static int balloon_suspend(struct hv_device *hv_dev)
1783+{
1784+ struct hv_dynmem_device *dm = hv_get_drvdata(hv_dev);
1785+
1786+ tasklet_disable(&hv_dev->channel->callback_event);
1787+
1788+ cancel_work_sync(&dm->balloon_wrk.wrk);
1789+ cancel_work_sync(&dm->ha_wrk.wrk);
1790+
1791+ if (dm->thread) {
1792+ kthread_stop(dm->thread);
1793+ dm->thread = NULL;
1794+ vmbus_close(hv_dev->channel);
1795+ }
1796+
1797+ tasklet_enable(&hv_dev->channel->callback_event);
1798+
1799+ return 0;
1800+
1801+}
1802+
1803+static int balloon_resume(struct hv_device *dev)
1804+{
1805+ int ret;
1806+
1807+ dm_device.state = DM_INITIALIZING;
1808+
1809+ ret = balloon_connect_vsp(dev);
1810+
1811+ if (ret != 0)
1812+ goto out;
1813+
1814+ dm_device.thread =
1815+ kthread_run(dm_thread_func, &dm_device, "hv_balloon");
1816+ if (IS_ERR(dm_device.thread)) {
1817+ ret = PTR_ERR(dm_device.thread);
1818+ dm_device.thread = NULL;
1819+ goto close_channel;
1820+ }
1821+
1822+ dm_device.state = DM_INITIALIZED;
1823+ return 0;
1824+close_channel:
1825+ vmbus_close(dev->channel);
1826+out:
1827+ dm_device.state = DM_INIT_ERROR;
1828+#ifdef CONFIG_MEMORY_HOTPLUG
1829+ unregister_memory_notifier(&hv_memory_nb);
1830+ restore_online_page_callback(&hv_online_page);
1831+#endif
1832+ return ret;
1833+}
1834+
17551835 static const struct hv_vmbus_device_id id_table[] = {
17561836 /* Dynamic Memory Class ID */
17571837 /* 525074DC-8985-46e2-8057-A307DC18A502 */
@@ -1766,6 +1846,8 @@ static struct hv_driver balloon_drv = { · 8 unmodified lines
17661846 .id_table = id_table,
17671847 .probe = balloon_probe,
17681848 .remove = balloon_remove,
1849+ .suspend = balloon_suspend,
1850+ .resume = balloon_resume,
17691851 .driver = {
17701852 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
17711853 },
drivers/hv/hv_debugfs.c+178−0
@@ -0,0 +1,178 @@
1+// SPDX-License-Identifier: GPL-2.0-only
2+/*
3+ * Authors:
4+ * Branden Bonaby <brandonbonaby94@gmail.com>
5+ */
6+
7+#include <linux/hyperv.h>
8+#include <linux/debugfs.h>
9+#include <linux/delay.h>
10+#include <linux/err.h>
11+
12+#include "hyperv_vmbus.h"
13+
14+struct dentry *hv_debug_root;
15+
16+static int hv_debugfs_delay_get(void *data, u64 *val)
17+{
18+ *val = *(u32 *)data;
19+ return 0;
20+}
21+
22+static int hv_debugfs_delay_set(void *data, u64 val)
23+{
24+ if (val > 1000)
25+ return -EINVAL;
26+ *(u32 *)data = val;
27+ return 0;
28+}
29+
30+DEFINE_DEBUGFS_ATTRIBUTE(hv_debugfs_delay_fops, hv_debugfs_delay_get,
31+ hv_debugfs_delay_set, "%llu\n");
32+
33+static int hv_debugfs_state_get(void *data, u64 *val)
34+{
35+ *val = *(bool *)data;
36+ return 0;
37+}
38+
39+static int hv_debugfs_state_set(void *data, u64 val)
40+{
41+ if (val == 1)
42+ *(bool *)data = true;
43+ else if (val == 0)
44+ *(bool *)data = false;
45+ else
46+ return -EINVAL;
47+ return 0;
48+}
49+
50+DEFINE_DEBUGFS_ATTRIBUTE(hv_debugfs_state_fops, hv_debugfs_state_get,
51+ hv_debugfs_state_set, "%llu\n");
52+
53+/* Setup delay files to store test values */
54+static int hv_debug_delay_files(struct hv_device *dev, struct dentry *root)
55+{
56+ struct vmbus_channel *channel = dev->channel;
57+ char *buffer = "fuzz_test_buffer_interrupt_delay";
58+ char *message = "fuzz_test_message_delay";
59+ int *buffer_val = &channel->fuzz_testing_interrupt_delay;
60+ int *message_val = &channel->fuzz_testing_message_delay;
61+ struct dentry *buffer_file, *message_file;
62+
63+ buffer_file = debugfs_create_file(buffer, 0644, root,
64+ buffer_val,
65+ &hv_debugfs_delay_fops);
66+ if (IS_ERR(buffer_file)) {
67+ pr_debug("debugfs_hyperv: file %s not created\n", buffer);
68+ return PTR_ERR(buffer_file);
69+ }
70+
71+ message_file = debugfs_create_file(message, 0644, root,
72+ message_val,
73+ &hv_debugfs_delay_fops);
74+ if (IS_ERR(message_file)) {
75+ pr_debug("debugfs_hyperv: file %s not created\n", message);
76+ return PTR_ERR(message_file);
77+ }
78+
79+ return 0;
80+}
81+
82+/* Setup test state value for vmbus device */
83+static int hv_debug_set_test_state(struct hv_device *dev, struct dentry *root)
84+{
85+ struct vmbus_channel *channel = dev->channel;
86+ bool *state = &channel->fuzz_testing_state;
87+ char *status = "fuzz_test_state";
88+ struct dentry *test_state;
89+
90+ test_state = debugfs_create_file(status, 0644, root,
91+ state,
92+ &hv_debugfs_state_fops);
93+ if (IS_ERR(test_state)) {
94+ pr_debug("debugfs_hyperv: file %s not created\n", status);
95+ return PTR_ERR(test_state);
96+ }
97+
98+ return 0;
99+}
100+
101+/* Bind hv device to a dentry for debugfs */
102+static void hv_debug_set_dir_dentry(struct hv_device *dev, struct dentry *root)
103+{
104+ if (hv_debug_root)
105+ dev->debug_dir = root;
106+}
107+
108+/* Create all test dentry's and names for fuzz testing */
109+int hv_debug_add_dev_dir(struct hv_device *dev)
110+{
111+ const char *device = dev_name(&dev->device);
112+ char *delay_name = "delay";
113+ struct dentry *delay, *dev_root;
114+ int ret;
115+
116+ if (!IS_ERR(hv_debug_root)) {
117+ dev_root = debugfs_create_dir(device, hv_debug_root);
118+ if (IS_ERR(dev_root)) {
119+ pr_debug("debugfs_hyperv: hyperv/%s/ not created\n",
120+ device);
121+ return PTR_ERR(dev_root);
122+ }
123+ hv_debug_set_test_state(dev, dev_root);
124+ hv_debug_set_dir_dentry(dev, dev_root);
125+ delay = debugfs_create_dir(delay_name, dev_root);
126+
127+ if (IS_ERR(delay)) {
128+ pr_debug("debugfs_hyperv: hyperv/%s/%s/ not created\n",
129+ device, delay_name);
130+ return PTR_ERR(delay);
131+ }
132+ ret = hv_debug_delay_files(dev, delay);
133+
134+ return ret;
135+ }
136+ pr_debug("debugfs_hyperv: hyperv/ not in root debugfs path\n");
137+ return PTR_ERR(hv_debug_root);
138+}
139+
140+/* Remove dentry associated with released hv device */
141+void hv_debug_rm_dev_dir(struct hv_device *dev)
142+{
143+ if (!IS_ERR(hv_debug_root))
144+ debugfs_remove_recursive(dev->debug_dir);
145+}
146+
147+/* Remove all dentrys associated with vmbus testing */
148+void hv_debug_rm_all_dir(void)
149+{
150+ debugfs_remove_recursive(hv_debug_root);
151+}
152+
153+/* Delay buffer/message reads on a vmbus channel */
154+void hv_debug_delay_test(struct vmbus_channel *channel, enum delay delay_type)
155+{
156+ struct vmbus_channel *test_channel = channel->primary_channel ?
157+ channel->primary_channel :
158+ channel;
159+ bool state = test_channel->fuzz_testing_state;
160+
161+ if (state) {
162+ if (delay_type == 0)
163+ udelay(test_channel->fuzz_testing_interrupt_delay);
164+ else
165+ udelay(test_channel->fuzz_testing_message_delay);
166+ }
167+}
168+
169+/* Initialize top dentry for vmbus testing */
170+int hv_debug_init(void)
171+{
172+ hv_debug_root = debugfs_create_dir("hyperv", NULL);
173+ if (IS_ERR(hv_debug_root)) {
174+ pr_debug("debugfs_hyperv: hyperv/ not created\n");
175+ return PTR_ERR(hv_debug_root);
176+ }
177+ return 0;
178+}
drivers/hv/hv_fcopy.c+2−1
@@ -13,6 +13,7 @@ · 12 unmodified lines
1313 #include <linux/workqueue.h>
1414 #include <linux/hyperv.h>
1515 #include <linux/sched.h>
16+#include <asm/hyperv-tlfs.h>
1617
1718 #include "hyperv_vmbus.h"
1819 #include "hv_utils_transport.h"
@@ -234,7 +235,7 @@ void hv_fcopy_onchannelcallback(void *context) · 215 unmodified lines
234235 if (fcopy_transaction.state > HVUTIL_READY)
235236 return;
236237
237− vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
238+ vmbus_recvpacket(channel, recv_buffer, HV_HYP_PAGE_SIZE * 2, &recvlen,
238239 &requestid);
239240 if (recvlen <= 0)
240241 return;
drivers/hv/hv_kvp.c+2−1
@@ -27,6 +27,7 @@ · 26 unmodified lines
2727 #include <linux/connector.h>
2828 #include <linux/workqueue.h>
2929 #include <linux/hyperv.h>
30+#include <asm/hyperv-tlfs.h>
3031
3132 #include "hyperv_vmbus.h"
3233 #include "hv_utils_transport.h"
@@ -661,7 +662,7 @@ void hv_kvp_onchannelcallback(void *context) · 628 unmodified lines
661662 if (kvp_transaction.state > HVUTIL_READY)
662663 return;
663664
664− vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 4, &recvlen,
665+ vmbus_recvpacket(channel, recv_buffer, HV_HYP_PAGE_SIZE * 4, &recvlen,
665666 &requestid);
666667
667668 if (recvlen > 0) {
drivers/hv/hv_snapshot.c+2−1
@@ -12,6 +12,7 @@ · 11 unmodified lines
1212 #include <linux/connector.h>
1313 #include <linux/workqueue.h>
1414 #include <linux/hyperv.h>
15+#include <asm/hyperv-tlfs.h>
1516
1617 #include "hyperv_vmbus.h"
1718 #include "hv_utils_transport.h"
@@ -297,7 +298,7 @@ void hv_vss_onchannelcallback(void *context) · 279 unmodified lines
297298 if (vss_transaction.state > HVUTIL_READY)
298299 return;
299300
300− vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
301+ vmbus_recvpacket(channel, recv_buffer, HV_HYP_PAGE_SIZE * 2, &recvlen,
301302 &requestid);
302303
303304 if (recvlen > 0) {
drivers/hv/hv_util.c+7−6
@@ -136,7 +136,7 @@ static void shutdown_onchannelcallback(void *context) · 135 unmodified lines
136136 struct icmsg_hdr *icmsghdrp;
137137
138138 vmbus_recvpacket(channel, shut_txf_buf,
139− PAGE_SIZE, &recvlen, &requestid);
139+ HV_HYP_PAGE_SIZE, &recvlen, &requestid);
140140
141141 if (recvlen > 0) {
142142 icmsghdrp = (struct icmsg_hdr *)&shut_txf_buf[
@@ -284,7 +284,7 @@ static void timesync_onchannelcallback(void *context) · 141 unmodified lines
284284 u8 *time_txf_buf = util_timesynch.recv_buffer;
285285
286286 vmbus_recvpacket(channel, time_txf_buf,
287− PAGE_SIZE, &recvlen, &requestid);
287+ HV_HYP_PAGE_SIZE, &recvlen, &requestid);
288288
289289 if (recvlen > 0) {
290290 icmsghdrp = (struct icmsg_hdr *)&time_txf_buf[
@@ -346,7 +346,7 @@ static void heartbeat_onchannelcallback(void *context) · 55 unmodified lines
346346 while (1) {
347347
348348 vmbus_recvpacket(channel, hbeat_txf_buf,
349− PAGE_SIZE, &recvlen, &requestid);
349+ HV_HYP_PAGE_SIZE, &recvlen, &requestid);
350350
351351 if (!recvlen)
352352 break;
@@ -390,7 +390,7 @@ static int util_probe(struct hv_device *dev, · 37 unmodified lines
390390 (struct hv_util_service *)dev_id->driver_data;
391391 int ret;
392392
393− srv->recv_buffer = kmalloc(PAGE_SIZE * 4, GFP_KERNEL);
393+ srv->recv_buffer = kmalloc(HV_HYP_PAGE_SIZE * 4, GFP_KERNEL);
394394 if (!srv->recv_buffer)
395395 return -ENOMEM;
396396 srv->channel = dev->channel;
@@ -413,8 +413,9 @@ static int util_probe(struct hv_device *dev, · 16 unmodified lines
413413
414414 hv_set_drvdata(dev, srv);
415415
416− ret = vmbus_open(dev->channel, 4 * PAGE_SIZE, 4 * PAGE_SIZE, NULL, 0,
417− srv->util_cb, dev->channel);
416+ ret = vmbus_open(dev->channel, 4 * HV_HYP_PAGE_SIZE,
417+ 4 * HV_HYP_PAGE_SIZE, NULL, 0, srv->util_cb,
418+ dev->channel);
418419 if (ret)
419420 goto error;
420421
drivers/hv/hyperv_vmbus.h+31−0
@@ -385,4 +385,35 @@ enum hvutil_device_state { · 384 unmodified lines
385385 HVUTIL_DEVICE_DYING, /* driver unload is in progress */
386386 };
387387
388+enum delay {
389+ INTERRUPT_DELAY = 0,
390+ MESSAGE_DELAY = 1,
391+};
392+
393+#ifdef CONFIG_HYPERV_TESTING
394+
395+int hv_debug_add_dev_dir(struct hv_device *dev);
396+void hv_debug_rm_dev_dir(struct hv_device *dev);
397+void hv_debug_rm_all_dir(void);
398+int hv_debug_init(void);
399+void hv_debug_delay_test(struct vmbus_channel *channel, enum delay delay_type);
400+
401+#else /* CONFIG_HYPERV_TESTING */
402+
403+static inline void hv_debug_rm_dev_dir(struct hv_device *dev) {};
404+static inline void hv_debug_rm_all_dir(void) {};
405+static inline void hv_debug_delay_test(struct vmbus_channel *channel,
406+ enum delay delay_type) {};
407+static inline int hv_debug_init(void)
408+{
409+ return -1;
410+}
411+
412+static inline int hv_debug_add_dev_dir(struct hv_device *dev)
413+{
414+ return -1;
415+}
416+
417+#endif /* CONFIG_HYPERV_TESTING */
418+
388419 #endif /* _HYPERV_VMBUS_H */
drivers/hv/ring_buffer.c+2−0
@@ -396,6 +396,7 @@ struct vmpacket_descriptor *hv_pkt_iter_first(struct vmbus_channel *channel) · 395 unmodified lines
396396 struct hv_ring_buffer_info *rbi = &channel->inbound;
397397 struct vmpacket_descriptor *desc;
398398
399+ hv_debug_delay_test(channel, MESSAGE_DELAY);
399400 if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor))
400401 return NULL;
401402
@@ -421,6 +422,7 @@ __hv_pkt_iter_next(struct vmbus_channel *channel, · 19 unmodified lines
421422 u32 packetlen = desc->len8 << 3;
422423 u32 dsize = rbi->ring_datasize;
423424
425+ hv_debug_delay_test(channel, MESSAGE_DELAY);
424426 /* bump offset to next potential packet */
425427 rbi->priv_read_index += packetlen + VMBUS_PKT_TRAILER;
426428 if (rbi->priv_read_index >= dsize)
drivers/hv/vmbus_drv.c+16−11
@@ -79,7 +79,7 @@ static struct notifier_block hyperv_panic_block = { · 78 unmodified lines
7979 static const char *fb_mmio_name = "fb_range";
8080 static struct resource *fb_mmio;
8181 static struct resource *hyperv_mmio;
82−static DEFINE_SEMAPHORE(hyperv_mmio_lock);
82+static DEFINE_MUTEX(hyperv_mmio_lock);
8383
8484 static int vmbus_exists(void)
8585 {
@@ -960,6 +960,8 @@ static void vmbus_device_release(struct device *device) · 874 unmodified lines
960960 struct hv_device *hv_dev = device_to_hv_device(device);
961961 struct vmbus_channel *channel = hv_dev->channel;
962962
963+ hv_debug_rm_dev_dir(hv_dev);
964+
963965 mutex_lock(&vmbus_connection.channel_mutex);
964966 hv_process_channel_removal(channel);
965967 mutex_unlock(&vmbus_connection.channel_mutex);
@@ -1273,7 +1275,7 @@ static void hv_kmsg_dump(struct kmsg_dumper *dumper, · 307 unmodified lines
12731275 * Write dump contents to the page. No need to synchronize; panic should
12741276 * be single-threaded.
12751277 */
1276− kmsg_dump_get_buffer(dumper, true, hv_panic_page, PAGE_SIZE,
1278+ kmsg_dump_get_buffer(dumper, true, hv_panic_page, HV_HYP_PAGE_SIZE,
12771279 &bytes_written);
12781280 if (bytes_written)
12791281 hyperv_report_panic_msg(panic_pa, bytes_written);
@@ -1373,7 +1375,7 @@ static int vmbus_bus_init(void) · 93 unmodified lines
13731375 */
13741376 hv_get_crash_ctl(hyperv_crash_ctl);
13751377 if (hyperv_crash_ctl & HV_CRASH_CTL_CRASH_NOTIFY_MSG) {
1376− hv_panic_page = (void *)get_zeroed_page(GFP_KERNEL);
1378+ hv_panic_page = (void *)hv_alloc_hyperv_zeroed_page();
13771379 if (hv_panic_page) {
13781380 ret = kmsg_dump_register(&hv_kmsg_dumper);
13791381 if (ret)
@@ -1401,7 +1403,7 @@ err_alloc: · 21 unmodified lines
14011403 hv_remove_vmbus_irq();
14021404
14031405 bus_unregister(&hv_bus);
1404− free_page((unsigned long)hv_panic_page);
1406+ hv_free_hyperv_page((unsigned long)hv_panic_page);
14051407 unregister_sysctl_table(hv_ctl_table_hdr);
14061408 hv_ctl_table_hdr = NULL;
14071409 return ret;
@@ -1809,6 +1811,7 @@ int vmbus_device_register(struct hv_device *child_device_obj) · 401 unmodified lines
18091811 pr_err("Unable to register primary channeln");
18101812 goto err_kset_unregister;
18111813 }
1814+ hv_debug_add_dev_dir(child_device_obj);
18121815
18131816 return 0;
18141817
@@ -2010,7 +2013,7 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj, · 195 unmodified lines
20102013 int retval;
20112014
20122015 retval = -ENXIO;
2013− down(&hyperv_mmio_lock);
2016+ mutex_lock(&hyperv_mmio_lock);
20142017
20152018 /*
20162019 * If overlaps with frame buffers are allowed, then first attempt to
@@ -2057,7 +2060,7 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj, · 40 unmodified lines
20572060 }
20582061
20592062 exit:
2060− up(&hyperv_mmio_lock);
2063+ mutex_unlock(&hyperv_mmio_lock);
20612064 return retval;
20622065 }
20632066 EXPORT_SYMBOL_GPL(vmbus_allocate_mmio);
@@ -2074,7 +2077,7 @@ void vmbus_free_mmio(resource_size_t start, resource_size_t size) · 10 unmodified lines
20742077 {
20752078 struct resource *iter;
20762079
2077− down(&hyperv_mmio_lock);
2080+ mutex_lock(&hyperv_mmio_lock);
20782081 for (iter = hyperv_mmio; iter; iter = iter->sibling) {
20792082 if ((iter->start >= start + size) || (iter->end <= start))
20802083 continue;
@@ -2082,7 +2085,7 @@ void vmbus_free_mmio(resource_size_t start, resource_size_t size) · 1 unmodified line
20822085 __release_region(iter, start, size);
20832086 }
20842087 release_mem_region(start, size);
2085− up(&hyperv_mmio_lock);
2088+ mutex_unlock(&hyperv_mmio_lock);
20862089
20872090 }
20882091 EXPORT_SYMBOL_GPL(vmbus_free_mmio);
@@ -2215,8 +2218,7 @@ static int vmbus_bus_resume(struct device *dev) · 126 unmodified lines
22152218 * We only use the 'vmbus_proto_version', which was in use before
22162219 * hibernation, to re-negotiate with the host.
22172220 */
2218− if (vmbus_proto_version == VERSION_INVAL ||
2219− vmbus_proto_version == 0) {
2221+ if (!vmbus_proto_version) {
22202222 pr_err("Invalid proto version = 0x%x\n", vmbus_proto_version);
22212223 return -EINVAL;
22222224 }
@@ -2303,7 +2305,7 @@ static void hv_crash_handler(struct pt_regs *regs) · 80 unmodified lines
23032305 vmbus_connection.conn_state = DISCONNECTED;
23042306 cpu = smp_processor_id();
23052307 hv_stimer_cleanup(cpu);
2306− hv_synic_cleanup(cpu);
2308+ hv_synic_disable_regs(cpu);
23072309 hyperv_cleanup();
23082310 };
23092311
@@ -2373,6 +2375,7 @@ static int __init hv_acpi_init(void) · 63 unmodified lines
23732375 ret = -ETIMEDOUT;
23742376 goto cleanup;
23752377 }
2378+ hv_debug_init();
23762379
23772380 ret = vmbus_bus_init();
23782381 if (ret)
@@ -2409,6 +2412,8 @@ static void __exit vmbus_exit(void) · 30 unmodified lines
24092412
24102413 tasklet_kill(&hv_cpu->msg_dpc);
24112414 }
2415+ hv_debug_rm_all_dir();
2416+
24122417 vmbus_free_channels();
24132418
24142419 if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) {
drivers/iommu/Kconfig+1−1
@@ -467,7 +467,7 @@ config QCOM_IOMMU · 466 unmodified lines
467467
468468 config HYPERV_IOMMU
469469 bool "Hyper-V x2APIC IRQ Handling"
470− depends on HYPERV
470+ depends on HYPERV && X86
471471 select IOMMU_API
472472 default HYPERV
473473 help
drivers/net/hyperv/hyperv_net.h+3−0
@@ -955,6 +955,9 @@ struct net_device_context { · 954 unmodified lines
955955 u32 vf_alloc;
956956 /* Serial number of the VF to team with */
957957 u32 vf_serial;
958+
959+ /* Used to temporarily save the config info across hibernation */
960+ struct netvsc_device_info *saved_netvsc_dev_info;
958961 };
959962
960963 /* Per channel data */
drivers/net/hyperv/netvsc_drv.c+57−0
@@ -2424,6 +2424,61 @@ static int netvsc_remove(struct hv_device *dev) · 2423 unmodified lines
24242424 return 0;
24252425 }
24262426
2427+static int netvsc_suspend(struct hv_device *dev)
2428+{
2429+ struct net_device_context *ndev_ctx;
2430+ struct net_device *vf_netdev, *net;
2431+ struct netvsc_device *nvdev;
2432+ int ret;
2433+
2434+ net = hv_get_drvdata(dev);
2435+
2436+ ndev_ctx = netdev_priv(net);
2437+ cancel_delayed_work_sync(&ndev_ctx->dwork);
2438+
2439+ rtnl_lock();
2440+
2441+ nvdev = rtnl_dereference(ndev_ctx->nvdev);
2442+ if (nvdev == NULL) {
2443+ ret = -ENODEV;
2444+ goto out;
2445+ }
2446+
2447+ vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev);
2448+ if (vf_netdev)
2449+ netvsc_unregister_vf(vf_netdev);
2450+
2451+ /* Save the current config info */
2452+ ndev_ctx->saved_netvsc_dev_info = netvsc_devinfo_get(nvdev);
2453+
2454+ ret = netvsc_detach(net, nvdev);
2455+out:
2456+ rtnl_unlock();
2457+
2458+ return ret;
2459+}
2460+
2461+static int netvsc_resume(struct hv_device *dev)
2462+{
2463+ struct net_device *net = hv_get_drvdata(dev);
2464+ struct net_device_context *net_device_ctx;
2465+ struct netvsc_device_info *device_info;
2466+ int ret;
2467+
2468+ rtnl_lock();
2469+
2470+ net_device_ctx = netdev_priv(net);
2471+ device_info = net_device_ctx->saved_netvsc_dev_info;
2472+
2473+ ret = netvsc_attach(net, device_info);
2474+
2475+ rtnl_unlock();
2476+
2477+ kfree(device_info);
2478+ net_device_ctx->saved_netvsc_dev_info = NULL;
2479+
2480+ return ret;
2481+}
24272482 static const struct hv_vmbus_device_id id_table[] = {
24282483 /* Network guid */
24292484 { HV_NIC_GUID, },
@@ -2438,6 +2493,8 @@ static struct hv_driver netvsc_drv = { · 8 unmodified lines
24382493 .id_table = id_table,
24392494 .probe = netvsc_probe,
24402495 .remove = netvsc_remove,
2496+ .suspend = netvsc_suspend,
2497+ .resume = netvsc_resume,
24412498 .driver = {
24422499 .probe_type = PROBE_FORCE_SYNCHRONOUS,
24432500 },
drivers/scsi/storvsc_drv.c+41−0
@@ -1727,6 +1727,13 @@ static const struct hv_vmbus_device_id id_table[] = { · 1726 unmodified lines
17271727
17281728 MODULE_DEVICE_TABLE(vmbus, id_table);
17291729
1730+static const struct { guid_t guid; } fc_guid = { HV_SYNTHFC_GUID };
1731+
1732+static bool hv_dev_is_fc(struct hv_device *hv_dev)
1733+{
1734+ return guid_equal(&fc_guid.guid, &hv_dev->dev_type);
1735+}
1736+
17301737 static int storvsc_probe(struct hv_device *device,
17311738 const struct hv_vmbus_device_id *dev_id)
17321739 {
@@ -1934,11 +1941,45 @@ static int storvsc_remove(struct hv_device *dev) · 201 unmodified lines
19341941 return 0;
19351942 }
19361943
1944+static int storvsc_suspend(struct hv_device *hv_dev)
1945+{
1946+ struct storvsc_device *stor_device = hv_get_drvdata(hv_dev);
1947+ struct Scsi_Host *host = stor_device->host;
1948+ struct hv_host_device *host_dev = shost_priv(host);
1949+
1950+ storvsc_wait_to_drain(stor_device);
1951+
1952+ drain_workqueue(host_dev->handle_error_wq);
1953+
1954+ vmbus_close(hv_dev->channel);
1955+
1956+ memset(stor_device->stor_chns, 0,
1957+ num_possible_cpus() * sizeof(void *));
1958+
1959+ kfree(stor_device->stor_chns);
1960+ stor_device->stor_chns = NULL;
1961+
1962+ cpumask_clear(&stor_device->alloced_cpus);
1963+
1964+ return 0;
1965+}
1966+
1967+static int storvsc_resume(struct hv_device *hv_dev)
1968+{
1969+ int ret;
1970+
1971+ ret = storvsc_connect_to_vsp(hv_dev, storvsc_ringbuffer_size,
1972+ hv_dev_is_fc(hv_dev));
1973+ return ret;
1974+}
1975+
19371976 static struct hv_driver storvsc_drv = {
19381977 .name = KBUILD_MODNAME,
19391978 .id_table = id_table,
19401979 .probe = storvsc_probe,
19411980 .remove = storvsc_remove,
1981+ .suspend = storvsc_suspend,
1982+ .resume = storvsc_resume,
19421983 .driver = {
19431984 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
19441985 },
drivers/video/fbdev/Kconfig+1−0
@@ -2214,6 +2214,7 @@ config FB_HYPERV · 2213 unmodified lines
22142214 select FB_CFB_FILLRECT
22152215 select FB_CFB_COPYAREA
22162216 select FB_CFB_IMAGEBLIT
2217+ select FB_DEFERRED_IO
22172218 help
22182219 This framebuffer driver supports Microsoft Hyper-V Synthetic Video.
22192220
drivers/video/fbdev/hyperv_fb.c+395−33
@@ -23,6 +23,14 @@ · 22 unmodified lines
2323 *
2424 * Portrait orientation is also supported:
2525 * For example: video=hyperv_fb:864x1152
26+ *
27+ * When a Windows 10 RS5+ host is used, the virtual machine screen
28+ * resolution is obtained from the host. The "video=hyperv_fb" option is
29+ * not needed, but still can be used to overwrite what the host specifies.
30+ * The VM resolution on the host could be set by executing the powershell
31+ * "set-vmvideo" command. For example
32+ * set-vmvideo -vmname name -horizontalresolution:1920 \
33+ * -verticalresolution:1200 -resolutiontype single
2634 */
2735
2836 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -34,6 +42,7 @@ · 5 unmodified lines
3442 #include <linux/fb.h>
3543 #include <linux/pci.h>
3644 #include <linux/efi.h>
45+#include <linux/console.h>
3746
3847 #include <linux/hyperv.h>
3948
@@ -44,6 +53,10 @@ · 4 unmodified lines
4453 #define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major))
4554 #define SYNTHVID_VERSION_WIN7 SYNTHVID_VERSION(3, 0)
4655 #define SYNTHVID_VERSION_WIN8 SYNTHVID_VERSION(3, 2)
56+#define SYNTHVID_VERSION_WIN10 SYNTHVID_VERSION(3, 5)
57+
58+#define SYNTHVID_VER_GET_MAJOR(ver) (ver & 0x0000ffff)
59+#define SYNTHVID_VER_GET_MINOR(ver) ((ver & 0xffff0000) >> 16)
4760
4861 #define SYNTHVID_DEPTH_WIN7 16
4962 #define SYNTHVID_DEPTH_WIN8 32
@@ -82,16 +95,25 @@ enum synthvid_msg_type { · 32 unmodified lines
8295 SYNTHVID_POINTER_SHAPE = 8,
8396 SYNTHVID_FEATURE_CHANGE = 9,
8497 SYNTHVID_DIRT = 10,
98+ SYNTHVID_RESOLUTION_REQUEST = 13,
99+ SYNTHVID_RESOLUTION_RESPONSE = 14,
85100
86− SYNTHVID_MAX = 11
101+ SYNTHVID_MAX = 15
87102 };
88103
104+#define SYNTHVID_EDID_BLOCK_SIZE 128
105+#define SYNTHVID_MAX_RESOLUTION_COUNT 64
106+
107+struct hvd_screen_info {
108+ u16 width;
109+ u16 height;
110+} __packed;
111+
89112 struct synthvid_msg_hdr {
90113 u32 type;
91114 u32 size; /* size of this header + payload after this field*/
92115 } __packed;
93116
94−
95117 struct synthvid_version_req {
96118 u32 version;
97119 } __packed;
@@ -102,6 +124,19 @@ struct synthvid_version_resp { · 4 unmodified lines
102124 u8 max_video_outputs;
103125 } __packed;
104126
127+struct synthvid_supported_resolution_req {
128+ u8 maximum_resolution_count;
129+} __packed;
130+
131+struct synthvid_supported_resolution_resp {
132+ u8 edid_block[SYNTHVID_EDID_BLOCK_SIZE];
133+ u8 resolution_count;
134+ u8 default_resolution_index;
135+ u8 is_standard;
136+ struct hvd_screen_info
137+ supported_resolution[SYNTHVID_MAX_RESOLUTION_COUNT];
138+} __packed;
139+
105140 struct synthvid_vram_location {
106141 u64 user_ctx;
107142 u8 is_vram_gpa_specified;
@@ -187,6 +222,8 @@ struct synthvid_msg { · 79 unmodified lines
187222 struct synthvid_pointer_shape ptr_shape;
188223 struct synthvid_feature_change feature_chg;
189224 struct synthvid_dirt dirt;
225+ struct synthvid_supported_resolution_req resolution_req;
226+ struct synthvid_supported_resolution_resp resolution_resp;
190227 };
191228 } __packed;
192229
@@ -201,6 +238,7 @@ struct synthvid_msg { · 8 unmodified lines
201238 #define RING_BUFSIZE (256 * 1024)
202239 #define VSP_TIMEOUT (10 * HZ)
203240 #define HVFB_UPDATE_DELAY (HZ / 20)
241+#define HVFB_ONDEMAND_THROTTLE (HZ / 20)
204242
205243 struct hvfb_par {
206244 struct fb_info *info;
@@ -211,6 +249,7 @@ struct hvfb_par { · 4 unmodified lines
211249
212250 struct delayed_work dwork;
213251 bool update;
252+ bool update_saved; /* The value of 'update' before hibernation */
214253
215254 u32 pseudo_palette[16];
216255 u8 init_buf[MAX_VMBUS_PKT_SIZE];
@@ -220,12 +259,25 @@ struct hvfb_par { · 3 unmodified lines
220259 bool synchronous_fb;
221260
222261 struct notifier_block hvfb_panic_nb;
262+
263+ /* Memory for deferred IO and frame buffer itself */
264+ unsigned char *dio_vp;
265+ unsigned char *mmio_vp;
266+ unsigned long mmio_pp;
267+
268+ /* Dirty rectangle, protected by delayed_refresh_lock */
269+ int x1, y1, x2, y2;
270+ bool delayed_refresh;
271+ spinlock_t delayed_refresh_lock;
223272 };
224273
225274 static uint screen_width = HVFB_WIDTH;
226275 static uint screen_height = HVFB_HEIGHT;
276+static uint screen_width_max = HVFB_WIDTH;
277+static uint screen_height_max = HVFB_HEIGHT;
227278 static uint screen_depth;
228279 static uint screen_fb_size;
280+static uint dio_fb_size; /* FB size for deferred IO */
229281
230282 /* Send message to Hyper-V host */
231283 static inline int synthvid_send(struct hv_device *hdev,
@@ -312,28 +364,88 @@ static int synthvid_send_ptr(struct hv_device *hdev) · 80 unmodified lines
312364 }
313365
314366 /* Send updated screen area (dirty rectangle) location to host */
315−static int synthvid_update(struct fb_info *info)
367+static int
368+synthvid_update(struct fb_info *info, int x1, int y1, int x2, int y2)
316369 {
317370 struct hv_device *hdev = device_to_hv_device(info->device);
318371 struct synthvid_msg msg;
319372
320373 memset(&msg, 0, sizeof(struct synthvid_msg));
374+ if (x2 == INT_MAX)
375+ x2 = info->var.xres;
376+ if (y2 == INT_MAX)
377+ y2 = info->var.yres;
321378
322379 msg.vid_hdr.type = SYNTHVID_DIRT;
323380 msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
324381 sizeof(struct synthvid_dirt);
325382 msg.dirt.video_output = 0;
326383 msg.dirt.dirt_count = 1;
327− msg.dirt.rect[0].x1 = 0;
328− msg.dirt.rect[0].y1 = 0;
329− msg.dirt.rect[0].x2 = info->var.xres;
330− msg.dirt.rect[0].y2 = info->var.yres;
384+ msg.dirt.rect[0].x1 = (x1 > x2) ? 0 : x1;
385+ msg.dirt.rect[0].y1 = (y1 > y2) ? 0 : y1;
386+ msg.dirt.rect[0].x2 =
387+ (x2 < x1 || x2 > info->var.xres) ? info->var.xres : x2;
388+ msg.dirt.rect[0].y2 =
389+ (y2 < y1 || y2 > info->var.yres) ? info->var.yres : y2;
331390
332391 synthvid_send(hdev, &msg);
333392
334393 return 0;
335394 }
336395
396+static void hvfb_docopy(struct hvfb_par *par,
397+ unsigned long offset,
398+ unsigned long size)
399+{
400+ if (!par || !par->mmio_vp || !par->dio_vp || !par->fb_ready ||
401+ size == 0 || offset >= dio_fb_size)
402+ return;
403+
404+ if (offset + size > dio_fb_size)
405+ size = dio_fb_size - offset;
406+
407+ memcpy(par->mmio_vp + offset, par->dio_vp + offset, size);
408+}
409+
410+/* Deferred IO callback */
411+static void synthvid_deferred_io(struct fb_info *p,
412+ struct list_head *pagelist)
413+{
414+ struct hvfb_par *par = p->par;
415+ struct page *page;
416+ unsigned long start, end;
417+ int y1, y2, miny, maxy;
418+
419+ miny = INT_MAX;
420+ maxy = 0;
421+
422+ /*
423+ * Merge dirty pages. It is possible that last page cross
424+ * over the end of frame buffer row yres. This is taken care of
425+ * in synthvid_update function by clamping the y2
426+ * value to yres.
427+ */
428+ list_for_each_entry(page, pagelist, lru) {
429+ start = page->index << PAGE_SHIFT;
430+ end = start + PAGE_SIZE - 1;
431+ y1 = start / p->fix.line_length;
432+ y2 = end / p->fix.line_length;
433+ miny = min_t(int, miny, y1);
434+ maxy = max_t(int, maxy, y2);
435+
436+ /* Copy from dio space to mmio address */
437+ if (par->fb_ready)
438+ hvfb_docopy(par, start, PAGE_SIZE);
439+ }
440+
441+ if (par->fb_ready && par->update)
442+ synthvid_update(p, 0, miny, p->var.xres, maxy + 1);
443+}
444+
445+static struct fb_deferred_io synthvid_defio = {
446+ .delay = HZ / 20,
447+ .deferred_io = synthvid_deferred_io,
448+};
337449
338450 /*
339451 * Actions on received messages from host:
@@ -354,6 +466,7 @@ static void synthvid_recv_sub(struct hv_device *hdev) · 14 unmodified lines
354466
355467 /* Complete the wait event */
356468 if (msg->vid_hdr.type == SYNTHVID_VERSION_RESPONSE ||
469+ msg->vid_hdr.type == SYNTHVID_RESOLUTION_RESPONSE ||
357470 msg->vid_hdr.type == SYNTHVID_VRAM_LOCATION_ACK) {
358471 memcpy(par->init_buf, msg, MAX_VMBUS_PKT_SIZE);
359472 complete(&par->wait);
@@ -400,6 +513,17 @@ static void synthvid_receive(void *ctx) · 40 unmodified lines
400513 } while (bytes_recvd > 0 && ret == 0);
401514 }
402515
516+/* Check if the ver1 version is equal or greater than ver2 */
517+static inline bool synthvid_ver_ge(u32 ver1, u32 ver2)
518+{
519+ if (SYNTHVID_VER_GET_MAJOR(ver1) > SYNTHVID_VER_GET_MAJOR(ver2) ||
520+ (SYNTHVID_VER_GET_MAJOR(ver1) == SYNTHVID_VER_GET_MAJOR(ver2) &&
521+ SYNTHVID_VER_GET_MINOR(ver1) >= SYNTHVID_VER_GET_MINOR(ver2)))
522+ return true;
523+
524+ return false;
525+}
526+
403527 /* Check synthetic video protocol version with the host */
404528 static int synthvid_negotiate_ver(struct hv_device *hdev, u32 ver)
405529 {
@@ -428,6 +552,64 @@ static int synthvid_negotiate_ver(struct hv_device *hdev, u32 ver) · 22 unmodified lines
428552 }
429553
430554 par->synthvid_version = ver;
555+ pr_info("Synthvid Version major %d, minor %d\n",
556+ SYNTHVID_VER_GET_MAJOR(ver), SYNTHVID_VER_GET_MINOR(ver));
557+
558+out:
559+ return ret;
560+}
561+
562+/* Get current resolution from the host */
563+static int synthvid_get_supported_resolution(struct hv_device *hdev)
564+{
565+ struct fb_info *info = hv_get_drvdata(hdev);
566+ struct hvfb_par *par = info->par;
567+ struct synthvid_msg *msg = (struct synthvid_msg *)par->init_buf;
568+ int ret = 0;
569+ unsigned long t;
570+ u8 index;
571+ int i;
572+
573+ memset(msg, 0, sizeof(struct synthvid_msg));
574+ msg->vid_hdr.type = SYNTHVID_RESOLUTION_REQUEST;
575+ msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
576+ sizeof(struct synthvid_supported_resolution_req);
577+
578+ msg->resolution_req.maximum_resolution_count =
579+ SYNTHVID_MAX_RESOLUTION_COUNT;
580+ synthvid_send(hdev, msg);
581+
582+ t = wait_for_completion_timeout(&par->wait, VSP_TIMEOUT);
583+ if (!t) {
584+ pr_err("Time out on waiting resolution response\n");
585+ ret = -ETIMEDOUT;
586+ goto out;
587+ }
588+
589+ if (msg->resolution_resp.resolution_count == 0) {
590+ pr_err("No supported resolutions\n");
591+ ret = -ENODEV;
592+ goto out;
593+ }
594+
595+ index = msg->resolution_resp.default_resolution_index;
596+ if (index >= msg->resolution_resp.resolution_count) {
597+ pr_err("Invalid resolution index: %d\n", index);
598+ ret = -ENODEV;
599+ goto out;
600+ }
601+
602+ for (i = 0; i < msg->resolution_resp.resolution_count; i++) {
603+ screen_width_max = max_t(unsigned int, screen_width_max,
604+ msg->resolution_resp.supported_resolution[i].width);
605+ screen_height_max = max_t(unsigned int, screen_height_max,
606+ msg->resolution_resp.supported_resolution[i].height);
607+ }
608+
609+ screen_width =
610+ msg->resolution_resp.supported_resolution[index].width;
611+ screen_height =
612+ msg->resolution_resp.supported_resolution[index].height;
431613
432614 out:
433615 return ret;
@@ -448,11 +630,27 @@ static int synthvid_connect_vsp(struct hv_device *hdev) · 14 unmodified lines
448630 }
449631
450632 /* Negotiate the protocol version with host */
451− if (vmbus_proto_version == VERSION_WS2008 ||
452− vmbus_proto_version == VERSION_WIN7)
453− ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN7);
454− else
633+ switch (vmbus_proto_version) {
634+ case VERSION_WIN10:
635+ case VERSION_WIN10_V5:
636+ ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN10);
637+ if (!ret)
638+ break;
639+ /* Fallthrough */
640+ case VERSION_WIN8:
641+ case VERSION_WIN8_1:
455642 ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN8);
643+ if (!ret)
644+ break;
645+ /* Fallthrough */
646+ case VERSION_WS2008:
647+ case VERSION_WIN7:
648+ ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN7);
649+ break;
650+ default:
651+ ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN10);
652+ break;
653+ }
456654
457655 if (ret) {
458656 pr_err("Synthetic video device version not accepted\n");
@@ -464,6 +662,12 @@ static int synthvid_connect_vsp(struct hv_device *hdev) · 5 unmodified lines
464662 else
465663 screen_depth = SYNTHVID_DEPTH_WIN8;
466664
665+ if (synthvid_ver_ge(par->synthvid_version, SYNTHVID_VERSION_WIN10)) {
666+ ret = synthvid_get_supported_resolution(hdev);
667+ if (ret)
668+ pr_info("Failed to get supported resolution from host, use default\n");
669+ }
670+
467671 screen_fb_size = hdev->channel->offermsg.offer.
468672 mmio_megabytes * 1024 * 1024;
469673
@@ -488,7 +692,7 @@ static int synthvid_send_config(struct hv_device *hdev) · 18 unmodified lines
488692 msg->vid_hdr.type = SYNTHVID_VRAM_LOCATION;
489693 msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
490694 sizeof(struct synthvid_vram_location);
491− msg->vram.user_ctx = msg->vram.vram_gpa = info->fix.smem_start;
695+ msg->vram.user_ctx = msg->vram.vram_gpa = par->mmio_pp;
492696 msg->vram.is_vram_gpa_specified = 1;
493697 synthvid_send(hdev, msg);
494698
@@ -498,7 +702,7 @@ static int synthvid_send_config(struct hv_device *hdev) · 3 unmodified lines
498702 ret = -ETIMEDOUT;
499703 goto out;
500704 }
501− if (msg->vram_ack.user_ctx != info->fix.smem_start) {
705+ if (msg->vram_ack.user_ctx != par->mmio_pp) {
502706 pr_err("Unable to set VRAM location\n");
503707 ret = -ENODEV;
504708 goto out;
@@ -515,19 +719,77 @@ out: · 10 unmodified lines
515719
516720 /*
517721 * Delayed work callback:
518− * It is called at HVFB_UPDATE_DELAY or longer time interval to process
519− * screen updates. It is re-scheduled if further update is necessary.
722+ * It is scheduled to call whenever update request is received and it has
723+ * not been called in last HVFB_ONDEMAND_THROTTLE time interval.
520724 */
521725 static void hvfb_update_work(struct work_struct *w)
522726 {
523727 struct hvfb_par *par = container_of(w, struct hvfb_par, dwork.work);
524728 struct fb_info *info = par->info;
729+ unsigned long flags;
730+ int x1, x2, y1, y2;
731+ int j;
732+
733+ spin_lock_irqsave(&par->delayed_refresh_lock, flags);
734+ /* Reset the request flag */
735+ par->delayed_refresh = false;
736+
737+ /* Store the dirty rectangle to local variables */
738+ x1 = par->x1;
739+ x2 = par->x2;
740+ y1 = par->y1;
741+ y2 = par->y2;
742+
743+ /* Clear dirty rectangle */
744+ par->x1 = par->y1 = INT_MAX;
745+ par->x2 = par->y2 = 0;
746+
747+ spin_unlock_irqrestore(&par->delayed_refresh_lock, flags);
748+
749+ if (x1 > info->var.xres || x2 > info->var.xres ||
750+ y1 > info->var.yres || y2 > info->var.yres || x2 <= x1)
751+ return;
752+
753+ /* Copy the dirty rectangle to frame buffer memory */
754+ for (j = y1; j < y2; j++) {
755+ hvfb_docopy(par,
756+ j * info->fix.line_length +
757+ (x1 * screen_depth / 8),
758+ (x2 - x1) * screen_depth / 8);
759+ }
760+
761+ /* Refresh */
762+ if (par->fb_ready && par->update)
763+ synthvid_update(info, x1, y1, x2, y2);
764+}
525765
526− if (par->fb_ready)
527− synthvid_update(info);
766+/*
767+ * Control the on-demand refresh frequency. It schedules a delayed
768+ * screen update if it has not yet.
769+ */
770+static void hvfb_ondemand_refresh_throttle(struct hvfb_par *par,
771+ int x1, int y1, int w, int h)
772+{
773+ unsigned long flags;
774+ int x2 = x1 + w;
775+ int y2 = y1 + h;
776+
777+ spin_lock_irqsave(&par->delayed_refresh_lock, flags);
778+
779+ /* Merge dirty rectangle */
780+ par->x1 = min_t(int, par->x1, x1);
781+ par->y1 = min_t(int, par->y1, y1);
782+ par->x2 = max_t(int, par->x2, x2);
783+ par->y2 = max_t(int, par->y2, y2);
784+
785+ /* Schedule a delayed screen update if not yet */
786+ if (par->delayed_refresh == false) {
787+ schedule_delayed_work(&par->dwork,
788+ HVFB_ONDEMAND_THROTTLE);
789+ par->delayed_refresh = true;
790+ }
528791
529− if (par->update)
530− schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY);
792+ spin_unlock_irqrestore(&par->delayed_refresh_lock, flags);
531793 }
532794
533795 static int hvfb_on_panic(struct notifier_block *nb,
@@ -539,7 +801,8 @@ static int hvfb_on_panic(struct notifier_block *nb, · 5 unmodified lines
539801 par = container_of(nb, struct hvfb_par, hvfb_panic_nb);
540802 par->synchronous_fb = true;
541803 info = par->info;
542− synthvid_update(info);
804+ hvfb_docopy(par, 0, dio_fb_size);
805+ synthvid_update(info, 0, 0, INT_MAX, INT_MAX);
543806
544807 return NOTIFY_DONE;
545808 }
@@ -600,7 +863,10 @@ static void hvfb_cfb_fillrect(struct fb_info *p, · 54 unmodified lines
600863
601864 cfb_fillrect(p, rect);
602865 if (par->synchronous_fb)
603− synthvid_update(p);
866+ synthvid_update(p, 0, 0, INT_MAX, INT_MAX);
867+ else
868+ hvfb_ondemand_refresh_throttle(par, rect->dx, rect->dy,
869+ rect->width, rect->height);
604870 }
605871
606872 static void hvfb_cfb_copyarea(struct fb_info *p,
@@ -610,7 +876,10 @@ static void hvfb_cfb_copyarea(struct fb_info *p, · 3 unmodified lines
610876
611877 cfb_copyarea(p, area);
612878 if (par->synchronous_fb)
613− synthvid_update(p);
879+ synthvid_update(p, 0, 0, INT_MAX, INT_MAX);
880+ else
881+ hvfb_ondemand_refresh_throttle(par, area->dx, area->dy,
882+ area->width, area->height);
614883 }
615884
616885 static void hvfb_cfb_imageblit(struct fb_info *p,
@@ -620,7 +889,10 @@ static void hvfb_cfb_imageblit(struct fb_info *p, · 3 unmodified lines
620889
621890 cfb_imageblit(p, image);
622891 if (par->synchronous_fb)
623− synthvid_update(p);
892+ synthvid_update(p, 0, 0, INT_MAX, INT_MAX);
893+ else
894+ hvfb_ondemand_refresh_throttle(par, image->dx, image->dy,
895+ image->width, image->height);
624896 }
625897
626898 static struct fb_ops hvfb_ops = {
@@ -653,6 +925,8 @@ static void hvfb_get_option(struct fb_info *info) · 26 unmodified lines
653925 }
654926
655927 if (x < HVFB_WIDTH_MIN || y < HVFB_HEIGHT_MIN ||
928+ (synthvid_ver_ge(par->synthvid_version, SYNTHVID_VERSION_WIN10) &&
929+ (x > screen_width_max || y > screen_height_max)) ||
656930 (par->synthvid_version == SYNTHVID_VERSION_WIN8 &&
657931 x * y * screen_depth / 8 > SYNTHVID_FB_SIZE_WIN8) ||
658932 (par->synthvid_version == SYNTHVID_VERSION_WIN7 &&
@@ -677,6 +951,9 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info) · 18 unmodified lines
677951 resource_size_t pot_start, pot_end;
678952 int ret;
679953
954+ dio_fb_size =
955+ screen_width * screen_height * screen_depth / 8;
956+
680957 if (gen2vm) {
681958 pot_start = 0;
682959 pot_end = -1;
@@ -689,8 +966,12 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info) · 6 unmodified lines
689966 }
690967
691968 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
692− pci_resource_len(pdev, 0) < screen_fb_size)
969+ pci_resource_len(pdev, 0) < screen_fb_size) {
970+ pr_err("Resource not available or (0x%lx < 0x%lx)\n",
971+ (unsigned long) pci_resource_len(pdev, 0),
972+ (unsigned long) screen_fb_size);
693973 goto err1;
974+ }
694975
695976 pot_end = pci_resource_end(pdev, 0);
696977 pot_start = pot_end - screen_fb_size + 1;
@@ -707,9 +988,14 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info) · 10 unmodified lines
707988 if (!fb_virt)
708989 goto err2;
709990
991+ /* Allocate memory for deferred IO */
992+ par->dio_vp = vzalloc(round_up(dio_fb_size, PAGE_SIZE));
993+ if (par->dio_vp == NULL)
994+ goto err3;
995+
710996 info->apertures = alloc_apertures(1);
711997 if (!info->apertures)
712− goto err3;
998+ goto err4;
713999
7141000 if (gen2vm) {
7151001 info->apertures->ranges[0].base = screen_info.lfb_base;
@@ -721,16 +1007,23 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info) · 5 unmodified lines
7211007 info->apertures->ranges[0].size = pci_resource_len(pdev, 0);
7221008 }
7231009
1010+ /* Physical address of FB device */
1011+ par->mmio_pp = par->mem->start;
1012+ /* Virtual address of FB device */
1013+ par->mmio_vp = (unsigned char *) fb_virt;
1014+
7241015 info->fix.smem_start = par->mem->start;
725− info->fix.smem_len = screen_fb_size;
726− info->screen_base = fb_virt;
727− info->screen_size = screen_fb_size;
1016+ info->fix.smem_len = dio_fb_size;
1017+ info->screen_base = par->dio_vp;
1018+ info->screen_size = dio_fb_size;
7281019
7291020 if (!gen2vm)
7301021 pci_dev_put(pdev);
7311022
7321023 return 0;
7331024
1025+err4:
1026+ vfree(par->dio_vp);
7341027 err3:
7351028 iounmap(fb_virt);
7361029 err2:
@@ -748,6 +1041,7 @@ static void hvfb_putmem(struct fb_info *info) · 11 unmodified lines
7481041 {
7491042 struct hvfb_par *par = info->par;
7501043
1044+ vfree(par->dio_vp);
7511045 iounmap(info->screen_base);
7521046 vmbus_free_mmio(par->mem->start, screen_fb_size);
7531047 par->mem = NULL;
@@ -771,6 +1065,11 @@ static int hvfb_probe(struct hv_device *hdev, · 17 unmodified lines
7711065 init_completion(&par->wait);
7721066 INIT_DELAYED_WORK(&par->dwork, hvfb_update_work);
7731067
1068+ par->delayed_refresh = false;
1069+ spin_lock_init(&par->delayed_refresh_lock);
1070+ par->x1 = par->y1 = INT_MAX;
1071+ par->x2 = par->y2 = 0;
1072+
7741073 /* Connect to VSP */
7751074 hv_set_drvdata(hdev, info);
7761075 ret = synthvid_connect_vsp(hdev);
@@ -779,17 +1078,16 @@ static int hvfb_probe(struct hv_device *hdev, · 2 unmodified lines
7791078 goto error1;
7801079 }
7811080
1081+ hvfb_get_option(info);
1082+ pr_info("Screen resolution: %dx%d, Color depth: %d\n",
1083+ screen_width, screen_height, screen_depth);
1084+
7821085 ret = hvfb_getmem(hdev, info);
7831086 if (ret) {
7841087 pr_err("No memory for framebuffer\n");
7851088 goto error2;
7861089 }
7871090
788− hvfb_get_option(info);
789− pr_info("Screen resolution: %dx%d, Color depth: %d\n",
790− screen_width, screen_height, screen_depth);
791−
792−
7931091 /* Set up fb_info */
7941092 info->flags = FBINFO_DEFAULT;
7951093
@@ -823,6 +1121,10 @@ static int hvfb_probe(struct hv_device *hdev, · 27 unmodified lines
8231121 info->fbops = &hvfb_ops;
8241122 info->pseudo_palette = par->pseudo_palette;
8251123
1124+ /* Initialize deferred IO */
1125+ info->fbdefio = &synthvid_defio;
1126+ fb_deferred_io_init(info);
1127+
8261128 /* Send config to host */
8271129 ret = synthvid_send_config(hdev);
8281130 if (ret)
@@ -844,6 +1146,7 @@ static int hvfb_probe(struct hv_device *hdev, · 15 unmodified lines
8441146 return 0;
8451147
8461148 error:
1149+ fb_deferred_io_cleanup(info);
8471150 hvfb_putmem(info);
8481151 error2:
8491152 vmbus_close(hdev->channel);
@@ -866,6 +1169,8 @@ static int hvfb_remove(struct hv_device *hdev) · 16 unmodified lines
8661169 par->update = false;
8671170 par->fb_ready = false;
8681171
1172+ fb_deferred_io_cleanup(info);
1173+
8691174 unregister_framebuffer(info);
8701175 cancel_delayed_work_sync(&par->dwork);
8711176
@@ -878,6 +1183,61 @@ static int hvfb_remove(struct hv_device *hdev) · 6 unmodified lines
8781183 return 0;
8791184 }
8801185
1186+static int hvfb_suspend(struct hv_device *hdev)
1187+{
1188+ struct fb_info *info = hv_get_drvdata(hdev);
1189+ struct hvfb_par *par = info->par;
1190+
1191+ console_lock();
1192+
1193+ /* 1 means do suspend */
1194+ fb_set_suspend(info, 1);
1195+
1196+ cancel_delayed_work_sync(&par->dwork);
1197+
1198+ par->update_saved = par->update;
1199+ par->update = false;
1200+ par->fb_ready = false;
1201+
1202+ vmbus_close(hdev->channel);
1203+
1204+ console_unlock();
1205+
1206+ return 0;
1207+}
1208+
1209+static int hvfb_resume(struct hv_device *hdev)
1210+{
1211+ struct fb_info *info = hv_get_drvdata(hdev);
1212+ struct hvfb_par *par = info->par;
1213+ int ret;
1214+
1215+ console_lock();
1216+
1217+ ret = synthvid_connect_vsp(hdev);
1218+ if (ret != 0)
1219+ goto out;
1220+
1221+ ret = synthvid_send_config(hdev);
1222+ if (ret != 0) {
1223+ vmbus_close(hdev->channel);
1224+ goto out;
1225+ }
1226+
1227+ par->fb_ready = true;
1228+ par->update = par->update_saved;
1229+
1230+ schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY);
1231+
1232+ /* 0 means do resume */
1233+ fb_set_suspend(info, 0);
1234+
1235+out:
1236+ console_unlock();
1237+
1238+ return ret;
1239+}
1240+
8811241
8821242 static const struct pci_device_id pci_stub_id_table[] = {
8831243 {
@@ -901,6 +1261,8 @@ static struct hv_driver hvfb_drv = { · 17 unmodified lines
9011261 .id_table = id_table,
9021262 .probe = hvfb_probe,
9031263 .remove = hvfb_remove,
1264+ .suspend = hvfb_suspend,
1265+ .resume = hvfb_resume,
9041266 .driver = {
9051267 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
9061268 },
include/asm-generic/mshyperv.h+2−0
@@ -166,10 +166,12 @@ static inline int cpumask_to_vpset(struct hv_vpset *vpset, · 165 unmodified lines
166166 void hyperv_report_panic(struct pt_regs *regs, long err);
167167 void hyperv_report_panic_msg(phys_addr_t pa, size_t size);
168168 bool hv_is_hyperv_initialized(void);
169+bool hv_is_hibernation_supported(void);
169170 void hyperv_cleanup(void);
170171 void hv_setup_sched_clock(void *sched_clock);
171172 #else /* CONFIG_HYPERV */
172173 static inline bool hv_is_hyperv_initialized(void) { return false; }
174+static inline bool hv_is_hibernation_supported(void) { return false; }
173175 static inline void hyperv_cleanup(void) {}
174176 #endif /* CONFIG_HYPERV */
175177
include/linux/hyperv.h+26−5
@@ -182,19 +182,21 @@ static inline u32 hv_get_avail_to_write_percent( · 181 unmodified lines
182182 * 2 . 4 (Windows 8)
183183 * 3 . 0 (Windows 8 R2)
184184 * 4 . 0 (Windows 10)
185+ * 4 . 1 (Windows 10 RS3)
185186 * 5 . 0 (Newer Windows 10)
187+ * 5 . 1 (Windows 10 RS4)
188+ * 5 . 2 (Windows Server 2019, RS5)
186189 */
187190
188191 #define VERSION_WS2008 ((0 << 16) | (13))
189192 #define VERSION_WIN7 ((1 << 16) | (1))
190193 #define VERSION_WIN8 ((2 << 16) | (4))
191194 #define VERSION_WIN8_1 ((3 << 16) | (0))
192−#define VERSION_WIN10 ((4 << 16) | (0))
195+#define VERSION_WIN10 ((4 << 16) | (0))
196+#define VERSION_WIN10_V4_1 ((4 << 16) | (1))
193197 #define VERSION_WIN10_V5 ((5 << 16) | (0))
194−
195−#define VERSION_INVAL -1
196−
197−#define VERSION_CURRENT VERSION_WIN10_V5
198+#define VERSION_WIN10_V5_1 ((5 << 16) | (1))
199+#define VERSION_WIN10_V5_2 ((5 << 16) | (2))
198200
199201 /* Make maximum size of pipe payload of 16K */
200202 #define MAX_PIPE_DATA_PAYLOAD (sizeof(u8) * 16384)
@@ -932,6 +934,21 @@ struct vmbus_channel { · 731 unmodified lines
932934 * full outbound ring buffer.
933935 */
934936 u64 out_full_first;
937+
938+ /* enabling/disabling fuzz testing on the channel (default is false)*/
939+ bool fuzz_testing_state;
940+
941+ /*
942+ * Interrupt delay will delay the guest from emptying the ring buffer
943+ * for a specific amount of time. The delay is in microseconds and will
944+ * be between 1 to a maximum of 1000, its default is 0 (no delay).
945+ * The Message delay will delay guest reading on a per message basis
946+ * in microseconds between 1 to 1000 with the default being 0
947+ * (no delay).
948+ */
949+ u32 fuzz_testing_interrupt_delay;
950+ u32 fuzz_testing_message_delay;
951+
935952 };
936953
937954 static inline bool is_hvsock_channel(const struct vmbus_channel *c)
@@ -1180,6 +1197,10 @@ struct hv_device { · 242 unmodified lines
11801197
11811198 struct vmbus_channel *channel;
11821199 struct kset *channels_kset;
1200+
1201+ /* place holder to keep track of the dir for hv device in debugfs */
1202+ struct dentry *debug_dir;
1203+
11831204 };
11841205
11851206
lib/Kconfig.debug+7−0
@@ -2167,4 +2167,11 @@ config IO_STRICT_DEVMEM · 2166 unmodified lines
21672167
21682168 source "arch/$(SRCARCH)/Kconfig.debug"
21692169
2170+config HYPERV_TESTING
2171+ bool "Microsoft Hyper-V driver testing"
2172+ default n
2173+ depends on HYPERV && DEBUG_FS
2174+ help
2175+ Select this option to enable Hyper-V vmbus testing.
2176+
21702177 endmenu # Kernel hacking
net/vmw_vsock/hyperv_transport.c+20−0
@@ -922,6 +922,24 @@ static int hvs_remove(struct hv_device *hdev) · 921 unmodified lines
922922 return 0;
923923 }
924924
925+/* hv_sock connections can not persist across hibernation, and all the hv_sock
926+ * channels are forced to be rescinded before hibernation: see
927+ * vmbus_bus_suspend(). Here the dummy hvs_suspend() and hvs_resume()
928+ * are only needed because hibernation requires that every vmbus device's
929+ * driver should have a .suspend and .resume callback: see vmbus_suspend().
930+ */
931+static int hvs_suspend(struct hv_device *hv_dev)
932+{
933+ /* Dummy */
934+ return 0;
935+}
936+
937+static int hvs_resume(struct hv_device *dev)
938+{
939+ /* Dummy */
940+ return 0;
941+}
942+
925943 /* This isn't really used. See vmbus_match() and vmbus_probe() */
926944 static const struct hv_vmbus_device_id id_table[] = {
927945 {},
@@ -933,6 +951,8 @@ static struct hv_driver hvs_drv = { · 5 unmodified lines
933951 .id_table = id_table,
934952 .probe = hvs_probe,
935953 .remove = hvs_remove,
954+ .suspend = hvs_suspend,
955+ .resume = hvs_resume,
936956 };
937957
938958 static int __init hvs_init(void)
tools/hv/vmbus_testing+376−0
@@ -0,0 +1,376 @@
1+#!/usr/bin/env python3
2+# SPDX-License-Identifier: GPL-2.0
3+#
4+# Program to allow users to fuzz test Hyper-V drivers
5+# by interfacing with Hyper-V debugfs attributes.
6+# Current test methods available:
7+# 1. delay testing
8+#
9+# Current file/directory structure of hyper-V debugfs:
10+# /sys/kernel/debug/hyperv/UUID
11+# /sys/kernel/debug/hyperv/UUID/<test-state filename>
12+# /sys/kernel/debug/hyperv/UUID/<test-method sub-directory>
13+#
14+# author: Branden Bonaby <brandonbonaby94@gmail.com>
15+
16+import os
17+import cmd
18+import argparse
19+import glob
20+from argparse import RawDescriptionHelpFormatter
21+from argparse import RawTextHelpFormatter
22+from enum import Enum
23+
24+# Do not change unless, you change the debugfs attributes
25+# in /drivers/hv/debugfs.c. All fuzz testing
26+# attributes will start with "fuzz_test".
27+
28+# debugfs path for hyperv must exist before proceeding
29+debugfs_hyperv_path = "/sys/kernel/debug/hyperv"
30+if not os.path.isdir(debugfs_hyperv_path):
31+ print("{} doesn't exist/check permissions".format(debugfs_hyperv_path))
32+ exit(-1)
33+
34+class dev_state(Enum):
35+ off = 0
36+ on = 1
37+
38+# File names, that correspond to the files created in
39+# /drivers/hv/debugfs.c
40+class f_names(Enum):
41+ state_f = "fuzz_test_state"
42+ buff_f = "fuzz_test_buffer_interrupt_delay"
43+ mess_f = "fuzz_test_message_delay"
44+
45+# Both single_actions and all_actions are used
46+# for error checking and to allow for some subparser
47+# names to be abbreviated. Do not abbreviate the
48+# test method names, as it will become less intuitive
49+# as to what the user can do. If you do decide to
50+# abbreviate the test method name, make sure the main
51+# function reflects this change.
52+
53+all_actions = [
54+ "disable_all",
55+ "D",
56+ "enable_all",
57+ "view_all",
58+ "V"
59+]
60+
61+single_actions = [
62+ "disable_single",
63+ "d",
64+ "enable_single",
65+ "view_single",
66+ "v"
67+]
68+
69+def main():
70+
71+ file_map = recursive_file_lookup(debugfs_hyperv_path, dict())
72+ args = parse_args()
73+ if (not args.action):
74+ print ("Error, no options selected...exiting")
75+ exit(-1)
76+ arg_set = { k for (k,v) in vars(args).items() if v and k != "action" }
77+ arg_set.add(args.action)
78+ path = args.path if "path" in arg_set else None
79+ if (path and path[-1] == "/"):
80+ path = path[:-1]
81+ validate_args_path(path, arg_set, file_map)
82+ if (path and "enable_single" in arg_set):
83+ state_path = locate_state(path, file_map)
84+ set_test_state(state_path, dev_state.on.value, args.quiet)
85+
86+ # Use subparsers as the key for different actions
87+ if ("delay" in arg_set):
88+ validate_delay_values(args.delay_time)
89+ if (args.enable_all):
90+ set_delay_all_devices(file_map, args.delay_time,
91+ args.quiet)
92+ else:
93+ set_delay_values(path, file_map, args.delay_time,
94+ args.quiet)
95+ elif ("disable_all" in arg_set or "D" in arg_set):
96+ disable_all_testing(file_map)
97+ elif ("disable_single" in arg_set or "d" in arg_set):
98+ disable_testing_single_device(path, file_map)
99+ elif ("view_all" in arg_set or "V" in arg_set):
100+ get_all_devices_test_status(file_map)
101+ elif ("view_single" in arg_set or "v" in arg_set):
102+ get_device_test_values(path, file_map)
103+
104+# Get the state location
105+def locate_state(device, file_map):
106+ return file_map[device][f_names.state_f.value]
107+
108+# Validate delay values to make sure they are acceptable to
109+# enable delays on a device
110+def validate_delay_values(delay):
111+
112+ if (delay[0] == -1 and delay[1] == -1):
113+ print("\nError, At least 1 value must be greater than 0")
114+ exit(-1)
115+ for i in delay:
116+ if (i < -1 or i == 0 or i > 1000):
117+ print("\nError, Values must be equal to -1 "
118+ "or be > 0 and <= 1000")
119+ exit(-1)
120+
121+# Validate argument path
122+def validate_args_path(path, arg_set, file_map):
123+
124+ if (not path and any(element in arg_set for element in single_actions)):
125+ print("Error, path (-p) REQUIRED for the specified option. "
126+ "Use (-h) to check usage.")
127+ exit(-1)
128+ elif (path and any(item in arg_set for item in all_actions)):
129+ print("Error, path (-p) NOT REQUIRED for the specified option. "
130+ "Use (-h) to check usage." )
131+ exit(-1)
132+ elif (path not in file_map and any(item in arg_set
133+ for item in single_actions)):
134+ print("Error, path '{}' not a valid vmbus device".format(path))
135+ exit(-1)
136+
137+# display Testing status of single device
138+def get_device_test_values(path, file_map):
139+
140+ for name in file_map[path]:
141+ file_location = file_map[path][name]
142+ print( name + " = " + str(read_test_files(file_location)))
143+
144+# Create a map of the vmbus devices and their associated files
145+# [key=device, value = [key = filename, value = file path]]
146+def recursive_file_lookup(path, file_map):
147+
148+ for f_path in glob.iglob(path + '**/*'):
149+ if (os.path.isfile(f_path)):
150+ if (f_path.rsplit("/",2)[0] == debugfs_hyperv_path):
151+ directory = f_path.rsplit("/",1)[0]
152+ else:
153+ directory = f_path.rsplit("/",2)[0]
154+ f_name = f_path.split("/")[-1]
155+ if (file_map.get(directory)):
156+ file_map[directory].update({f_name:f_path})
157+ else:
158+ file_map[directory] = {f_name:f_path}
159+ elif (os.path.isdir(f_path)):
160+ recursive_file_lookup(f_path,file_map)
161+ return file_map
162+
163+# display Testing state of devices
164+def get_all_devices_test_status(file_map):
165+
166+ for device in file_map:
167+ if (get_test_state(locate_state(device, file_map)) is 1):
168+ print("Testing = ON for: {}"
169+ .format(device.split("/")[5]))
170+ else:
171+ print("Testing = OFF for: {}"
172+ .format(device.split("/")[5]))
173+
174+# read the vmbus device files, path must be absolute path before calling
175+def read_test_files(path):
176+ try:
177+ with open(path,"r") as f:
178+ file_value = f.readline().strip()
179+ return int(file_value)
180+
181+ except IOError as e:
182+ errno, strerror = e.args
183+ print("I/O error({0}): {1} on file {2}"
184+ .format(errno, strerror, path))
185+ exit(-1)
186+ except ValueError:
187+ print ("Element to int conversion error in: \n{}".format(path))
188+ exit(-1)
189+
190+# writing to vmbus device files, path must be absolute path before calling
191+def write_test_files(path, value):
192+
193+ try:
194+ with open(path,"w") as f:
195+ f.write("{}".format(value))
196+ except IOError as e:
197+ errno, strerror = e.args
198+ print("I/O error({0}): {1} on file {2}"
199+ .format(errno, strerror, path))
200+ exit(-1)
201+
202+# set testing state of device
203+def set_test_state(state_path, state_value, quiet):
204+
205+ write_test_files(state_path, state_value)
206+ if (get_test_state(state_path) is 1):
207+ if (not quiet):
208+ print("Testing = ON for device: {}"
209+ .format(state_path.split("/")[5]))
210+ else:
211+ if (not quiet):
212+ print("Testing = OFF for device: {}"
213+ .format(state_path.split("/")[5]))
214+
215+# get testing state of device
216+def get_test_state(state_path):
217+ #state == 1 - test = ON
218+ #state == 0 - test = OFF
219+ return read_test_files(state_path)
220+
221+# write 1 - 1000 microseconds, into a single device using the
222+# fuzz_test_buffer_interrupt_delay and fuzz_test_message_delay
223+# debugfs attributes
224+def set_delay_values(device, file_map, delay_length, quiet):
225+
226+ try:
227+ interrupt = file_map[device][f_names.buff_f.value]
228+ message = file_map[device][f_names.mess_f.value]
229+
230+ # delay[0]- buffer interrupt delay, delay[1]- message delay
231+ if (delay_length[0] >= 0 and delay_length[0] <= 1000):
232+ write_test_files(interrupt, delay_length[0])
233+ if (delay_length[1] >= 0 and delay_length[1] <= 1000):
234+ write_test_files(message, delay_length[1])
235+ if (not quiet):
236+ print("Buffer delay testing = {} for: {}"
237+ .format(read_test_files(interrupt),
238+ interrupt.split("/")[5]))
239+ print("Message delay testing = {} for: {}"
240+ .format(read_test_files(message),
241+ message.split("/")[5]))
242+ except IOError as e:
243+ errno, strerror = e.args
244+ print("I/O error({0}): {1} on files {2}{3}"
245+ .format(errno, strerror, interrupt, message))
246+ exit(-1)
247+
248+# enabling delay testing on all devices
249+def set_delay_all_devices(file_map, delay, quiet):
250+
251+ for device in (file_map):
252+ set_test_state(locate_state(device, file_map),
253+ dev_state.on.value,
254+ quiet)
255+ set_delay_values(device, file_map, delay, quiet)
256+
257+# disable all testing on a SINGLE device.
258+def disable_testing_single_device(device, file_map):
259+
260+ for name in file_map[device]:
261+ file_location = file_map[device][name]
262+ write_test_files(file_location, dev_state.off.value)
263+ print("ALL testing now OFF for {}".format(device.split("/")[-1]))
264+
265+# disable all testing on ALL devices
266+def disable_all_testing(file_map):
267+
268+ for device in file_map:
269+ disable_testing_single_device(device, file_map)
270+
271+def parse_args():
272+ parser = argparse.ArgumentParser(prog = "vmbus_testing",usage ="\n"
273+ "%(prog)s [delay] [-h] [-e|-E] -t [-p]\n"
274+ "%(prog)s [view_all | V] [-h]\n"
275+ "%(prog)s [disable_all | D] [-h]\n"
276+ "%(prog)s [disable_single | d] [-h|-p]\n"
277+ "%(prog)s [view_single | v] [-h|-p]\n"
278+ "%(prog)s --version\n",
279+ description = "\nUse lsvmbus to get vmbus device type "
280+ "information.\n" "\nThe debugfs root path is "
281+ "/sys/kernel/debug/hyperv",
282+ formatter_class = RawDescriptionHelpFormatter)
283+ subparsers = parser.add_subparsers(dest = "action")
284+ parser.add_argument("--version", action = "version",
285+ version = '%(prog)s 0.1.0')
286+ parser.add_argument("-q","--quiet", action = "store_true",
287+ help = "silence none important test messages."
288+ " This will only work when enabling testing"
289+ " on a device.")
290+ # Use the path parser to hold the --path attribute so it can
291+ # be shared between subparsers. Also do the same for the state
292+ # parser, as all testing methods will use --enable_all and
293+ # enable_single.
294+ path_parser = argparse.ArgumentParser(add_help=False)
295+ path_parser.add_argument("-p","--path", metavar = "",
296+ help = "Debugfs path to a vmbus device. The path "
297+ "must be the absolute path to the device.")
298+ state_parser = argparse.ArgumentParser(add_help=False)
299+ state_group = state_parser.add_mutually_exclusive_group(required = True)
300+ state_group.add_argument("-E", "--enable_all", action = "store_const",
301+ const = "enable_all",
302+ help = "Enable the specified test type "
303+ "on ALL vmbus devices.")
304+ state_group.add_argument("-e", "--enable_single",
305+ action = "store_const",
306+ const = "enable_single",
307+ help = "Enable the specified test type on a "
308+ "SINGLE vmbus device.")
309+ parser_delay = subparsers.add_parser("delay",
310+ parents = [state_parser, path_parser],
311+ help = "Delay the ring buffer interrupt or the "
312+ "ring buffer message reads in microseconds.",
313+ prog = "vmbus_testing",
314+ usage = "%(prog)s [-h]\n"
315+ "%(prog)s -E -t [value] [value]\n"
316+ "%(prog)s -e -t [value] [value] -p",
317+ description = "Delay the ring buffer interrupt for "
318+ "vmbus devices, or delay the ring buffer message "
319+ "reads for vmbus devices (both in microseconds). This "
320+ "is only on the host to guest channel.")
321+ parser_delay.add_argument("-t", "--delay_time", metavar = "", nargs = 2,
322+ type = check_range, default =[0,0], required = (True),
323+ help = "Set [buffer] & [message] delay time. "
324+ "Value constraints: -1 == value "
325+ "or 0 < value <= 1000.\n"
326+ "Use -1 to keep the previous value for that delay "
327+ "type, or a value > 0 <= 1000 to change the delay "
328+ "time.")
329+ parser_dis_all = subparsers.add_parser("disable_all",
330+ aliases = ['D'], prog = "vmbus_testing",
331+ usage = "%(prog)s [disable_all | D] -h\n"
332+ "%(prog)s [disable_all | D]\n",
333+ help = "Disable ALL testing on ALL vmbus devices.",
334+ description = "Disable ALL testing on ALL vmbus "
335+ "devices.")
336+ parser_dis_single = subparsers.add_parser("disable_single",
337+ aliases = ['d'],
338+ parents = [path_parser], prog = "vmbus_testing",
339+ usage = "%(prog)s [disable_single | d] -h\n"
340+ "%(prog)s [disable_single | d] -p\n",
341+ help = "Disable ALL testing on a SINGLE vmbus device.",
342+ description = "Disable ALL testing on a SINGLE vmbus "
343+ "device.")
344+ parser_view_all = subparsers.add_parser("view_all", aliases = ['V'],
345+ help = "View the test state for ALL vmbus devices.",
346+ prog = "vmbus_testing",
347+ usage = "%(prog)s [view_all | V] -h\n"
348+ "%(prog)s [view_all | V]\n",
349+ description = "This shows the test state for ALL the "
350+ "vmbus devices.")
351+ parser_view_single = subparsers.add_parser("view_single",
352+ aliases = ['v'],parents = [path_parser],
353+ help = "View the test values for a SINGLE vmbus "
354+ "device.",
355+ description = "This shows the test values for a SINGLE "
356+ "vmbus device.", prog = "vmbus_testing",
357+ usage = "%(prog)s [view_single | v] -h\n"
358+ "%(prog)s [view_single | v] -p")
359+
360+ return parser.parse_args()
361+
362+# value checking for range checking input in parser
363+def check_range(arg1):
364+
365+ try:
366+ val = int(arg1)
367+ except ValueError as err:
368+ raise argparse.ArgumentTypeError(str(err))
369+ if val < -1 or val > 1000:
370+ message = ("\n\nvalue must be -1 or 0 < value <= 1000. "
371+ "Value program received: {}\n").format(val)
372+ raise argparse.ArgumentTypeError(message)
373+ return val
374+
375+if __name__ == "__main__":
376+ main()

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t