Commit 0e0073eb authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'hyperv-next-signed-20221009' of...

Merge tag 'hyperv-next-signed-20221009' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux

Pull hyperv updates from Wei Liu:

 - Remove unnecessary delay while probing for VMBus (Stanislav
   Kinsburskiy)

 - Optimize vmbus_on_event (Saurabh Sengar)

 - Fix a race in Hyper-V DRM driver (Saurabh Sengar)

 - Miscellaneous clean-up patches from various people

* tag 'hyperv-next-signed-20221009' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux:
  x86/hyperv: Replace kmap() with kmap_local_page()
  drm/hyperv: Add ratelimit on error message
  hyperv: simplify and rename generate_guest_id
  Drivers: hv: vmbus: Split memcpy of flex-array
  scsi: storvsc: remove an extraneous "to" in a comment
  Drivers: hv: vmbus: Don't wait for the ACPI device upon initialization
  Drivers: hv: vmbus: Use PCI_VENDOR_ID_MICROSOFT for better discoverability
  Drivers: hv: vmbus: Fix kernel-doc
  drm/hyperv: Don't overwrite dirt_needed value set by host
  Drivers: hv: vmbus: Optimize vmbus_on_event
parents aa512c11 154fb14d
...@@ -38,7 +38,7 @@ static int __init hyperv_init(void) ...@@ -38,7 +38,7 @@ static int __init hyperv_init(void)
return 0; return 0;
/* Setup the guest ID */ /* Setup the guest ID */
guest_id = generate_guest_id(0, LINUX_VERSION_CODE, 0); guest_id = hv_generate_guest_id(LINUX_VERSION_CODE);
hv_set_vpreg(HV_REGISTER_GUEST_OSID, guest_id); hv_set_vpreg(HV_REGISTER_GUEST_OSID, guest_id);
/* Get the features and hints from Hyper-V */ /* Get the features and hints from Hyper-V */
......
...@@ -426,7 +426,7 @@ void __init hyperv_init(void) ...@@ -426,7 +426,7 @@ void __init hyperv_init(void)
* 1. Register the guest ID * 1. Register the guest ID
* 2. Enable the hypercall and register the hypercall page * 2. Enable the hypercall and register the hypercall page
*/ */
guest_id = generate_guest_id(0, LINUX_VERSION_CODE, 0); guest_id = hv_generate_guest_id(LINUX_VERSION_CODE);
wrmsrl(HV_X64_MSR_GUEST_OS_ID, guest_id); wrmsrl(HV_X64_MSR_GUEST_OS_ID, guest_id);
/* Hyper-V requires to write guest os id via ghcb in SNP IVM. */ /* Hyper-V requires to write guest os id via ghcb in SNP IVM. */
...@@ -459,13 +459,13 @@ void __init hyperv_init(void) ...@@ -459,13 +459,13 @@ void __init hyperv_init(void)
wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
pg = vmalloc_to_page(hv_hypercall_pg); pg = vmalloc_to_page(hv_hypercall_pg);
dst = kmap(pg); dst = kmap_local_page(pg);
src = memremap(hypercall_msr.guest_physical_address << PAGE_SHIFT, PAGE_SIZE, src = memremap(hypercall_msr.guest_physical_address << PAGE_SHIFT, PAGE_SIZE,
MEMREMAP_WB); MEMREMAP_WB);
BUG_ON(!(src && dst)); BUG_ON(!(src && dst));
memcpy(dst, src, HV_HYP_PAGE_SIZE); memcpy(dst, src, HV_HYP_PAGE_SIZE);
memunmap(src); memunmap(src);
kunmap(pg); kunmap_local(dst);
} else { } else {
hypercall_msr.guest_physical_address = vmalloc_to_pfn(hv_hypercall_pg); hypercall_msr.guest_physical_address = vmalloc_to_pfn(hv_hypercall_pg);
wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
......
...@@ -142,8 +142,6 @@ static int hyperv_vmbus_probe(struct hv_device *hdev, ...@@ -142,8 +142,6 @@ static int hyperv_vmbus_probe(struct hv_device *hdev,
if (ret) if (ret)
drm_warn(dev, "Failed to update vram location.\n"); drm_warn(dev, "Failed to update vram location.\n");
hv->dirt_needed = true;
ret = hyperv_mode_config_init(hv); ret = hyperv_mode_config_init(hv);
if (ret) if (ret)
goto err_free_mmio; goto err_free_mmio;
......
...@@ -208,7 +208,7 @@ static inline int hyperv_sendpacket(struct hv_device *hdev, struct synthvid_msg ...@@ -208,7 +208,7 @@ static inline int hyperv_sendpacket(struct hv_device *hdev, struct synthvid_msg
VM_PKT_DATA_INBAND, 0); VM_PKT_DATA_INBAND, 0);
if (ret) if (ret)
drm_err(&hv->dev, "Unable to send packet via vmbus\n"); drm_err_ratelimited(&hv->dev, "Unable to send packet via vmbus; error %d\n", ret);
return ret; return ret;
} }
......
...@@ -431,34 +431,29 @@ struct vmbus_channel *relid2channel(u32 relid) ...@@ -431,34 +431,29 @@ struct vmbus_channel *relid2channel(u32 relid)
void vmbus_on_event(unsigned long data) void vmbus_on_event(unsigned long data)
{ {
struct vmbus_channel *channel = (void *) data; struct vmbus_channel *channel = (void *) data;
unsigned long time_limit = jiffies + 2; void (*callback_fn)(void *context);
trace_vmbus_on_event(channel); trace_vmbus_on_event(channel);
hv_debug_delay_test(channel, INTERRUPT_DELAY); hv_debug_delay_test(channel, INTERRUPT_DELAY);
do {
void (*callback_fn)(void *);
/* A channel once created is persistent even when /* A channel once created is persistent even when
* there is no driver handling the device. An * there is no driver handling the device. An
* unloading driver sets the onchannel_callback to NULL. * unloading driver sets the onchannel_callback to NULL.
*/ */
callback_fn = READ_ONCE(channel->onchannel_callback); callback_fn = READ_ONCE(channel->onchannel_callback);
if (unlikely(callback_fn == NULL)) if (unlikely(!callback_fn))
return; return;
(*callback_fn)(channel->channel_callback_context);
if (channel->callback_mode != HV_CALL_BATCHED) (*callback_fn)(channel->channel_callback_context);
return;
if (likely(hv_end_read(&channel->inbound) == 0)) if (channel->callback_mode != HV_CALL_BATCHED)
return; return;
hv_begin_read(&channel->inbound); if (likely(hv_end_read(&channel->inbound) == 0))
} while (likely(time_before(jiffies, time_limit))); return;
/* The time limit (2 jiffies) has been reached */ hv_begin_read(&channel->inbound);
tasklet_schedule(&channel->callback_event); tasklet_schedule(&channel->callback_event);
} }
......
...@@ -46,8 +46,6 @@ struct vmbus_dynid { ...@@ -46,8 +46,6 @@ struct vmbus_dynid {
static struct acpi_device *hv_acpi_dev; static struct acpi_device *hv_acpi_dev;
static struct completion probe_event;
static int hyperv_cpuhp_online; static int hyperv_cpuhp_online;
static void *hv_panic_page; static void *hv_panic_page;
...@@ -1132,7 +1130,8 @@ void vmbus_on_msg_dpc(unsigned long data) ...@@ -1132,7 +1130,8 @@ void vmbus_on_msg_dpc(unsigned long data)
return; return;
INIT_WORK(&ctx->work, vmbus_onmessage_work); INIT_WORK(&ctx->work, vmbus_onmessage_work);
memcpy(&ctx->msg, &msg_copy, sizeof(msg->header) + payload_size); ctx->msg.header = msg_copy.header;
memcpy(&ctx->msg.payload, msg_copy.u.payload, payload_size);
/* /*
* The host can generate a rescind message while we * The host can generate a rescind message while we
...@@ -1573,7 +1572,7 @@ static int vmbus_bus_init(void) ...@@ -1573,7 +1572,7 @@ static int vmbus_bus_init(void)
} }
/** /**
* __vmbus_child_driver_register() - Register a vmbus's driver * __vmbus_driver_register() - Register a vmbus's driver
* @hv_driver: Pointer to driver structure you want to register * @hv_driver: Pointer to driver structure you want to register
* @owner: owner module of the drv * @owner: owner module of the drv
* @mod_name: module name string * @mod_name: module name string
...@@ -2052,7 +2051,7 @@ struct hv_device *vmbus_device_create(const guid_t *type, ...@@ -2052,7 +2051,7 @@ struct hv_device *vmbus_device_create(const guid_t *type,
child_device_obj->channel = channel; child_device_obj->channel = channel;
guid_copy(&child_device_obj->dev_type, type); guid_copy(&child_device_obj->dev_type, type);
guid_copy(&child_device_obj->dev_instance, instance); guid_copy(&child_device_obj->dev_instance, instance);
child_device_obj->vendor_id = 0x1414; /* MSFT vendor ID */ child_device_obj->vendor_id = PCI_VENDOR_ID_MICROSOFT;
return child_device_obj; return child_device_obj;
} }
...@@ -2468,7 +2467,6 @@ static int vmbus_acpi_add(struct acpi_device *device) ...@@ -2468,7 +2467,6 @@ static int vmbus_acpi_add(struct acpi_device *device)
ret_val = 0; ret_val = 0;
acpi_walk_err: acpi_walk_err:
complete(&probe_event);
if (ret_val) if (ret_val)
vmbus_acpi_remove(device); vmbus_acpi_remove(device);
return ret_val; return ret_val;
...@@ -2647,6 +2645,7 @@ static struct acpi_driver vmbus_acpi_driver = { ...@@ -2647,6 +2645,7 @@ static struct acpi_driver vmbus_acpi_driver = {
.remove = vmbus_acpi_remove, .remove = vmbus_acpi_remove,
}, },
.drv.pm = &vmbus_bus_pm, .drv.pm = &vmbus_bus_pm,
.drv.probe_type = PROBE_FORCE_SYNCHRONOUS,
}; };
static void hv_kexec_handler(void) static void hv_kexec_handler(void)
...@@ -2719,7 +2718,7 @@ static struct syscore_ops hv_synic_syscore_ops = { ...@@ -2719,7 +2718,7 @@ static struct syscore_ops hv_synic_syscore_ops = {
static int __init hv_acpi_init(void) static int __init hv_acpi_init(void)
{ {
int ret, t; int ret;
if (!hv_is_hyperv_initialized()) if (!hv_is_hyperv_initialized())
return -ENODEV; return -ENODEV;
...@@ -2727,8 +2726,6 @@ static int __init hv_acpi_init(void) ...@@ -2727,8 +2726,6 @@ static int __init hv_acpi_init(void)
if (hv_root_partition) if (hv_root_partition)
return 0; return 0;
init_completion(&probe_event);
/* /*
* Get ACPI resources first. * Get ACPI resources first.
*/ */
...@@ -2737,9 +2734,8 @@ static int __init hv_acpi_init(void) ...@@ -2737,9 +2734,8 @@ static int __init hv_acpi_init(void)
if (ret) if (ret)
return ret; return ret;
t = wait_for_completion_timeout(&probe_event, 5*HZ); if (!hv_acpi_dev) {
if (t == 0) { ret = -ENODEV;
ret = -ETIMEDOUT;
goto cleanup; goto cleanup;
} }
......
...@@ -60,6 +60,9 @@ ...@@ -60,6 +60,9 @@
#define VMSTOR_PROTO_VERSION_WIN8_1 VMSTOR_PROTO_VERSION(6, 0) #define VMSTOR_PROTO_VERSION_WIN8_1 VMSTOR_PROTO_VERSION(6, 0)
#define VMSTOR_PROTO_VERSION_WIN10 VMSTOR_PROTO_VERSION(6, 2) #define VMSTOR_PROTO_VERSION_WIN10 VMSTOR_PROTO_VERSION(6, 2)
/* channel callback timeout in ms */
#define CALLBACK_TIMEOUT 2
/* Packet structure describing virtual storage requests. */ /* Packet structure describing virtual storage requests. */
enum vstor_packet_operation { enum vstor_packet_operation {
VSTOR_OPERATION_COMPLETE_IO = 1, VSTOR_OPERATION_COMPLETE_IO = 1,
...@@ -1204,6 +1207,7 @@ static void storvsc_on_channel_callback(void *context) ...@@ -1204,6 +1207,7 @@ static void storvsc_on_channel_callback(void *context)
struct hv_device *device; struct hv_device *device;
struct storvsc_device *stor_device; struct storvsc_device *stor_device;
struct Scsi_Host *shost; struct Scsi_Host *shost;
unsigned long time_limit = jiffies + msecs_to_jiffies(CALLBACK_TIMEOUT);
if (channel->primary_channel != NULL) if (channel->primary_channel != NULL)
device = channel->primary_channel->device_obj; device = channel->primary_channel->device_obj;
...@@ -1224,6 +1228,11 @@ static void storvsc_on_channel_callback(void *context) ...@@ -1224,6 +1228,11 @@ static void storvsc_on_channel_callback(void *context)
u32 minlen = rqst_id ? sizeof(struct vstor_packet) : u32 minlen = rqst_id ? sizeof(struct vstor_packet) :
sizeof(enum vstor_packet_operation); sizeof(enum vstor_packet_operation);
if (unlikely(time_after(jiffies, time_limit))) {
hv_pkt_iter_close(channel);
return;
}
if (pktlen < minlen) { if (pktlen < minlen) {
dev_err(&device->device, dev_err(&device->device,
"Invalid pkt: id=%llu, len=%u, minlen=%u\n", "Invalid pkt: id=%llu, len=%u, minlen=%u\n",
...@@ -2059,7 +2068,7 @@ static int storvsc_probe(struct hv_device *device, ...@@ -2059,7 +2068,7 @@ static int storvsc_probe(struct hv_device *device,
err_out2: err_out2:
/* /*
* Once we have connected with the host, we would need to * Once we have connected with the host, we would need to
* to invoke storvsc_dev_remove() to rollback this state and * invoke storvsc_dev_remove() to rollback this state and
* this call also frees up the stor_device; hence the jump around * this call also frees up the stor_device; hence the jump around
* err_out1 label. * err_out1 label.
*/ */
......
...@@ -105,15 +105,12 @@ static inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size, ...@@ -105,15 +105,12 @@ static inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size,
} }
/* Generate the guest OS identifier as described in the Hyper-V TLFS */ /* Generate the guest OS identifier as described in the Hyper-V TLFS */
static inline __u64 generate_guest_id(__u64 d_info1, __u64 kernel_version, static inline u64 hv_generate_guest_id(u64 kernel_version)
__u64 d_info2)
{ {
__u64 guest_id = 0; u64 guest_id;
guest_id = (((__u64)HV_LINUX_VENDOR_ID) << 48); guest_id = (((u64)HV_LINUX_VENDOR_ID) << 48);
guest_id |= (d_info1 << 48);
guest_id |= (kernel_version << 16); guest_id |= (kernel_version << 16);
guest_id |= d_info2;
return guest_id; return guest_id;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment