1b4ead12dSLorenzo Pieralisi // SPDX-License-Identifier: GPL-2.0-only
2b4ead12dSLorenzo Pieralisi // Copyright (C) 2013-2015 ARM Limited, All Rights Reserved.
3b4ead12dSLorenzo Pieralisi // Author: Marc Zyngier <marc.zyngier@arm.com>
4b4ead12dSLorenzo Pieralisi // Copyright (C) 2022 Linutronix GmbH
5b4ead12dSLorenzo Pieralisi // Copyright (C) 2022 Intel
6b4ead12dSLorenzo Pieralisi
7b4ead12dSLorenzo Pieralisi #include <linux/acpi_iort.h>
8*57d72196SLorenzo Pieralisi #include <linux/of_address.h>
9b4ead12dSLorenzo Pieralisi #include <linux/pci.h>
10b4ead12dSLorenzo Pieralisi
11b4ead12dSLorenzo Pieralisi #include "irq-gic-its-msi-parent.h"
12b4ead12dSLorenzo Pieralisi #include <linux/irqchip/irq-msi-lib.h>
13b4ead12dSLorenzo Pieralisi
14b4ead12dSLorenzo Pieralisi #define ITS_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \
15b4ead12dSLorenzo Pieralisi MSI_FLAG_USE_DEF_CHIP_OPS | \
16b4ead12dSLorenzo Pieralisi MSI_FLAG_PCI_MSI_MASK_PARENT)
17b4ead12dSLorenzo Pieralisi
18b4ead12dSLorenzo Pieralisi #define ITS_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \
19b4ead12dSLorenzo Pieralisi MSI_FLAG_PCI_MSIX | \
20b4ead12dSLorenzo Pieralisi MSI_FLAG_MULTI_PCI_MSI)
21b4ead12dSLorenzo Pieralisi
its_translate_frame_address(struct device_node * msi_node,phys_addr_t * pa)22*57d72196SLorenzo Pieralisi static int its_translate_frame_address(struct device_node *msi_node, phys_addr_t *pa)
23*57d72196SLorenzo Pieralisi {
24*57d72196SLorenzo Pieralisi struct resource res;
25*57d72196SLorenzo Pieralisi int ret;
26*57d72196SLorenzo Pieralisi
27*57d72196SLorenzo Pieralisi ret = of_property_match_string(msi_node, "reg-names", "ns-translate");
28*57d72196SLorenzo Pieralisi if (ret < 0)
29*57d72196SLorenzo Pieralisi return ret;
30*57d72196SLorenzo Pieralisi
31*57d72196SLorenzo Pieralisi ret = of_address_to_resource(msi_node, ret, &res);
32*57d72196SLorenzo Pieralisi if (ret)
33*57d72196SLorenzo Pieralisi return ret;
34*57d72196SLorenzo Pieralisi
35*57d72196SLorenzo Pieralisi *pa = res.start;
36*57d72196SLorenzo Pieralisi return 0;
37*57d72196SLorenzo Pieralisi }
38*57d72196SLorenzo Pieralisi
39b4ead12dSLorenzo Pieralisi #ifdef CONFIG_PCI_MSI
its_pci_msi_vec_count(struct pci_dev * pdev,void * data)40b4ead12dSLorenzo Pieralisi static int its_pci_msi_vec_count(struct pci_dev *pdev, void *data)
41b4ead12dSLorenzo Pieralisi {
42b4ead12dSLorenzo Pieralisi int msi, msix, *count = data;
43b4ead12dSLorenzo Pieralisi
44b4ead12dSLorenzo Pieralisi msi = max(pci_msi_vec_count(pdev), 0);
45b4ead12dSLorenzo Pieralisi msix = max(pci_msix_vec_count(pdev), 0);
46b4ead12dSLorenzo Pieralisi *count += max(msi, msix);
47b4ead12dSLorenzo Pieralisi
48b4ead12dSLorenzo Pieralisi return 0;
49b4ead12dSLorenzo Pieralisi }
50b4ead12dSLorenzo Pieralisi
its_get_pci_alias(struct pci_dev * pdev,u16 alias,void * data)51b4ead12dSLorenzo Pieralisi static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data)
52b4ead12dSLorenzo Pieralisi {
53b4ead12dSLorenzo Pieralisi struct pci_dev **alias_dev = data;
54b4ead12dSLorenzo Pieralisi
55b4ead12dSLorenzo Pieralisi *alias_dev = pdev;
56b4ead12dSLorenzo Pieralisi
57b4ead12dSLorenzo Pieralisi return 0;
58b4ead12dSLorenzo Pieralisi }
59b4ead12dSLorenzo Pieralisi
its_pci_msi_prepare(struct irq_domain * domain,struct device * dev,int nvec,msi_alloc_info_t * info)60b4ead12dSLorenzo Pieralisi static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev,
61b4ead12dSLorenzo Pieralisi int nvec, msi_alloc_info_t *info)
62b4ead12dSLorenzo Pieralisi {
63b4ead12dSLorenzo Pieralisi struct pci_dev *pdev, *alias_dev;
64b4ead12dSLorenzo Pieralisi struct msi_domain_info *msi_info;
65b4ead12dSLorenzo Pieralisi int alias_count = 0, minnvec = 1;
66b4ead12dSLorenzo Pieralisi
67b4ead12dSLorenzo Pieralisi if (!dev_is_pci(dev))
68b4ead12dSLorenzo Pieralisi return -EINVAL;
69b4ead12dSLorenzo Pieralisi
70b4ead12dSLorenzo Pieralisi pdev = to_pci_dev(dev);
71b4ead12dSLorenzo Pieralisi /*
72b4ead12dSLorenzo Pieralisi * If pdev is downstream of any aliasing bridges, take an upper
73b4ead12dSLorenzo Pieralisi * bound of how many other vectors could map to the same DevID.
74b4ead12dSLorenzo Pieralisi * Also tell the ITS that the signalling will come from a proxy
75b4ead12dSLorenzo Pieralisi * device, and that special allocation rules apply.
76b4ead12dSLorenzo Pieralisi */
77b4ead12dSLorenzo Pieralisi pci_for_each_dma_alias(pdev, its_get_pci_alias, &alias_dev);
78b4ead12dSLorenzo Pieralisi if (alias_dev != pdev) {
79b4ead12dSLorenzo Pieralisi if (alias_dev->subordinate)
80b4ead12dSLorenzo Pieralisi pci_walk_bus(alias_dev->subordinate,
81b4ead12dSLorenzo Pieralisi its_pci_msi_vec_count, &alias_count);
82b4ead12dSLorenzo Pieralisi info->flags |= MSI_ALLOC_FLAGS_PROXY_DEVICE;
83b4ead12dSLorenzo Pieralisi }
84b4ead12dSLorenzo Pieralisi
85b4ead12dSLorenzo Pieralisi /* ITS specific DeviceID, as the core ITS ignores dev. */
86b4ead12dSLorenzo Pieralisi info->scratchpad[0].ul = pci_msi_domain_get_msi_rid(domain->parent, pdev);
87b4ead12dSLorenzo Pieralisi
88b4ead12dSLorenzo Pieralisi /*
89b4ead12dSLorenzo Pieralisi * Always allocate a power of 2, and special case device 0 for
90b4ead12dSLorenzo Pieralisi * broken systems where the DevID is not wired (and all devices
91b4ead12dSLorenzo Pieralisi * appear as DevID 0). For that reason, we generously allocate a
92b4ead12dSLorenzo Pieralisi * minimum of 32 MSIs for DevID 0. If you want more because all
93b4ead12dSLorenzo Pieralisi * your devices are aliasing to DevID 0, consider fixing your HW.
94b4ead12dSLorenzo Pieralisi */
95b4ead12dSLorenzo Pieralisi nvec = max(nvec, alias_count);
96b4ead12dSLorenzo Pieralisi if (!info->scratchpad[0].ul)
97b4ead12dSLorenzo Pieralisi minnvec = 32;
98b4ead12dSLorenzo Pieralisi nvec = max_t(int, minnvec, roundup_pow_of_two(nvec));
99b4ead12dSLorenzo Pieralisi
100b4ead12dSLorenzo Pieralisi msi_info = msi_get_domain_info(domain->parent);
101b4ead12dSLorenzo Pieralisi return msi_info->ops->msi_prepare(domain->parent, dev, nvec, info);
102b4ead12dSLorenzo Pieralisi }
103*57d72196SLorenzo Pieralisi
its_v5_pci_msi_prepare(struct irq_domain * domain,struct device * dev,int nvec,msi_alloc_info_t * info)104*57d72196SLorenzo Pieralisi static int its_v5_pci_msi_prepare(struct irq_domain *domain, struct device *dev,
105*57d72196SLorenzo Pieralisi int nvec, msi_alloc_info_t *info)
106*57d72196SLorenzo Pieralisi {
107*57d72196SLorenzo Pieralisi struct device_node *msi_node = NULL;
108*57d72196SLorenzo Pieralisi struct msi_domain_info *msi_info;
109*57d72196SLorenzo Pieralisi struct pci_dev *pdev;
110*57d72196SLorenzo Pieralisi phys_addr_t pa;
111*57d72196SLorenzo Pieralisi u32 rid;
112*57d72196SLorenzo Pieralisi int ret;
113*57d72196SLorenzo Pieralisi
114*57d72196SLorenzo Pieralisi if (!dev_is_pci(dev))
115*57d72196SLorenzo Pieralisi return -EINVAL;
116*57d72196SLorenzo Pieralisi
117*57d72196SLorenzo Pieralisi pdev = to_pci_dev(dev);
118*57d72196SLorenzo Pieralisi
119*57d72196SLorenzo Pieralisi rid = pci_msi_map_rid_ctlr_node(pdev, &msi_node);
120*57d72196SLorenzo Pieralisi if (!msi_node)
121*57d72196SLorenzo Pieralisi return -ENODEV;
122*57d72196SLorenzo Pieralisi
123*57d72196SLorenzo Pieralisi ret = its_translate_frame_address(msi_node, &pa);
124*57d72196SLorenzo Pieralisi if (ret)
125*57d72196SLorenzo Pieralisi return -ENODEV;
126*57d72196SLorenzo Pieralisi
127*57d72196SLorenzo Pieralisi of_node_put(msi_node);
128*57d72196SLorenzo Pieralisi
129*57d72196SLorenzo Pieralisi /* ITS specific DeviceID */
130*57d72196SLorenzo Pieralisi info->scratchpad[0].ul = rid;
131*57d72196SLorenzo Pieralisi /* ITS translate frame physical address */
132*57d72196SLorenzo Pieralisi info->scratchpad[1].ul = pa;
133*57d72196SLorenzo Pieralisi
134*57d72196SLorenzo Pieralisi /* Always allocate power of two vectors */
135*57d72196SLorenzo Pieralisi nvec = roundup_pow_of_two(nvec);
136*57d72196SLorenzo Pieralisi
137*57d72196SLorenzo Pieralisi msi_info = msi_get_domain_info(domain->parent);
138*57d72196SLorenzo Pieralisi return msi_info->ops->msi_prepare(domain->parent, dev, nvec, info);
139*57d72196SLorenzo Pieralisi }
140b4ead12dSLorenzo Pieralisi #else /* CONFIG_PCI_MSI */
141b4ead12dSLorenzo Pieralisi #define its_pci_msi_prepare NULL
142*57d72196SLorenzo Pieralisi #define its_v5_pci_msi_prepare NULL
143b4ead12dSLorenzo Pieralisi #endif /* !CONFIG_PCI_MSI */
144b4ead12dSLorenzo Pieralisi
of_pmsi_get_dev_id(struct irq_domain * domain,struct device * dev,u32 * dev_id)145b4ead12dSLorenzo Pieralisi static int of_pmsi_get_dev_id(struct irq_domain *domain, struct device *dev,
146b4ead12dSLorenzo Pieralisi u32 *dev_id)
147b4ead12dSLorenzo Pieralisi {
148b4ead12dSLorenzo Pieralisi int ret, index = 0;
149b4ead12dSLorenzo Pieralisi
150b4ead12dSLorenzo Pieralisi /* Suck the DeviceID out of the msi-parent property */
151b4ead12dSLorenzo Pieralisi do {
152b4ead12dSLorenzo Pieralisi struct of_phandle_args args;
153b4ead12dSLorenzo Pieralisi
154b4ead12dSLorenzo Pieralisi ret = of_parse_phandle_with_args(dev->of_node,
155b4ead12dSLorenzo Pieralisi "msi-parent", "#msi-cells",
156b4ead12dSLorenzo Pieralisi index, &args);
157b4ead12dSLorenzo Pieralisi if (args.np == irq_domain_get_of_node(domain)) {
158b4ead12dSLorenzo Pieralisi if (WARN_ON(args.args_count != 1))
159b4ead12dSLorenzo Pieralisi return -EINVAL;
160b4ead12dSLorenzo Pieralisi *dev_id = args.args[0];
161b4ead12dSLorenzo Pieralisi break;
162b4ead12dSLorenzo Pieralisi }
163b4ead12dSLorenzo Pieralisi index++;
164b4ead12dSLorenzo Pieralisi } while (!ret);
165b4ead12dSLorenzo Pieralisi
166b4ead12dSLorenzo Pieralisi if (ret) {
167b4ead12dSLorenzo Pieralisi struct device_node *np = NULL;
168b4ead12dSLorenzo Pieralisi
169b4ead12dSLorenzo Pieralisi ret = of_map_id(dev->of_node, dev->id, "msi-map", "msi-map-mask", &np, dev_id);
170b4ead12dSLorenzo Pieralisi if (np)
171b4ead12dSLorenzo Pieralisi of_node_put(np);
172b4ead12dSLorenzo Pieralisi }
173b4ead12dSLorenzo Pieralisi
174b4ead12dSLorenzo Pieralisi return ret;
175b4ead12dSLorenzo Pieralisi }
176b4ead12dSLorenzo Pieralisi
of_v5_pmsi_get_msi_info(struct irq_domain * domain,struct device * dev,u32 * dev_id,phys_addr_t * pa)177*57d72196SLorenzo Pieralisi static int of_v5_pmsi_get_msi_info(struct irq_domain *domain, struct device *dev,
178*57d72196SLorenzo Pieralisi u32 *dev_id, phys_addr_t *pa)
179*57d72196SLorenzo Pieralisi {
180*57d72196SLorenzo Pieralisi int ret, index = 0;
181*57d72196SLorenzo Pieralisi /*
182*57d72196SLorenzo Pieralisi * Retrieve the DeviceID and the ITS translate frame node pointer
183*57d72196SLorenzo Pieralisi * out of the msi-parent property.
184*57d72196SLorenzo Pieralisi */
185*57d72196SLorenzo Pieralisi do {
186*57d72196SLorenzo Pieralisi struct of_phandle_args args;
187*57d72196SLorenzo Pieralisi
188*57d72196SLorenzo Pieralisi ret = of_parse_phandle_with_args(dev->of_node,
189*57d72196SLorenzo Pieralisi "msi-parent", "#msi-cells",
190*57d72196SLorenzo Pieralisi index, &args);
191*57d72196SLorenzo Pieralisi if (ret)
192*57d72196SLorenzo Pieralisi break;
193*57d72196SLorenzo Pieralisi /*
194*57d72196SLorenzo Pieralisi * The IRQ domain fwnode is the msi controller parent
195*57d72196SLorenzo Pieralisi * in GICv5 (where the msi controller nodes are the
196*57d72196SLorenzo Pieralisi * ITS translate frames).
197*57d72196SLorenzo Pieralisi */
198*57d72196SLorenzo Pieralisi if (args.np->parent == irq_domain_get_of_node(domain)) {
199*57d72196SLorenzo Pieralisi if (WARN_ON(args.args_count != 1))
200*57d72196SLorenzo Pieralisi return -EINVAL;
201*57d72196SLorenzo Pieralisi *dev_id = args.args[0];
202*57d72196SLorenzo Pieralisi
203*57d72196SLorenzo Pieralisi ret = its_translate_frame_address(args.np, pa);
204*57d72196SLorenzo Pieralisi if (ret)
205*57d72196SLorenzo Pieralisi return -ENODEV;
206*57d72196SLorenzo Pieralisi break;
207*57d72196SLorenzo Pieralisi }
208*57d72196SLorenzo Pieralisi index++;
209*57d72196SLorenzo Pieralisi } while (!ret);
210*57d72196SLorenzo Pieralisi
211*57d72196SLorenzo Pieralisi if (ret) {
212*57d72196SLorenzo Pieralisi struct device_node *np = NULL;
213*57d72196SLorenzo Pieralisi
214*57d72196SLorenzo Pieralisi ret = of_map_id(dev->of_node, dev->id, "msi-map", "msi-map-mask", &np, dev_id);
215*57d72196SLorenzo Pieralisi if (np) {
216*57d72196SLorenzo Pieralisi ret = its_translate_frame_address(np, pa);
217*57d72196SLorenzo Pieralisi of_node_put(np);
218*57d72196SLorenzo Pieralisi }
219*57d72196SLorenzo Pieralisi }
220*57d72196SLorenzo Pieralisi
221*57d72196SLorenzo Pieralisi return ret;
222*57d72196SLorenzo Pieralisi }
223*57d72196SLorenzo Pieralisi
iort_pmsi_get_dev_id(struct device * dev,u32 * dev_id)224b4ead12dSLorenzo Pieralisi int __weak iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id)
225b4ead12dSLorenzo Pieralisi {
226b4ead12dSLorenzo Pieralisi return -1;
227b4ead12dSLorenzo Pieralisi }
228b4ead12dSLorenzo Pieralisi
its_pmsi_prepare(struct irq_domain * domain,struct device * dev,int nvec,msi_alloc_info_t * info)229b4ead12dSLorenzo Pieralisi static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
230b4ead12dSLorenzo Pieralisi int nvec, msi_alloc_info_t *info)
231b4ead12dSLorenzo Pieralisi {
232b4ead12dSLorenzo Pieralisi struct msi_domain_info *msi_info;
233b4ead12dSLorenzo Pieralisi u32 dev_id;
234b4ead12dSLorenzo Pieralisi int ret;
235b4ead12dSLorenzo Pieralisi
236b4ead12dSLorenzo Pieralisi if (dev->of_node)
237b4ead12dSLorenzo Pieralisi ret = of_pmsi_get_dev_id(domain->parent, dev, &dev_id);
238b4ead12dSLorenzo Pieralisi else
239b4ead12dSLorenzo Pieralisi ret = iort_pmsi_get_dev_id(dev, &dev_id);
240b4ead12dSLorenzo Pieralisi if (ret)
241b4ead12dSLorenzo Pieralisi return ret;
242b4ead12dSLorenzo Pieralisi
243b4ead12dSLorenzo Pieralisi /* ITS specific DeviceID, as the core ITS ignores dev. */
244b4ead12dSLorenzo Pieralisi info->scratchpad[0].ul = dev_id;
245b4ead12dSLorenzo Pieralisi
246b4ead12dSLorenzo Pieralisi /* Allocate at least 32 MSIs, and always as a power of 2 */
247b4ead12dSLorenzo Pieralisi nvec = max_t(int, 32, roundup_pow_of_two(nvec));
248b4ead12dSLorenzo Pieralisi
249b4ead12dSLorenzo Pieralisi msi_info = msi_get_domain_info(domain->parent);
250b4ead12dSLorenzo Pieralisi return msi_info->ops->msi_prepare(domain->parent,
251b4ead12dSLorenzo Pieralisi dev, nvec, info);
252b4ead12dSLorenzo Pieralisi }
253b4ead12dSLorenzo Pieralisi
its_v5_pmsi_prepare(struct irq_domain * domain,struct device * dev,int nvec,msi_alloc_info_t * info)254*57d72196SLorenzo Pieralisi static int its_v5_pmsi_prepare(struct irq_domain *domain, struct device *dev,
255*57d72196SLorenzo Pieralisi int nvec, msi_alloc_info_t *info)
256*57d72196SLorenzo Pieralisi {
257*57d72196SLorenzo Pieralisi struct msi_domain_info *msi_info;
258*57d72196SLorenzo Pieralisi phys_addr_t pa;
259*57d72196SLorenzo Pieralisi u32 dev_id;
260*57d72196SLorenzo Pieralisi int ret;
261*57d72196SLorenzo Pieralisi
262*57d72196SLorenzo Pieralisi if (!dev->of_node)
263*57d72196SLorenzo Pieralisi return -ENODEV;
264*57d72196SLorenzo Pieralisi
265*57d72196SLorenzo Pieralisi ret = of_v5_pmsi_get_msi_info(domain->parent, dev, &dev_id, &pa);
266*57d72196SLorenzo Pieralisi if (ret)
267*57d72196SLorenzo Pieralisi return ret;
268*57d72196SLorenzo Pieralisi
269*57d72196SLorenzo Pieralisi /* ITS specific DeviceID */
270*57d72196SLorenzo Pieralisi info->scratchpad[0].ul = dev_id;
271*57d72196SLorenzo Pieralisi /* ITS translate frame physical address */
272*57d72196SLorenzo Pieralisi info->scratchpad[1].ul = pa;
273*57d72196SLorenzo Pieralisi
274*57d72196SLorenzo Pieralisi /* Allocate always as a power of 2 */
275*57d72196SLorenzo Pieralisi nvec = roundup_pow_of_two(nvec);
276*57d72196SLorenzo Pieralisi
277*57d72196SLorenzo Pieralisi msi_info = msi_get_domain_info(domain->parent);
278*57d72196SLorenzo Pieralisi return msi_info->ops->msi_prepare(domain->parent, dev, nvec, info);
279*57d72196SLorenzo Pieralisi }
280*57d72196SLorenzo Pieralisi
its_msi_teardown(struct irq_domain * domain,msi_alloc_info_t * info)281b4ead12dSLorenzo Pieralisi static void its_msi_teardown(struct irq_domain *domain, msi_alloc_info_t *info)
282b4ead12dSLorenzo Pieralisi {
283b4ead12dSLorenzo Pieralisi struct msi_domain_info *msi_info;
284b4ead12dSLorenzo Pieralisi
285b4ead12dSLorenzo Pieralisi msi_info = msi_get_domain_info(domain->parent);
286b4ead12dSLorenzo Pieralisi msi_info->ops->msi_teardown(domain->parent, info);
287b4ead12dSLorenzo Pieralisi }
288b4ead12dSLorenzo Pieralisi
its_init_dev_msi_info(struct device * dev,struct irq_domain * domain,struct irq_domain * real_parent,struct msi_domain_info * info)289b4ead12dSLorenzo Pieralisi static bool its_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
290b4ead12dSLorenzo Pieralisi struct irq_domain *real_parent, struct msi_domain_info *info)
291b4ead12dSLorenzo Pieralisi {
292b4ead12dSLorenzo Pieralisi if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info))
293b4ead12dSLorenzo Pieralisi return false;
294b4ead12dSLorenzo Pieralisi
295b4ead12dSLorenzo Pieralisi switch(info->bus_token) {
296b4ead12dSLorenzo Pieralisi case DOMAIN_BUS_PCI_DEVICE_MSI:
297b4ead12dSLorenzo Pieralisi case DOMAIN_BUS_PCI_DEVICE_MSIX:
298b4ead12dSLorenzo Pieralisi /*
299b4ead12dSLorenzo Pieralisi * FIXME: This probably should be done after a (not yet
300b4ead12dSLorenzo Pieralisi * existing) post domain creation callback once to make
301b4ead12dSLorenzo Pieralisi * support for dynamic post-enable MSI-X allocations
302b4ead12dSLorenzo Pieralisi * work without having to reevaluate the domain size
303b4ead12dSLorenzo Pieralisi * over and over. It is known already at allocation
304b4ead12dSLorenzo Pieralisi * time via info->hwsize.
305b4ead12dSLorenzo Pieralisi *
306b4ead12dSLorenzo Pieralisi * That should work perfectly fine for MSI/MSI-X but needs
307b4ead12dSLorenzo Pieralisi * some thoughts for purely software managed MSI domains
308b4ead12dSLorenzo Pieralisi * where the index space is only limited artificially via
309b4ead12dSLorenzo Pieralisi * %MSI_MAX_INDEX.
310b4ead12dSLorenzo Pieralisi */
311b4ead12dSLorenzo Pieralisi info->ops->msi_prepare = its_pci_msi_prepare;
312b4ead12dSLorenzo Pieralisi info->ops->msi_teardown = its_msi_teardown;
313b4ead12dSLorenzo Pieralisi break;
314b4ead12dSLorenzo Pieralisi case DOMAIN_BUS_DEVICE_MSI:
315b4ead12dSLorenzo Pieralisi case DOMAIN_BUS_WIRED_TO_MSI:
316b4ead12dSLorenzo Pieralisi /*
317b4ead12dSLorenzo Pieralisi * FIXME: See the above PCI prepare comment. The domain
318b4ead12dSLorenzo Pieralisi * size is also known at domain creation time.
319b4ead12dSLorenzo Pieralisi */
320b4ead12dSLorenzo Pieralisi info->ops->msi_prepare = its_pmsi_prepare;
321b4ead12dSLorenzo Pieralisi info->ops->msi_teardown = its_msi_teardown;
322b4ead12dSLorenzo Pieralisi break;
323b4ead12dSLorenzo Pieralisi default:
324b4ead12dSLorenzo Pieralisi /* Confused. How did the lib return true? */
325b4ead12dSLorenzo Pieralisi WARN_ON_ONCE(1);
326b4ead12dSLorenzo Pieralisi return false;
327b4ead12dSLorenzo Pieralisi }
328b4ead12dSLorenzo Pieralisi
329b4ead12dSLorenzo Pieralisi return true;
330b4ead12dSLorenzo Pieralisi }
331b4ead12dSLorenzo Pieralisi
its_v5_init_dev_msi_info(struct device * dev,struct irq_domain * domain,struct irq_domain * real_parent,struct msi_domain_info * info)332*57d72196SLorenzo Pieralisi static bool its_v5_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
333*57d72196SLorenzo Pieralisi struct irq_domain *real_parent, struct msi_domain_info *info)
334*57d72196SLorenzo Pieralisi {
335*57d72196SLorenzo Pieralisi if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info))
336*57d72196SLorenzo Pieralisi return false;
337*57d72196SLorenzo Pieralisi
338*57d72196SLorenzo Pieralisi switch (info->bus_token) {
339*57d72196SLorenzo Pieralisi case DOMAIN_BUS_PCI_DEVICE_MSI:
340*57d72196SLorenzo Pieralisi case DOMAIN_BUS_PCI_DEVICE_MSIX:
341*57d72196SLorenzo Pieralisi info->ops->msi_prepare = its_v5_pci_msi_prepare;
342*57d72196SLorenzo Pieralisi info->ops->msi_teardown = its_msi_teardown;
343*57d72196SLorenzo Pieralisi break;
344*57d72196SLorenzo Pieralisi case DOMAIN_BUS_DEVICE_MSI:
345*57d72196SLorenzo Pieralisi case DOMAIN_BUS_WIRED_TO_MSI:
346*57d72196SLorenzo Pieralisi info->ops->msi_prepare = its_v5_pmsi_prepare;
347*57d72196SLorenzo Pieralisi info->ops->msi_teardown = its_msi_teardown;
348*57d72196SLorenzo Pieralisi break;
349*57d72196SLorenzo Pieralisi default:
350*57d72196SLorenzo Pieralisi /* Confused. How did the lib return true? */
351*57d72196SLorenzo Pieralisi WARN_ON_ONCE(1);
352*57d72196SLorenzo Pieralisi return false;
353*57d72196SLorenzo Pieralisi }
354*57d72196SLorenzo Pieralisi
355*57d72196SLorenzo Pieralisi return true;
356*57d72196SLorenzo Pieralisi }
357*57d72196SLorenzo Pieralisi
358b4ead12dSLorenzo Pieralisi const struct msi_parent_ops gic_v3_its_msi_parent_ops = {
359b4ead12dSLorenzo Pieralisi .supported_flags = ITS_MSI_FLAGS_SUPPORTED,
360b4ead12dSLorenzo Pieralisi .required_flags = ITS_MSI_FLAGS_REQUIRED,
361b4ead12dSLorenzo Pieralisi .chip_flags = MSI_CHIP_FLAG_SET_EOI,
362b4ead12dSLorenzo Pieralisi .bus_select_token = DOMAIN_BUS_NEXUS,
363b4ead12dSLorenzo Pieralisi .bus_select_mask = MATCH_PCI_MSI | MATCH_PLATFORM_MSI,
364b4ead12dSLorenzo Pieralisi .prefix = "ITS-",
365b4ead12dSLorenzo Pieralisi .init_dev_msi_info = its_init_dev_msi_info,
366b4ead12dSLorenzo Pieralisi };
367*57d72196SLorenzo Pieralisi
368*57d72196SLorenzo Pieralisi const struct msi_parent_ops gic_v5_its_msi_parent_ops = {
369*57d72196SLorenzo Pieralisi .supported_flags = ITS_MSI_FLAGS_SUPPORTED,
370*57d72196SLorenzo Pieralisi .required_flags = ITS_MSI_FLAGS_REQUIRED,
371*57d72196SLorenzo Pieralisi .chip_flags = MSI_CHIP_FLAG_SET_EOI,
372*57d72196SLorenzo Pieralisi .bus_select_token = DOMAIN_BUS_NEXUS,
373*57d72196SLorenzo Pieralisi .bus_select_mask = MATCH_PCI_MSI | MATCH_PLATFORM_MSI,
374*57d72196SLorenzo Pieralisi .prefix = "ITS-v5-",
375*57d72196SLorenzo Pieralisi .init_dev_msi_info = its_v5_init_dev_msi_info,
376*57d72196SLorenzo Pieralisi };
377