From: Yu Zhang <[email protected]> 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 <[email protected]>
> Signed-off-by: Easwar Hariharan <[email protected]>
> Signed-off-by: Yu Zhang <[email protected]>

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

Reviewed-by: Michael Kelley <[email protected]>

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

Reply via email to