diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-10-15 08:06:26 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-10-15 08:06:26 -0700 |
| commit | 6a66840a68683d9361a9b31faf3bd8104428ad29 (patch) | |
| tree | 0033c284126c9ba3445b06bdb52281f9cd864d77 /drivers | |
| parent | 9fee1f650a0a9ea6fa7c0b26244a778dd92542d5 (diff) | |
| parent | dbc393f6f009a2bf7e4a22ef2d70b53f533f20f4 (diff) | |
Merge tag 'hyperv-fixes-signed-20261015' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux
Pull Hyper-V fixes from Wei Liu:
- Typo and comment fixes (Hemanth Selam, Jiangshan Yi)
- Update maintainers list (Wei Liu, Long Li)
- Two Hyper-V PCI driver fixes (Naman Jain, Sahil Chandna)
- Small fixes for core Hyper-V code (Hardik Garg, Michael Kelley,
Waiman Long)
* tag 'hyperv-fixes-signed-20261015' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux:
MAINTAINERS: drop KY from Hyper-V maintainers list
PCI: hv: Warn when wait_for_response() waits indefinitely
PCI: hv: Probe vPCI buses asynchronously
MAINTAINERS: remove myself from the Hyper-V entries
mshv_vtl: Check per-CPU register page before mmap
tools/hv: fix typo "retrive" in comment
Drivers: hv: vmbus: fix typo "substract" in comment
Drivers: hv: Don't reset VMBus connection state on error/exit paths
x86/hyperv: Avoid using per-cpu output page in hv_apicid_to_vp_index()
x86/hyperv: Fix stale comments after stimer message mode removal
Drivers: hv: Avoid infinite retry loop in init_vp_index()
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/hv/channel.c | 2 | ||||
| -rw-r--r-- | drivers/hv/channel_mgmt.c | 12 | ||||
| -rw-r--r-- | drivers/hv/connection.c | 1 | ||||
| -rw-r--r-- | drivers/hv/mshv_vtl_main.c | 3 | ||||
| -rw-r--r-- | drivers/hv/vmbus_drv.c | 19 | ||||
| -rw-r--r-- | drivers/pci/controller/pci-hyperv.c | 49 |
6 files changed, 59 insertions, 27 deletions
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 7e4cc6f55237..a0883ddf32e2 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -79,7 +79,7 @@ static inline u32 hv_ring_gpadl_send_hvpgoffset(u32 offset) * therefore leaving a (PAGE_SIZE - HV_HYP_PAGE_SIZE) gap. * * And to calculate the effective send offset in gpadl, we need to - * substract this gap. + * subtract this gap. */ return (offset - (PAGE_SIZE - HV_HYP_PAGE_SIZE)) >> HV_HYP_PAGE_SHIFT; } diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index a044fd3b3c4e..c42def04ac41 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -752,13 +752,14 @@ static void init_vp_index(struct vmbus_channel *channel) u32 i, ncpu = num_online_cpus(); cpumask_var_t available_mask; struct cpumask *allocated_mask; + const struct cpumask *node_mask; const struct cpumask *hk_mask = housekeeping_cpumask(HK_TYPE_MANAGED_IRQ); u32 target_cpu; int numa_node; if (!perf_chn || !alloc_cpumask_var(&available_mask, GFP_KERNEL) || - cpumask_empty(hk_mask)) { + !cpumask_intersects(hk_mask, cpu_online_mask)) { /* * If the channel is not a performance critical * channel, bind it to VMBUS_CONNECT_CPU. @@ -780,14 +781,19 @@ static void init_vp_index(struct vmbus_channel *channel) next_numa_node_id = 0; continue; } - if (cpumask_empty(cpumask_of_node(numa_node))) + /* + * Try next NUMA node if current NUMA node has no CPU + * or doesn't contain any housekeeping CPU. + */ + node_mask = cpumask_of_node(numa_node); + if (!cpumask_intersects(node_mask, hk_mask)) continue; break; } allocated_mask = &hv_context.hv_numa_map[numa_node]; retry: - cpumask_xor(available_mask, allocated_mask, cpumask_of_node(numa_node)); + cpumask_xor(available_mask, allocated_mask, node_mask); cpumask_and(available_mask, available_mask, hk_mask); if (cpumask_empty(available_mask)) { diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index 1ab3581b096a..818667ef9c74 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c @@ -346,7 +346,6 @@ int vmbus_connect(void) cleanup: pr_err("Unable to connect to host\n"); - vmbus_connection.conn_state = DISCONNECTED; vmbus_disconnect(); kfree(msginfo); diff --git a/drivers/hv/mshv_vtl_main.c b/drivers/hv/mshv_vtl_main.c index 6e3c11c68171..d8225242c73f 100644 --- a/drivers/hv/mshv_vtl_main.c +++ b/drivers/hv/mshv_vtl_main.c @@ -819,6 +819,9 @@ static vm_fault_t mshv_vtl_fault(struct vm_fault *vmf) return VM_FAULT_NOPAGE; } + if (!page) + return VM_FAULT_SIGBUS; + get_page(page); vmf->page = page; diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 5ebdbe24b5a1..4692687cdbf3 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -2923,23 +2923,19 @@ static void hv_crash_handler(struct pt_regs *regs) static int hv_synic_suspend(void *data) { /* - * When we reach here, all the non-boot CPUs have been offlined. - * If we're in a legacy configuration where stimer Direct Mode is - * not enabled, the stimers on the non-boot CPUs have been unbound - * in hv_synic_cleanup() -> hv_stimer_legacy_cleanup() -> - * hv_stimer_cleanup() -> clockevents_unbind_device(). + * When we reach here, all the non-boot CPUs have been offlined, + * and their stimers have been cleaned up by the cpuhp teardown + * callback hv_stimer_cleanup(). * * hv_synic_suspend() only runs on CPU0 with interrupts disabled. - * Here we do not call hv_stimer_legacy_cleanup() on CPU0 because: - * 1) it's unnecessary as interrupts remain disabled between - * syscore_suspend() and syscore_resume(): see create_image() and + * The stimer on CPU0 is not explicitly cleaned up here because: + * 1) it's harmless as interrupts remain disabled between + * syscore_suspend() and syscore_resume(), so the stimer cannot + * fire during this window: see create_image() and * resume_target_kernel() * 2) the stimer on CPU0 is automatically disabled later by * syscore_suspend() -> timekeeping_suspend() -> tick_suspend() -> ... * -> clockevents_shutdown() -> ... -> hv_ce_shutdown() - * 3) a warning would be triggered if we call - * clockevents_unbind_device(), which may sleep, in an - * interrupts-disabled context. */ hv_hyp_synic_disable_regs(0); @@ -3043,7 +3039,6 @@ static void __exit vmbus_exit(void) hv_remove_kexec_handler(); hv_remove_crash_handler(); - vmbus_connection.conn_state = DISCONNECTED; hv_stimer_global_cleanup(); vmbus_disconnect(); if (vmbus_irq == -1) diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c index 89816a2bd7cd..85d826f8f68d 100644 --- a/drivers/pci/controller/pci-hyperv.c +++ b/drivers/pci/controller/pci-hyperv.c @@ -1040,19 +1040,38 @@ static void put_pcichild(struct hv_pci_dev *hpdev) /* * There is no good way to get notified from vmbus_onoffer_rescind(), - * so let's use polling here, since this is not a hot path. + * so let's use polling here, since this is not a hot path. If + * wait_for_response() has been polling for 2 minutes + * without either a rescind or completion, add a warning. */ +#define PCI_RESPONSE_WARN_POLL_COUNT 1200 + static int wait_for_response(struct hv_device *hdev, - struct completion *comp) + struct completion *comp, + const char *msg_type) { + u64 counter = 0; + while (true) { if (hdev->channel->rescind) { dev_warn_once(&hdev->device, "The device is gone.\n"); return -ENODEV; } - if (wait_for_completion_timeout(comp, HZ / 10)) + counter++; + + if (wait_for_completion_timeout(comp, HZ / 10)) { + if (counter > PCI_RESPONSE_WARN_POLL_COUNT) + dev_warn(&hdev->device, + "Late %s completion arrived.\n", msg_type); break; + } + + if (counter == PCI_RESPONSE_WARN_POLL_COUNT) { + dev_err(&hdev->device, + "%s stuck waiting for response, relid = %u\n", + msg_type, hdev->channel->offermsg.child_relid); + } } return 0; @@ -1518,7 +1537,8 @@ static int hv_read_config_block(struct pci_dev *pdev, void *buf, if (ret) return ret; - ret = wait_for_response(hbus->hdev, &comp_pkt.comp_pkt.host_event); + ret = wait_for_response(hbus->hdev, &comp_pkt.comp_pkt.host_event, + "PCI_READ_BLOCK"); if (ret) return ret; @@ -1607,7 +1627,8 @@ static int hv_write_config_block(struct pci_dev *pdev, void *buf, if (ret) return ret; - ret = wait_for_response(hbus->hdev, &comp_pkt.host_event); + ret = wait_for_response(hbus->hdev, &comp_pkt.host_event, + "PCI_WRITE_BLOCK"); if (ret) return ret; @@ -2624,7 +2645,8 @@ static struct hv_pci_dev *new_pcichild_device(struct hv_pcibus_device *hbus, if (ret) goto error; - if (wait_for_response(hbus->hdev, &comp_pkt.host_event)) + if (wait_for_response(hbus->hdev, &comp_pkt.host_event, + "PCI_QUERY_RESOURCE_REQUIREMENTS")) goto error; hpdev->desc = *desc; @@ -3256,7 +3278,8 @@ static int hv_pci_protocol_negotiation(struct hv_device *hdev, (unsigned long)pkt, VM_PKT_DATA_INBAND, VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); if (!ret) - ret = wait_for_response(hdev, &comp_pkt.host_event); + ret = wait_for_response(hdev, &comp_pkt.host_event, + "PCI_QUERY_PROTOCOL_VERSION"); if (ret) { dev_err(&hdev->device, @@ -3476,7 +3499,8 @@ enter_d0_retry: (unsigned long)pkt, VM_PKT_DATA_INBAND, VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); if (!ret) - ret = wait_for_response(hdev, &comp_pkt.host_event); + ret = wait_for_response(hdev, &comp_pkt.host_event, + "PCI_BUS_D0ENTRY"); if (ret) goto exit; @@ -3553,7 +3577,8 @@ static int hv_pci_query_relations(struct hv_device *hdev) ret = vmbus_sendpacket(hdev->channel, &message, sizeof(message), 0, VM_PKT_DATA_INBAND, 0); if (!ret) - ret = wait_for_response(hdev, &comp); + ret = wait_for_response(hdev, &comp, + "PCI_QUERY_BUS_RELATIONS"); /* * In the case of fast device addition/removal, it's possible that @@ -3644,7 +3669,8 @@ static int hv_send_resources_allocated(struct hv_device *hdev) VM_PKT_DATA_INBAND, VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); if (!ret) - ret = wait_for_response(hdev, &comp_pkt.host_event); + ret = wait_for_response(hdev, &comp_pkt.host_event, + "PCI_RESOURCE_ASSIGNED"); if (ret) break; @@ -4155,6 +4181,9 @@ static struct hv_driver hv_pci_drv = { .remove = hv_pci_remove, .suspend = hv_pci_suspend, .resume = hv_pci_resume, + .driver = { + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, }; static void __exit exit_hv_pci_drv(void) |
