| 1 | // SPDX-License-Identifier: GPL-2.0 | 
|---|
| 2 | /* | 
|---|
| 3 | * PCI Message Signaled Interrupt (MSI) - irqdomain support | 
|---|
| 4 | */ | 
|---|
| 5 | #include <linux/acpi_iort.h> | 
|---|
| 6 | #include <linux/irqdomain.h> | 
|---|
| 7 | #include <linux/of_irq.h> | 
|---|
| 8 |  | 
|---|
| 9 | #include "msi.h" | 
|---|
| 10 |  | 
|---|
| 11 | int pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | 
|---|
| 12 | { | 
|---|
| 13 | struct irq_domain *domain; | 
|---|
| 14 |  | 
|---|
| 15 | domain = dev_get_msi_domain(dev: &dev->dev); | 
|---|
| 16 | if (domain && irq_domain_is_hierarchy(domain)) | 
|---|
| 17 | return msi_domain_alloc_irqs_all_locked(dev: &dev->dev, domid: MSI_DEFAULT_DOMAIN, nirqs: nvec); | 
|---|
| 18 |  | 
|---|
| 19 | return pci_msi_legacy_setup_msi_irqs(dev, nvec, type); | 
|---|
| 20 | } | 
|---|
| 21 |  | 
|---|
| 22 | void pci_msi_teardown_msi_irqs(struct pci_dev *dev) | 
|---|
| 23 | { | 
|---|
| 24 | struct irq_domain *domain; | 
|---|
| 25 |  | 
|---|
| 26 | domain = dev_get_msi_domain(dev: &dev->dev); | 
|---|
| 27 | if (domain && irq_domain_is_hierarchy(domain)) { | 
|---|
| 28 | msi_domain_free_irqs_all_locked(dev: &dev->dev, domid: MSI_DEFAULT_DOMAIN); | 
|---|
| 29 | } else { | 
|---|
| 30 | pci_msi_legacy_teardown_msi_irqs(dev); | 
|---|
| 31 | msi_free_msi_descs(dev: &dev->dev); | 
|---|
| 32 | } | 
|---|
| 33 | } | 
|---|
| 34 |  | 
|---|
| 35 | /** | 
|---|
| 36 | * pci_msi_domain_write_msg - Helper to write MSI message to PCI config space | 
|---|
| 37 | * @irq_data:	Pointer to interrupt data of the MSI interrupt | 
|---|
| 38 | * @msg:	Pointer to the message | 
|---|
| 39 | */ | 
|---|
| 40 | static void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg) | 
|---|
| 41 | { | 
|---|
| 42 | struct msi_desc *desc = irq_data_get_msi_desc(d: irq_data); | 
|---|
| 43 |  | 
|---|
| 44 | /* | 
|---|
| 45 | * For MSI-X desc->irq is always equal to irq_data->irq. For | 
|---|
| 46 | * MSI only the first interrupt of MULTI MSI passes the test. | 
|---|
| 47 | */ | 
|---|
| 48 | if (desc->irq == irq_data->irq) | 
|---|
| 49 | __pci_write_msi_msg(entry: desc, msg); | 
|---|
| 50 | } | 
|---|
| 51 |  | 
|---|
| 52 | /** | 
|---|
| 53 | * pci_msi_domain_calc_hwirq - Generate a unique ID for an MSI source | 
|---|
| 54 | * @desc:	Pointer to the MSI descriptor | 
|---|
| 55 | * | 
|---|
| 56 | * The ID number is only used within the irqdomain. | 
|---|
| 57 | */ | 
|---|
| 58 | static irq_hw_number_t pci_msi_domain_calc_hwirq(struct msi_desc *desc) | 
|---|
| 59 | { | 
|---|
| 60 | struct pci_dev *dev = msi_desc_to_pci_dev(desc); | 
|---|
| 61 |  | 
|---|
| 62 | return (irq_hw_number_t)desc->msi_index | | 
|---|
| 63 | pci_dev_id(dev) << 11 | | 
|---|
| 64 | ((irq_hw_number_t)(pci_domain_nr(bus: dev->bus) & 0xFFFFFFFF)) << 27; | 
|---|
| 65 | } | 
|---|
| 66 |  | 
|---|
| 67 | static void pci_msi_domain_set_desc(msi_alloc_info_t *arg, | 
|---|
| 68 | struct msi_desc *desc) | 
|---|
| 69 | { | 
|---|
| 70 | arg->desc = desc; | 
|---|
| 71 | arg->hwirq = pci_msi_domain_calc_hwirq(desc); | 
|---|
| 72 | } | 
|---|
| 73 |  | 
|---|
| 74 | static struct msi_domain_ops pci_msi_domain_ops_default = { | 
|---|
| 75 | .set_desc	= pci_msi_domain_set_desc, | 
|---|
| 76 | }; | 
|---|
| 77 |  | 
|---|
| 78 | static void pci_msi_domain_update_dom_ops(struct msi_domain_info *info) | 
|---|
| 79 | { | 
|---|
| 80 | struct msi_domain_ops *ops = info->ops; | 
|---|
| 81 |  | 
|---|
| 82 | if (ops == NULL) { | 
|---|
| 83 | info->ops = &pci_msi_domain_ops_default; | 
|---|
| 84 | } else { | 
|---|
| 85 | if (ops->set_desc == NULL) | 
|---|
| 86 | ops->set_desc = pci_msi_domain_set_desc; | 
|---|
| 87 | } | 
|---|
| 88 | } | 
|---|
| 89 |  | 
|---|
| 90 | static void pci_msi_domain_update_chip_ops(struct msi_domain_info *info) | 
|---|
| 91 | { | 
|---|
| 92 | struct irq_chip *chip = info->chip; | 
|---|
| 93 |  | 
|---|
| 94 | BUG_ON(!chip); | 
|---|
| 95 | if (!chip->irq_write_msi_msg) | 
|---|
| 96 | chip->irq_write_msi_msg = pci_msi_domain_write_msg; | 
|---|
| 97 | if (!chip->irq_mask) | 
|---|
| 98 | chip->irq_mask = pci_msi_mask_irq; | 
|---|
| 99 | if (!chip->irq_unmask) | 
|---|
| 100 | chip->irq_unmask = pci_msi_unmask_irq; | 
|---|
| 101 | } | 
|---|
| 102 |  | 
|---|
| 103 | /** | 
|---|
| 104 | * pci_msi_create_irq_domain - Create a MSI interrupt domain | 
|---|
| 105 | * @fwnode:	Optional fwnode of the interrupt controller | 
|---|
| 106 | * @info:	MSI domain info | 
|---|
| 107 | * @parent:	Parent irq domain | 
|---|
| 108 | * | 
|---|
| 109 | * Updates the domain and chip ops and creates a MSI interrupt domain. | 
|---|
| 110 | * | 
|---|
| 111 | * Returns: | 
|---|
| 112 | * A domain pointer or NULL in case of failure. | 
|---|
| 113 | */ | 
|---|
| 114 | struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode, | 
|---|
| 115 | struct msi_domain_info *info, | 
|---|
| 116 | struct irq_domain *parent) | 
|---|
| 117 | { | 
|---|
| 118 | if (WARN_ON(info->flags & MSI_FLAG_LEVEL_CAPABLE)) | 
|---|
| 119 | info->flags &= ~MSI_FLAG_LEVEL_CAPABLE; | 
|---|
| 120 |  | 
|---|
| 121 | if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS) | 
|---|
| 122 | pci_msi_domain_update_dom_ops(info); | 
|---|
| 123 | if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS) | 
|---|
| 124 | pci_msi_domain_update_chip_ops(info); | 
|---|
| 125 |  | 
|---|
| 126 | /* Let the core code free MSI descriptors when freeing interrupts */ | 
|---|
| 127 | info->flags |= MSI_FLAG_FREE_MSI_DESCS; | 
|---|
| 128 |  | 
|---|
| 129 | info->flags |= MSI_FLAG_ACTIVATE_EARLY | MSI_FLAG_DEV_SYSFS; | 
|---|
| 130 | if (IS_ENABLED(CONFIG_GENERIC_IRQ_RESERVATION_MODE)) | 
|---|
| 131 | info->flags |= MSI_FLAG_MUST_REACTIVATE; | 
|---|
| 132 |  | 
|---|
| 133 | /* PCI-MSI is oneshot-safe */ | 
|---|
| 134 | info->chip->flags |= IRQCHIP_ONESHOT_SAFE; | 
|---|
| 135 | /* Let the core update the bus token */ | 
|---|
| 136 | info->bus_token = DOMAIN_BUS_PCI_MSI; | 
|---|
| 137 |  | 
|---|
| 138 | return msi_create_irq_domain(fwnode, info, parent); | 
|---|
| 139 | } | 
|---|
| 140 | EXPORT_SYMBOL_GPL(pci_msi_create_irq_domain); | 
|---|
| 141 |  | 
|---|
| 142 | /* | 
|---|
| 143 | * Per device MSI[-X] domain functionality | 
|---|
| 144 | */ | 
|---|
| 145 | static void pci_device_domain_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc) | 
|---|
| 146 | { | 
|---|
| 147 | arg->desc = desc; | 
|---|
| 148 | arg->hwirq = desc->msi_index; | 
|---|
| 149 | } | 
|---|
| 150 |  | 
|---|
| 151 | static void cond_shutdown_parent(struct irq_data *data) | 
|---|
| 152 | { | 
|---|
| 153 | struct msi_domain_info *info = data->domain->host_data; | 
|---|
| 154 |  | 
|---|
| 155 | if (unlikely(info->flags & MSI_FLAG_PCI_MSI_STARTUP_PARENT)) | 
|---|
| 156 | irq_chip_shutdown_parent(data); | 
|---|
| 157 | else if (unlikely(info->flags & MSI_FLAG_PCI_MSI_MASK_PARENT)) | 
|---|
| 158 | irq_chip_mask_parent(data); | 
|---|
| 159 | } | 
|---|
| 160 |  | 
|---|
| 161 | static unsigned int cond_startup_parent(struct irq_data *data) | 
|---|
| 162 | { | 
|---|
| 163 | struct msi_domain_info *info = data->domain->host_data; | 
|---|
| 164 |  | 
|---|
| 165 | if (unlikely(info->flags & MSI_FLAG_PCI_MSI_STARTUP_PARENT)) | 
|---|
| 166 | return irq_chip_startup_parent(data); | 
|---|
| 167 | else if (unlikely(info->flags & MSI_FLAG_PCI_MSI_MASK_PARENT)) | 
|---|
| 168 | irq_chip_unmask_parent(data); | 
|---|
| 169 |  | 
|---|
| 170 | return 0; | 
|---|
| 171 | } | 
|---|
| 172 |  | 
|---|
| 173 | static void pci_irq_shutdown_msi(struct irq_data *data) | 
|---|
| 174 | { | 
|---|
| 175 | struct msi_desc *desc = irq_data_get_msi_desc(d: data); | 
|---|
| 176 |  | 
|---|
| 177 | pci_msi_mask(desc, BIT(data->irq - desc->irq)); | 
|---|
| 178 | cond_shutdown_parent(data); | 
|---|
| 179 | } | 
|---|
| 180 |  | 
|---|
| 181 | static unsigned int pci_irq_startup_msi(struct irq_data *data) | 
|---|
| 182 | { | 
|---|
| 183 | struct msi_desc *desc = irq_data_get_msi_desc(d: data); | 
|---|
| 184 | unsigned int ret = cond_startup_parent(data); | 
|---|
| 185 |  | 
|---|
| 186 | pci_msi_unmask(desc, BIT(data->irq - desc->irq)); | 
|---|
| 187 | return ret; | 
|---|
| 188 | } | 
|---|
| 189 |  | 
|---|
| 190 | static void pci_irq_mask_msi(struct irq_data *data) | 
|---|
| 191 | { | 
|---|
| 192 | struct msi_desc *desc = irq_data_get_msi_desc(d: data); | 
|---|
| 193 |  | 
|---|
| 194 | pci_msi_mask(desc, BIT(data->irq - desc->irq)); | 
|---|
| 195 | } | 
|---|
| 196 |  | 
|---|
| 197 | static void pci_irq_unmask_msi(struct irq_data *data) | 
|---|
| 198 | { | 
|---|
| 199 | struct msi_desc *desc = irq_data_get_msi_desc(d: data); | 
|---|
| 200 |  | 
|---|
| 201 | pci_msi_unmask(desc, BIT(data->irq - desc->irq)); | 
|---|
| 202 | } | 
|---|
| 203 |  | 
|---|
| 204 | #ifdef CONFIG_GENERIC_IRQ_RESERVATION_MODE | 
|---|
| 205 | # define MSI_REACTIVATE		MSI_FLAG_MUST_REACTIVATE | 
|---|
| 206 | #else | 
|---|
| 207 | # define MSI_REACTIVATE		0 | 
|---|
| 208 | #endif | 
|---|
| 209 |  | 
|---|
| 210 | #define MSI_COMMON_FLAGS	(MSI_FLAG_FREE_MSI_DESCS |	\ | 
|---|
| 211 | MSI_FLAG_ACTIVATE_EARLY |	\ | 
|---|
| 212 | MSI_FLAG_DEV_SYSFS |		\ | 
|---|
| 213 | MSI_REACTIVATE) | 
|---|
| 214 |  | 
|---|
| 215 | static const struct msi_domain_template pci_msi_template = { | 
|---|
| 216 | .chip = { | 
|---|
| 217 | .name			= "PCI-MSI", | 
|---|
| 218 | .irq_startup		= pci_irq_startup_msi, | 
|---|
| 219 | .irq_shutdown		= pci_irq_shutdown_msi, | 
|---|
| 220 | .irq_mask		= pci_irq_mask_msi, | 
|---|
| 221 | .irq_unmask		= pci_irq_unmask_msi, | 
|---|
| 222 | .irq_write_msi_msg	= pci_msi_domain_write_msg, | 
|---|
| 223 | .flags			= IRQCHIP_ONESHOT_SAFE, | 
|---|
| 224 | }, | 
|---|
| 225 |  | 
|---|
| 226 | .ops = { | 
|---|
| 227 | .set_desc		= pci_device_domain_set_desc, | 
|---|
| 228 | }, | 
|---|
| 229 |  | 
|---|
| 230 | .info = { | 
|---|
| 231 | .flags			= MSI_COMMON_FLAGS | MSI_FLAG_MULTI_PCI_MSI, | 
|---|
| 232 | .bus_token		= DOMAIN_BUS_PCI_DEVICE_MSI, | 
|---|
| 233 | }, | 
|---|
| 234 | }; | 
|---|
| 235 |  | 
|---|
| 236 | static void pci_irq_shutdown_msix(struct irq_data *data) | 
|---|
| 237 | { | 
|---|
| 238 | pci_msix_mask(desc: irq_data_get_msi_desc(d: data)); | 
|---|
| 239 | cond_shutdown_parent(data); | 
|---|
| 240 | } | 
|---|
| 241 |  | 
|---|
| 242 | static unsigned int pci_irq_startup_msix(struct irq_data *data) | 
|---|
| 243 | { | 
|---|
| 244 | unsigned int ret = cond_startup_parent(data); | 
|---|
| 245 |  | 
|---|
| 246 | pci_msix_unmask(desc: irq_data_get_msi_desc(d: data)); | 
|---|
| 247 | return ret; | 
|---|
| 248 | } | 
|---|
| 249 |  | 
|---|
| 250 | static void pci_irq_mask_msix(struct irq_data *data) | 
|---|
| 251 | { | 
|---|
| 252 | pci_msix_mask(desc: irq_data_get_msi_desc(d: data)); | 
|---|
| 253 | } | 
|---|
| 254 |  | 
|---|
| 255 | static void pci_irq_unmask_msix(struct irq_data *data) | 
|---|
| 256 | { | 
|---|
| 257 | pci_msix_unmask(desc: irq_data_get_msi_desc(d: data)); | 
|---|
| 258 | } | 
|---|
| 259 |  | 
|---|
| 260 | void pci_msix_prepare_desc(struct irq_domain *domain, msi_alloc_info_t *arg, | 
|---|
| 261 | struct msi_desc *desc) | 
|---|
| 262 | { | 
|---|
| 263 | /* Don't fiddle with preallocated MSI descriptors */ | 
|---|
| 264 | if (!desc->pci.mask_base) | 
|---|
| 265 | msix_prepare_msi_desc(to_pci_dev(desc->dev), desc); | 
|---|
| 266 | } | 
|---|
| 267 | EXPORT_SYMBOL_GPL(pci_msix_prepare_desc); | 
|---|
| 268 |  | 
|---|
| 269 | static const struct msi_domain_template pci_msix_template = { | 
|---|
| 270 | .chip = { | 
|---|
| 271 | .name			= "PCI-MSIX", | 
|---|
| 272 | .irq_startup		= pci_irq_startup_msix, | 
|---|
| 273 | .irq_shutdown		= pci_irq_shutdown_msix, | 
|---|
| 274 | .irq_mask		= pci_irq_mask_msix, | 
|---|
| 275 | .irq_unmask		= pci_irq_unmask_msix, | 
|---|
| 276 | .irq_write_msi_msg	= pci_msi_domain_write_msg, | 
|---|
| 277 | .flags			= IRQCHIP_ONESHOT_SAFE, | 
|---|
| 278 | }, | 
|---|
| 279 |  | 
|---|
| 280 | .ops = { | 
|---|
| 281 | .prepare_desc		= pci_msix_prepare_desc, | 
|---|
| 282 | .set_desc		= pci_device_domain_set_desc, | 
|---|
| 283 | }, | 
|---|
| 284 |  | 
|---|
| 285 | .info = { | 
|---|
| 286 | .flags			= MSI_COMMON_FLAGS | MSI_FLAG_PCI_MSIX | | 
|---|
| 287 | MSI_FLAG_PCI_MSIX_ALLOC_DYN, | 
|---|
| 288 | .bus_token		= DOMAIN_BUS_PCI_DEVICE_MSIX, | 
|---|
| 289 | }, | 
|---|
| 290 | }; | 
|---|
| 291 |  | 
|---|
| 292 | static bool pci_match_device_domain(struct pci_dev *pdev, enum irq_domain_bus_token bus_token) | 
|---|
| 293 | { | 
|---|
| 294 | return msi_match_device_irq_domain(dev: &pdev->dev, domid: MSI_DEFAULT_DOMAIN, bus_token); | 
|---|
| 295 | } | 
|---|
| 296 |  | 
|---|
| 297 | static bool pci_create_device_domain(struct pci_dev *pdev, const struct msi_domain_template *tmpl, | 
|---|
| 298 | unsigned int hwsize) | 
|---|
| 299 | { | 
|---|
| 300 | struct irq_domain *domain = dev_get_msi_domain(dev: &pdev->dev); | 
|---|
| 301 |  | 
|---|
| 302 | if (!domain || !irq_domain_is_msi_parent(domain)) | 
|---|
| 303 | return true; | 
|---|
| 304 |  | 
|---|
| 305 | return msi_create_device_irq_domain(dev: &pdev->dev, domid: MSI_DEFAULT_DOMAIN, template: tmpl, | 
|---|
| 306 | hwsize, NULL, NULL); | 
|---|
| 307 | } | 
|---|
| 308 |  | 
|---|
| 309 | /** | 
|---|
| 310 | * pci_setup_msi_device_domain - Setup a device MSI interrupt domain | 
|---|
| 311 | * @pdev:	The PCI device to create the domain on | 
|---|
| 312 | * @hwsize:	The maximum number of MSI vectors | 
|---|
| 313 | * | 
|---|
| 314 | * Return: | 
|---|
| 315 | *  True when: | 
|---|
| 316 | *	- The device does not have a MSI parent irq domain associated, | 
|---|
| 317 | *	  which keeps the legacy architecture specific and the global | 
|---|
| 318 | *	  PCI/MSI domain models working | 
|---|
| 319 | *	- The MSI domain exists already | 
|---|
| 320 | *	- The MSI domain was successfully allocated | 
|---|
| 321 | *  False when: | 
|---|
| 322 | *	- MSI-X is enabled | 
|---|
| 323 | *	- The domain creation fails. | 
|---|
| 324 | * | 
|---|
| 325 | * The created MSI domain is preserved until: | 
|---|
| 326 | *	- The device is removed | 
|---|
| 327 | *	- MSI is disabled and a MSI-X domain is created | 
|---|
| 328 | */ | 
|---|
| 329 | bool pci_setup_msi_device_domain(struct pci_dev *pdev, unsigned int hwsize) | 
|---|
| 330 | { | 
|---|
| 331 | if (WARN_ON_ONCE(pdev->msix_enabled)) | 
|---|
| 332 | return false; | 
|---|
| 333 |  | 
|---|
| 334 | if (pci_match_device_domain(pdev, bus_token: DOMAIN_BUS_PCI_DEVICE_MSI)) | 
|---|
| 335 | return true; | 
|---|
| 336 | if (pci_match_device_domain(pdev, bus_token: DOMAIN_BUS_PCI_DEVICE_MSIX)) | 
|---|
| 337 | msi_remove_device_irq_domain(dev: &pdev->dev, domid: MSI_DEFAULT_DOMAIN); | 
|---|
| 338 |  | 
|---|
| 339 | return pci_create_device_domain(pdev, tmpl: &pci_msi_template, hwsize); | 
|---|
| 340 | } | 
|---|
| 341 |  | 
|---|
| 342 | /** | 
|---|
| 343 | * pci_setup_msix_device_domain - Setup a device MSI-X interrupt domain | 
|---|
| 344 | * @pdev:	The PCI device to create the domain on | 
|---|
| 345 | * @hwsize:	The size of the MSI-X vector table | 
|---|
| 346 | * | 
|---|
| 347 | * Return: | 
|---|
| 348 | *  True when: | 
|---|
| 349 | *	- The device does not have a MSI parent irq domain associated, | 
|---|
| 350 | *	  which keeps the legacy architecture specific and the global | 
|---|
| 351 | *	  PCI/MSI domain models working | 
|---|
| 352 | *	- The MSI-X domain exists already | 
|---|
| 353 | *	- The MSI-X domain was successfully allocated | 
|---|
| 354 | *  False when: | 
|---|
| 355 | *	- MSI is enabled | 
|---|
| 356 | *	- The domain creation fails. | 
|---|
| 357 | * | 
|---|
| 358 | * The created MSI-X domain is preserved until: | 
|---|
| 359 | *	- The device is removed | 
|---|
| 360 | *	- MSI-X is disabled and a MSI domain is created | 
|---|
| 361 | */ | 
|---|
| 362 | bool pci_setup_msix_device_domain(struct pci_dev *pdev, unsigned int hwsize) | 
|---|
| 363 | { | 
|---|
| 364 | if (WARN_ON_ONCE(pdev->msi_enabled)) | 
|---|
| 365 | return false; | 
|---|
| 366 |  | 
|---|
| 367 | if (pci_match_device_domain(pdev, bus_token: DOMAIN_BUS_PCI_DEVICE_MSIX)) | 
|---|
| 368 | return true; | 
|---|
| 369 | if (pci_match_device_domain(pdev, bus_token: DOMAIN_BUS_PCI_DEVICE_MSI)) | 
|---|
| 370 | msi_remove_device_irq_domain(dev: &pdev->dev, domid: MSI_DEFAULT_DOMAIN); | 
|---|
| 371 |  | 
|---|
| 372 | return pci_create_device_domain(pdev, tmpl: &pci_msix_template, hwsize); | 
|---|
| 373 | } | 
|---|
| 374 |  | 
|---|
| 375 | /** | 
|---|
| 376 | * pci_msi_domain_supports - Check for support of a particular feature flag | 
|---|
| 377 | * @pdev:		The PCI device to operate on | 
|---|
| 378 | * @feature_mask:	The feature mask to check for (full match) | 
|---|
| 379 | * @mode:		If ALLOW_LEGACY this grants the feature when there is no irq domain | 
|---|
| 380 | *			associated to the device. If DENY_LEGACY the lack of an irq domain | 
|---|
| 381 | *			makes the feature unsupported | 
|---|
| 382 | */ | 
|---|
| 383 | bool pci_msi_domain_supports(struct pci_dev *pdev, unsigned int feature_mask, | 
|---|
| 384 | enum support_mode mode) | 
|---|
| 385 | { | 
|---|
| 386 | struct msi_domain_info *info; | 
|---|
| 387 | struct irq_domain *domain; | 
|---|
| 388 | unsigned int supported; | 
|---|
| 389 |  | 
|---|
| 390 | domain = dev_get_msi_domain(dev: &pdev->dev); | 
|---|
| 391 |  | 
|---|
| 392 | if (!domain || !irq_domain_is_hierarchy(domain)) { | 
|---|
| 393 | if (IS_ENABLED(CONFIG_PCI_MSI_ARCH_FALLBACKS)) | 
|---|
| 394 | return mode == ALLOW_LEGACY; | 
|---|
| 395 | return false; | 
|---|
| 396 | } | 
|---|
| 397 |  | 
|---|
| 398 | if (!irq_domain_is_msi_parent(domain)) { | 
|---|
| 399 | /* | 
|---|
| 400 | * For "global" PCI/MSI interrupt domains the associated | 
|---|
| 401 | * msi_domain_info::flags is the authoritative source of | 
|---|
| 402 | * information. | 
|---|
| 403 | */ | 
|---|
| 404 | info = domain->host_data; | 
|---|
| 405 | supported = info->flags; | 
|---|
| 406 | } else { | 
|---|
| 407 | /* | 
|---|
| 408 | * For MSI parent domains the supported feature set | 
|---|
| 409 | * is available in the parent ops. This makes checks | 
|---|
| 410 | * possible before actually instantiating the | 
|---|
| 411 | * per device domain because the parent is never | 
|---|
| 412 | * expanding the PCI/MSI functionality. | 
|---|
| 413 | */ | 
|---|
| 414 | supported = domain->msi_parent_ops->supported_flags; | 
|---|
| 415 | } | 
|---|
| 416 |  | 
|---|
| 417 | return (supported & feature_mask) == feature_mask; | 
|---|
| 418 | } | 
|---|
| 419 |  | 
|---|
| 420 | /* | 
|---|
| 421 | * Users of the generic MSI infrastructure expect a device to have a single ID, | 
|---|
| 422 | * so with DMA aliases we have to pick the least-worst compromise. Devices with | 
|---|
| 423 | * DMA phantom functions tend to still emit MSIs from the real function number, | 
|---|
| 424 | * so we ignore those and only consider topological aliases where either the | 
|---|
| 425 | * alias device or RID appears on a different bus number. We also make the | 
|---|
| 426 | * reasonable assumption that bridges are walked in an upstream direction (so | 
|---|
| 427 | * the last one seen wins), and the much braver assumption that the most likely | 
|---|
| 428 | * case is that of PCI->PCIe so we should always use the alias RID. This echoes | 
|---|
| 429 | * the logic from intel_irq_remapping's set_msi_sid(), which presumably works | 
|---|
| 430 | * well enough in practice; in the face of the horrible PCIe<->PCI-X conditions | 
|---|
| 431 | * for taking ownership all we can really do is close our eyes and hope... | 
|---|
| 432 | */ | 
|---|
| 433 | static int get_msi_id_cb(struct pci_dev *pdev, u16 alias, void *data) | 
|---|
| 434 | { | 
|---|
| 435 | u32 *pa = data; | 
|---|
| 436 | u8 bus = PCI_BUS_NUM(*pa); | 
|---|
| 437 |  | 
|---|
| 438 | if (pdev->bus->number != bus || PCI_BUS_NUM(alias) != bus) | 
|---|
| 439 | *pa = alias; | 
|---|
| 440 |  | 
|---|
| 441 | return 0; | 
|---|
| 442 | } | 
|---|
| 443 |  | 
|---|
| 444 | /** | 
|---|
| 445 | * pci_msi_domain_get_msi_rid - Get the MSI requester id (RID) | 
|---|
| 446 | * @domain:	The interrupt domain | 
|---|
| 447 | * @pdev:	The PCI device. | 
|---|
| 448 | * | 
|---|
| 449 | * The RID for a device is formed from the alias, with a firmware | 
|---|
| 450 | * supplied mapping applied | 
|---|
| 451 | * | 
|---|
| 452 | * Returns: The RID. | 
|---|
| 453 | */ | 
|---|
| 454 | u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev) | 
|---|
| 455 | { | 
|---|
| 456 | struct device_node *of_node; | 
|---|
| 457 | u32 rid = pci_dev_id(dev: pdev); | 
|---|
| 458 |  | 
|---|
| 459 | pci_for_each_dma_alias(pdev, fn: get_msi_id_cb, data: &rid); | 
|---|
| 460 |  | 
|---|
| 461 | of_node = irq_domain_get_of_node(d: domain); | 
|---|
| 462 | rid = of_node ? of_msi_xlate(dev: &pdev->dev, msi_np: &of_node, id_in: rid) : | 
|---|
| 463 | iort_msi_map_id(dev: &pdev->dev, id: rid); | 
|---|
| 464 |  | 
|---|
| 465 | return rid; | 
|---|
| 466 | } | 
|---|
| 467 |  | 
|---|
| 468 | /** | 
|---|
| 469 | * pci_msi_map_rid_ctlr_node - Get the MSI controller node and MSI requester id (RID) | 
|---|
| 470 | * @pdev:	The PCI device | 
|---|
| 471 | * @node:	Pointer to store the MSI controller device node | 
|---|
| 472 | * | 
|---|
| 473 | * Use the firmware data to find the MSI controller node for @pdev. | 
|---|
| 474 | * If found map the RID and initialize @node with it. @node value must | 
|---|
| 475 | * be set to NULL on entry. | 
|---|
| 476 | * | 
|---|
| 477 | * Returns: The RID. | 
|---|
| 478 | */ | 
|---|
| 479 | u32 pci_msi_map_rid_ctlr_node(struct pci_dev *pdev, struct device_node **node) | 
|---|
| 480 | { | 
|---|
| 481 | u32 rid = pci_dev_id(dev: pdev); | 
|---|
| 482 |  | 
|---|
| 483 | pci_for_each_dma_alias(pdev, fn: get_msi_id_cb, data: &rid); | 
|---|
| 484 |  | 
|---|
| 485 | return of_msi_xlate(dev: &pdev->dev, msi_np: node, id_in: rid); | 
|---|
| 486 | } | 
|---|
| 487 |  | 
|---|
| 488 | /** | 
|---|
| 489 | * pci_msi_get_device_domain - Get the MSI domain for a given PCI device | 
|---|
| 490 | * @pdev:	The PCI device | 
|---|
| 491 | * | 
|---|
| 492 | * Use the firmware data to find a device-specific MSI domain | 
|---|
| 493 | * (i.e. not one that is set as a default). | 
|---|
| 494 | * | 
|---|
| 495 | * Returns: The corresponding MSI domain or NULL if none has been found. | 
|---|
| 496 | */ | 
|---|
| 497 | struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev) | 
|---|
| 498 | { | 
|---|
| 499 | struct irq_domain *dom; | 
|---|
| 500 | u32 rid = pci_dev_id(dev: pdev); | 
|---|
| 501 |  | 
|---|
| 502 | pci_for_each_dma_alias(pdev, fn: get_msi_id_cb, data: &rid); | 
|---|
| 503 | dom = of_msi_map_get_device_domain(dev: &pdev->dev, id: rid, bus_token: DOMAIN_BUS_PCI_MSI); | 
|---|
| 504 | if (!dom) | 
|---|
| 505 | dom = iort_get_device_domain(dev: &pdev->dev, id: rid, | 
|---|
| 506 | bus_token: DOMAIN_BUS_PCI_MSI); | 
|---|
| 507 | return dom; | 
|---|
| 508 | } | 
|---|
| 509 |  | 
|---|