On Mon, May 11, 2026 at 07:02:56PM -0700, Mukesh R wrote:
> On Hyper-V, most hypercalls related to PCI passthru to map/unmap regions,
> interrupts, etc need a device ID as a parameter. This device ID refers
> to that specific device during the lifetime of passthru.
>
> An L1VH VM only contains VMBus based devices. A device ID for a VMBus
> device is slightly different in that it uses the hv_pcibus_device info
> for building it to make sure it matches exactly what the hypervisor
> expects. This VMBus based device ID is needed when attaching devices in
> an L1VH based guest VM. Add a function to build and export it. Before
> building it, a check is done to make sure the device is a valid VMBus
> device.
>
> In remaining cases, PCI device ID is used. So, also make PCI device ID
> build function hv_build_devid_type_pci() public.
>
Reviewed-by: Souradeep Chakrabarti <[email protected]>
> Signed-off-by: Mukesh R <[email protected]>
> ---
> arch/x86/hyperv/irqdomain.c | 9 +++++----
> arch/x86/include/asm/mshyperv.h | 6 ++++++
> drivers/pci/controller/pci-hyperv.c | 24 ++++++++++++++++++++++++
> include/asm-generic/mshyperv.h | 11 +++++++++++
> 4 files changed, 46 insertions(+), 4 deletions(-)
>
> diff --git a/arch/x86/hyperv/irqdomain.c b/arch/x86/hyperv/irqdomain.c
> index b3ad50a874dc..8780573a4332 100644
> --- a/arch/x86/hyperv/irqdomain.c
> +++ b/arch/x86/hyperv/irqdomain.c
> @@ -112,7 +112,7 @@ static int get_rid_cb(struct pci_dev *pdev, u16 alias,
> void *data)
> return 0;
> }
>
> -static union hv_device_id hv_build_devid_type_pci(struct pci_dev *pdev)
> +u64 hv_build_devid_type_pci(struct pci_dev *pdev)
> {
> int pos;
> union hv_device_id hv_devid;
> @@ -172,8 +172,9 @@ static union hv_device_id hv_build_devid_type_pci(struct
> pci_dev *pdev)
> }
>
> out:
> - return hv_devid;
> + return hv_devid.as_uint64;
> }
> +EXPORT_SYMBOL_GPL(hv_build_devid_type_pci);
>
> /*
> * hv_map_msi_interrupt() - Map the MSI IRQ in the hypervisor.
> @@ -196,7 +197,7 @@ int hv_map_msi_interrupt(struct irq_data *data,
>
> msidesc = irq_data_get_msi_desc(data);
> pdev = msi_desc_to_pci_dev(msidesc);
> - hv_devid = hv_build_devid_type_pci(pdev);
> + hv_devid.as_uint64 = hv_build_devid_type_pci(pdev);
> cpu = cpumask_first(irq_data_get_effective_affinity_mask(data));
>
> return hv_map_interrupt(hv_devid, false, cpu, cfg->vector,
> @@ -271,7 +272,7 @@ static int hv_unmap_msi_interrupt(struct pci_dev *pdev,
> {
> union hv_device_id hv_devid;
>
> - hv_devid = hv_build_devid_type_pci(pdev);
> + hv_devid.as_uint64 = hv_build_devid_type_pci(pdev);
> return hv_unmap_interrupt(hv_devid.as_uint64, irq_entry);
> }
>
> diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h
> index f64393e853ee..2ef34001f8d3 100644
> --- a/arch/x86/include/asm/mshyperv.h
> +++ b/arch/x86/include/asm/mshyperv.h
> @@ -248,6 +248,12 @@ void hv_crash_asm_end(void);
> static inline void hv_root_crash_init(void) {}
> #endif /* CONFIG_MSHV_ROOT && CONFIG_CRASH_DUMP */
>
> +#if IS_ENABLED(CONFIG_HYPERV_IOMMU)
> +u64 hv_build_devid_type_pci(struct pci_dev *pdev);
> +#else
> +static inline u64 hv_build_devid_type_pci(struct pci_dev *pdev) { return 0; }
> +#endif /* IS_ENABLED(CONFIG_HYPERV_IOMMU) */
> +
> #else /* CONFIG_HYPERV */
> static inline void hyperv_init(void) {}
> static inline void hyperv_setup_mmu_ops(void) {}
> diff --git a/drivers/pci/controller/pci-hyperv.c
> b/drivers/pci/controller/pci-hyperv.c
> index cfc8fa403dad..50d793ca8f31 100644
> --- a/drivers/pci/controller/pci-hyperv.c
> +++ b/drivers/pci/controller/pci-hyperv.c
> @@ -573,6 +573,7 @@ struct hv_pci_compl {
> };
>
> static void hv_pci_onchannelcallback(void *context);
> +static bool hv_vmbus_pci_device(struct pci_bus *pbus);
>
> #ifdef CONFIG_X86
> #define DELIVERY_MODE APIC_DELIVERY_MODE_FIXED
> @@ -1005,6 +1006,24 @@ static struct irq_domain *hv_pci_get_root_domain(void)
> static void hv_arch_irq_unmask(struct irq_data *data) { }
> #endif /* CONFIG_ARM64 */
>
> +u64 hv_pci_vmbus_device_id(struct pci_dev *pdev)
> +{
> + struct hv_pcibus_device *hbus;
> + struct pci_bus *pbus = pdev->bus;
> +
> + if (!hv_vmbus_pci_device(pbus))
> + return 0;
> +
> + hbus = container_of(pbus->sysdata, struct hv_pcibus_device, sysdata);
> +
> + return (hbus->hdev->dev_instance.b[5] << 24) |
> + (hbus->hdev->dev_instance.b[4] << 16) |
> + (hbus->hdev->dev_instance.b[7] << 8) |
> + (hbus->hdev->dev_instance.b[6] & 0xf8) |
> + PCI_FUNC(pdev->devfn);
> +}
> +EXPORT_SYMBOL_GPL(hv_pci_vmbus_device_id);
> +
> /**
> * hv_pci_generic_compl() - Invoked for a completion packet
> * @context: Set up by the sender of the packet.
> @@ -1403,6 +1422,11 @@ static struct pci_ops hv_pcifront_ops = {
> .write = hv_pcifront_write_config,
> };
>
> +static bool hv_vmbus_pci_device(struct pci_bus *pbus)
> +{
> + return pbus->ops == &hv_pcifront_ops;
> +}
> +
> /*
> * Paravirtual backchannel
> *
> diff --git a/include/asm-generic/mshyperv.h b/include/asm-generic/mshyperv.h
> index e8cbc4e3f7ad..25ac7ca0fd8b 100644
> --- a/include/asm-generic/mshyperv.h
> +++ b/include/asm-generic/mshyperv.h
> @@ -204,6 +204,9 @@ extern u64 (*hv_read_reference_counter)(void);
> /* Sentinel value for an uninitialized entry in hv_vp_index array */
> #define VP_INVAL U32_MAX
>
> +/* Forward declarations */
> +struct pci_dev;
> +
> int __init hv_common_init(void);
> void __init hv_get_partition_id(void);
> void __init hv_common_free(void);
> @@ -316,6 +319,14 @@ void hv_para_set_synic_register(unsigned int reg, u64
> val);
> void hyperv_cleanup(void);
> bool hv_query_ext_cap(u64 cap_query);
> void hv_setup_dma_ops(struct device *dev, bool coherent);
> +
> +#if IS_ENABLED(CONFIG_PCI_HYPERV)
> +u64 hv_pci_vmbus_device_id(struct pci_dev *pdev);
> +#else
> +static inline u64 hv_pci_vmbus_device_id(struct pci_dev *pdev)
> +{ return 0; }
> +#endif /* IS_ENABLED(CONFIG_PCI_HYPERV) */
> +
> #else /* CONFIG_HYPERV */
> static inline void hv_identify_partition_type(void) {}
> static inline bool hv_is_hyperv_initialized(void) { return false; }
> --
> 2.51.2.vfs.0.1
>