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 @@
1What: /sys/kernel/debug/hyperv/<UUID>/fuzz_test_state
2Date: October 2019
3KernelVersion: 5.5
4Contact: Branden Bonaby <brandonbonaby94@gmail.com>
5Description: Fuzz testing status of a vmbus device, whether its in an ON
6 state or a OFF state
7Users: Debugging tools
8
9What: /sys/kernel/debug/hyperv/<UUID>/delay/fuzz_test_buffer_interrupt_delay
10Date: October 2019
11KernelVersion: 5.5
12Contact: Branden Bonaby <brandonbonaby94@gmail.com>
13Description: Fuzz testing buffer interrupt delay value between 0 - 1000
14 microseconds (inclusive).
15Users: Debugging tools
16
17What: /sys/kernel/debug/hyperv/<UUID>/delay/fuzz_test_message_delay
18Date: October 2019
19KernelVersion: 5.5
20Contact: Branden Bonaby <brandonbonaby94@gmail.com>
21Description: Fuzz testing message delay value between 0 - 1000 microseconds
22 (inclusive).
23Users: Debugging tools
MAINTAINERS+1−0
@@ -7654,6 +7654,7 @@ F: include/uapi/linux/hyperv.h · 7653 unmodified lines
7654F: include/asm-generic/mshyperv.h7654F: include/asm-generic/mshyperv.h
7655F: tools/hv/7655F: tools/hv/
7656F: Documentation/ABI/stable/sysfs-bus-vmbus7656F: Documentation/ABI/stable/sysfs-bus-vmbus
7657F: Documentation/ABI/testing/debugfs-hyperv
7657 7658
7658HYPERBUS SUPPORT7659HYPERBUS SUPPORT
7659M: Vignesh Raghavendra <vigneshr@ti.com>7660M: Vignesh Raghavendra <vigneshr@ti.com>
arch/x86/hyperv/hv_init.c+15−0
@@ -7,6 +7,7 @@ · 6 unmodified lines
7 * Author : K. Y. Srinivasan <kys@microsoft.com>7 * Author : K. Y. Srinivasan <kys@microsoft.com>
8 */8 */
9 9
10#include <linux/acpi.h>
10#include <linux/efi.h>11#include <linux/efi.h>
11#include <linux/types.h>12#include <linux/types.h>
12#include <asm/apic.h>13#include <asm/apic.h>
@@ -45,6 +46,14 @@ void *hv_alloc_hyperv_page(void) · 32 unmodified lines
45}46}
46EXPORT_SYMBOL_GPL(hv_alloc_hyperv_page);47EXPORT_SYMBOL_GPL(hv_alloc_hyperv_page);
47 48
49void *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}
55EXPORT_SYMBOL_GPL(hv_alloc_hyperv_zeroed_page);
56
48void hv_free_hyperv_page(unsigned long addr)57void hv_free_hyperv_page(unsigned long addr)
49{58{
50 free_page(addr);59 free_page(addr);
@@ -437,3 +446,9 @@ bool hv_is_hyperv_initialized(void) · 386 unmodified lines
437 return hypercall_msr.enable;446 return hypercall_msr.enable;
438}447}
439EXPORT_SYMBOL_GPL(hv_is_hyperv_initialized);448EXPORT_SYMBOL_GPL(hv_is_hyperv_initialized);
449
450bool hv_is_hibernation_supported(void)
451{
452 return acpi_sleep_state_supported(ACPI_STATE_S4);
453}
454EXPORT_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
219void __init hyperv_init(void);219void __init hyperv_init(void);
220void hyperv_setup_mmu_ops(void);220void hyperv_setup_mmu_ops(void);
221void *hv_alloc_hyperv_page(void);221void *hv_alloc_hyperv_page(void);
222void *hv_alloc_hyperv_zeroed_page(void);
222void hv_free_hyperv_page(unsigned long addr);223void hv_free_hyperv_page(unsigned long addr);
223void hyperv_reenlightenment_intr(struct pt_regs *regs);224void hyperv_reenlightenment_intr(struct pt_regs *regs);
224void set_hv_tscchange_cb(void (*cb)(void));225void 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
192 if (desc->bLength == 0)192 if (desc->bLength == 0)
193 goto cleanup;193 goto cleanup;
194 194
195 /* The pointer is not NULL when we resume from hibernation */
196 if (input_device->hid_desc != NULL)
197 kfree(input_device->hid_desc);
195 input_device->hid_desc = kmemdup(desc, desc->bLength, GFP_ATOMIC);198 input_device->hid_desc = kmemdup(desc, desc->bLength, GFP_ATOMIC);
196 199
197 if (!input_device->hid_desc)200 if (!input_device->hid_desc)
@@ -203,6 +206,9 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device, · 5 unmodified lines
203 goto cleanup;206 goto cleanup;
204 }207 }
205 208
209 /* The pointer is not NULL when we resume from hibernation */
210 if (input_device->report_desc != NULL)
211 kfree(input_device->report_desc);
206 input_device->report_desc = kzalloc(input_device->report_desc_size,212 input_device->report_desc = kzalloc(input_device->report_desc_size,
207 GFP_ATOMIC);213 GFP_ATOMIC);
208 214
@@ -342,6 +348,8 @@ static int mousevsc_connect_to_vsp(struct hv_device *device) · 133 unmodified lines
342 struct mousevsc_prt_msg *request;348 struct mousevsc_prt_msg *request;
343 struct mousevsc_prt_msg *response;349 struct mousevsc_prt_msg *response;
344 350
351 reinit_completion(&input_dev->wait_event);
352
345 request = &input_dev->protocol_req;353 request = &input_dev->protocol_req;
346 memset(request, 0, sizeof(struct mousevsc_prt_msg));354 memset(request, 0, sizeof(struct mousevsc_prt_msg));
347 355
@@ -541,6 +549,30 @@ static int mousevsc_remove(struct hv_device *dev) · 193 unmodified lines
541 return 0;549 return 0;
542}550}
543 551
552static int mousevsc_suspend(struct hv_device *dev)
553{
554 vmbus_close(dev->channel);
555
556 return 0;
557}
558
559static 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
544static const struct hv_vmbus_device_id id_table[] = {576static const struct hv_vmbus_device_id id_table[] = {
545 /* Mouse guid */577 /* Mouse guid */
546 { HV_MOUSE_GUID, },578 { HV_MOUSE_GUID, },
@@ -554,6 +586,8 @@ static struct hv_driver mousevsc_drv = { · 7 unmodified lines
554 .id_table = id_table,586 .id_table = id_table,
555 .probe = mousevsc_probe,587 .probe = mousevsc_probe,
556 .remove = mousevsc_remove,588 .remove = mousevsc_remove,
589 .suspend = mousevsc_suspend,
590 .resume = mousevsc_resume,
557 .driver = {591 .driver = {
558 .probe_type = PROBE_PREFER_ASYNCHRONOUS,592 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
559 },593 },
drivers/hv/Makefile+1−0
@@ -9,4 +9,5 @@ CFLAGS_hv_balloon.o = -I$(src) · 8 unmodified lines
9hv_vmbus-y := vmbus_drv.o \9hv_vmbus-y := vmbus_drv.o \
10 hv.o connection.o channel.o \10 hv.o connection.o channel.o \
11 channel_mgmt.o ring_buffer.o hv_trace.o11 channel_mgmt.o ring_buffer.o hv_trace.o
12hv_vmbus-$(CONFIG_HYPERV_TESTING) += hv_debugfs.o
12hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o hv_fcopy.o hv_utils_transport.o13hv_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
14#include <linux/wait.h>14#include <linux/wait.h>
15#include <linux/delay.h>15#include <linux/delay.h>
16#include <linux/mm.h>16#include <linux/mm.h>
17#include <linux/module.h>
17#include <linux/slab.h>18#include <linux/slab.h>
18#include <linux/vmalloc.h>19#include <linux/vmalloc.h>
19#include <linux/hyperv.h>20#include <linux/hyperv.h>
@@ -40,29 +41,30 @@ EXPORT_SYMBOL_GPL(vmbus_connection); · 20 unmodified lines
40__u32 vmbus_proto_version;41__u32 vmbus_proto_version;
41EXPORT_SYMBOL_GPL(vmbus_proto_version);42EXPORT_SYMBOL_GPL(vmbus_proto_version);
42 43
43static __u32 vmbus_get_next_version(__u32 current_version)44/*
44{45 * Table of VMBus versions listed from newest to oldest.
45 switch (current_version) {46 */
46 case (VERSION_WIN7):47static __u32 vmbus_versions[] = {
47 return VERSION_WS2008;48 VERSION_WIN10_V5_2,
48 49 VERSION_WIN10_V5_1,
49 case (VERSION_WIN8):50 VERSION_WIN10_V5,
50 return VERSION_WIN7;51 VERSION_WIN10_V4_1,
51 52 VERSION_WIN10,
52 case (VERSION_WIN8_1):53 VERSION_WIN8_1,
53 return VERSION_WIN8;54 VERSION_WIN8,
55 VERSION_WIN7,
56 VERSION_WS2008
57};
54 58
55 case (VERSION_WIN10):59/*
56 return VERSION_WIN8_1;60 * Maximal VMBus protocol version guests can negotiate. Useful to cap the
61 * VMBus version for testing and debugging purpose.
62 */
63static uint max_version = VERSION_WIN10_V5_2;
57 64
58 case (VERSION_WIN10_V5):65module_param(max_version, uint, S_IRUGO);
59 return VERSION_WIN10;66MODULE_PARM_DESC(max_version,
60 67 "Maximal VMBus protocol version which can be negotiated");
61 case (VERSION_WS2008):
62 default:
63 return VERSION_INVAL;
64 }
65}
66 68
67int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)69int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version)
68{70{
@@ -80,12 +82,12 @@ int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, u32 version) · 11 unmodified lines
80 msg->vmbus_version_requested = version;82 msg->vmbus_version_requested = version;
81 83
82 /*84 /*
83 * VMBus protocol 5.0 (VERSION_WIN10_V5) requires that we must use85 * VMBus protocol 5.0 (VERSION_WIN10_V5) and higher require that we must
84 * VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate Contact Message,86 * use VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate Contact Message,
85 * and for subsequent messages, we must use the Message Connection ID87 * and for subsequent messages, we must use the Message Connection ID
86 * field in the host-returned Version Response Message. And, with88 * field in the host-returned Version Response Message. And, with
87 * VERSION_WIN10_V5, we don't use msg->interrupt_page, but we tell89 * VERSION_WIN10_V5 and higher, we don't use msg->interrupt_page, but we
88 * the host explicitly that we still use VMBUS_MESSAGE_SINT(2) for90 * tell the host explicitly that we still use VMBUS_MESSAGE_SINT(2) for
89 * compatibility.91 * compatibility.
90 *92 *
91 * On old hosts, we should always use VMBUS_MESSAGE_CONNECTION_ID (1).93 * 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
169 */171 */
170int vmbus_connect(void)172int vmbus_connect(void)
171{173{
172 int ret = 0;
173 struct vmbus_channel_msginfo *msginfo = NULL;174 struct vmbus_channel_msginfo *msginfo = NULL;
175 int i, ret = 0;
174 __u32 version;176 __u32 version;
175 177
176 /* Initialize the vmbus connection */178 /* Initialize the vmbus connection */
@@ -206,7 +208,7 @@ int vmbus_connect(void) · 29 unmodified lines
206 * abstraction stuff208 * abstraction stuff
207 */209 */
208 vmbus_connection.int_page =210 vmbus_connection.int_page =
209 (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, 0);211 (void *)hv_alloc_hyperv_zeroed_page();
210 if (vmbus_connection.int_page == NULL) {212 if (vmbus_connection.int_page == NULL) {
211 ret = -ENOMEM;213 ret = -ENOMEM;
212 goto cleanup;214 goto cleanup;
@@ -215,14 +217,14 @@ int vmbus_connect(void) · 2 unmodified lines
215 vmbus_connection.recv_int_page = vmbus_connection.int_page;217 vmbus_connection.recv_int_page = vmbus_connection.int_page;
216 vmbus_connection.send_int_page =218 vmbus_connection.send_int_page =
217 (void *)((unsigned long)vmbus_connection.int_page +219 (void *)((unsigned long)vmbus_connection.int_page +
218 (PAGE_SIZE >> 1));220 (HV_HYP_PAGE_SIZE >> 1));
219 221
220 /*222 /*
221 * Setup the monitor notification facility. The 1st page for223 * Setup the monitor notification facility. The 1st page for
222 * parent->child and the 2nd page for child->parent224 * parent->child and the 2nd page for child->parent
223 */225 */
224 vmbus_connection.monitor_pages[0] = (void *)__get_free_pages((GFP_KERNEL|__GFP_ZERO), 0);226 vmbus_connection.monitor_pages[0] = (void *)hv_alloc_hyperv_zeroed_page();
225 vmbus_connection.monitor_pages[1] = (void *)__get_free_pages((GFP_KERNEL|__GFP_ZERO), 0);227 vmbus_connection.monitor_pages[1] = (void *)hv_alloc_hyperv_zeroed_page();
226 if ((vmbus_connection.monitor_pages[0] == NULL) ||228 if ((vmbus_connection.monitor_pages[0] == NULL) ||
227 (vmbus_connection.monitor_pages[1] == NULL)) {229 (vmbus_connection.monitor_pages[1] == NULL)) {
228 ret = -ENOMEM;230 ret = -ENOMEM;
@@ -244,21 +246,21 @@ int vmbus_connect(void) · 15 unmodified lines
244 * version.246 * version.
245 */247 */
246 248
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;
248 256
249 do {
250 ret = vmbus_negotiate_version(msginfo, version);257 ret = vmbus_negotiate_version(msginfo, version);
251 if (ret == -ETIMEDOUT)258 if (ret == -ETIMEDOUT)
252 goto cleanup;259 goto cleanup;
253 260
254 if (vmbus_connection.conn_state == CONNECTED)261 if (vmbus_connection.conn_state == CONNECTED)
255 break;262 break;
256 263 }
257 version = vmbus_get_next_version(version);
258 } while (version != VERSION_INVAL);
259
260 if (version == VERSION_INVAL)
261 goto cleanup;
262 264
263 vmbus_proto_version = version;265 vmbus_proto_version = version;
264 pr_info("Vmbus version:%d.%d\n",266 pr_info("Vmbus version:%d.%d\n",
@@ -295,12 +297,12 @@ void vmbus_disconnect(void) · 30 unmodified lines
295 destroy_workqueue(vmbus_connection.work_queue);297 destroy_workqueue(vmbus_connection.work_queue);
296 298
297 if (vmbus_connection.int_page) {299 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);
299 vmbus_connection.int_page = NULL;301 vmbus_connection.int_page = NULL;
300 }302 }
301 303
302 free_pages((unsigned long)vmbus_connection.monitor_pages[0], 0);304 hv_free_hyperv_page((unsigned long)vmbus_connection.monitor_pages[0]);
303 free_pages((unsigned long)vmbus_connection.monitor_pages[1], 0);305 hv_free_hyperv_page((unsigned long)vmbus_connection.monitor_pages[1]);
304 vmbus_connection.monitor_pages[0] = NULL;306 vmbus_connection.monitor_pages[0] = NULL;
305 vmbus_connection.monitor_pages[1] = NULL;307 vmbus_connection.monitor_pages[1] = NULL;
306}308}
@@ -361,6 +363,7 @@ void vmbus_on_event(unsigned long data) · 54 unmodified lines
361 363
362 trace_vmbus_on_event(channel);364 trace_vmbus_on_event(channel);
363 365
366 hv_debug_delay_test(channel, INTERRUPT_DELAY);
364 do {367 do {
365 void (*callback_fn)(void *);368 void (*callback_fn)(void *);
366 369
@@ -413,7 +416,7 @@ int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep) · 46 unmodified lines
413 case HV_STATUS_INVALID_CONNECTION_ID:416 case HV_STATUS_INVALID_CONNECTION_ID:
414 /*417 /*
415 * See vmbus_negotiate_version(): VMBus protocol 5.0418 * See vmbus_negotiate_version(): VMBus protocol 5.0
416 * requires that we must use419 * and higher require that we must use
417 * VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate420 * VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate
418 * Contact message, but on old hosts that only421 * Contact message, but on old hosts that only
419 * support VMBus protocol 4.0 or lower, here we get422 * support VMBus protocol 4.0 or lower, here we get
drivers/hv/hv_balloon.c+97−15
@@ -23,6 +23,9 @@ · 22 unmodified lines
23#include <linux/percpu_counter.h>23#include <linux/percpu_counter.h>
24 24
25#include <linux/hyperv.h>25#include <linux/hyperv.h>
26#include <asm/hyperv-tlfs.h>
27
28#include <asm/mshyperv.h>
26 29
27#define CREATE_TRACE_POINTS30#define CREATE_TRACE_POINTS
28#include "hv_trace_balloon.h"31#include "hv_trace_balloon.h"
@@ -341,8 +344,6 @@ struct dm_unballoon_response { · 312 unmodified lines
341 *344 *
342 * mem_range: Memory range to hot add.345 * mem_range: Memory range to hot add.
343 *346 *
344 * On Linux we currently don't support this since we cannot hot add
345 * arbitrary granularity of memory.
346 */347 */
347 348
348struct dm_hot_add {349struct dm_hot_add {
@@ -457,6 +458,7 @@ struct hot_add_wrk { · 108 unmodified lines
457 struct work_struct wrk;458 struct work_struct wrk;
458};459};
459 460
461static bool allow_hibernation;
460static bool hot_add = true;462static bool hot_add = true;
461static bool do_hot_add;463static bool do_hot_add;
462/*464/*
@@ -477,7 +479,7 @@ module_param(pressure_report_delay, uint, (S_IRUGO | S_IWUSR)); · 14 unmodified lines
477MODULE_PARM_DESC(pressure_report_delay, "Delay in secs in reporting pressure");479MODULE_PARM_DESC(pressure_report_delay, "Delay in secs in reporting pressure");
478static atomic_t trans_id = ATOMIC_INIT(0);480static atomic_t trans_id = ATOMIC_INIT(0);
479 481
480static int dm_ring_size = (5 * PAGE_SIZE);482static int dm_ring_size = 20 * 1024;
481 483
482/*484/*
483 * Driver specific state.485 * Driver specific state.
@@ -493,10 +495,10 @@ enum hv_dm_state { · 9 unmodified lines
493};495};
494 496
495 497
496static __u8 recv_buffer[PAGE_SIZE];498static __u8 recv_buffer[HV_HYP_PAGE_SIZE];
497static __u8 balloon_up_send_buffer[PAGE_SIZE];499static __u8 balloon_up_send_buffer[HV_HYP_PAGE_SIZE];
498#define PAGES_IN_2M 512500#define PAGES_IN_2M (2 * 1024 * 1024 / PAGE_SIZE)
499#define HA_CHUNK (32 * 1024)501#define HA_CHUNK (128 * 1024 * 1024 / PAGE_SIZE)
500 502
501struct hv_dynmem_device {503struct hv_dynmem_device {
502 struct hv_device *dev;504 struct hv_device *dev;
@@ -1053,8 +1055,12 @@ static void hot_add_req(struct work_struct *dummy) · 550 unmodified lines
1053 else1055 else
1054 resp.result = 0;1056 resp.result = 0;
1055 1057
1056 if (!do_hot_add || (resp.page_count == 0))1058 if (!do_hot_add || resp.page_count == 0) {
1057 pr_err("Memory hot add failed\n");1059 if (!allow_hibernation)
1060 pr_err("Memory hot add failed\n");
1061 else
1062 pr_info("Ignore hot-add request!\n");
1063 }
1058 1064
1059 dm->state = DM_INITIALIZED;1065 dm->state = DM_INITIALIZED;
1060 resp.hdr.trans_id = atomic_inc_return(&trans_id);1066 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
1076 __u64 *max_page_count = (__u64 *)&info_hdr[1];1082 __u64 *max_page_count = (__u64 *)&info_hdr[1];
1077 1083
1078 pr_info("Max. dynamic memory size: %llu MB\n",1084 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));
1080 }1086 }
1081 1087
1082 break;1088 break;
@@ -1218,7 +1224,7 @@ static unsigned int alloc_balloon_pages(struct hv_dynmem_device *dm, · 135 unmodified lines
1218 1224
1219 for (i = 0; (i * alloc_unit) < num_pages; i++) {1225 for (i = 0; (i * alloc_unit) < num_pages; i++) {
1220 if (bl_resp->hdr.size + sizeof(union dm_mem_page_range) >1226 if (bl_resp->hdr.size + sizeof(union dm_mem_page_range) >
1221 PAGE_SIZE)1227 HV_HYP_PAGE_SIZE)
1222 return i * alloc_unit;1228 return i * alloc_unit;
1223 1229
1224 /*1230 /*
@@ -1274,9 +1280,9 @@ static void balloon_up(struct work_struct *dummy) · 49 unmodified lines
1274 1280
1275 /*1281 /*
1276 * We will attempt 2M allocations. However, if we fail to1282 * 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.
1278 */1284 */
1279 alloc_unit = 512;1285 alloc_unit = PAGES_IN_2M;
1280 1286
1281 avail_pages = si_mem_available();1287 avail_pages = si_mem_available();
1282 floor = compute_balloon_floor();1288 floor = compute_balloon_floor();
@@ -1292,7 +1298,7 @@ static void balloon_up(struct work_struct *dummy) · 9 unmodified lines
1292 }1298 }
1293 1299
1294 while (!done) {1300 while (!done) {
1295 memset(balloon_up_send_buffer, 0, PAGE_SIZE);1301 memset(balloon_up_send_buffer, 0, HV_HYP_PAGE_SIZE);
1296 bl_resp = (struct dm_balloon_response *)balloon_up_send_buffer;1302 bl_resp = (struct dm_balloon_response *)balloon_up_send_buffer;
1297 bl_resp->hdr.type = DM_BALLOON_RESPONSE;1303 bl_resp->hdr.type = DM_BALLOON_RESPONSE;
1298 bl_resp->hdr.size = sizeof(struct dm_balloon_response);1304 bl_resp->hdr.size = sizeof(struct dm_balloon_response);
@@ -1491,7 +1497,7 @@ static void balloon_onchannelcallback(void *context) · 192 unmodified lines
1491 1497
1492 memset(recv_buffer, 0, sizeof(recv_buffer));1498 memset(recv_buffer, 0, sizeof(recv_buffer));
1493 vmbus_recvpacket(dev->channel, recv_buffer,1499 vmbus_recvpacket(dev->channel, recv_buffer,
1494 PAGE_SIZE, &recvlen, &requestid);1500 HV_HYP_PAGE_SIZE, &recvlen, &requestid);
1495 1501
1496 if (recvlen > 0) {1502 if (recvlen > 0) {
1497 dm_msg = (struct dm_message *)recv_buffer;1503 dm_msg = (struct dm_message *)recv_buffer;
@@ -1509,6 +1515,11 @@ static void balloon_onchannelcallback(void *context) · 11 unmodified lines
1509 break;1515 break;
1510 1516
1511 case DM_BALLOON_REQUEST:1517 case DM_BALLOON_REQUEST:
1518 if (allow_hibernation) {
1519 pr_info("Ignore balloon-up request!\n");
1520 break;
1521 }
1522
1512 if (dm->state == DM_BALLOON_UP)1523 if (dm->state == DM_BALLOON_UP)
1513 pr_warn("Currently ballooning\n");1524 pr_warn("Currently ballooning\n");
1514 bal_msg = (struct dm_balloon *)recv_buffer;1525 bal_msg = (struct dm_balloon *)recv_buffer;
@@ -1518,6 +1529,11 @@ static void balloon_onchannelcallback(void *context) · 3 unmodified lines
1518 break;1529 break;
1519 1530
1520 case DM_UNBALLOON_REQUEST:1531 case DM_UNBALLOON_REQUEST:
1532 if (allow_hibernation) {
1533 pr_info("Ignore balloon-down request!\n");
1534 break;
1535 }
1536
1521 dm->state = DM_BALLOON_DOWN;1537 dm->state = DM_BALLOON_DOWN;
1522 balloon_down(dm,1538 balloon_down(dm,
1523 (struct dm_unballoon_request *)recv_buffer);1539 (struct dm_unballoon_request *)recv_buffer);
@@ -1623,6 +1639,11 @@ static int balloon_connect_vsp(struct hv_device *dev) · 99 unmodified lines
1623 cap_msg.hdr.size = sizeof(struct dm_capabilities);1639 cap_msg.hdr.size = sizeof(struct dm_capabilities);
1624 cap_msg.hdr.trans_id = atomic_inc_return(&trans_id);1640 cap_msg.hdr.trans_id = atomic_inc_return(&trans_id);
1625 1641
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 */
1626 cap_msg.caps.cap_bits.balloon = 1;1647 cap_msg.caps.cap_bits.balloon = 1;
1627 cap_msg.caps.cap_bits.hot_add = 1;1648 cap_msg.caps.cap_bits.hot_add = 1;
1628 1649
@@ -1672,6 +1693,10 @@ static int balloon_probe(struct hv_device *dev, · 43 unmodified lines
1672{1693{
1673 int ret;1694 int ret;
1674 1695
1696 allow_hibernation = hv_is_hibernation_supported();
1697 if (allow_hibernation)
1698 hot_add = false;
1699
1675#ifdef CONFIG_MEMORY_HOTPLUG1700#ifdef CONFIG_MEMORY_HOTPLUG
1676 do_hot_add = hot_add;1701 do_hot_add = hot_add;
1677#else1702#else
@@ -1711,6 +1736,8 @@ static int balloon_probe(struct hv_device *dev, · 33 unmodified lines
1711 return 0;1736 return 0;
1712 1737
1713probe_error:1738probe_error:
1739 dm_device.state = DM_INIT_ERROR;
1740 dm_device.thread = NULL;
1714 vmbus_close(dev->channel);1741 vmbus_close(dev->channel);
1715#ifdef CONFIG_MEMORY_HOTPLUG1742#ifdef CONFIG_MEMORY_HOTPLUG
1716 unregister_memory_notifier(&hv_memory_nb);1743 unregister_memory_notifier(&hv_memory_nb);
@@ -1752,6 +1779,59 @@ static int balloon_remove(struct hv_device *dev) · 35 unmodified lines
1752 return 0;1779 return 0;
1753}1780}
1754 1781
1782static 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
1803static 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;
1824close_channel:
1825 vmbus_close(dev->channel);
1826out:
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
1755static const struct hv_vmbus_device_id id_table[] = {1835static const struct hv_vmbus_device_id id_table[] = {
1756 /* Dynamic Memory Class ID */1836 /* Dynamic Memory Class ID */
1757 /* 525074DC-8985-46e2-8057-A307DC18A502 */1837 /* 525074DC-8985-46e2-8057-A307DC18A502 */
@@ -1766,6 +1846,8 @@ static struct hv_driver balloon_drv = { · 8 unmodified lines
1766 .id_table = id_table,1846 .id_table = id_table,
1767 .probe = balloon_probe,1847 .probe = balloon_probe,
1768 .remove = balloon_remove,1848 .remove = balloon_remove,
1849 .suspend = balloon_suspend,
1850 .resume = balloon_resume,
1769 .driver = {1851 .driver = {
1770 .probe_type = PROBE_PREFER_ASYNCHRONOUS,1852 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
1771 },1853 },
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
14struct dentry *hv_debug_root;
15
16static int hv_debugfs_delay_get(void *data, u64 *val)
17{
18 *val = *(u32 *)data;
19 return 0;
20}
21
22static 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
30DEFINE_DEBUGFS_ATTRIBUTE(hv_debugfs_delay_fops, hv_debugfs_delay_get,
31 hv_debugfs_delay_set, "%llu\n");
32
33static int hv_debugfs_state_get(void *data, u64 *val)
34{
35 *val = *(bool *)data;
36 return 0;
37}
38
39static 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
50DEFINE_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 */
54static 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 */
83static 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 */
102static 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 */
109int 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 */
141void 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 */
148void 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 */
154void 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 */
170int 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
13#include <linux/workqueue.h>13#include <linux/workqueue.h>
14#include <linux/hyperv.h>14#include <linux/hyperv.h>
15#include <linux/sched.h>15#include <linux/sched.h>
16#include <asm/hyperv-tlfs.h>
16 17
17#include "hyperv_vmbus.h"18#include "hyperv_vmbus.h"
18#include "hv_utils_transport.h"19#include "hv_utils_transport.h"
@@ -234,7 +235,7 @@ void hv_fcopy_onchannelcallback(void *context) · 215 unmodified lines
234 if (fcopy_transaction.state > HVUTIL_READY)235 if (fcopy_transaction.state > HVUTIL_READY)
235 return;236 return;
236 237
237 vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,238 vmbus_recvpacket(channel, recv_buffer, HV_HYP_PAGE_SIZE * 2, &recvlen,
238 &requestid);239 &requestid);
239 if (recvlen <= 0)240 if (recvlen <= 0)
240 return;241 return;
drivers/hv/hv_kvp.c+2−1
@@ -27,6 +27,7 @@ · 26 unmodified lines
27#include <linux/connector.h>27#include <linux/connector.h>
28#include <linux/workqueue.h>28#include <linux/workqueue.h>
29#include <linux/hyperv.h>29#include <linux/hyperv.h>
30#include <asm/hyperv-tlfs.h>
30 31
31#include "hyperv_vmbus.h"32#include "hyperv_vmbus.h"
32#include "hv_utils_transport.h"33#include "hv_utils_transport.h"
@@ -661,7 +662,7 @@ void hv_kvp_onchannelcallback(void *context) · 628 unmodified lines
661 if (kvp_transaction.state > HVUTIL_READY)662 if (kvp_transaction.state > HVUTIL_READY)
662 return;663 return;
663 664
664 vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 4, &recvlen,665 vmbus_recvpacket(channel, recv_buffer, HV_HYP_PAGE_SIZE * 4, &recvlen,
665 &requestid);666 &requestid);
666 667
667 if (recvlen > 0) {668 if (recvlen > 0) {
drivers/hv/hv_snapshot.c+2−1
@@ -12,6 +12,7 @@ · 11 unmodified lines
12#include <linux/connector.h>12#include <linux/connector.h>
13#include <linux/workqueue.h>13#include <linux/workqueue.h>
14#include <linux/hyperv.h>14#include <linux/hyperv.h>
15#include <asm/hyperv-tlfs.h>
15 16
16#include "hyperv_vmbus.h"17#include "hyperv_vmbus.h"
17#include "hv_utils_transport.h"18#include "hv_utils_transport.h"
@@ -297,7 +298,7 @@ void hv_vss_onchannelcallback(void *context) · 279 unmodified lines
297 if (vss_transaction.state > HVUTIL_READY)298 if (vss_transaction.state > HVUTIL_READY)
298 return;299 return;
299 300
300 vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,301 vmbus_recvpacket(channel, recv_buffer, HV_HYP_PAGE_SIZE * 2, &recvlen,
301 &requestid);302 &requestid);
302 303
303 if (recvlen > 0) {304 if (recvlen > 0) {
drivers/hv/hv_util.c+7−6
@@ -136,7 +136,7 @@ static void shutdown_onchannelcallback(void *context) · 135 unmodified lines
136 struct icmsg_hdr *icmsghdrp;136 struct icmsg_hdr *icmsghdrp;
137 137
138 vmbus_recvpacket(channel, shut_txf_buf,138 vmbus_recvpacket(channel, shut_txf_buf,
139 PAGE_SIZE, &recvlen, &requestid);139 HV_HYP_PAGE_SIZE, &recvlen, &requestid);
140 140
141 if (recvlen > 0) {141 if (recvlen > 0) {
142 icmsghdrp = (struct icmsg_hdr *)&shut_txf_buf[142 icmsghdrp = (struct icmsg_hdr *)&shut_txf_buf[
@@ -284,7 +284,7 @@ static void timesync_onchannelcallback(void *context) · 141 unmodified lines
284 u8 *time_txf_buf = util_timesynch.recv_buffer;284 u8 *time_txf_buf = util_timesynch.recv_buffer;
285 285
286 vmbus_recvpacket(channel, time_txf_buf,286 vmbus_recvpacket(channel, time_txf_buf,
287 PAGE_SIZE, &recvlen, &requestid);287 HV_HYP_PAGE_SIZE, &recvlen, &requestid);
288 288
289 if (recvlen > 0) {289 if (recvlen > 0) {
290 icmsghdrp = (struct icmsg_hdr *)&time_txf_buf[290 icmsghdrp = (struct icmsg_hdr *)&time_txf_buf[
@@ -346,7 +346,7 @@ static void heartbeat_onchannelcallback(void *context) · 55 unmodified lines
346 while (1) {346 while (1) {
347 347
348 vmbus_recvpacket(channel, hbeat_txf_buf,348 vmbus_recvpacket(channel, hbeat_txf_buf,
349 PAGE_SIZE, &recvlen, &requestid);349 HV_HYP_PAGE_SIZE, &recvlen, &requestid);
350 350
351 if (!recvlen)351 if (!recvlen)
352 break;352 break;
@@ -390,7 +390,7 @@ static int util_probe(struct hv_device *dev, · 37 unmodified lines
390 (struct hv_util_service *)dev_id->driver_data;390 (struct hv_util_service *)dev_id->driver_data;
391 int ret;391 int ret;
392 392
393 srv->recv_buffer = kmalloc(PAGE_SIZE * 4, GFP_KERNEL);393 srv->recv_buffer = kmalloc(HV_HYP_PAGE_SIZE * 4, GFP_KERNEL);
394 if (!srv->recv_buffer)394 if (!srv->recv_buffer)
395 return -ENOMEM;395 return -ENOMEM;
396 srv->channel = dev->channel;396 srv->channel = dev->channel;
@@ -413,8 +413,9 @@ static int util_probe(struct hv_device *dev, · 16 unmodified lines
413 413
414 hv_set_drvdata(dev, srv);414 hv_set_drvdata(dev, srv);
415 415
416 ret = vmbus_open(dev->channel, 4 * PAGE_SIZE, 4 * PAGE_SIZE, NULL, 0,416 ret = vmbus_open(dev->channel, 4 * HV_HYP_PAGE_SIZE,
417 srv->util_cb, dev->channel);417 4 * HV_HYP_PAGE_SIZE, NULL, 0, srv->util_cb,
418 dev->channel);
418 if (ret)419 if (ret)
419 goto error;420 goto error;
420 421
drivers/hv/hyperv_vmbus.h+31−0
@@ -385,4 +385,35 @@ enum hvutil_device_state { · 384 unmodified lines
385 HVUTIL_DEVICE_DYING, /* driver unload is in progress */385 HVUTIL_DEVICE_DYING, /* driver unload is in progress */
386};386};
387 387
388enum delay {
389 INTERRUPT_DELAY = 0,
390 MESSAGE_DELAY = 1,
391};
392
393#ifdef CONFIG_HYPERV_TESTING
394
395int hv_debug_add_dev_dir(struct hv_device *dev);
396void hv_debug_rm_dev_dir(struct hv_device *dev);
397void hv_debug_rm_all_dir(void);
398int hv_debug_init(void);
399void hv_debug_delay_test(struct vmbus_channel *channel, enum delay delay_type);
400
401#else /* CONFIG_HYPERV_TESTING */
402
403static inline void hv_debug_rm_dev_dir(struct hv_device *dev) {};
404static inline void hv_debug_rm_all_dir(void) {};
405static inline void hv_debug_delay_test(struct vmbus_channel *channel,
406 enum delay delay_type) {};
407static inline int hv_debug_init(void)
408{
409 return -1;
410}
411
412static inline int hv_debug_add_dev_dir(struct hv_device *dev)
413{
414 return -1;
415}
416
417#endif /* CONFIG_HYPERV_TESTING */
418
388#endif /* _HYPERV_VMBUS_H */419#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
396 struct hv_ring_buffer_info *rbi = &channel->inbound;396 struct hv_ring_buffer_info *rbi = &channel->inbound;
397 struct vmpacket_descriptor *desc;397 struct vmpacket_descriptor *desc;
398 398
399 hv_debug_delay_test(channel, MESSAGE_DELAY);
399 if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor))400 if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor))
400 return NULL;401 return NULL;
401 402
@@ -421,6 +422,7 @@ __hv_pkt_iter_next(struct vmbus_channel *channel, · 19 unmodified lines
421 u32 packetlen = desc->len8 << 3;422 u32 packetlen = desc->len8 << 3;
422 u32 dsize = rbi->ring_datasize;423 u32 dsize = rbi->ring_datasize;
423 424
425 hv_debug_delay_test(channel, MESSAGE_DELAY);
424 /* bump offset to next potential packet */426 /* bump offset to next potential packet */
425 rbi->priv_read_index += packetlen + VMBUS_PKT_TRAILER;427 rbi->priv_read_index += packetlen + VMBUS_PKT_TRAILER;
426 if (rbi->priv_read_index >= dsize)428 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
79static const char *fb_mmio_name = "fb_range";79static const char *fb_mmio_name = "fb_range";
80static struct resource *fb_mmio;80static struct resource *fb_mmio;
81static struct resource *hyperv_mmio;81static struct resource *hyperv_mmio;
82static DEFINE_SEMAPHORE(hyperv_mmio_lock);82static DEFINE_MUTEX(hyperv_mmio_lock);
83 83
84static int vmbus_exists(void)84static int vmbus_exists(void)
85{85{
@@ -960,6 +960,8 @@ static void vmbus_device_release(struct device *device) · 874 unmodified lines
960 struct hv_device *hv_dev = device_to_hv_device(device);960 struct hv_device *hv_dev = device_to_hv_device(device);
961 struct vmbus_channel *channel = hv_dev->channel;961 struct vmbus_channel *channel = hv_dev->channel;
962 962
963 hv_debug_rm_dev_dir(hv_dev);
964
963 mutex_lock(&vmbus_connection.channel_mutex);965 mutex_lock(&vmbus_connection.channel_mutex);
964 hv_process_channel_removal(channel);966 hv_process_channel_removal(channel);
965 mutex_unlock(&vmbus_connection.channel_mutex);967 mutex_unlock(&vmbus_connection.channel_mutex);
@@ -1273,7 +1275,7 @@ static void hv_kmsg_dump(struct kmsg_dumper *dumper, · 307 unmodified lines
1273 * Write dump contents to the page. No need to synchronize; panic should1275 * Write dump contents to the page. No need to synchronize; panic should
1274 * be single-threaded.1276 * be single-threaded.
1275 */1277 */
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,
1277 &bytes_written);1279 &bytes_written);
1278 if (bytes_written)1280 if (bytes_written)
1279 hyperv_report_panic_msg(panic_pa, bytes_written);1281 hyperv_report_panic_msg(panic_pa, bytes_written);
@@ -1373,7 +1375,7 @@ static int vmbus_bus_init(void) · 93 unmodified lines
1373 */1375 */
1374 hv_get_crash_ctl(hyperv_crash_ctl);1376 hv_get_crash_ctl(hyperv_crash_ctl);
1375 if (hyperv_crash_ctl & HV_CRASH_CTL_CRASH_NOTIFY_MSG) {1377 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();
1377 if (hv_panic_page) {1379 if (hv_panic_page) {
1378 ret = kmsg_dump_register(&hv_kmsg_dumper);1380 ret = kmsg_dump_register(&hv_kmsg_dumper);
1379 if (ret)1381 if (ret)
@@ -1401,7 +1403,7 @@ err_alloc: · 21 unmodified lines
1401 hv_remove_vmbus_irq();1403 hv_remove_vmbus_irq();
1402 1404
1403 bus_unregister(&hv_bus);1405 bus_unregister(&hv_bus);
1404 free_page((unsigned long)hv_panic_page);1406 hv_free_hyperv_page((unsigned long)hv_panic_page);
1405 unregister_sysctl_table(hv_ctl_table_hdr);1407 unregister_sysctl_table(hv_ctl_table_hdr);
1406 hv_ctl_table_hdr = NULL;1408 hv_ctl_table_hdr = NULL;
1407 return ret;1409 return ret;
@@ -1809,6 +1811,7 @@ int vmbus_device_register(struct hv_device *child_device_obj) · 401 unmodified lines
1809 pr_err("Unable to register primary channeln");1811 pr_err("Unable to register primary channeln");
1810 goto err_kset_unregister;1812 goto err_kset_unregister;
1811 }1813 }
1814 hv_debug_add_dev_dir(child_device_obj);
1812 1815
1813 return 0;1816 return 0;
1814 1817
@@ -2010,7 +2013,7 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj, · 195 unmodified lines
2010 int retval;2013 int retval;
2011 2014
2012 retval = -ENXIO;2015 retval = -ENXIO;
2013 down(&hyperv_mmio_lock);2016 mutex_lock(&hyperv_mmio_lock);
2014 2017
2015 /*2018 /*
2016 * If overlaps with frame buffers are allowed, then first attempt to2019 * 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
2057 }2060 }
2058 2061
2059exit:2062exit:
2060 up(&hyperv_mmio_lock);2063 mutex_unlock(&hyperv_mmio_lock);
2061 return retval;2064 return retval;
2062}2065}
2063EXPORT_SYMBOL_GPL(vmbus_allocate_mmio);2066EXPORT_SYMBOL_GPL(vmbus_allocate_mmio);
@@ -2074,7 +2077,7 @@ void vmbus_free_mmio(resource_size_t start, resource_size_t size) · 10 unmodified lines
2074{2077{
2075 struct resource *iter;2078 struct resource *iter;
2076 2079
2077 down(&hyperv_mmio_lock);2080 mutex_lock(&hyperv_mmio_lock);
2078 for (iter = hyperv_mmio; iter; iter = iter->sibling) {2081 for (iter = hyperv_mmio; iter; iter = iter->sibling) {
2079 if ((iter->start >= start + size) || (iter->end <= start))2082 if ((iter->start >= start + size) || (iter->end <= start))
2080 continue;2083 continue;
@@ -2082,7 +2085,7 @@ void vmbus_free_mmio(resource_size_t start, resource_size_t size) · 1 unmodified line
2082 __release_region(iter, start, size);2085 __release_region(iter, start, size);
2083 }2086 }
2084 release_mem_region(start, size);2087 release_mem_region(start, size);
2085 up(&hyperv_mmio_lock);2088 mutex_unlock(&hyperv_mmio_lock);
2086 2089
2087}2090}
2088EXPORT_SYMBOL_GPL(vmbus_free_mmio);2091EXPORT_SYMBOL_GPL(vmbus_free_mmio);
@@ -2215,8 +2218,7 @@ static int vmbus_bus_resume(struct device *dev) · 126 unmodified lines
2215 * We only use the 'vmbus_proto_version', which was in use before2218 * We only use the 'vmbus_proto_version', which was in use before
2216 * hibernation, to re-negotiate with the host.2219 * hibernation, to re-negotiate with the host.
2217 */2220 */
2218 if (vmbus_proto_version == VERSION_INVAL ||2221 if (!vmbus_proto_version) {
2219 vmbus_proto_version == 0) {
2220 pr_err("Invalid proto version = 0x%x\n", vmbus_proto_version);2222 pr_err("Invalid proto version = 0x%x\n", vmbus_proto_version);
2221 return -EINVAL;2223 return -EINVAL;
2222 }2224 }
@@ -2303,7 +2305,7 @@ static void hv_crash_handler(struct pt_regs *regs) · 80 unmodified lines
2303 vmbus_connection.conn_state = DISCONNECTED;2305 vmbus_connection.conn_state = DISCONNECTED;
2304 cpu = smp_processor_id();2306 cpu = smp_processor_id();
2305 hv_stimer_cleanup(cpu);2307 hv_stimer_cleanup(cpu);
2306 hv_synic_cleanup(cpu);2308 hv_synic_disable_regs(cpu);
2307 hyperv_cleanup();2309 hyperv_cleanup();
2308};2310};
2309 2311
@@ -2373,6 +2375,7 @@ static int __init hv_acpi_init(void) · 63 unmodified lines
2373 ret = -ETIMEDOUT;2375 ret = -ETIMEDOUT;
2374 goto cleanup;2376 goto cleanup;
2375 }2377 }
2378 hv_debug_init();
2376 2379
2377 ret = vmbus_bus_init();2380 ret = vmbus_bus_init();
2378 if (ret)2381 if (ret)
@@ -2409,6 +2412,8 @@ static void __exit vmbus_exit(void) · 30 unmodified lines
2409 2412
2410 tasklet_kill(&hv_cpu->msg_dpc);2413 tasklet_kill(&hv_cpu->msg_dpc);
2411 }2414 }
2415 hv_debug_rm_all_dir();
2416
2412 vmbus_free_channels();2417 vmbus_free_channels();
2413 2418
2414 if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) {2419 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
467 467
468config HYPERV_IOMMU468config HYPERV_IOMMU
469 bool "Hyper-V x2APIC IRQ Handling"469 bool "Hyper-V x2APIC IRQ Handling"
470 depends on HYPERV470 depends on HYPERV && X86
471 select IOMMU_API471 select IOMMU_API
472 default HYPERV472 default HYPERV
473 help473 help
drivers/net/hyperv/hyperv_net.h+3−0
@@ -955,6 +955,9 @@ struct net_device_context { · 954 unmodified lines
955 u32 vf_alloc;955 u32 vf_alloc;
956 /* Serial number of the VF to team with */956 /* Serial number of the VF to team with */
957 u32 vf_serial;957 u32 vf_serial;
958
959 /* Used to temporarily save the config info across hibernation */
960 struct netvsc_device_info *saved_netvsc_dev_info;
958};961};
959 962
960/* Per channel data */963/* 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
2424 return 0;2424 return 0;
2425}2425}
2426 2426
2427static 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);
2455out:
2456 rtnl_unlock();
2457
2458 return ret;
2459}
2460
2461static 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}
2427static const struct hv_vmbus_device_id id_table[] = {2482static const struct hv_vmbus_device_id id_table[] = {
2428 /* Network guid */2483 /* Network guid */
2429 { HV_NIC_GUID, },2484 { HV_NIC_GUID, },
@@ -2438,6 +2493,8 @@ static struct hv_driver netvsc_drv = { · 8 unmodified lines
2438 .id_table = id_table,2493 .id_table = id_table,
2439 .probe = netvsc_probe,2494 .probe = netvsc_probe,
2440 .remove = netvsc_remove,2495 .remove = netvsc_remove,
2496 .suspend = netvsc_suspend,
2497 .resume = netvsc_resume,
2441 .driver = {2498 .driver = {
2442 .probe_type = PROBE_FORCE_SYNCHRONOUS,2499 .probe_type = PROBE_FORCE_SYNCHRONOUS,
2443 },2500 },
drivers/scsi/storvsc_drv.c+41−0
@@ -1727,6 +1727,13 @@ static const struct hv_vmbus_device_id id_table[] = { · 1726 unmodified lines
1727 1727
1728MODULE_DEVICE_TABLE(vmbus, id_table);1728MODULE_DEVICE_TABLE(vmbus, id_table);
1729 1729
1730static const struct { guid_t guid; } fc_guid = { HV_SYNTHFC_GUID };
1731
1732static bool hv_dev_is_fc(struct hv_device *hv_dev)
1733{
1734 return guid_equal(&fc_guid.guid, &hv_dev->dev_type);
1735}
1736
1730static int storvsc_probe(struct hv_device *device,1737static int storvsc_probe(struct hv_device *device,
1731 const struct hv_vmbus_device_id *dev_id)1738 const struct hv_vmbus_device_id *dev_id)
1732{1739{
@@ -1934,11 +1941,45 @@ static int storvsc_remove(struct hv_device *dev) · 201 unmodified lines
1934 return 0;1941 return 0;
1935}1942}
1936 1943
1944static 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
1967static 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
1937static struct hv_driver storvsc_drv = {1976static struct hv_driver storvsc_drv = {
1938 .name = KBUILD_MODNAME,1977 .name = KBUILD_MODNAME,
1939 .id_table = id_table,1978 .id_table = id_table,
1940 .probe = storvsc_probe,1979 .probe = storvsc_probe,
1941 .remove = storvsc_remove,1980 .remove = storvsc_remove,
1981 .suspend = storvsc_suspend,
1982 .resume = storvsc_resume,
1942 .driver = {1983 .driver = {
1943 .probe_type = PROBE_PREFER_ASYNCHRONOUS,1984 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
1944 },1985 },
drivers/video/fbdev/Kconfig+1−0
@@ -2214,6 +2214,7 @@ config FB_HYPERV · 2213 unmodified lines
2214 select FB_CFB_FILLRECT2214 select FB_CFB_FILLRECT
2215 select FB_CFB_COPYAREA2215 select FB_CFB_COPYAREA
2216 select FB_CFB_IMAGEBLIT2216 select FB_CFB_IMAGEBLIT
2217 select FB_DEFERRED_IO
2217 help2218 help
2218 This framebuffer driver supports Microsoft Hyper-V Synthetic Video.2219 This framebuffer driver supports Microsoft Hyper-V Synthetic Video.
2219 2220
drivers/video/fbdev/hyperv_fb.c+395−33
@@ -23,6 +23,14 @@ · 22 unmodified lines
23 *23 *
24 * Portrait orientation is also supported:24 * Portrait orientation is also supported:
25 * For example: video=hyperv_fb:864x115225 * 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
26 */34 */
27 35
28#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt36#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -34,6 +42,7 @@ · 5 unmodified lines
34#include <linux/fb.h>42#include <linux/fb.h>
35#include <linux/pci.h>43#include <linux/pci.h>
36#include <linux/efi.h>44#include <linux/efi.h>
45#include <linux/console.h>
37 46
38#include <linux/hyperv.h>47#include <linux/hyperv.h>
39 48
@@ -44,6 +53,10 @@ · 4 unmodified lines
44#define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major))53#define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major))
45#define SYNTHVID_VERSION_WIN7 SYNTHVID_VERSION(3, 0)54#define SYNTHVID_VERSION_WIN7 SYNTHVID_VERSION(3, 0)
46#define SYNTHVID_VERSION_WIN8 SYNTHVID_VERSION(3, 2)55#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)
47 60
48#define SYNTHVID_DEPTH_WIN7 1661#define SYNTHVID_DEPTH_WIN7 16
49#define SYNTHVID_DEPTH_WIN8 3262#define SYNTHVID_DEPTH_WIN8 32
@@ -82,16 +95,25 @@ enum synthvid_msg_type { · 32 unmodified lines
82 SYNTHVID_POINTER_SHAPE = 8,95 SYNTHVID_POINTER_SHAPE = 8,
83 SYNTHVID_FEATURE_CHANGE = 9,96 SYNTHVID_FEATURE_CHANGE = 9,
84 SYNTHVID_DIRT = 10,97 SYNTHVID_DIRT = 10,
98 SYNTHVID_RESOLUTION_REQUEST = 13,
99 SYNTHVID_RESOLUTION_RESPONSE = 14,
85 100
86 SYNTHVID_MAX = 11101 SYNTHVID_MAX = 15
87};102};
88 103
104#define SYNTHVID_EDID_BLOCK_SIZE 128
105#define SYNTHVID_MAX_RESOLUTION_COUNT 64
106
107struct hvd_screen_info {
108 u16 width;
109 u16 height;
110} __packed;
111
89struct synthvid_msg_hdr {112struct synthvid_msg_hdr {
90 u32 type;113 u32 type;
91 u32 size; /* size of this header + payload after this field*/114 u32 size; /* size of this header + payload after this field*/
92} __packed;115} __packed;
93 116
94
95struct synthvid_version_req {117struct synthvid_version_req {
96 u32 version;118 u32 version;
97} __packed;119} __packed;
@@ -102,6 +124,19 @@ struct synthvid_version_resp { · 4 unmodified lines
102 u8 max_video_outputs;124 u8 max_video_outputs;
103} __packed;125} __packed;
104 126
127struct synthvid_supported_resolution_req {
128 u8 maximum_resolution_count;
129} __packed;
130
131struct 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
105struct synthvid_vram_location {140struct synthvid_vram_location {
106 u64 user_ctx;141 u64 user_ctx;
107 u8 is_vram_gpa_specified;142 u8 is_vram_gpa_specified;
@@ -187,6 +222,8 @@ struct synthvid_msg { · 79 unmodified lines
187 struct synthvid_pointer_shape ptr_shape;222 struct synthvid_pointer_shape ptr_shape;
188 struct synthvid_feature_change feature_chg;223 struct synthvid_feature_change feature_chg;
189 struct synthvid_dirt dirt;224 struct synthvid_dirt dirt;
225 struct synthvid_supported_resolution_req resolution_req;
226 struct synthvid_supported_resolution_resp resolution_resp;
190 };227 };
191} __packed;228} __packed;
192 229
@@ -201,6 +238,7 @@ struct synthvid_msg { · 8 unmodified lines
201#define RING_BUFSIZE (256 * 1024)238#define RING_BUFSIZE (256 * 1024)
202#define VSP_TIMEOUT (10 * HZ)239#define VSP_TIMEOUT (10 * HZ)
203#define HVFB_UPDATE_DELAY (HZ / 20)240#define HVFB_UPDATE_DELAY (HZ / 20)
241#define HVFB_ONDEMAND_THROTTLE (HZ / 20)
204 242
205struct hvfb_par {243struct hvfb_par {
206 struct fb_info *info;244 struct fb_info *info;
@@ -211,6 +249,7 @@ struct hvfb_par { · 4 unmodified lines
211 249
212 struct delayed_work dwork;250 struct delayed_work dwork;
213 bool update;251 bool update;
252 bool update_saved; /* The value of 'update' before hibernation */
214 253
215 u32 pseudo_palette[16];254 u32 pseudo_palette[16];
216 u8 init_buf[MAX_VMBUS_PKT_SIZE];255 u8 init_buf[MAX_VMBUS_PKT_SIZE];
@@ -220,12 +259,25 @@ struct hvfb_par { · 3 unmodified lines
220 bool synchronous_fb;259 bool synchronous_fb;
221 260
222 struct notifier_block hvfb_panic_nb;261 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;
223};272};
224 273
225static uint screen_width = HVFB_WIDTH;274static uint screen_width = HVFB_WIDTH;
226static uint screen_height = HVFB_HEIGHT;275static uint screen_height = HVFB_HEIGHT;
276static uint screen_width_max = HVFB_WIDTH;
277static uint screen_height_max = HVFB_HEIGHT;
227static uint screen_depth;278static uint screen_depth;
228static uint screen_fb_size;279static uint screen_fb_size;
280static uint dio_fb_size; /* FB size for deferred IO */
229 281
230/* Send message to Hyper-V host */282/* Send message to Hyper-V host */
231static inline int synthvid_send(struct hv_device *hdev,283static inline int synthvid_send(struct hv_device *hdev,
@@ -312,28 +364,88 @@ static int synthvid_send_ptr(struct hv_device *hdev) · 80 unmodified lines
312}364}
313 365
314/* Send updated screen area (dirty rectangle) location to host */366/* Send updated screen area (dirty rectangle) location to host */
315static int synthvid_update(struct fb_info *info)367static int
368synthvid_update(struct fb_info *info, int x1, int y1, int x2, int y2)
316{369{
317 struct hv_device *hdev = device_to_hv_device(info->device);370 struct hv_device *hdev = device_to_hv_device(info->device);
318 struct synthvid_msg msg;371 struct synthvid_msg msg;
319 372
320 memset(&msg, 0, sizeof(struct synthvid_msg));373 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;
321 378
322 msg.vid_hdr.type = SYNTHVID_DIRT;379 msg.vid_hdr.type = SYNTHVID_DIRT;
323 msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +380 msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
324 sizeof(struct synthvid_dirt);381 sizeof(struct synthvid_dirt);
325 msg.dirt.video_output = 0;382 msg.dirt.video_output = 0;
326 msg.dirt.dirt_count = 1;383 msg.dirt.dirt_count = 1;
327 msg.dirt.rect[0].x1 = 0;384 msg.dirt.rect[0].x1 = (x1 > x2) ? 0 : x1;
328 msg.dirt.rect[0].y1 = 0;385 msg.dirt.rect[0].y1 = (y1 > y2) ? 0 : y1;
329 msg.dirt.rect[0].x2 = info->var.xres;386 msg.dirt.rect[0].x2 =
330 msg.dirt.rect[0].y2 = info->var.yres;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;
331 390
332 synthvid_send(hdev, &msg);391 synthvid_send(hdev, &msg);
333 392
334 return 0;393 return 0;
335}394}
336 395
396static 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 */
411static 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
445static struct fb_deferred_io synthvid_defio = {
446 .delay = HZ / 20,
447 .deferred_io = synthvid_deferred_io,
448};
337 449
338/*450/*
339 * Actions on received messages from host:451 * Actions on received messages from host:
@@ -354,6 +466,7 @@ static void synthvid_recv_sub(struct hv_device *hdev) · 14 unmodified lines
354 466
355 /* Complete the wait event */467 /* Complete the wait event */
356 if (msg->vid_hdr.type == SYNTHVID_VERSION_RESPONSE ||468 if (msg->vid_hdr.type == SYNTHVID_VERSION_RESPONSE ||
469 msg->vid_hdr.type == SYNTHVID_RESOLUTION_RESPONSE ||
357 msg->vid_hdr.type == SYNTHVID_VRAM_LOCATION_ACK) {470 msg->vid_hdr.type == SYNTHVID_VRAM_LOCATION_ACK) {
358 memcpy(par->init_buf, msg, MAX_VMBUS_PKT_SIZE);471 memcpy(par->init_buf, msg, MAX_VMBUS_PKT_SIZE);
359 complete(&par->wait);472 complete(&par->wait);
@@ -400,6 +513,17 @@ static void synthvid_receive(void *ctx) · 40 unmodified lines
400 } while (bytes_recvd > 0 && ret == 0);513 } while (bytes_recvd > 0 && ret == 0);
401}514}
402 515
516/* Check if the ver1 version is equal or greater than ver2 */
517static 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
403/* Check synthetic video protocol version with the host */527/* Check synthetic video protocol version with the host */
404static int synthvid_negotiate_ver(struct hv_device *hdev, u32 ver)528static int synthvid_negotiate_ver(struct hv_device *hdev, u32 ver)
405{529{
@@ -428,6 +552,64 @@ static int synthvid_negotiate_ver(struct hv_device *hdev, u32 ver) · 22 unmodified lines
428 }552 }
429 553
430 par->synthvid_version = ver;554 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
558out:
559 return ret;
560}
561
562/* Get current resolution from the host */
563static 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;
431 613
432out:614out:
433 return ret;615 return ret;
@@ -448,11 +630,27 @@ static int synthvid_connect_vsp(struct hv_device *hdev) · 14 unmodified lines
448 }630 }
449 631
450 /* Negotiate the protocol version with host */632 /* Negotiate the protocol version with host */
451 if (vmbus_proto_version == VERSION_WS2008 ||633 switch (vmbus_proto_version) {
452 vmbus_proto_version == VERSION_WIN7)634 case VERSION_WIN10:
453 ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN7);635 case VERSION_WIN10_V5:
454 else636 ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN10);
637 if (!ret)
638 break;
639 /* Fallthrough */
640 case VERSION_WIN8:
641 case VERSION_WIN8_1:
455 ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN8);642 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 }
456 654
457 if (ret) {655 if (ret) {
458 pr_err("Synthetic video device version not accepted\n");656 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
464 else662 else
465 screen_depth = SYNTHVID_DEPTH_WIN8;663 screen_depth = SYNTHVID_DEPTH_WIN8;
466 664
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
467 screen_fb_size = hdev->channel->offermsg.offer.671 screen_fb_size = hdev->channel->offermsg.offer.
468 mmio_megabytes * 1024 * 1024;672 mmio_megabytes * 1024 * 1024;
469 673
@@ -488,7 +692,7 @@ static int synthvid_send_config(struct hv_device *hdev) · 18 unmodified lines
488 msg->vid_hdr.type = SYNTHVID_VRAM_LOCATION;692 msg->vid_hdr.type = SYNTHVID_VRAM_LOCATION;
489 msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +693 msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
490 sizeof(struct synthvid_vram_location);694 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;
492 msg->vram.is_vram_gpa_specified = 1;696 msg->vram.is_vram_gpa_specified = 1;
493 synthvid_send(hdev, msg);697 synthvid_send(hdev, msg);
494 698
@@ -498,7 +702,7 @@ static int synthvid_send_config(struct hv_device *hdev) · 3 unmodified lines
498 ret = -ETIMEDOUT;702 ret = -ETIMEDOUT;
499 goto out;703 goto out;
500 }704 }
501 if (msg->vram_ack.user_ctx != info->fix.smem_start) {705 if (msg->vram_ack.user_ctx != par->mmio_pp) {
502 pr_err("Unable to set VRAM location\n");706 pr_err("Unable to set VRAM location\n");
503 ret = -ENODEV;707 ret = -ENODEV;
504 goto out;708 goto out;
@@ -515,19 +719,77 @@ out: · 10 unmodified lines
515 719
516/*720/*
517 * Delayed work callback:721 * Delayed work callback:
518 * It is called at HVFB_UPDATE_DELAY or longer time interval to process722 * It is scheduled to call whenever update request is received and it has
519 * screen updates. It is re-scheduled if further update is necessary.723 * not been called in last HVFB_ONDEMAND_THROTTLE time interval.
520 */724 */
521static void hvfb_update_work(struct work_struct *w)725static void hvfb_update_work(struct work_struct *w)
522{726{
523 struct hvfb_par *par = container_of(w, struct hvfb_par, dwork.work);727 struct hvfb_par *par = container_of(w, struct hvfb_par, dwork.work);
524 struct fb_info *info = par->info;728 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}
525 765
526 if (par->fb_ready)766/*
527 synthvid_update(info);767 * Control the on-demand refresh frequency. It schedules a delayed
768 * screen update if it has not yet.
769 */
770static 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 }
528 791
529 if (par->update)792 spin_unlock_irqrestore(&par->delayed_refresh_lock, flags);
530 schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY);
531}793}
532 794
533static int hvfb_on_panic(struct notifier_block *nb,795static int hvfb_on_panic(struct notifier_block *nb,
@@ -539,7 +801,8 @@ static int hvfb_on_panic(struct notifier_block *nb, · 5 unmodified lines
539 par = container_of(nb, struct hvfb_par, hvfb_panic_nb);801 par = container_of(nb, struct hvfb_par, hvfb_panic_nb);
540 par->synchronous_fb = true;802 par->synchronous_fb = true;
541 info = par->info;803 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);
543 806
544 return NOTIFY_DONE;807 return NOTIFY_DONE;
545}808}
@@ -600,7 +863,10 @@ static void hvfb_cfb_fillrect(struct fb_info *p, · 54 unmodified lines
600 863
601 cfb_fillrect(p, rect);864 cfb_fillrect(p, rect);
602 if (par->synchronous_fb)865 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);
604}870}
605 871
606static void hvfb_cfb_copyarea(struct fb_info *p,872static void hvfb_cfb_copyarea(struct fb_info *p,
@@ -610,7 +876,10 @@ static void hvfb_cfb_copyarea(struct fb_info *p, · 3 unmodified lines
610 876
611 cfb_copyarea(p, area);877 cfb_copyarea(p, area);
612 if (par->synchronous_fb)878 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);
614}883}
615 884
616static void hvfb_cfb_imageblit(struct fb_info *p,885static void hvfb_cfb_imageblit(struct fb_info *p,
@@ -620,7 +889,10 @@ static void hvfb_cfb_imageblit(struct fb_info *p, · 3 unmodified lines
620 889
621 cfb_imageblit(p, image);890 cfb_imageblit(p, image);
622 if (par->synchronous_fb)891 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);
624}896}
625 897
626static struct fb_ops hvfb_ops = {898static struct fb_ops hvfb_ops = {
@@ -653,6 +925,8 @@ static void hvfb_get_option(struct fb_info *info) · 26 unmodified lines
653 }925 }
654 926
655 if (x < HVFB_WIDTH_MIN || y < HVFB_HEIGHT_MIN ||927 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)) ||
656 (par->synthvid_version == SYNTHVID_VERSION_WIN8 &&930 (par->synthvid_version == SYNTHVID_VERSION_WIN8 &&
657 x * y * screen_depth / 8 > SYNTHVID_FB_SIZE_WIN8) ||931 x * y * screen_depth / 8 > SYNTHVID_FB_SIZE_WIN8) ||
658 (par->synthvid_version == SYNTHVID_VERSION_WIN7 &&932 (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
677 resource_size_t pot_start, pot_end;951 resource_size_t pot_start, pot_end;
678 int ret;952 int ret;
679 953
954 dio_fb_size =
955 screen_width * screen_height * screen_depth / 8;
956
680 if (gen2vm) {957 if (gen2vm) {
681 pot_start = 0;958 pot_start = 0;
682 pot_end = -1;959 pot_end = -1;
@@ -689,8 +966,12 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info) · 6 unmodified lines
689 }966 }
690 967
691 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||968 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);
693 goto err1;973 goto err1;
974 }
694 975
695 pot_end = pci_resource_end(pdev, 0);976 pot_end = pci_resource_end(pdev, 0);
696 pot_start = pot_end - screen_fb_size + 1;977 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
707 if (!fb_virt)988 if (!fb_virt)
708 goto err2;989 goto err2;
709 990
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
710 info->apertures = alloc_apertures(1);996 info->apertures = alloc_apertures(1);
711 if (!info->apertures)997 if (!info->apertures)
712 goto err3;998 goto err4;
713 999
714 if (gen2vm) {1000 if (gen2vm) {
715 info->apertures->ranges[0].base = screen_info.lfb_base;1001 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
721 info->apertures->ranges[0].size = pci_resource_len(pdev, 0);1007 info->apertures->ranges[0].size = pci_resource_len(pdev, 0);
722 }1008 }
723 1009
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
724 info->fix.smem_start = par->mem->start;1015 info->fix.smem_start = par->mem->start;
725 info->fix.smem_len = screen_fb_size;1016 info->fix.smem_len = dio_fb_size;
726 info->screen_base = fb_virt;1017 info->screen_base = par->dio_vp;
727 info->screen_size = screen_fb_size;1018 info->screen_size = dio_fb_size;
728 1019
729 if (!gen2vm)1020 if (!gen2vm)
730 pci_dev_put(pdev);1021 pci_dev_put(pdev);
731 1022
732 return 0;1023 return 0;
733 1024
1025err4:
1026 vfree(par->dio_vp);
734err3:1027err3:
735 iounmap(fb_virt);1028 iounmap(fb_virt);
736err2:1029err2:
@@ -748,6 +1041,7 @@ static void hvfb_putmem(struct fb_info *info) · 11 unmodified lines
748{1041{
749 struct hvfb_par *par = info->par;1042 struct hvfb_par *par = info->par;
750 1043
1044 vfree(par->dio_vp);
751 iounmap(info->screen_base);1045 iounmap(info->screen_base);
752 vmbus_free_mmio(par->mem->start, screen_fb_size);1046 vmbus_free_mmio(par->mem->start, screen_fb_size);
753 par->mem = NULL;1047 par->mem = NULL;
@@ -771,6 +1065,11 @@ static int hvfb_probe(struct hv_device *hdev, · 17 unmodified lines
771 init_completion(&par->wait);1065 init_completion(&par->wait);
772 INIT_DELAYED_WORK(&par->dwork, hvfb_update_work);1066 INIT_DELAYED_WORK(&par->dwork, hvfb_update_work);
773 1067
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
774 /* Connect to VSP */1073 /* Connect to VSP */
775 hv_set_drvdata(hdev, info);1074 hv_set_drvdata(hdev, info);
776 ret = synthvid_connect_vsp(hdev);1075 ret = synthvid_connect_vsp(hdev);
@@ -779,17 +1078,16 @@ static int hvfb_probe(struct hv_device *hdev, · 2 unmodified lines
779 goto error1;1078 goto error1;
780 }1079 }
781 1080
1081 hvfb_get_option(info);
1082 pr_info("Screen resolution: %dx%d, Color depth: %d\n",
1083 screen_width, screen_height, screen_depth);
1084
782 ret = hvfb_getmem(hdev, info);1085 ret = hvfb_getmem(hdev, info);
783 if (ret) {1086 if (ret) {
784 pr_err("No memory for framebuffer\n");1087 pr_err("No memory for framebuffer\n");
785 goto error2;1088 goto error2;
786 }1089 }
787 1090
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
793 /* Set up fb_info */1091 /* Set up fb_info */
794 info->flags = FBINFO_DEFAULT;1092 info->flags = FBINFO_DEFAULT;
795 1093
@@ -823,6 +1121,10 @@ static int hvfb_probe(struct hv_device *hdev, · 27 unmodified lines
823 info->fbops = &hvfb_ops;1121 info->fbops = &hvfb_ops;
824 info->pseudo_palette = par->pseudo_palette;1122 info->pseudo_palette = par->pseudo_palette;
825 1123
1124 /* Initialize deferred IO */
1125 info->fbdefio = &synthvid_defio;
1126 fb_deferred_io_init(info);
1127
826 /* Send config to host */1128 /* Send config to host */
827 ret = synthvid_send_config(hdev);1129 ret = synthvid_send_config(hdev);
828 if (ret)1130 if (ret)
@@ -844,6 +1146,7 @@ static int hvfb_probe(struct hv_device *hdev, · 15 unmodified lines
844 return 0;1146 return 0;
845 1147
846error:1148error:
1149 fb_deferred_io_cleanup(info);
847 hvfb_putmem(info);1150 hvfb_putmem(info);
848error2:1151error2:
849 vmbus_close(hdev->channel);1152 vmbus_close(hdev->channel);
@@ -866,6 +1169,8 @@ static int hvfb_remove(struct hv_device *hdev) · 16 unmodified lines
866 par->update = false;1169 par->update = false;
867 par->fb_ready = false;1170 par->fb_ready = false;
868 1171
1172 fb_deferred_io_cleanup(info);
1173
869 unregister_framebuffer(info);1174 unregister_framebuffer(info);
870 cancel_delayed_work_sync(&par->dwork);1175 cancel_delayed_work_sync(&par->dwork);
871 1176
@@ -878,6 +1183,61 @@ static int hvfb_remove(struct hv_device *hdev) · 6 unmodified lines
878 return 0;1183 return 0;
879}1184}
880 1185
1186static 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
1209static 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
1235out:
1236 console_unlock();
1237
1238 return ret;
1239}
1240
881 1241
882static const struct pci_device_id pci_stub_id_table[] = {1242static const struct pci_device_id pci_stub_id_table[] = {
883 {1243 {
@@ -901,6 +1261,8 @@ static struct hv_driver hvfb_drv = { · 17 unmodified lines
901 .id_table = id_table,1261 .id_table = id_table,
902 .probe = hvfb_probe,1262 .probe = hvfb_probe,
903 .remove = hvfb_remove,1263 .remove = hvfb_remove,
1264 .suspend = hvfb_suspend,
1265 .resume = hvfb_resume,
904 .driver = {1266 .driver = {
905 .probe_type = PROBE_PREFER_ASYNCHRONOUS,1267 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
906 },1268 },
include/asm-generic/mshyperv.h+2−0
@@ -166,10 +166,12 @@ static inline int cpumask_to_vpset(struct hv_vpset *vpset, · 165 unmodified lines
166void hyperv_report_panic(struct pt_regs *regs, long err);166void hyperv_report_panic(struct pt_regs *regs, long err);
167void hyperv_report_panic_msg(phys_addr_t pa, size_t size);167void hyperv_report_panic_msg(phys_addr_t pa, size_t size);
168bool hv_is_hyperv_initialized(void);168bool hv_is_hyperv_initialized(void);
169bool hv_is_hibernation_supported(void);
169void hyperv_cleanup(void);170void hyperv_cleanup(void);
170void hv_setup_sched_clock(void *sched_clock);171void hv_setup_sched_clock(void *sched_clock);
171#else /* CONFIG_HYPERV */172#else /* CONFIG_HYPERV */
172static inline bool hv_is_hyperv_initialized(void) { return false; }173static inline bool hv_is_hyperv_initialized(void) { return false; }
174static inline bool hv_is_hibernation_supported(void) { return false; }
173static inline void hyperv_cleanup(void) {}175static inline void hyperv_cleanup(void) {}
174#endif /* CONFIG_HYPERV */176#endif /* CONFIG_HYPERV */
175 177
include/linux/hyperv.h+26−5
@@ -182,19 +182,21 @@ static inline u32 hv_get_avail_to_write_percent( · 181 unmodified lines
182 * 2 . 4 (Windows 8)182 * 2 . 4 (Windows 8)
183 * 3 . 0 (Windows 8 R2)183 * 3 . 0 (Windows 8 R2)
184 * 4 . 0 (Windows 10)184 * 4 . 0 (Windows 10)
185 * 4 . 1 (Windows 10 RS3)
185 * 5 . 0 (Newer Windows 10)186 * 5 . 0 (Newer Windows 10)
187 * 5 . 1 (Windows 10 RS4)
188 * 5 . 2 (Windows Server 2019, RS5)
186 */189 */
187 190
188#define VERSION_WS2008 ((0 << 16) | (13))191#define VERSION_WS2008 ((0 << 16) | (13))
189#define VERSION_WIN7 ((1 << 16) | (1))192#define VERSION_WIN7 ((1 << 16) | (1))
190#define VERSION_WIN8 ((2 << 16) | (4))193#define VERSION_WIN8 ((2 << 16) | (4))
191#define VERSION_WIN8_1 ((3 << 16) | (0))194#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))
193#define VERSION_WIN10_V5 ((5 << 16) | (0))197#define VERSION_WIN10_V5 ((5 << 16) | (0))
194 198#define VERSION_WIN10_V5_1 ((5 << 16) | (1))
195#define VERSION_INVAL -1199#define VERSION_WIN10_V5_2 ((5 << 16) | (2))
196
197#define VERSION_CURRENT VERSION_WIN10_V5
198 200
199/* Make maximum size of pipe payload of 16K */201/* Make maximum size of pipe payload of 16K */
200#define MAX_PIPE_DATA_PAYLOAD (sizeof(u8) * 16384)202#define MAX_PIPE_DATA_PAYLOAD (sizeof(u8) * 16384)
@@ -932,6 +934,21 @@ struct vmbus_channel { · 731 unmodified lines
932 * full outbound ring buffer.934 * full outbound ring buffer.
933 */935 */
934 u64 out_full_first;936 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
935};952};
936 953
937static inline bool is_hvsock_channel(const struct vmbus_channel *c)954static inline bool is_hvsock_channel(const struct vmbus_channel *c)
@@ -1180,6 +1197,10 @@ struct hv_device { · 242 unmodified lines
1180 1197
1181 struct vmbus_channel *channel;1198 struct vmbus_channel *channel;
1182 struct kset *channels_kset;1199 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
1183};1204};
1184 1205
1185 1206
lib/Kconfig.debug+7−0
@@ -2167,4 +2167,11 @@ config IO_STRICT_DEVMEM · 2166 unmodified lines
2167 2167
2168source "arch/$(SRCARCH)/Kconfig.debug"2168source "arch/$(SRCARCH)/Kconfig.debug"
2169 2169
2170config 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
2170endmenu # Kernel hacking2177endmenu # 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
922 return 0;922 return 0;
923}923}
924 924
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 */
931static int hvs_suspend(struct hv_device *hv_dev)
932{
933 /* Dummy */
934 return 0;
935}
936
937static int hvs_resume(struct hv_device *dev)
938{
939 /* Dummy */
940 return 0;
941}
942
925/* This isn't really used. See vmbus_match() and vmbus_probe() */943/* This isn't really used. See vmbus_match() and vmbus_probe() */
926static const struct hv_vmbus_device_id id_table[] = {944static const struct hv_vmbus_device_id id_table[] = {
927 {},945 {},
@@ -933,6 +951,8 @@ static struct hv_driver hvs_drv = { · 5 unmodified lines
933 .id_table = id_table,951 .id_table = id_table,
934 .probe = hvs_probe,952 .probe = hvs_probe,
935 .remove = hvs_remove,953 .remove = hvs_remove,
954 .suspend = hvs_suspend,
955 .resume = hvs_resume,
936};956};
937 957
938static int __init hvs_init(void)958static 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
16import os
17import cmd
18import argparse
19import glob
20from argparse import RawDescriptionHelpFormatter
21from argparse import RawTextHelpFormatter
22from 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
29debugfs_hyperv_path = "/sys/kernel/debug/hyperv"
30if not os.path.isdir(debugfs_hyperv_path):
31 print("{} doesn't exist/check permissions".format(debugfs_hyperv_path))
32 exit(-1)
33
34class 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
40class 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
53all_actions = [
54 "disable_all",
55 "D",
56 "enable_all",
57 "view_all",
58 "V"
59]
60
61single_actions = [
62 "disable_single",
63 "d",
64 "enable_single",
65 "view_single",
66 "v"
67]
68
69def 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
105def 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
110def 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
122def 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
138def 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]]
146def 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
164def 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
175def 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
191def 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
203def 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
216def 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
224def 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
249def 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.
258def 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
266def disable_all_testing(file_map):
267
268 for device in file_map:
269 disable_testing_single_device(device, file_map)
270
271def 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
363def 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
375if __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