1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright (C) 2013-2015 ARM Limited, All Rights Reserved.
3 // Author: Marc Zyngier <marc.zyngier@arm.com>
4 // Copyright (C) 2022 Linutronix GmbH
5 // Copyright (C) 2022 Intel
6
7 #include <linux/acpi_iort.h>
8 #include <linux/pci.h>
9
10 #include "irq-gic-common.h"
11 #include <linux/irqchip/irq-msi-lib.h>
12
13 #define ITS_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \
14 MSI_FLAG_USE_DEF_CHIP_OPS | \
15 MSI_FLAG_PCI_MSI_MASK_PARENT)
16
17 #define ITS_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \
18 MSI_FLAG_PCI_MSIX | \
19 MSI_FLAG_MULTI_PCI_MSI)
20
21 #ifdef CONFIG_PCI_MSI
its_pci_msi_vec_count(struct pci_dev * pdev,void * data)22 static int its_pci_msi_vec_count(struct pci_dev *pdev, void *data)
23 {
24 int msi, msix, *count = data;
25
26 msi = max(pci_msi_vec_count(pdev), 0);
27 msix = max(pci_msix_vec_count(pdev), 0);
28 *count += max(msi, msix);
29
30 return 0;
31 }
32
its_get_pci_alias(struct pci_dev * pdev,u16 alias,void * data)33 static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data)
34 {
35 struct pci_dev **alias_dev = data;
36
37 *alias_dev = pdev;
38
39 return 0;
40 }
41
its_pci_msi_prepare(struct irq_domain * domain,struct device * dev,int nvec,msi_alloc_info_t * info)42 static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev,
43 int nvec, msi_alloc_info_t *info)
44 {
45 struct pci_dev *pdev, *alias_dev;
46 struct msi_domain_info *msi_info;
47 int alias_count = 0, minnvec = 1;
48
49 if (!dev_is_pci(dev))
50 return -EINVAL;
51
52 pdev = to_pci_dev(dev);
53 /*
54 * If pdev is downstream of any aliasing bridges, take an upper
55 * bound of how many other vectors could map to the same DevID.
56 * Also tell the ITS that the signalling will come from a proxy
57 * device, and that special allocation rules apply.
58 */
59 pci_for_each_dma_alias(pdev, its_get_pci_alias, &alias_dev);
60 if (alias_dev != pdev) {
61 if (alias_dev->subordinate)
62 pci_walk_bus(alias_dev->subordinate,
63 its_pci_msi_vec_count, &alias_count);
64 info->flags |= MSI_ALLOC_FLAGS_PROXY_DEVICE;
65 }
66
67 /* ITS specific DeviceID, as the core ITS ignores dev. */
68 info->scratchpad[0].ul = pci_msi_domain_get_msi_rid(domain->parent, pdev);
69
70 /*
71 * Always allocate a power of 2, and special case device 0 for
72 * broken systems where the DevID is not wired (and all devices
73 * appear as DevID 0). For that reason, we generously allocate a
74 * minimum of 32 MSIs for DevID 0. If you want more because all
75 * your devices are aliasing to DevID 0, consider fixing your HW.
76 */
77 nvec = max(nvec, alias_count);
78 if (!info->scratchpad[0].ul)
79 minnvec = 32;
80 nvec = max_t(int, minnvec, roundup_pow_of_two(nvec));
81
82 msi_info = msi_get_domain_info(domain->parent);
83 return msi_info->ops->msi_prepare(domain->parent, dev, nvec, info);
84 }
85 #else /* CONFIG_PCI_MSI */
86 #define its_pci_msi_prepare NULL
87 #endif /* !CONFIG_PCI_MSI */
88
of_pmsi_get_dev_id(struct irq_domain * domain,struct device * dev,u32 * dev_id)89 static int of_pmsi_get_dev_id(struct irq_domain *domain, struct device *dev,
90 u32 *dev_id)
91 {
92 int ret, index = 0;
93
94 /* Suck the DeviceID out of the msi-parent property */
95 do {
96 struct of_phandle_args args;
97
98 ret = of_parse_phandle_with_args(dev->of_node,
99 "msi-parent", "#msi-cells",
100 index, &args);
101 if (args.np == irq_domain_get_of_node(domain)) {
102 if (WARN_ON(args.args_count != 1))
103 return -EINVAL;
104 *dev_id = args.args[0];
105 break;
106 }
107 index++;
108 } while (!ret);
109
110 if (ret) {
111 struct device_node *np = NULL;
112
113 ret = of_map_id(dev->of_node, dev->id, "msi-map", "msi-map-mask", &np, dev_id);
114 if (np)
115 of_node_put(np);
116 }
117
118 return ret;
119 }
120
iort_pmsi_get_dev_id(struct device * dev,u32 * dev_id)121 int __weak iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id)
122 {
123 return -1;
124 }
125
its_pmsi_prepare(struct irq_domain * domain,struct device * dev,int nvec,msi_alloc_info_t * info)126 static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
127 int nvec, msi_alloc_info_t *info)
128 {
129 struct msi_domain_info *msi_info;
130 u32 dev_id;
131 int ret;
132
133 if (dev->of_node)
134 ret = of_pmsi_get_dev_id(domain->parent, dev, &dev_id);
135 else
136 ret = iort_pmsi_get_dev_id(dev, &dev_id);
137 if (ret)
138 return ret;
139
140 /* ITS specific DeviceID, as the core ITS ignores dev. */
141 info->scratchpad[0].ul = dev_id;
142
143 /* Allocate at least 32 MSIs, and always as a power of 2 */
144 nvec = max_t(int, 32, roundup_pow_of_two(nvec));
145
146 msi_info = msi_get_domain_info(domain->parent);
147 return msi_info->ops->msi_prepare(domain->parent,
148 dev, nvec, info);
149 }
150
its_msi_teardown(struct irq_domain * domain,msi_alloc_info_t * info)151 static void its_msi_teardown(struct irq_domain *domain, msi_alloc_info_t *info)
152 {
153 struct msi_domain_info *msi_info;
154
155 msi_info = msi_get_domain_info(domain->parent);
156 msi_info->ops->msi_teardown(domain->parent, info);
157 }
158
its_init_dev_msi_info(struct device * dev,struct irq_domain * domain,struct irq_domain * real_parent,struct msi_domain_info * info)159 static bool its_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
160 struct irq_domain *real_parent, struct msi_domain_info *info)
161 {
162 if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info))
163 return false;
164
165 switch(info->bus_token) {
166 case DOMAIN_BUS_PCI_DEVICE_MSI:
167 case DOMAIN_BUS_PCI_DEVICE_MSIX:
168 /*
169 * FIXME: This probably should be done after a (not yet
170 * existing) post domain creation callback once to make
171 * support for dynamic post-enable MSI-X allocations
172 * work without having to reevaluate the domain size
173 * over and over. It is known already at allocation
174 * time via info->hwsize.
175 *
176 * That should work perfectly fine for MSI/MSI-X but needs
177 * some thoughts for purely software managed MSI domains
178 * where the index space is only limited artificially via
179 * %MSI_MAX_INDEX.
180 */
181 info->ops->msi_prepare = its_pci_msi_prepare;
182 info->ops->msi_teardown = its_msi_teardown;
183 break;
184 case DOMAIN_BUS_DEVICE_MSI:
185 case DOMAIN_BUS_WIRED_TO_MSI:
186 /*
187 * FIXME: See the above PCI prepare comment. The domain
188 * size is also known at domain creation time.
189 */
190 info->ops->msi_prepare = its_pmsi_prepare;
191 info->ops->msi_teardown = its_msi_teardown;
192 break;
193 default:
194 /* Confused. How did the lib return true? */
195 WARN_ON_ONCE(1);
196 return false;
197 }
198
199 return true;
200 }
201
202 const struct msi_parent_ops gic_v3_its_msi_parent_ops = {
203 .supported_flags = ITS_MSI_FLAGS_SUPPORTED,
204 .required_flags = ITS_MSI_FLAGS_REQUIRED,
205 .chip_flags = MSI_CHIP_FLAG_SET_EOI,
206 .bus_select_token = DOMAIN_BUS_NEXUS,
207 .bus_select_mask = MATCH_PCI_MSI | MATCH_PLATFORM_MSI,
208 .prefix = "ITS-",
209 .init_dev_msi_info = its_init_dev_msi_info,
210 };
211