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 "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 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 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 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 * @domain->msi_domain_info->hwsize contains the size of the 72 * MSI[-X] domain, but vector allocation happens one by one. This 73 * needs some thought when MSI comes into play as the size of MSI 74 * might be unknown at domain creation time and therefore set to 75 * MSI_MAX_INDEX. 76 */ 77 msi_info = msi_get_domain_info(domain); 78 if (msi_info->hwsize > nvec) 79 nvec = msi_info->hwsize; 80 81 /* 82 * Always allocate a power of 2, and special case device 0 for 83 * broken systems where the DevID is not wired (and all devices 84 * appear as DevID 0). For that reason, we generously allocate a 85 * minimum of 32 MSIs for DevID 0. If you want more because all 86 * your devices are aliasing to DevID 0, consider fixing your HW. 87 */ 88 nvec = max(nvec, alias_count); 89 if (!info->scratchpad[0].ul) 90 minnvec = 32; 91 nvec = max_t(int, minnvec, roundup_pow_of_two(nvec)); 92 93 msi_info = msi_get_domain_info(domain->parent); 94 return msi_info->ops->msi_prepare(domain->parent, dev, nvec, info); 95 } 96 #else /* CONFIG_PCI_MSI */ 97 #define its_pci_msi_prepare NULL 98 #endif /* !CONFIG_PCI_MSI */ 99 100 static int of_pmsi_get_dev_id(struct irq_domain *domain, struct device *dev, 101 u32 *dev_id) 102 { 103 int ret, index = 0; 104 105 /* Suck the DeviceID out of the msi-parent property */ 106 do { 107 struct of_phandle_args args; 108 109 ret = of_parse_phandle_with_args(dev->of_node, 110 "msi-parent", "#msi-cells", 111 index, &args); 112 if (args.np == irq_domain_get_of_node(domain)) { 113 if (WARN_ON(args.args_count != 1)) 114 return -EINVAL; 115 *dev_id = args.args[0]; 116 break; 117 } 118 index++; 119 } while (!ret); 120 121 return ret; 122 } 123 124 int __weak iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id) 125 { 126 return -1; 127 } 128 129 static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev, 130 int nvec, msi_alloc_info_t *info) 131 { 132 struct msi_domain_info *msi_info; 133 u32 dev_id; 134 int ret; 135 136 if (dev->of_node) 137 ret = of_pmsi_get_dev_id(domain->parent, dev, &dev_id); 138 else 139 ret = iort_pmsi_get_dev_id(dev, &dev_id); 140 if (ret) 141 return ret; 142 143 /* ITS specific DeviceID, as the core ITS ignores dev. */ 144 info->scratchpad[0].ul = dev_id; 145 146 /* 147 * @domain->msi_domain_info->hwsize contains the size of the device 148 * domain, but vector allocation happens one by one. 149 */ 150 msi_info = msi_get_domain_info(domain); 151 if (msi_info->hwsize > nvec) 152 nvec = msi_info->hwsize; 153 154 /* Allocate at least 32 MSIs, and always as a power of 2 */ 155 nvec = max_t(int, 32, roundup_pow_of_two(nvec)); 156 157 msi_info = msi_get_domain_info(domain->parent); 158 return msi_info->ops->msi_prepare(domain->parent, 159 dev, nvec, info); 160 } 161 162 static bool its_init_dev_msi_info(struct device *dev, struct irq_domain *domain, 163 struct irq_domain *real_parent, struct msi_domain_info *info) 164 { 165 if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info)) 166 return false; 167 168 switch(info->bus_token) { 169 case DOMAIN_BUS_PCI_DEVICE_MSI: 170 case DOMAIN_BUS_PCI_DEVICE_MSIX: 171 /* 172 * FIXME: This probably should be done after a (not yet 173 * existing) post domain creation callback once to make 174 * support for dynamic post-enable MSI-X allocations 175 * work without having to reevaluate the domain size 176 * over and over. It is known already at allocation 177 * time via info->hwsize. 178 * 179 * That should work perfectly fine for MSI/MSI-X but needs 180 * some thoughts for purely software managed MSI domains 181 * where the index space is only limited artificially via 182 * %MSI_MAX_INDEX. 183 */ 184 info->ops->msi_prepare = its_pci_msi_prepare; 185 break; 186 case DOMAIN_BUS_DEVICE_MSI: 187 case DOMAIN_BUS_WIRED_TO_MSI: 188 /* 189 * FIXME: See the above PCI prepare comment. The domain 190 * size is also known at domain creation time. 191 */ 192 info->ops->msi_prepare = its_pmsi_prepare; 193 break; 194 default: 195 /* Confused. How did the lib return true? */ 196 WARN_ON_ONCE(1); 197 return false; 198 } 199 200 return true; 201 } 202 203 const struct msi_parent_ops gic_v3_its_msi_parent_ops = { 204 .supported_flags = ITS_MSI_FLAGS_SUPPORTED, 205 .required_flags = ITS_MSI_FLAGS_REQUIRED, 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