Skip to content

Commit b5712bf

Browse files
committed
irqchip/gic-v3-its: Provide MSI parent for PCI/MSI[-X]
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 <[email protected]> Signed-off-by: Anna-Maria Behnsen <[email protected]> Signed-off-by: Shivamurthy Shastri <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 8c41cce commit b5712bf

File tree

3 files changed

+111
-206
lines changed

3 files changed

+111
-206
lines changed

drivers/irqchip/Makefile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ obj-$(CONFIG_IRQ_MSI_LIB) += irq-msi-lib.o
3333
obj-$(CONFIG_ARM_GIC_V2M) += irq-gic-v2m.o
3434
obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-v3-mbi.o irq-gic-common.o
3535
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
36-
obj-$(CONFIG_ARM_GIC_V3_ITS_PCI) += irq-gic-v3-its-pci-msi.o
3736
obj-$(CONFIG_ARM_GIC_V3_ITS_FSL_MC) += irq-gic-v3-its-fsl-mc-msi.o
3837
obj-$(CONFIG_PARTITION_PERCPU) += irq-partition-percpu.o
3938
obj-$(CONFIG_HISILICON_IRQ_MBIGEN) += irq-mbigen.o
Lines changed: 111 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,139 @@
11
// SPDX-License-Identifier: GPL-2.0-only
2+
// Copyright (C) 2013-2015 ARM Limited, All Rights Reserved.
3+
// Author: Marc Zyngier <[email protected]>
24
// Copyright (C) 2022 Linutronix GmbH
35
// Copyright (C) 2022 Intel
46

7+
#include <linux/pci.h>
8+
59
#include "irq-gic-common.h"
610
#include "irq-msi-lib.h"
711

812
#define ITS_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \
9-
MSI_FLAG_USE_DEF_CHIP_OPS)
13+
MSI_FLAG_USE_DEF_CHIP_OPS | \
14+
MSI_FLAG_PCI_MSI_MASK_PARENT)
1015

1116
#define ITS_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \
1217
MSI_FLAG_PCI_MSIX | \
13-
MSI_FLAG_MULTI_PCI_MSI | \
14-
MSI_FLAG_PCI_MSI_MASK_PARENT)
18+
MSI_FLAG_MULTI_PCI_MSI)
19+
20+
#ifdef CONFIG_PCI_MSI
21+
static int its_pci_msi_vec_count(struct pci_dev *pdev, void *data)
22+
{
23+
int msi, msix, *count = data;
24+
25+
msi = max(pci_msi_vec_count(pdev), 0);
26+
msix = max(pci_msix_vec_count(pdev), 0);
27+
*count += max(msi, msix);
28+
29+
return 0;
30+
}
31+
32+
static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data)
33+
{
34+
struct pci_dev **alias_dev = data;
35+
36+
*alias_dev = pdev;
37+
38+
return 0;
39+
}
40+
41+
static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev,
42+
int nvec, msi_alloc_info_t *info)
43+
{
44+
struct pci_dev *pdev, *alias_dev;
45+
struct msi_domain_info *msi_info;
46+
int alias_count = 0, minnvec = 1;
47+
48+
if (!dev_is_pci(dev))
49+
return -EINVAL;
50+
51+
pdev = to_pci_dev(dev);
52+
/*
53+
* If pdev is downstream of any aliasing bridges, take an upper
54+
* bound of how many other vectors could map to the same DevID.
55+
* Also tell the ITS that the signalling will come from a proxy
56+
* device, and that special allocation rules apply.
57+
*/
58+
pci_for_each_dma_alias(pdev, its_get_pci_alias, &alias_dev);
59+
if (alias_dev != pdev) {
60+
if (alias_dev->subordinate)
61+
pci_walk_bus(alias_dev->subordinate,
62+
its_pci_msi_vec_count, &alias_count);
63+
info->flags |= MSI_ALLOC_FLAGS_PROXY_DEVICE;
64+
}
65+
66+
/* ITS specific DeviceID, as the core ITS ignores dev. */
67+
info->scratchpad[0].ul = pci_msi_domain_get_msi_rid(domain, pdev);
68+
69+
/*
70+
* @domain->msi_domain_info->hwsize contains the size of the
71+
* MSI[-X] domain, but vector allocation happens one by one. This
72+
* needs some thought when MSI comes into play as the size of MSI
73+
* might be unknown at domain creation time and therefore set to
74+
* MSI_MAX_INDEX.
75+
*/
76+
msi_info = msi_get_domain_info(domain);
77+
if (msi_info->hwsize > nvec)
78+
nvec = msi_info->hwsize;
79+
80+
/*
81+
* Always allocate a power of 2, and special case device 0 for
82+
* broken systems where the DevID is not wired (and all devices
83+
* appear as DevID 0). For that reason, we generously allocate a
84+
* minimum of 32 MSIs for DevID 0. If you want more because all
85+
* your devices are aliasing to DevID 0, consider fixing your HW.
86+
*/
87+
nvec = max(nvec, alias_count);
88+
if (!info->scratchpad[0].ul)
89+
minnvec = 32;
90+
nvec = max_t(int, minnvec, roundup_pow_of_two(nvec));
91+
92+
msi_info = msi_get_domain_info(domain->parent);
93+
return msi_info->ops->msi_prepare(domain->parent, dev, nvec, info);
94+
}
95+
#else /* CONFIG_PCI_MSI */
96+
#define its_pci_msi_prepare NULL
97+
#endif /* !CONFIG_PCI_MSI */
1598

1699
static bool its_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
17100
struct irq_domain *real_parent, struct msi_domain_info *info)
18101
{
19102
if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info))
20103
return false;
21104

105+
switch(info->bus_token) {
106+
case DOMAIN_BUS_PCI_DEVICE_MSI:
107+
case DOMAIN_BUS_PCI_DEVICE_MSIX:
108+
/*
109+
* FIXME: This probably should be done after a (not yet
110+
* existing) post domain creation callback once to make
111+
* support for dynamic post-enable MSI-X allocations
112+
* work without having to reevaluate the domain size
113+
* over and over. It is known already at allocation
114+
* time via info->hwsize.
115+
*
116+
* That should work perfectly fine for MSI/MSI-X but needs
117+
* some thoughts for purely software managed MSI domains
118+
* where the index space is only limited artificially via
119+
* %MSI_MAX_INDEX.
120+
*/
121+
info->ops->msi_prepare = its_pci_msi_prepare;
122+
break;
123+
default:
124+
/* Confused. How did the lib return true? */
125+
WARN_ON_ONCE(1);
126+
return false;
127+
}
128+
22129
return true;
23130
}
24131

25132
const struct msi_parent_ops gic_v3_its_msi_parent_ops = {
26133
.supported_flags = ITS_MSI_FLAGS_SUPPORTED,
27134
.required_flags = ITS_MSI_FLAGS_REQUIRED,
28135
.bus_select_token = DOMAIN_BUS_NEXUS,
136+
.bus_select_mask = MATCH_PCI_MSI,
29137
.prefix = "ITS-",
30138
.init_dev_msi_info = its_init_dev_msi_info,
31139
};

drivers/irqchip/irq-gic-v3-its-pci-msi.c

Lines changed: 0 additions & 202 deletions
This file was deleted.

0 commit comments

Comments
 (0)