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