diff --git a/sdk_container/src/third_party/coreos-overlay/sys-kernel/coreos-modules/files/amd64_defconfig-5.15 b/sdk_container/src/third_party/coreos-overlay/sys-kernel/coreos-modules/files/amd64_defconfig-5.15 index e9b5d8a28f..f0c9b4d247 100644 --- a/sdk_container/src/third_party/coreos-overlay/sys-kernel/coreos-modules/files/amd64_defconfig-5.15 +++ b/sdk_container/src/third_party/coreos-overlay/sys-kernel/coreos-modules/files/amd64_defconfig-5.15 @@ -92,7 +92,6 @@ CONFIG_NET_SWITCHDEV=y CONFIG_NVRAM=m CONFIG_OPTPROBES=y CONFIG_PARAVIRT_SPINLOCKS=y -CONFIG_PCI_HYPERV=m CONFIG_PCI_MMCONFIG=y CONFIG_PHYSICAL_ALIGN=0x1000000 CONFIG_PMIC_OPREGION=y diff --git a/sdk_container/src/third_party/coreos-overlay/sys-kernel/coreos-modules/files/commonconfig-5.15 b/sdk_container/src/third_party/coreos-overlay/sys-kernel/coreos-modules/files/commonconfig-5.15 index 069a568a26..204e311191 100644 --- a/sdk_container/src/third_party/coreos-overlay/sys-kernel/coreos-modules/files/commonconfig-5.15 +++ b/sdk_container/src/third_party/coreos-overlay/sys-kernel/coreos-modules/files/commonconfig-5.15 @@ -730,6 +730,7 @@ CONFIG_PCI=y CONFIG_PCIEAER=y CONFIG_PCIEPORTBUS=y CONFIG_PCIE_ECRC=y +CONFIG_PCI_HYPERV=m CONFIG_PCI_IOV=y CONFIG_PCI_MSI=y CONFIG_PCNET32=m diff --git a/sdk_container/src/third_party/coreos-overlay/sys-kernel/coreos-sources/coreos-sources-5.15.15.ebuild b/sdk_container/src/third_party/coreos-overlay/sys-kernel/coreos-sources/coreos-sources-5.15.15.ebuild index ddc6adc562..72f2597b8d 100644 --- a/sdk_container/src/third_party/coreos-overlay/sys-kernel/coreos-sources/coreos-sources-5.15.15.ebuild +++ b/sdk_container/src/third_party/coreos-overlay/sys-kernel/coreos-sources/coreos-sources-5.15.15.ebuild @@ -8,7 +8,7 @@ ETYPE="sources" # Final releases should be versioned L.M.N, even for N == 0 # Only needed for RCs -K_BASE_VER="5.10" +K_BASE_VER="5.15" inherit kernel-2 EXTRAVERSION="-flatcar" @@ -34,4 +34,6 @@ IUSE="" UNIPATCH_LIST=" ${PATCH_DIR}/z0001-kbuild-derive-relative-path-for-srctree-from-CURDIR.patch \ ${PATCH_DIR}/z0002-tools-objtool-Makefile-Don-t-fail-on-fallthrough-wit.patch \ + ${PATCH_DIR}/z0003-PCI-hv-Make-the-code-arch-neutral-by-adding-arch-spe.patch \ + ${PATCH_DIR}/z0004-PCI-hv-Add-arm64-Hyper-V-vPCI-support.patch \ " diff --git a/sdk_container/src/third_party/coreos-overlay/sys-kernel/coreos-sources/files/5.15/z0003-PCI-hv-Make-the-code-arch-neutral-by-adding-arch-spe.patch b/sdk_container/src/third_party/coreos-overlay/sys-kernel/coreos-sources/files/5.15/z0003-PCI-hv-Make-the-code-arch-neutral-by-adding-arch-spe.patch new file mode 100644 index 0000000000..8db0da8940 --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/sys-kernel/coreos-sources/files/5.15/z0003-PCI-hv-Make-the-code-arch-neutral-by-adding-arch-spe.patch @@ -0,0 +1,334 @@ +From 831c1ae725f7d2f8f858b0840692b48e75b49331 Mon Sep 17 00:00:00 2001 +From: Sunil Muthuswamy +Date: Wed, 5 Jan 2022 11:32:35 -0800 +Subject: [PATCH 1/2] PCI: hv: Make the code arch neutral by adding arch + specific interfaces + +Encapsulate arch dependencies in Hyper-V vPCI through a set of +arch-dependent interfaces. Adding these arch specific interfaces will +allow for an implementation for other architectures, such as arm64. + +There are no functional changes expected from this patch. + +Link: https://lore.kernel.org/r/1641411156-31705-2-git-send-email-sunilmut@linux.microsoft.com +Signed-off-by: Sunil Muthuswamy +Signed-off-by: Lorenzo Pieralisi +Signed-off-by: Bjorn Helgaas +Reviewed-by: Boqun Feng +Reviewed-by: Marc Zyngier +Reviewed-by: Michael Kelley +--- + arch/x86/include/asm/hyperv-tlfs.h | 33 ++++++++++++ + arch/x86/include/asm/mshyperv.h | 7 --- + drivers/pci/controller/pci-hyperv.c | 79 ++++++++++++++++++++--------- + include/asm-generic/hyperv-tlfs.h | 33 ------------ + 4 files changed, 87 insertions(+), 65 deletions(-) + +diff --git a/arch/x86/include/asm/hyperv-tlfs.h b/arch/x86/include/asm/hyperv-tlfs.h +index 381e88122a5f..0a9407dc0859 100644 +--- a/arch/x86/include/asm/hyperv-tlfs.h ++++ b/arch/x86/include/asm/hyperv-tlfs.h +@@ -602,6 +602,39 @@ enum hv_interrupt_type { + HV_X64_INTERRUPT_TYPE_MAXIMUM = 0x000A, + }; + ++union hv_msi_address_register { ++ u32 as_uint32; ++ struct { ++ u32 reserved1:2; ++ u32 destination_mode:1; ++ u32 redirection_hint:1; ++ u32 reserved2:8; ++ u32 destination_id:8; ++ u32 msi_base:12; ++ }; ++} __packed; ++ ++union hv_msi_data_register { ++ u32 as_uint32; ++ struct { ++ u32 vector:8; ++ u32 delivery_mode:3; ++ u32 reserved1:3; ++ u32 level_assert:1; ++ u32 trigger_mode:1; ++ u32 reserved2:16; ++ }; ++} __packed; ++ ++/* HvRetargetDeviceInterrupt hypercall */ ++union hv_msi_entry { ++ u64 as_uint64; ++ struct { ++ union hv_msi_address_register address; ++ union hv_msi_data_register data; ++ } __packed; ++}; ++ + #include + + #endif +diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h +index da3972fe5a7a..a1c3dceff8eb 100644 +--- a/arch/x86/include/asm/mshyperv.h ++++ b/arch/x86/include/asm/mshyperv.h +@@ -169,13 +169,6 @@ bool hv_vcpu_is_preempted(int vcpu); + static inline void hv_apic_init(void) {} + #endif + +-static inline void hv_set_msi_entry_from_desc(union hv_msi_entry *msi_entry, +- struct msi_desc *msi_desc) +-{ +- msi_entry->address.as_uint32 = msi_desc->msg.address_lo; +- msi_entry->data.as_uint32 = msi_desc->msg.data; +-} +- + struct irq_domain *hv_create_pci_msi_domain(void); + + int hv_map_ioapic_interrupt(int ioapic_id, bool level, int vcpu, int vector, +diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c +index 6733cb14e775..ead7d6cb6bf1 100644 +--- a/drivers/pci/controller/pci-hyperv.c ++++ b/drivers/pci/controller/pci-hyperv.c +@@ -43,9 +43,6 @@ + #include + #include + #include +-#include +-#include +-#include + #include + #include + #include +@@ -583,6 +580,42 @@ struct hv_pci_compl { + + static void hv_pci_onchannelcallback(void *context); + ++#ifdef CONFIG_X86 ++#define DELIVERY_MODE APIC_DELIVERY_MODE_FIXED ++#define FLOW_HANDLER handle_edge_irq ++#define FLOW_NAME "edge" ++ ++static int hv_pci_irqchip_init(void) ++{ ++ return 0; ++} ++ ++static struct irq_domain *hv_pci_get_root_domain(void) ++{ ++ return x86_vector_domain; ++} ++ ++static unsigned int hv_msi_get_int_vector(struct irq_data *data) ++{ ++ struct irq_cfg *cfg = irqd_cfg(data); ++ ++ return cfg->vector; ++} ++ ++static void hv_set_msi_entry_from_desc(union hv_msi_entry *msi_entry, ++ struct msi_desc *msi_desc) ++{ ++ msi_entry->address.as_uint32 = msi_desc->msg.address_lo; ++ msi_entry->data.as_uint32 = msi_desc->msg.data; ++} ++ ++static int hv_msi_prepare(struct irq_domain *domain, struct device *dev, ++ int nvec, msi_alloc_info_t *info) ++{ ++ return pci_msi_prepare(domain, dev, nvec, info); ++} ++#endif /* CONFIG_X86 */ ++ + /** + * hv_pci_generic_compl() - Invoked for a completion packet + * @context: Set up by the sender of the packet. +@@ -1191,14 +1224,6 @@ static void hv_msi_free(struct irq_domain *domain, struct msi_domain_info *info, + put_pcichild(hpdev); + } + +-static int hv_set_affinity(struct irq_data *data, const struct cpumask *dest, +- bool force) +-{ +- struct irq_data *parent = data->parent_data; +- +- return parent->chip->irq_set_affinity(parent, dest, force); +-} +- + static void hv_irq_mask(struct irq_data *data) + { + pci_msi_mask_irq(data); +@@ -1217,7 +1242,6 @@ static void hv_irq_mask(struct irq_data *data) + static void hv_irq_unmask(struct irq_data *data) + { + struct msi_desc *msi_desc = irq_data_get_msi_desc(data); +- struct irq_cfg *cfg = irqd_cfg(data); + struct hv_retarget_device_interrupt *params; + struct hv_pcibus_device *hbus; + struct cpumask *dest; +@@ -1246,7 +1270,7 @@ static void hv_irq_unmask(struct irq_data *data) + (hbus->hdev->dev_instance.b[7] << 8) | + (hbus->hdev->dev_instance.b[6] & 0xf8) | + PCI_FUNC(pdev->devfn); +- params->int_target.vector = cfg->vector; ++ params->int_target.vector = hv_msi_get_int_vector(data); + + /* + * Honoring apic->delivery_mode set to APIC_DELIVERY_MODE_FIXED by +@@ -1347,7 +1371,7 @@ static u32 hv_compose_msi_req_v1( + int_pkt->wslot.slot = slot; + int_pkt->int_desc.vector = vector; + int_pkt->int_desc.vector_count = 1; +- int_pkt->int_desc.delivery_mode = APIC_DELIVERY_MODE_FIXED; ++ int_pkt->int_desc.delivery_mode = DELIVERY_MODE; + + /* + * Create MSI w/ dummy vCPU set, overwritten by subsequent retarget in +@@ -1377,7 +1401,7 @@ static u32 hv_compose_msi_req_v2( + int_pkt->wslot.slot = slot; + int_pkt->int_desc.vector = vector; + int_pkt->int_desc.vector_count = 1; +- int_pkt->int_desc.delivery_mode = APIC_DELIVERY_MODE_FIXED; ++ int_pkt->int_desc.delivery_mode = DELIVERY_MODE; + cpu = hv_compose_msi_req_get_cpu(affinity); + int_pkt->int_desc.processor_array[0] = + hv_cpu_number_to_vp_number(cpu); +@@ -1397,7 +1421,7 @@ static u32 hv_compose_msi_req_v3( + int_pkt->int_desc.vector = vector; + int_pkt->int_desc.reserved = 0; + int_pkt->int_desc.vector_count = 1; +- int_pkt->int_desc.delivery_mode = APIC_DELIVERY_MODE_FIXED; ++ int_pkt->int_desc.delivery_mode = DELIVERY_MODE; + cpu = hv_compose_msi_req_get_cpu(affinity); + int_pkt->int_desc.processor_array[0] = + hv_cpu_number_to_vp_number(cpu); +@@ -1419,7 +1443,6 @@ static u32 hv_compose_msi_req_v3( + */ + static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) + { +- struct irq_cfg *cfg = irqd_cfg(data); + struct hv_pcibus_device *hbus; + struct vmbus_channel *channel; + struct hv_pci_dev *hpdev; +@@ -1470,7 +1493,7 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) + size = hv_compose_msi_req_v1(&ctxt.int_pkts.v1, + dest, + hpdev->desc.win_slot.slot, +- cfg->vector); ++ hv_msi_get_int_vector(data)); + break; + + case PCI_PROTOCOL_VERSION_1_2: +@@ -1478,14 +1501,14 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) + size = hv_compose_msi_req_v2(&ctxt.int_pkts.v2, + dest, + hpdev->desc.win_slot.slot, +- cfg->vector); ++ hv_msi_get_int_vector(data)); + break; + + case PCI_PROTOCOL_VERSION_1_4: + size = hv_compose_msi_req_v3(&ctxt.int_pkts.v3, + dest, + hpdev->desc.win_slot.slot, +- cfg->vector); ++ hv_msi_get_int_vector(data)); + break; + + default: +@@ -1594,14 +1617,14 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) + static struct irq_chip hv_msi_irq_chip = { + .name = "Hyper-V PCIe MSI", + .irq_compose_msi_msg = hv_compose_msi_msg, +- .irq_set_affinity = hv_set_affinity, ++ .irq_set_affinity = irq_chip_set_affinity_parent, + .irq_ack = irq_chip_ack_parent, + .irq_mask = hv_irq_mask, + .irq_unmask = hv_irq_unmask, + }; + + static struct msi_domain_ops hv_msi_ops = { +- .msi_prepare = pci_msi_prepare, ++ .msi_prepare = hv_msi_prepare, + .msi_free = hv_msi_free, + }; + +@@ -1625,12 +1648,12 @@ static int hv_pcie_init_irq_domain(struct hv_pcibus_device *hbus) + hbus->msi_info.flags = (MSI_FLAG_USE_DEF_DOM_OPS | + MSI_FLAG_USE_DEF_CHIP_OPS | MSI_FLAG_MULTI_PCI_MSI | + MSI_FLAG_PCI_MSIX); +- hbus->msi_info.handler = handle_edge_irq; +- hbus->msi_info.handler_name = "edge"; ++ hbus->msi_info.handler = FLOW_HANDLER; ++ hbus->msi_info.handler_name = FLOW_NAME; + hbus->msi_info.data = hbus; + hbus->irq_domain = pci_msi_create_irq_domain(hbus->fwnode, + &hbus->msi_info, +- x86_vector_domain); ++ hv_pci_get_root_domain()); + if (!hbus->irq_domain) { + dev_err(&hbus->hdev->device, + "Failed to build an MSI IRQ domain\n"); +@@ -3542,9 +3565,15 @@ static void __exit exit_hv_pci_drv(void) + + static int __init init_hv_pci_drv(void) + { ++ int ret; ++ + if (!hv_is_hyperv_initialized()) + return -ENODEV; + ++ ret = hv_pci_irqchip_init(); ++ if (ret) ++ return ret; ++ + /* Set the invalid domain number's bit, so it will not be used */ + set_bit(HVPCI_DOM_INVALID, hvpci_dom_map); + +diff --git a/include/asm-generic/hyperv-tlfs.h b/include/asm-generic/hyperv-tlfs.h +index 8ed6733d5146..8f97c2927bee 100644 +--- a/include/asm-generic/hyperv-tlfs.h ++++ b/include/asm-generic/hyperv-tlfs.h +@@ -540,39 +540,6 @@ enum hv_interrupt_source { + HV_INTERRUPT_SOURCE_IOAPIC, + }; + +-union hv_msi_address_register { +- u32 as_uint32; +- struct { +- u32 reserved1:2; +- u32 destination_mode:1; +- u32 redirection_hint:1; +- u32 reserved2:8; +- u32 destination_id:8; +- u32 msi_base:12; +- }; +-} __packed; +- +-union hv_msi_data_register { +- u32 as_uint32; +- struct { +- u32 vector:8; +- u32 delivery_mode:3; +- u32 reserved1:3; +- u32 level_assert:1; +- u32 trigger_mode:1; +- u32 reserved2:16; +- }; +-} __packed; +- +-/* HvRetargetDeviceInterrupt hypercall */ +-union hv_msi_entry { +- u64 as_uint64; +- struct { +- union hv_msi_address_register address; +- union hv_msi_data_register data; +- } __packed; +-}; +- + union hv_ioapic_rte { + u64 as_uint64; + +-- +2.32.0 + diff --git a/sdk_container/src/third_party/coreos-overlay/sys-kernel/coreos-sources/files/5.15/z0004-PCI-hv-Add-arm64-Hyper-V-vPCI-support.patch b/sdk_container/src/third_party/coreos-overlay/sys-kernel/coreos-sources/files/5.15/z0004-PCI-hv-Add-arm64-Hyper-V-vPCI-support.patch new file mode 100644 index 0000000000..9d223379c0 --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/sys-kernel/coreos-sources/files/5.15/z0004-PCI-hv-Add-arm64-Hyper-V-vPCI-support.patch @@ -0,0 +1,349 @@ +From d9932b46915664c88709d59927fa67e797adec56 Mon Sep 17 00:00:00 2001 +From: Sunil Muthuswamy +Date: Wed, 5 Jan 2022 11:32:36 -0800 +Subject: [PATCH 2/2] PCI: hv: Add arm64 Hyper-V vPCI support + +Add arm64 Hyper-V vPCI support by implementing the arch specific +interfaces. Introduce an IRQ domain and chip specific to Hyper-v vPCI that +is based on SPIs. The IRQ domain parents itself to the arch GIC IRQ domain +for basic vector management. + +[bhelgaas: squash in fix from Yang Li : +https://lore.kernel.org/r/20220112003324.62755-1-yang.lee@linux.alibaba.com] +Link: https://lore.kernel.org/r/1641411156-31705-3-git-send-email-sunilmut@linux.microsoft.com +Signed-off-by: Sunil Muthuswamy +Signed-off-by: Lorenzo Pieralisi +Signed-off-by: Bjorn Helgaas +Reviewed-by: Marc Zyngier +Reviewed-by: Michael Kelley +--- + arch/arm64/include/asm/hyperv-tlfs.h | 9 + + drivers/pci/Kconfig | 2 +- + drivers/pci/controller/Kconfig | 2 +- + drivers/pci/controller/pci-hyperv.c | 235 ++++++++++++++++++++++++++- + 4 files changed, 245 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/include/asm/hyperv-tlfs.h b/arch/arm64/include/asm/hyperv-tlfs.h +index 4d964a7f02ee..bc6c7ac934a1 100644 +--- a/arch/arm64/include/asm/hyperv-tlfs.h ++++ b/arch/arm64/include/asm/hyperv-tlfs.h +@@ -64,6 +64,15 @@ + #define HV_REGISTER_STIMER0_CONFIG 0x000B0000 + #define HV_REGISTER_STIMER0_COUNT 0x000B0001 + ++union hv_msi_entry { ++ u64 as_uint64[2]; ++ struct { ++ u64 address; ++ u32 data; ++ u32 reserved; ++ } __packed; ++}; ++ + #include + + #endif +diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig +index 43e615aa12ff..d98fafdd0f99 100644 +--- a/drivers/pci/Kconfig ++++ b/drivers/pci/Kconfig +@@ -184,7 +184,7 @@ config PCI_LABEL + + config PCI_HYPERV + tristate "Hyper-V PCI Frontend" +- depends on X86_64 && HYPERV && PCI_MSI && PCI_MSI_IRQ_DOMAIN && SYSFS ++ depends on ((X86 && X86_64) || ARM64) && HYPERV && PCI_MSI && PCI_MSI_IRQ_DOMAIN && SYSFS + select PCI_HYPERV_INTERFACE + help + The PCI device frontend driver allows the kernel to import arbitrary +diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig +index 93b141110537..2536abcc045a 100644 +--- a/drivers/pci/controller/Kconfig ++++ b/drivers/pci/controller/Kconfig +@@ -281,7 +281,7 @@ config PCIE_BRCMSTB + + config PCI_HYPERV_INTERFACE + tristate "Hyper-V PCI Interface" +- depends on X86 && HYPERV && PCI_MSI && PCI_MSI_IRQ_DOMAIN && X86_64 ++ depends on ((X86 && X86_64) || ARM64) && HYPERV && PCI_MSI && PCI_MSI_IRQ_DOMAIN + help + The Hyper-V PCI Interface is a helper driver allows other drivers to + have a common interface with the Hyper-V PCI frontend driver. +diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c +index ead7d6cb6bf1..31743f93199e 100644 +--- a/drivers/pci/controller/pci-hyperv.c ++++ b/drivers/pci/controller/pci-hyperv.c +@@ -47,6 +47,8 @@ + #include + #include + #include ++#include ++#include + #include + + /* +@@ -614,7 +616,230 @@ static int hv_msi_prepare(struct irq_domain *domain, struct device *dev, + { + return pci_msi_prepare(domain, dev, nvec, info); + } +-#endif /* CONFIG_X86 */ ++#elif defined(CONFIG_ARM64) ++/* ++ * SPI vectors to use for vPCI; arch SPIs range is [32, 1019], but leaving a bit ++ * of room at the start to allow for SPIs to be specified through ACPI and ++ * starting with a power of two to satisfy power of 2 multi-MSI requirement. ++ */ ++#define HV_PCI_MSI_SPI_START 64 ++#define HV_PCI_MSI_SPI_NR (1020 - HV_PCI_MSI_SPI_START) ++#define DELIVERY_MODE 0 ++#define FLOW_HANDLER NULL ++#define FLOW_NAME NULL ++#define hv_msi_prepare NULL ++ ++struct hv_pci_chip_data { ++ DECLARE_BITMAP(spi_map, HV_PCI_MSI_SPI_NR); ++ struct mutex map_lock; ++}; ++ ++/* Hyper-V vPCI MSI GIC IRQ domain */ ++static struct irq_domain *hv_msi_gic_irq_domain; ++ ++/* Hyper-V PCI MSI IRQ chip */ ++static struct irq_chip hv_arm64_msi_irq_chip = { ++ .name = "MSI", ++ .irq_set_affinity = irq_chip_set_affinity_parent, ++ .irq_eoi = irq_chip_eoi_parent, ++ .irq_mask = irq_chip_mask_parent, ++ .irq_unmask = irq_chip_unmask_parent ++}; ++ ++static unsigned int hv_msi_get_int_vector(struct irq_data *irqd) ++{ ++ return irqd->parent_data->hwirq; ++} ++ ++static void hv_set_msi_entry_from_desc(union hv_msi_entry *msi_entry, ++ struct msi_desc *msi_desc) ++{ ++ msi_entry->address = ((u64)msi_desc->msg.address_hi << 32) | ++ msi_desc->msg.address_lo; ++ msi_entry->data = msi_desc->msg.data; ++} ++ ++/* ++ * @nr_bm_irqs: Indicates the number of IRQs that were allocated from ++ * the bitmap. ++ * @nr_dom_irqs: Indicates the number of IRQs that were allocated from ++ * the parent domain. ++ */ ++static void hv_pci_vec_irq_free(struct irq_domain *domain, ++ unsigned int virq, ++ unsigned int nr_bm_irqs, ++ unsigned int nr_dom_irqs) ++{ ++ struct hv_pci_chip_data *chip_data = domain->host_data; ++ struct irq_data *d = irq_domain_get_irq_data(domain, virq); ++ int first = d->hwirq - HV_PCI_MSI_SPI_START; ++ int i; ++ ++ mutex_lock(&chip_data->map_lock); ++ bitmap_release_region(chip_data->spi_map, ++ first, ++ get_count_order(nr_bm_irqs)); ++ mutex_unlock(&chip_data->map_lock); ++ for (i = 0; i < nr_dom_irqs; i++) { ++ if (i) ++ d = irq_domain_get_irq_data(domain, virq + i); ++ irq_domain_reset_irq_data(d); ++ } ++ ++ irq_domain_free_irqs_parent(domain, virq, nr_dom_irqs); ++} ++ ++static void hv_pci_vec_irq_domain_free(struct irq_domain *domain, ++ unsigned int virq, ++ unsigned int nr_irqs) ++{ ++ hv_pci_vec_irq_free(domain, virq, nr_irqs, nr_irqs); ++} ++ ++static int hv_pci_vec_alloc_device_irq(struct irq_domain *domain, ++ unsigned int nr_irqs, ++ irq_hw_number_t *hwirq) ++{ ++ struct hv_pci_chip_data *chip_data = domain->host_data; ++ int index; ++ ++ /* Find and allocate region from the SPI bitmap */ ++ mutex_lock(&chip_data->map_lock); ++ index = bitmap_find_free_region(chip_data->spi_map, ++ HV_PCI_MSI_SPI_NR, ++ get_count_order(nr_irqs)); ++ mutex_unlock(&chip_data->map_lock); ++ if (index < 0) ++ return -ENOSPC; ++ ++ *hwirq = index + HV_PCI_MSI_SPI_START; ++ ++ return 0; ++} ++ ++static int hv_pci_vec_irq_gic_domain_alloc(struct irq_domain *domain, ++ unsigned int virq, ++ irq_hw_number_t hwirq) ++{ ++ struct irq_fwspec fwspec; ++ struct irq_data *d; ++ int ret; ++ ++ fwspec.fwnode = domain->parent->fwnode; ++ fwspec.param_count = 2; ++ fwspec.param[0] = hwirq; ++ fwspec.param[1] = IRQ_TYPE_EDGE_RISING; ++ ++ ret = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec); ++ if (ret) ++ return ret; ++ ++ /* ++ * Since the interrupt specifier is not coming from ACPI or DT, the ++ * trigger type will need to be set explicitly. Otherwise, it will be ++ * set to whatever is in the GIC configuration. ++ */ ++ d = irq_domain_get_irq_data(domain->parent, virq); ++ ++ return d->chip->irq_set_type(d, IRQ_TYPE_EDGE_RISING); ++} ++ ++static int hv_pci_vec_irq_domain_alloc(struct irq_domain *domain, ++ unsigned int virq, unsigned int nr_irqs, ++ void *args) ++{ ++ irq_hw_number_t hwirq; ++ unsigned int i; ++ int ret; ++ ++ ret = hv_pci_vec_alloc_device_irq(domain, nr_irqs, &hwirq); ++ if (ret) ++ return ret; ++ ++ for (i = 0; i < nr_irqs; i++) { ++ ret = hv_pci_vec_irq_gic_domain_alloc(domain, virq + i, ++ hwirq + i); ++ if (ret) { ++ hv_pci_vec_irq_free(domain, virq, nr_irqs, i); ++ return ret; ++ } ++ ++ irq_domain_set_hwirq_and_chip(domain, virq + i, ++ hwirq + i, ++ &hv_arm64_msi_irq_chip, ++ domain->host_data); ++ pr_debug("pID:%d vID:%u\n", (int)(hwirq + i), virq + i); ++ } ++ ++ return 0; ++} ++ ++/* ++ * Pick the first cpu as the irq affinity that can be temporarily used for ++ * composing MSI from the hypervisor. GIC will eventually set the right ++ * affinity for the irq and the 'unmask' will retarget the interrupt to that ++ * cpu. ++ */ ++static int hv_pci_vec_irq_domain_activate(struct irq_domain *domain, ++ struct irq_data *irqd, bool reserve) ++{ ++ int cpu = cpumask_first(cpu_present_mask); ++ ++ irq_data_update_effective_affinity(irqd, cpumask_of(cpu)); ++ ++ return 0; ++} ++ ++static const struct irq_domain_ops hv_pci_domain_ops = { ++ .alloc = hv_pci_vec_irq_domain_alloc, ++ .free = hv_pci_vec_irq_domain_free, ++ .activate = hv_pci_vec_irq_domain_activate, ++}; ++ ++static int hv_pci_irqchip_init(void) ++{ ++ static struct hv_pci_chip_data *chip_data; ++ struct fwnode_handle *fn = NULL; ++ int ret = -ENOMEM; ++ ++ chip_data = kzalloc(sizeof(*chip_data), GFP_KERNEL); ++ if (!chip_data) ++ return ret; ++ ++ mutex_init(&chip_data->map_lock); ++ fn = irq_domain_alloc_named_fwnode("hv_vpci_arm64"); ++ if (!fn) ++ goto free_chip; ++ ++ /* ++ * IRQ domain once enabled, should not be removed since there is no ++ * way to ensure that all the corresponding devices are also gone and ++ * no interrupts will be generated. ++ */ ++ hv_msi_gic_irq_domain = acpi_irq_create_hierarchy(0, HV_PCI_MSI_SPI_NR, ++ fn, &hv_pci_domain_ops, ++ chip_data); ++ ++ if (!hv_msi_gic_irq_domain) { ++ pr_err("Failed to create Hyper-V arm64 vPCI MSI IRQ domain\n"); ++ goto free_chip; ++ } ++ ++ return 0; ++ ++free_chip: ++ kfree(chip_data); ++ if (fn) ++ irq_domain_free_fwnode(fn); ++ ++ return ret; ++} ++ ++static struct irq_domain *hv_pci_get_root_domain(void) ++{ ++ return hv_msi_gic_irq_domain; ++} ++#endif /* CONFIG_ARM64 */ + + /** + * hv_pci_generic_compl() - Invoked for a completion packet +@@ -1227,6 +1452,8 @@ static void hv_msi_free(struct irq_domain *domain, struct msi_domain_info *info, + static void hv_irq_mask(struct irq_data *data) + { + pci_msi_mask_irq(data); ++ if (data->parent_data->chip->irq_mask) ++ irq_chip_mask_parent(data); + } + + /** +@@ -1343,6 +1570,8 @@ static void hv_irq_unmask(struct irq_data *data) + dev_err(&hbus->hdev->device, + "%s() failed: %#llx", __func__, res); + ++ if (data->parent_data->chip->irq_unmask) ++ irq_chip_unmask_parent(data); + pci_msi_unmask_irq(data); + } + +@@ -1618,7 +1847,11 @@ static struct irq_chip hv_msi_irq_chip = { + .name = "Hyper-V PCIe MSI", + .irq_compose_msi_msg = hv_compose_msi_msg, + .irq_set_affinity = irq_chip_set_affinity_parent, ++#ifdef CONFIG_X86 + .irq_ack = irq_chip_ack_parent, ++#elif defined(CONFIG_ARM64) ++ .irq_eoi = irq_chip_eoi_parent, ++#endif + .irq_mask = hv_irq_mask, + .irq_unmask = hv_irq_unmask, + }; +-- +2.32.0 +