RE: [PATCH v4 2/5] Drivers: hv: Add logical device ID registry for vPCI devices

From: Michael Kelley

Date: Fri Aug 28 2026 - 13:21:55 EST


From: Yu Zhang <zhangyu1@xxxxxxxxxxxxxxxxxxx> Sent: Friday, August 21, 2026 6:27 AM
>
> Hyper-V identifies each PCI pass-thru device by a logical device ID in
> its hypercall interface. This ID consists of a per-bus prefix, derived
> from the VMBus device instance GUID, combined with the PCI function
> number of the endpoint device.
>
> Add a registry in hv_common.c that maps a PCI domain number to its
> logical device ID prefix. The vPCI bus driver (pci-hyperv) registers the
> prefix when a bus is probed and unregisters it when the bus is removed.
> Consumers such as the para-virtualized IOMMU driver look up the prefix
> by PCI domain number and combine it with the function number to form the
> complete logical device ID for hypercalls.
>
> Use rhashtable for the sparse exact-match mapping. Lookups copy the
> prefix while holding the RCU read lock, and removal defers freeing the
> entry until existing readers have completed.
>
> The prefix construction is shared via hv_build_logical_dev_id_prefix() so
> that pci-hyperv's interrupt retargeting path and the registry use exactly
> the same byte layout. It is derived on demand from the constant hv_device
> instance GUID rather than cached in struct hv_pcibus_device, which is
> private to the pci-hyperv module; this keeps the interface narrow and
> avoids depending on pci-hyperv internals.
>
> Co-developed-by: Easwar Hariharan <easwar.hariharan@xxxxxxxxxxxxxxxxxxx>
> Signed-off-by: Easwar Hariharan <easwar.hariharan@xxxxxxxxxxxxxxxxxxx>
> Signed-off-by: Yu Zhang <zhangyu1@xxxxxxxxxxxxxxxxxxx>

This all looks good to me except for a couple nits below. Modulo the nits:

Reviewed-by: Michael Kelley <mhklinux@xxxxxxxxxxx>

> ---
> drivers/hv/hv_common.c | 112 ++++++++++++++++++++++++++++
> drivers/pci/controller/pci-hyperv.c | 21 ++++--
> include/asm-generic/mshyperv.h | 4 +
> include/linux/hyperv.h | 8 ++
> 4 files changed, 140 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/hv/hv_common.c b/drivers/hv/hv_common.c
> index b5d2d6cd65ae..808751aa356b 100644
> --- a/drivers/hv/hv_common.c
> +++ b/drivers/hv/hv_common.c
> @@ -21,6 +21,7 @@
> #include <linux/panic_notifier.h>
> #include <linux/ptrace.h>
> #include <linux/random.h>
> +#include <linux/rhashtable.h>
> #include <linux/efi.h>
> #include <linux/kdebug.h>
> #include <linux/kmsg_dump.h>
> @@ -78,6 +79,22 @@ static struct ctl_table_header *hv_ctl_table_hdr;
> u8 * __percpu *hv_synic_eventring_tail;
> EXPORT_SYMBOL_GPL(hv_synic_eventring_tail);
>
> +struct hv_pci_busdata {
> + int pci_domain_nr;
> + u32 logical_dev_id_prefix;
> + struct rhash_head node;
> + struct rcu_head rcu;
> +};
> +
> +static struct rhashtable hv_pci_bus_ht;
> +static bool hv_pci_bus_ht_initialized;
> +
> +static const struct rhashtable_params hv_pci_bus_ht_params = {
> + .key_len = sizeof_field(struct hv_pci_busdata, pci_domain_nr),
> + .key_offset = offsetof(struct hv_pci_busdata, pci_domain_nr),
> + .head_offset = offsetof(struct hv_pci_busdata, node),
> +};
> +
> /*
> * Hyper-V specific initialization and shutdown code that is
> * common across all architectures. Called from architecture
> @@ -86,6 +103,11 @@ EXPORT_SYMBOL_GPL(hv_synic_eventring_tail);
>
> void __init hv_common_free(void)
> {
> + if (hv_pci_bus_ht_initialized) {
> + rhashtable_destroy(&hv_pci_bus_ht);
> + hv_pci_bus_ht_initialized = false;
> + }
> +
> unregister_sysctl_table(hv_ctl_table_hdr);
> hv_ctl_table_hdr = NULL;
>
> @@ -315,6 +337,7 @@ u8 __init get_vtl(void)
> int __init hv_common_init(void)
> {
> int i;
> + int ret;
> union hv_hypervisor_version_info version;
>
> /* Get information about the Microsoft Hypervisor version */
> @@ -394,6 +417,13 @@ int __init hv_common_init(void)
> for (i = 0; i < nr_cpu_ids; i++)
> hv_vp_index[i] = VP_INVAL;
>
> + ret = rhashtable_init(&hv_pci_bus_ht, &hv_pci_bus_ht_params);
> + if (ret) {
> + hv_common_free();
> + return ret;
> + }
> + hv_pci_bus_ht_initialized = true;
> +
> return 0;
> }
>
> @@ -864,3 +894,85 @@ const char *hv_result_to_string(u64 status)
> return "Unknown";
> }
> EXPORT_SYMBOL_GPL(hv_result_to_string);
> +
> +/*
> + * Logical device ID registry for Hyper-V PCI buses. The pci-hyperv
> + * driver registers each bus's logical device ID prefix before scanning
> + * its devices. Consumers look up the prefix by PCI domain number when
> + * building logical device IDs for Hyper-V interfaces.
> + */
> +int hv_pci_register_dev_id(int pci_domain_nr, u32 logical_dev_id_prefix)
> +{
> + struct hv_pci_busdata *bus, *new;
> + int ret;
> +
> + new = kzalloc_obj(*new, GFP_KERNEL);
> + if (!new)
> + return -ENOMEM;
> +
> + new->pci_domain_nr = pci_domain_nr;
> + new->logical_dev_id_prefix = logical_dev_id_prefix;
> +
> + bus = rhashtable_lookup_get_insert_fast(&hv_pci_bus_ht, &new->node,
> + hv_pci_bus_ht_params);
> + if (IS_ERR(bus)) {
> + ret = PTR_ERR(bus);
> + goto free_new;
> + }
> +
> + if (WARN_ONCE(bus != NULL,
> + "Hyper-V PCI domain %d is already registered\n",

PCI domain numbers should be displayed as 4-digit hex numbers.
Use format string %04x so that leading zeros are supplied if needed
to make 4 digits.

> + pci_domain_nr)) {
> + ret = -EEXIST;
> + goto free_new;
> + }
> +
> + return 0;
> +
> +free_new:
> + kfree(new);
> + return ret;
> +}
> +EXPORT_SYMBOL_FOR_MODULES(hv_pci_register_dev_id, "pci-hyperv");
> +
> +void hv_pci_unregister_dev_id(int pci_domain_nr)
> +{
> + struct hv_pci_busdata *bus;
> + int ret = -ENOENT;
> +
> + rcu_read_lock();
> + bus = rhashtable_lookup(&hv_pci_bus_ht, &pci_domain_nr,
> + hv_pci_bus_ht_params);
> + if (bus)
> + ret = rhashtable_remove_fast(&hv_pci_bus_ht, &bus->node,
> + hv_pci_bus_ht_params);
> + rcu_read_unlock();
> +
> + if (WARN_ON_ONCE(ret))

For symmetry, I'd suggest including a message like in the "register"
function. Include the PCI domain number in the message.

Michael