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

