xref: /linux/drivers/irqchip/irq-gic-its-msi-parent.c (revision 57d72196dfc8502b7e376ecdffb11c4f8766f26d)
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 
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
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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