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