[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250212014321.1108840-7-romank@linux.microsoft.com>
Date: Tue, 11 Feb 2025 17:43:21 -0800
From: Roman Kisel <romank@...ux.microsoft.com>
To: arnd@...db.de,
bhelgaas@...gle.com,
bp@...en8.de,
catalin.marinas@....com,
conor+dt@...nel.org,
dave.hansen@...ux.intel.com,
decui@...rosoft.com,
haiyangz@...rosoft.com,
hpa@...or.com,
krzk+dt@...nel.org,
kw@...ux.com,
kys@...rosoft.com,
lpieralisi@...nel.org,
manivannan.sadhasivam@...aro.org,
mingo@...hat.com,
robh@...nel.org,
ssengar@...ux.microsoft.com,
tglx@...utronix.de,
wei.liu@...nel.org,
will@...nel.org,
devicetree@...r.kernel.org,
linux-arch@...r.kernel.org,
linux-arm-kernel@...ts.infradead.org,
linux-hyperv@...r.kernel.org,
linux-kernel@...r.kernel.org,
linux-pci@...r.kernel.org,
x86@...nel.org
Cc: benhill@...rosoft.com,
bperkins@...rosoft.com,
sunilmut@...rosoft.com
Subject: [PATCH hyperv-next v4 6/6] PCI: hv: Get vPCI MSI IRQ domain from DeviceTree
The hyperv-pci driver uses ACPI for MSI IRQ domain configuration on
arm64. It won't be able to do that in the VTL mode where only DeviceTree
can be used.
Update the hyperv-pci driver to get vPCI MSI IRQ domain in the DeviceTree
case, too.
Signed-off-by: Roman Kisel <romank@...ux.microsoft.com>
---
drivers/hv/vmbus_drv.c | 23 ++++++----
drivers/pci/controller/pci-hyperv.c | 69 ++++++++++++++++++++++++++---
include/linux/hyperv.h | 2 +
3 files changed, 80 insertions(+), 14 deletions(-)
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 9d0c2dbd2a69..3f0f9f01b520 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -45,7 +45,8 @@ struct vmbus_dynid {
struct hv_vmbus_device_id id;
};
-static struct device *hv_dev;
+/* VMBus Root Device */
+static struct device *vmbus_root_device;
static int hyperv_cpuhp_online;
@@ -80,9 +81,15 @@ static struct resource *fb_mmio;
static struct resource *hyperv_mmio;
static DEFINE_MUTEX(hyperv_mmio_lock);
+struct device *hv_get_vmbus_root_device(void)
+{
+ return vmbus_root_device;
+}
+EXPORT_SYMBOL_GPL(hv_get_vmbus_root_device);
+
static int vmbus_exists(void)
{
- if (hv_dev == NULL)
+ if (vmbus_root_device == NULL)
return -ENODEV;
return 0;
@@ -861,7 +868,7 @@ static int vmbus_dma_configure(struct device *child_device)
* On x86/x64 coherence is assumed and these calls have no effect.
*/
hv_setup_dma_ops(child_device,
- device_get_dma_attr(hv_dev) == DEV_DMA_COHERENT);
+ device_get_dma_attr(vmbus_root_device) == DEV_DMA_COHERENT);
return 0;
}
@@ -1920,7 +1927,7 @@ int vmbus_device_register(struct hv_device *child_device_obj)
&child_device_obj->channel->offermsg.offer.if_instance);
child_device_obj->device.bus = &hv_bus;
- child_device_obj->device.parent = hv_dev;
+ child_device_obj->device.parent = vmbus_root_device;
child_device_obj->device.release = vmbus_device_release;
child_device_obj->device.dma_parms = &child_device_obj->dma_parms;
@@ -2282,7 +2289,7 @@ static int vmbus_acpi_add(struct platform_device *pdev)
struct acpi_device *ancestor;
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
- hv_dev = &device->dev;
+ vmbus_root_device = &device->dev;
/*
* Older versions of Hyper-V for ARM64 fail to include the _CCA
@@ -2373,7 +2380,7 @@ static int vmbus_device_add(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
int ret;
- hv_dev = &pdev->dev;
+ vmbus_root_device = &pdev->dev;
ret = of_range_parser_init(&parser, np);
if (ret)
@@ -2692,7 +2699,7 @@ static int __init hv_acpi_init(void)
if (ret)
return ret;
- if (!hv_dev) {
+ if (!vmbus_root_device) {
ret = -ENODEV;
goto cleanup;
}
@@ -2723,7 +2730,7 @@ static int __init hv_acpi_init(void)
cleanup:
platform_driver_unregister(&vmbus_platform_driver);
- hv_dev = NULL;
+ vmbus_root_device = NULL;
return ret;
}
diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c
index cdd5be16021d..24725bea9ef1 100644
--- a/drivers/pci/controller/pci-hyperv.c
+++ b/drivers/pci/controller/pci-hyperv.c
@@ -50,6 +50,7 @@
#include <linux/irqdomain.h>
#include <linux/acpi.h>
#include <linux/sizes.h>
+#include <linux/of_irq.h>
#include <asm/mshyperv.h>
/*
@@ -817,9 +818,17 @@ static int hv_pci_vec_irq_gic_domain_alloc(struct irq_domain *domain,
int ret;
fwspec.fwnode = domain->parent->fwnode;
- fwspec.param_count = 2;
- fwspec.param[0] = hwirq;
- fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
+ if (is_of_node(fwspec.fwnode)) {
+ /* SPI lines for OF translations start at offset 32 */
+ fwspec.param_count = 3;
+ fwspec.param[0] = 0;
+ fwspec.param[1] = hwirq - 32;
+ fwspec.param[2] = IRQ_TYPE_EDGE_RISING;
+ } else {
+ 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)
@@ -887,6 +896,35 @@ static const struct irq_domain_ops hv_pci_domain_ops = {
.activate = hv_pci_vec_irq_domain_activate,
};
+#ifdef CONFIG_OF
+
+static struct irq_domain *hv_pci_of_irq_domain_parent(void)
+{
+ struct device_node *parent;
+ struct irq_domain *domain;
+
+ parent = of_irq_find_parent(hv_get_vmbus_root_device()->of_node);
+ domain = NULL;
+ if (parent) {
+ domain = irq_find_host(parent);
+ of_node_put(parent);
+ }
+
+ /*
+ * `domain == NULL` shouldn't happen.
+ *
+ * If somehow the code does end up in that state, treat this as a configuration
+ * issue rather than a hard error, emit a warning, and let the code proceed.
+ * The NULL parent domain is an acceptable option for the `irq_domain_create_hierarchy`
+ * function called later.
+ */
+ if (!domain)
+ WARN_ONCE(1, "No interrupt-parent found, check the DeviceTree data.\n");
+ return domain;
+}
+
+#endif
+
static int hv_pci_irqchip_init(void)
{
static struct hv_pci_chip_data *chip_data;
@@ -906,10 +944,29 @@ static int hv_pci_irqchip_init(void)
* 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.
+ *
+ * In the ACPI case, the parent IRQ domain is supplied by the ACPI
+ * subsystem, and it is the default GSI domain pointing to the GIC.
+ * Neither is available outside of the ACPI subsystem, cannot avoid
+ * the messy ifdef below.
+ * There is apparently no such default in the OF subsystem, and
+ * `hv_pci_of_irq_domain_parent` finds the parent IRQ domain that
+ * points to the GIC as well.
+ * None of these two cases reaches for the MSI parent domain.
*/
- hv_msi_gic_irq_domain = acpi_irq_create_hierarchy(0, HV_PCI_MSI_SPI_NR,
- fn, &hv_pci_domain_ops,
- chip_data);
+#ifdef CONFIG_ACPI
+ if (!acpi_disabled)
+ hv_msi_gic_irq_domain = acpi_irq_create_hierarchy(0, HV_PCI_MSI_SPI_NR,
+ fn, &hv_pci_domain_ops,
+ chip_data);
+#endif
+#if defined(CONFIG_OF)
+ if (!hv_msi_gic_irq_domain)
+ hv_msi_gic_irq_domain = irq_domain_create_hierarchy(
+ hv_pci_of_irq_domain_parent(), 0, HV_PCI_MSI_SPI_NR,
+ fn, &hv_pci_domain_ops,
+ chip_data);
+#endif
if (!hv_msi_gic_irq_domain) {
pr_err("Failed to create Hyper-V arm64 vPCI MSI IRQ domain\n");
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 4179add2864b..2be4dd83b0e1 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -1333,6 +1333,8 @@ static inline void *hv_get_drvdata(struct hv_device *dev)
return dev_get_drvdata(&dev->device);
}
+struct device *hv_get_vmbus_root_device(void);
+
struct hv_ring_buffer_debug_info {
u32 current_interrupt_mask;
u32 current_read_index;
--
2.43.0
Powered by blists - more mailing lists