Message ID | 20240623142235.024567623@linutronix.de (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | genirq, irqchip: Convert ARM MSI handling to per device MSI domains | expand |
Hi Thomas, On Sun, Jun 23, 2024 at 05:18:39PM +0200, Thomas Gleixner wrote: > From: Thomas Gleixner <tglx@linutronix.de> > > The its_pci_msi_prepare() function from the ITS-PCI/MSI code provides the > 'global' PCI/MSI domains. Move this function to the ITS-MSI parent code and > amend the function to use the domain hardware size, which is the MSI[X] > vector count, for allocating the ITS slots for the PCI device. > > Enable PCI matching in msi_parent_ops and provide the necessary update to > the ITS specific child domain initialization function so that the prepare > callback gets invoked on allocations. > > The latter might be optimized to do the allocation right at the point where > the child domain is initialized, but keep it simple for now. > > Signed-off-by: Thomas Gleixner <tglx@linutronix.de> > Signed-off-by: Anna-Maria Behnsen <anna-maria@linutronix.de> > Signed-off-by: Shivamurthy Shastri <shivamurthy.shastri@linutronix.de> > Signed-off-by: Thomas Gleixner <tglx@linutronix.de> I just noticed guests (under KVM) failing to boot on my TX2 with your latest branch. I bisected to this patch as the first bad commit. I'm away this weekend, so won't have time to dive deeper. It looks like the CPU is stuck in do_idle() (no timer interrupts?). Also sysrq did not seem able to get the stack trace on the other CPUs. It fails both with a single or multiple CPUs in the same way place (shortly before mounting the rootfs and starting user space). Not sure whether it's related by Red Hat's CI is also reporting boot failures: https://lore.kernel.org/r/66859.124062817530400571@us-mta-477.us.mimecast.lan I'll drop your branch from the arm64 for-kernelci for now and have a look again on Monday.
On Fri, Jun 28 2024 at 23:24, Catalin Marinas wrote: > I just noticed guests (under KVM) failing to boot on my TX2 with your > latest branch. I bisected to this patch as the first bad commit. > > I'm away this weekend, so won't have time to dive deeper. It looks like > the CPU is stuck in do_idle() (no timer interrupts?). Also sysrq did not > seem able to get the stack trace on the other CPUs. It fails both with a > single or multiple CPUs in the same way place (shortly before mounting > the rootfs and starting user space). From the RH log it's clear that PCI interrupts are not delivered. > I'll drop your branch from the arm64 for-kernelci for now and have a > look again on Monday. I stare too. Unfortunately I don't have access to such hardware :( Thanks, Thomas
On Fri, 28 Jun 2024 23:24:56 +0100, Catalin Marinas <catalin.marinas@arm.com> wrote: > > Hi Thomas, > > On Sun, Jun 23, 2024 at 05:18:39PM +0200, Thomas Gleixner wrote: > > From: Thomas Gleixner <tglx@linutronix.de> > > > > The its_pci_msi_prepare() function from the ITS-PCI/MSI code provides the > > 'global' PCI/MSI domains. Move this function to the ITS-MSI parent code and > > amend the function to use the domain hardware size, which is the MSI[X] > > vector count, for allocating the ITS slots for the PCI device. > > > > Enable PCI matching in msi_parent_ops and provide the necessary update to > > the ITS specific child domain initialization function so that the prepare > > callback gets invoked on allocations. > > > > The latter might be optimized to do the allocation right at the point where > > the child domain is initialized, but keep it simple for now. > > > > Signed-off-by: Thomas Gleixner <tglx@linutronix.de> > > Signed-off-by: Anna-Maria Behnsen <anna-maria@linutronix.de> > > Signed-off-by: Shivamurthy Shastri <shivamurthy.shastri@linutronix.de> > > Signed-off-by: Thomas Gleixner <tglx@linutronix.de> > > I just noticed guests (under KVM) failing to boot on my TX2 with your > latest branch. I bisected to this patch as the first bad commit. Reproduced here on a different host (M1), so this is not specific to TX2 (which would have been odd since KVM emulates the ITS entirely). I'll start digging. M.
On Sat, 29 Jun 2024 09:37:59 +0100, Thomas Gleixner <tglx@linutronix.de> wrote: > > On Fri, Jun 28 2024 at 23:24, Catalin Marinas wrote: > > I just noticed guests (under KVM) failing to boot on my TX2 with your > > latest branch. I bisected to this patch as the first bad commit. > > > > I'm away this weekend, so won't have time to dive deeper. It looks like > > the CPU is stuck in do_idle() (no timer interrupts?). Also sysrq did not > > seem able to get the stack trace on the other CPUs. It fails both with a > > single or multiple CPUs in the same way place (shortly before mounting > > the rootfs and starting user space). > > From the RH log it's clear that PCI interrupts are not delivered. > > > I'll drop your branch from the arm64 for-kernelci for now and have a > > look again on Monday. > > I stare too. Unfortunately I don't have access to such hardware :( On the face of it, the LPIs are never unmasked (grepping in /sys/kernel/debug/kvm/*/vgic-state): Distributor =========== vgic_model: GICv3 nr_spis: 32 nr_lpis: 7 enabled: 1 P=pending_latch, L=line_level, A=active E=enabled, H=hw, C=config (level=1, edge=0) G=group VCPU 0 TYP ID TGT_ID PLAEHCG HWID TARGET SRC PRI VCPU_ID ---------------------------------------------------------------- [...] LPI 8192 0 1000001 0 0 0 160 -1 LPI 8193 1 0000001 0 0 0 160 -1 LPI 8194 2 0000001 0 0 0 160 -1 LPI 8256 3 0000001 0 0 0 160 -1 LPI 8257 4 0000001 0 0 0 160 -1 LPI 8320 5 0000001 0 0 0 160 -1 LPI 8321 6 1000001 0 0 0 160 -1 8192 and 8321 are pending, but never enabled. This is further confirmed by placing traces in the guest. Now trying to find my way through the new maze of callbacks, because something is clearly missing there. M.
On Sat, 29 Jun 2024 10:42:35 +0100, Marc Zyngier <maz@kernel.org> wrote: > > On Sat, 29 Jun 2024 09:37:59 +0100, > Thomas Gleixner <tglx@linutronix.de> wrote: > > > > On Fri, Jun 28 2024 at 23:24, Catalin Marinas wrote: > > > I just noticed guests (under KVM) failing to boot on my TX2 with your > > > latest branch. I bisected to this patch as the first bad commit. > > > > > > I'm away this weekend, so won't have time to dive deeper. It looks like > > > the CPU is stuck in do_idle() (no timer interrupts?). Also sysrq did not > > > seem able to get the stack trace on the other CPUs. It fails both with a > > > single or multiple CPUs in the same way place (shortly before mounting > > > the rootfs and starting user space). > > > > From the RH log it's clear that PCI interrupts are not delivered. > > > > > I'll drop your branch from the arm64 for-kernelci for now and have a > > > look again on Monday. > > > > I stare too. Unfortunately I don't have access to such hardware :( > > On the face of it, the LPIs are never unmasked (grepping in > /sys/kernel/debug/kvm/*/vgic-state): > > Distributor > =========== > vgic_model: GICv3 > nr_spis: 32 > nr_lpis: 7 > enabled: 1 > > P=pending_latch, L=line_level, A=active > E=enabled, H=hw, C=config (level=1, edge=0) > G=group > > VCPU 0 TYP ID TGT_ID PLAEHCG HWID TARGET SRC PRI VCPU_ID > ---------------------------------------------------------------- > [...] > LPI 8192 0 1000001 0 0 0 160 -1 > LPI 8193 1 0000001 0 0 0 160 -1 > LPI 8194 2 0000001 0 0 0 160 -1 > LPI 8256 3 0000001 0 0 0 160 -1 > LPI 8257 4 0000001 0 0 0 160 -1 > LPI 8320 5 0000001 0 0 0 160 -1 > LPI 8321 6 1000001 0 0 0 160 -1 > > 8192 and 8321 are pending, but never enabled. > > This is further confirmed by placing traces in the guest. Now trying > to find my way through the new maze of callbacks, because something is > clearly missing there. This is clearly related to MSI_FLAG_PCI_MSI_MASK_PARENT which is not seen as being set from cond_unmask_parent(), and ignoring this condition results in a booting VM. I have the ugly feeling that the flag is applied at the wrong level, or not propagated. M.
On Sat, 29 Jun 2024 10:50:33 +0100, Marc Zyngier <maz@kernel.org> wrote: > > On Sat, 29 Jun 2024 10:42:35 +0100, > Marc Zyngier <maz@kernel.org> wrote: > > > > On Sat, 29 Jun 2024 09:37:59 +0100, > > Thomas Gleixner <tglx@linutronix.de> wrote: > > > > > > On Fri, Jun 28 2024 at 23:24, Catalin Marinas wrote: > > > > I just noticed guests (under KVM) failing to boot on my TX2 with your > > > > latest branch. I bisected to this patch as the first bad commit. > > > > > > > > I'm away this weekend, so won't have time to dive deeper. It looks like > > > > the CPU is stuck in do_idle() (no timer interrupts?). Also sysrq did not > > > > seem able to get the stack trace on the other CPUs. It fails both with a > > > > single or multiple CPUs in the same way place (shortly before mounting > > > > the rootfs and starting user space). > > > > > > From the RH log it's clear that PCI interrupts are not delivered. > > > > > > > I'll drop your branch from the arm64 for-kernelci for now and have a > > > > look again on Monday. > > > > > > I stare too. Unfortunately I don't have access to such hardware :( > > > > On the face of it, the LPIs are never unmasked (grepping in > > /sys/kernel/debug/kvm/*/vgic-state): > > > > Distributor > > =========== > > vgic_model: GICv3 > > nr_spis: 32 > > nr_lpis: 7 > > enabled: 1 > > > > P=pending_latch, L=line_level, A=active > > E=enabled, H=hw, C=config (level=1, edge=0) > > G=group > > > > VCPU 0 TYP ID TGT_ID PLAEHCG HWID TARGET SRC PRI VCPU_ID > > ---------------------------------------------------------------- > > [...] > > LPI 8192 0 1000001 0 0 0 160 -1 > > LPI 8193 1 0000001 0 0 0 160 -1 > > LPI 8194 2 0000001 0 0 0 160 -1 > > LPI 8256 3 0000001 0 0 0 160 -1 > > LPI 8257 4 0000001 0 0 0 160 -1 > > LPI 8320 5 0000001 0 0 0 160 -1 > > LPI 8321 6 1000001 0 0 0 160 -1 > > > > 8192 and 8321 are pending, but never enabled. > > > > This is further confirmed by placing traces in the guest. Now trying > > to find my way through the new maze of callbacks, because something is > > clearly missing there. > > This is clearly related to MSI_FLAG_PCI_MSI_MASK_PARENT which is not > seen as being set from cond_unmask_parent(), and ignoring this > condition results in a booting VM. > > I have the ugly feeling that the flag is applied at the wrong level, > or not propagated. Here's a possible fix. Making the masking at the ITS level optional is not an option (haha). It is the PCI masking that is totally superfluous and that could completely be elided. With this hack, I can boot a GICv3+ITS guest as usual. M. diff --git a/drivers/irqchip/irq-gic-v3-its-msi-parent.c b/drivers/irqchip/irq-gic-v3-its-msi-parent.c index 21daa452ffa6d..b66e64eaae440 100644 --- a/drivers/irqchip/irq-gic-v3-its-msi-parent.c +++ b/drivers/irqchip/irq-gic-v3-its-msi-parent.c @@ -10,13 +10,13 @@ #include "irq-gic-common.h" #include "irq-msi-lib.h" -#define ITS_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ - MSI_FLAG_USE_DEF_CHIP_OPS) +#define ITS_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ + MSI_FLAG_USE_DEF_CHIP_OPS | \ + MSI_FLAG_PCI_MSI_MASK_PARENT) #define ITS_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \ MSI_FLAG_PCI_MSIX | \ - MSI_FLAG_MULTI_PCI_MSI | \ - MSI_FLAG_PCI_MSI_MASK_PARENT) + MSI_FLAG_MULTI_PCI_MSI) #ifdef CONFIG_PCI_MSI static int its_pci_msi_vec_count(struct pci_dev *pdev, void *data)
Marc! On Sat, Jun 29 2024 at 11:11, Marc Zyngier wrote: >> I have the ugly feeling that the flag is applied at the wrong level, >> or not propagated. Indeed. > Here's a possible fix. Making the masking at the ITS level optional is > not an option (haha). It is the PCI masking that is totally > superfluous and that could completely be elided. It's the right fix because ITS requires this bit to be set. Vs. PCI masking, you are right from a pure ITS point of view, but not from the PCI side. PCI can't be unmsaked until there is a valid message and we need to mask it on shutdown. It's not a run time issue at all because PCI/MSI is edge triggered so the mask/unmask dance only matters during startup, shutdown and message update. > With this hack, I can boot a GICv3+ITS guest as usual. It's not a hack. It's the proper solution. Let me fold that back and look at the other PCI conversions which probably have the same issue. Thanks for digging into this. This help is truly welcome right now. Thanks, tglx
On Sat, Jun 29 2024 at 12:44, Thomas Gleixner wrote: >> With this hack, I can boot a GICv3+ITS guest as usual. > > It's not a hack. It's the proper solution. Let me fold that back and > look at the other PCI conversions which probably have the same issue. > > Thanks for digging into this. This help is truly welcome right now. So while I pondered to do it slightly differently for a moment I went back to this approach and fixed up the other affected ones too. Full delta vs. devmsi-arm-v4-1 below. Updated branch: git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git devmsi-arm-v4-2 Thanks, tglx --- diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c index 428132aa26cc..51af63c046ed 100644 --- a/drivers/irqchip/irq-gic-v2m.c +++ b/drivers/irqchip/irq-gic-v2m.c @@ -243,13 +243,14 @@ static void __init gicv2m_teardown(void) } } -#define GICV2M_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ - MSI_FLAG_USE_DEF_CHIP_OPS) + +#define GICV2M_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ + MSI_FLAG_USE_DEF_CHIP_OPS | \ + MSI_FLAG_PCI_MSI_MASK_PARENT) #define GICV2M_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \ MSI_FLAG_PCI_MSIX | \ - MSI_FLAG_MULTI_PCI_MSI | \ - MSI_FLAG_PCI_MSI_MASK_PARENT) + MSI_FLAG_MULTI_PCI_MSI) static struct msi_parent_ops gicv2m_msi_parent_ops = { .supported_flags = GICV2M_MSI_FLAGS_SUPPORTED, diff --git a/drivers/irqchip/irq-gic-v3-its-msi-parent.c b/drivers/irqchip/irq-gic-v3-its-msi-parent.c index 21daa452ffa6..780e1bc9df54 100644 --- a/drivers/irqchip/irq-gic-v3-its-msi-parent.c +++ b/drivers/irqchip/irq-gic-v3-its-msi-parent.c @@ -11,12 +11,12 @@ #include "irq-msi-lib.h" #define ITS_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ - MSI_FLAG_USE_DEF_CHIP_OPS) + MSI_FLAG_USE_DEF_CHIP_OPS | \ + MSI_FLAG_PCI_MSI_MASK_PARENT) #define ITS_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \ MSI_FLAG_PCI_MSIX | \ - MSI_FLAG_MULTI_PCI_MSI | \ - MSI_FLAG_PCI_MSI_MASK_PARENT) + MSI_FLAG_MULTI_PCI_MSI) #ifdef CONFIG_PCI_MSI static int its_pci_msi_vec_count(struct pci_dev *pdev, void *data) diff --git a/drivers/irqchip/irq-gic-v3-mbi.c b/drivers/irqchip/irq-gic-v3-mbi.c index 0aad9699be33..3fe870f8ee17 100644 --- a/drivers/irqchip/irq-gic-v3-mbi.c +++ b/drivers/irqchip/irq-gic-v3-mbi.c @@ -191,12 +191,12 @@ static bool mbi_init_dev_msi_info(struct device *dev, struct irq_domain *domain, } #define MBI_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ - MSI_FLAG_USE_DEF_CHIP_OPS) + MSI_FLAG_USE_DEF_CHIP_OPS | \ + MSI_FLAG_PCI_MSI_MASK_PARENT) #define MBI_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \ MSI_FLAG_PCI_MSIX | \ - MSI_FLAG_MULTI_PCI_MSI | \ - MSI_FLAG_PCI_MSI_MASK_PARENT) + MSI_FLAG_MULTI_PCI_MSI) static const struct msi_parent_ops gic_v3_mbi_msi_parent_ops = { .supported_flags = MBI_MSI_FLAGS_SUPPORTED, diff --git a/drivers/irqchip/irq-msi-lib.c b/drivers/irqchip/irq-msi-lib.c index 15f92ce4d1e8..e93917b98d7d 100644 --- a/drivers/irqchip/irq-msi-lib.c +++ b/drivers/irqchip/irq-msi-lib.c @@ -28,6 +28,7 @@ bool msi_lib_init_dev_msi_info(struct device *dev, struct irq_domain *domain, struct msi_domain_info *info) { const struct msi_parent_ops *pops = real_parent->msi_parent_ops; + u32 required_flags = pops->required_flags; /* * MSI parent domain specific settings. For now there is only the @@ -66,8 +67,10 @@ bool msi_lib_init_dev_msi_info(struct device *dev, struct irq_domain *domain, /* Core managed MSI descriptors */ info->flags = MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS | MSI_FLAG_FREE_MSI_DESCS; - break; + fallthrough; case DOMAIN_BUS_WIRED_TO_MSI: + /* Remove PCI specific flags */ + required_flags &= ~MSI_FLAG_PCI_MSI_MASK_PARENT; break; default: /* @@ -84,7 +87,7 @@ bool msi_lib_init_dev_msi_info(struct device *dev, struct irq_domain *domain, */ info->flags &= pops->supported_flags; /* Enforce the required flags */ - info->flags |= pops->required_flags; + info->flags |= required_flags; /* Chip updates for all child bus types */ if (!info->chip->irq_eoi)
On Sat, Jun 29, 2024 at 09:51:08PM +0200, Thomas Gleixner wrote: > On Sat, Jun 29 2024 at 12:44, Thomas Gleixner wrote: > >> With this hack, I can boot a GICv3+ITS guest as usual. > > > > It's not a hack. It's the proper solution. Let me fold that back and > > look at the other PCI conversions which probably have the same issue. > > > > Thanks for digging into this. This help is truly welcome right now. > > So while I pondered to do it slightly differently for a moment I went > back to this approach and fixed up the other affected ones too. Full > delta vs. devmsi-arm-v4-1 below. > > Updated branch: > > git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git devmsi-arm-v4-2 This seems to work for me as well. I re-added this branch to arm64 for-kernelci for wider exposure. Thanks.
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 6e4f7715206d..c5316634637f 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -33,7 +33,6 @@ obj-$(CONFIG_IRQ_MSI_LIB) += irq-msi-lib.o obj-$(CONFIG_ARM_GIC_V2M) += irq-gic-v2m.o obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-v3-mbi.o irq-gic-common.o obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o irq-gic-v3-its-platform-msi.o irq-gic-v4.o irq-gic-v3-its-msi-parent.o -obj-$(CONFIG_ARM_GIC_V3_ITS_PCI) += irq-gic-v3-its-pci-msi.o obj-$(CONFIG_ARM_GIC_V3_ITS_FSL_MC) += irq-gic-v3-its-fsl-mc-msi.o obj-$(CONFIG_PARTITION_PERCPU) += irq-partition-percpu.o obj-$(CONFIG_HISILICON_IRQ_MBIGEN) += irq-mbigen.o diff --git a/drivers/irqchip/irq-gic-v3-its-msi-parent.c b/drivers/irqchip/irq-gic-v3-its-msi-parent.c index cdc0844229b5..e81fefa428e2 100644 --- a/drivers/irqchip/irq-gic-v3-its-msi-parent.c +++ b/drivers/irqchip/irq-gic-v3-its-msi-parent.c @@ -1,7 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2013-2015 ARM Limited, All Rights Reserved. +// Author: Marc Zyngier <marc.zyngier@arm.com> // Copyright (C) 2022 Linutronix GmbH // Copyright (C) 2022 Intel +#include <linux/pci.h> + #include "irq-gic-common.h" #include "irq-msi-lib.h" @@ -13,12 +17,115 @@ MSI_FLAG_MULTI_PCI_MSI | \ MSI_FLAG_PCI_MSI_MASK_PARENT) +#ifdef CONFIG_PCI_MSI +static int its_pci_msi_vec_count(struct pci_dev *pdev, void *data) +{ + int msi, msix, *count = data; + + msi = max(pci_msi_vec_count(pdev), 0); + msix = max(pci_msix_vec_count(pdev), 0); + *count += max(msi, msix); + + return 0; +} + +static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data) +{ + struct pci_dev **alias_dev = data; + + *alias_dev = pdev; + + return 0; +} + +static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev, + int nvec, msi_alloc_info_t *info) +{ + struct pci_dev *pdev, *alias_dev; + struct msi_domain_info *msi_info; + int alias_count = 0, minnvec = 1; + + if (!dev_is_pci(dev)) + return -EINVAL; + + pdev = to_pci_dev(dev); + /* + * If pdev is downstream of any aliasing bridges, take an upper + * bound of how many other vectors could map to the same DevID. + * Also tell the ITS that the signalling will come from a proxy + * device, and that special allocation rules apply. + */ + pci_for_each_dma_alias(pdev, its_get_pci_alias, &alias_dev); + if (alias_dev != pdev) { + if (alias_dev->subordinate) + pci_walk_bus(alias_dev->subordinate, + its_pci_msi_vec_count, &alias_count); + info->flags |= MSI_ALLOC_FLAGS_PROXY_DEVICE; + } + + /* ITS specific DeviceID, as the core ITS ignores dev. */ + info->scratchpad[0].ul = pci_msi_domain_get_msi_rid(domain, pdev); + + /* + * @domain->msi_domain_info->hwsize contains the size of the + * MSI[-X] domain, but vector allocation happens one by one. This + * needs some thought when MSI comes into play as the size of MSI + * might be unknown at domain creation time and therefore set to + * MSI_MAX_INDEX. + */ + msi_info = msi_get_domain_info(domain); + if (msi_info->hwsize > nvec) + nvec = msi_info->hwsize; + + /* + * Always allocate a power of 2, and special case device 0 for + * broken systems where the DevID is not wired (and all devices + * appear as DevID 0). For that reason, we generously allocate a + * minimum of 32 MSIs for DevID 0. If you want more because all + * your devices are aliasing to DevID 0, consider fixing your HW. + */ + nvec = max(nvec, alias_count); + if (!info->scratchpad[0].ul) + minnvec = 32; + nvec = max_t(int, minnvec, roundup_pow_of_two(nvec)); + + msi_info = msi_get_domain_info(domain->parent); + return msi_info->ops->msi_prepare(domain->parent, dev, nvec, info); +} +#else /* CONFIG_PCI_MSI */ +#define its_pci_msi_prepare NULL +#endif /* !CONFIG_PCI_MSI */ + static bool its_init_dev_msi_info(struct device *dev, struct irq_domain *domain, struct irq_domain *real_parent, struct msi_domain_info *info) { if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info)) return false; + switch(info->bus_token) { + case DOMAIN_BUS_PCI_DEVICE_MSI: + case DOMAIN_BUS_PCI_DEVICE_MSIX: + /* + * FIXME: This probably should be done after a (not yet + * existing) post domain creation callback once to make + * support for dynamic post-enable MSI-X allocations + * work without having to reevaluate the domain size + * over and over. It is known already at allocation + * time via info->hwsize. + * + * That should work perfectly fine for MSI/MSI-X but needs + * some thoughts for purely software managed MSI domains + * where the index space is only limited artificially via + * %MSI_MAX_INDEX. + */ + info->ops->msi_prepare = its_pci_msi_prepare; + break; + default: + /* Confused. How did the lib return true? */ + WARN_ON_ONCE(1); + return false; + } + return true; } @@ -26,6 +133,7 @@ const struct msi_parent_ops gic_v3_its_msi_parent_ops = { .supported_flags = ITS_MSI_FLAGS_SUPPORTED, .required_flags = ITS_MSI_FLAGS_REQUIRED, .bus_select_token = DOMAIN_BUS_NEXUS, + .bus_select_mask = MATCH_PCI_MSI, .prefix = "ITS-", .init_dev_msi_info = its_init_dev_msi_info, }; diff --git a/drivers/irqchip/irq-gic-v3-its-pci-msi.c b/drivers/irqchip/irq-gic-v3-its-pci-msi.c deleted file mode 100644 index 93f77a8196da..000000000000 --- a/drivers/irqchip/irq-gic-v3-its-pci-msi.c +++ /dev/null @@ -1,202 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2013-2015 ARM Limited, All Rights Reserved. - * Author: Marc Zyngier <marc.zyngier@arm.com> - */ - -#include <linux/acpi_iort.h> -#include <linux/pci.h> -#include <linux/msi.h> -#include <linux/of.h> -#include <linux/of_irq.h> -#include <linux/of_pci.h> - -static void its_mask_msi_irq(struct irq_data *d) -{ - pci_msi_mask_irq(d); - irq_chip_mask_parent(d); -} - -static void its_unmask_msi_irq(struct irq_data *d) -{ - pci_msi_unmask_irq(d); - irq_chip_unmask_parent(d); -} - -static struct irq_chip its_msi_irq_chip = { - .name = "ITS-MSI", - .irq_unmask = its_unmask_msi_irq, - .irq_mask = its_mask_msi_irq, - .irq_eoi = irq_chip_eoi_parent, -}; - -static int its_pci_msi_vec_count(struct pci_dev *pdev, void *data) -{ - int msi, msix, *count = data; - - msi = max(pci_msi_vec_count(pdev), 0); - msix = max(pci_msix_vec_count(pdev), 0); - *count += max(msi, msix); - - return 0; -} - -static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data) -{ - struct pci_dev **alias_dev = data; - - *alias_dev = pdev; - - return 0; -} - -static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev, - int nvec, msi_alloc_info_t *info) -{ - struct pci_dev *pdev, *alias_dev; - struct msi_domain_info *msi_info; - int alias_count = 0, minnvec = 1; - - if (!dev_is_pci(dev)) - return -EINVAL; - - msi_info = msi_get_domain_info(domain->parent); - - pdev = to_pci_dev(dev); - /* - * If pdev is downstream of any aliasing bridges, take an upper - * bound of how many other vectors could map to the same DevID. - * Also tell the ITS that the signalling will come from a proxy - * device, and that special allocation rules apply. - */ - pci_for_each_dma_alias(pdev, its_get_pci_alias, &alias_dev); - if (alias_dev != pdev) { - if (alias_dev->subordinate) - pci_walk_bus(alias_dev->subordinate, - its_pci_msi_vec_count, &alias_count); - info->flags |= MSI_ALLOC_FLAGS_PROXY_DEVICE; - } - - /* ITS specific DeviceID, as the core ITS ignores dev. */ - info->scratchpad[0].ul = pci_msi_domain_get_msi_rid(domain, pdev); - - /* - * Always allocate a power of 2, and special case device 0 for - * broken systems where the DevID is not wired (and all devices - * appear as DevID 0). For that reason, we generously allocate a - * minimum of 32 MSIs for DevID 0. If you want more because all - * your devices are aliasing to DevID 0, consider fixing your HW. - */ - nvec = max(nvec, alias_count); - if (!info->scratchpad[0].ul) - minnvec = 32; - nvec = max_t(int, minnvec, roundup_pow_of_two(nvec)); - return msi_info->ops->msi_prepare(domain->parent, dev, nvec, info); -} - -static struct msi_domain_ops its_pci_msi_ops = { - .msi_prepare = its_pci_msi_prepare, -}; - -static struct msi_domain_info its_pci_msi_domain_info = { - .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | - MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX), - .ops = &its_pci_msi_ops, - .chip = &its_msi_irq_chip, -}; - -static struct of_device_id its_device_id[] = { - { .compatible = "arm,gic-v3-its", }, - {}, -}; - -static int __init its_pci_msi_init_one(struct fwnode_handle *handle, - const char *name) -{ - struct irq_domain *parent; - - parent = irq_find_matching_fwnode(handle, DOMAIN_BUS_NEXUS); - if (!parent || !msi_get_domain_info(parent)) { - pr_err("%s: Unable to locate ITS domain\n", name); - return -ENXIO; - } - - if (!pci_msi_create_irq_domain(handle, &its_pci_msi_domain_info, - parent)) { - pr_err("%s: Unable to create PCI domain\n", name); - return -ENOMEM; - } - - return 0; -} - -static int __init its_pci_of_msi_init(void) -{ - struct device_node *np; - - for (np = of_find_matching_node(NULL, its_device_id); np; - np = of_find_matching_node(np, its_device_id)) { - if (!of_device_is_available(np)) - continue; - if (!of_property_read_bool(np, "msi-controller")) - continue; - - if (its_pci_msi_init_one(of_node_to_fwnode(np), np->full_name)) - continue; - - pr_info("PCI/MSI: %pOF domain created\n", np); - } - - return 0; -} - -#ifdef CONFIG_ACPI - -static int __init -its_pci_msi_parse_madt(union acpi_subtable_headers *header, - const unsigned long end) -{ - struct acpi_madt_generic_translator *its_entry; - struct fwnode_handle *dom_handle; - const char *node_name; - int err = -ENXIO; - - its_entry = (struct acpi_madt_generic_translator *)header; - node_name = kasprintf(GFP_KERNEL, "ITS@0x%lx", - (long)its_entry->base_address); - dom_handle = iort_find_domain_token(its_entry->translation_id); - if (!dom_handle) { - pr_err("%s: Unable to locate ITS domain handle\n", node_name); - goto out; - } - - err = its_pci_msi_init_one(dom_handle, node_name); - if (!err) - pr_info("PCI/MSI: %s domain created\n", node_name); - -out: - kfree(node_name); - return err; -} - -static int __init its_pci_acpi_msi_init(void) -{ - acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR, - its_pci_msi_parse_madt, 0); - return 0; -} -#else -static int __init its_pci_acpi_msi_init(void) -{ - return 0; -} -#endif - -static int __init its_pci_msi_init(void) -{ - its_pci_of_msi_init(); - its_pci_acpi_msi_init(); - - return 0; -} -early_initcall(its_pci_msi_init);