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