irq-msi-lib.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. // Copyright (C) 2022 Linutronix GmbH
  3. // Copyright (C) 2022 Intel
  4. #include <linux/export.h>
  5. #include "irq-msi-lib.h"
  6. /**
  7. * msi_lib_init_dev_msi_info - Domain info setup for MSI domains
  8. * @dev: The device for which the domain is created for
  9. * @domain: The domain providing this callback
  10. * @real_parent: The real parent domain of the domain to be initialized
  11. * which might be a domain built on top of @domain or
  12. * @domain itself
  13. * @info: The domain info for the domain to be initialize
  14. *
  15. * This function is to be used for all types of MSI domains above the root
  16. * parent domain and any intermediates. The topmost parent domain specific
  17. * functionality is determined via @real_parent.
  18. *
  19. * All intermediate domains between the root and the device domain must
  20. * have either msi_parent_ops.init_dev_msi_info = msi_parent_init_dev_msi_info
  21. * or invoke it down the line.
  22. */
  23. bool msi_lib_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
  24. struct irq_domain *real_parent,
  25. struct msi_domain_info *info)
  26. {
  27. const struct msi_parent_ops *pops = real_parent->msi_parent_ops;
  28. u32 required_flags;
  29. /* Parent ops available? */
  30. if (WARN_ON_ONCE(!pops))
  31. return false;
  32. /*
  33. * MSI parent domain specific settings. For now there is only the
  34. * root parent domain, e.g. NEXUS, acting as a MSI parent, but it is
  35. * possible to stack MSI parents. See x86 vector -> irq remapping
  36. */
  37. if (domain->bus_token == pops->bus_select_token) {
  38. if (WARN_ON_ONCE(domain != real_parent))
  39. return false;
  40. } else {
  41. WARN_ON_ONCE(1);
  42. return false;
  43. }
  44. required_flags = pops->required_flags;
  45. /* Is the target domain bus token supported? */
  46. switch(info->bus_token) {
  47. case DOMAIN_BUS_PCI_DEVICE_MSI:
  48. case DOMAIN_BUS_PCI_DEVICE_MSIX:
  49. if (WARN_ON_ONCE(!IS_ENABLED(CONFIG_PCI_MSI)))
  50. return false;
  51. break;
  52. case DOMAIN_BUS_DEVICE_MSI:
  53. /*
  54. * Per device MSI should never have any MSI feature bits
  55. * set. It's sole purpose is to create a dumb interrupt
  56. * chip which has a device specific irq_write_msi_msg()
  57. * callback.
  58. */
  59. if (WARN_ON_ONCE(info->flags))
  60. return false;
  61. /* Core managed MSI descriptors */
  62. info->flags = MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS | MSI_FLAG_FREE_MSI_DESCS;
  63. fallthrough;
  64. case DOMAIN_BUS_WIRED_TO_MSI:
  65. /* Remove PCI specific flags */
  66. required_flags &= ~MSI_FLAG_PCI_MSI_MASK_PARENT;
  67. break;
  68. default:
  69. /*
  70. * This should never be reached. See
  71. * msi_lib_irq_domain_select()
  72. */
  73. WARN_ON_ONCE(1);
  74. return false;
  75. }
  76. /*
  77. * Mask out the domain specific MSI feature flags which are not
  78. * supported by the real parent.
  79. */
  80. info->flags &= pops->supported_flags;
  81. /* Enforce the required flags */
  82. info->flags |= required_flags;
  83. /* Chip updates for all child bus types */
  84. if (!info->chip->irq_eoi)
  85. info->chip->irq_eoi = irq_chip_eoi_parent;
  86. if (!info->chip->irq_ack)
  87. info->chip->irq_ack = irq_chip_ack_parent;
  88. /*
  89. * The device MSI domain can never have a set affinity callback. It
  90. * always has to rely on the parent domain to handle affinity
  91. * settings. The device MSI domain just has to write the resulting
  92. * MSI message into the hardware which is the whole purpose of the
  93. * device MSI domain aside of mask/unmask which is provided e.g. by
  94. * PCI/MSI device domains.
  95. */
  96. info->chip->irq_set_affinity = msi_domain_set_affinity;
  97. return true;
  98. }
  99. EXPORT_SYMBOL_GPL(msi_lib_init_dev_msi_info);
  100. /**
  101. * msi_lib_irq_domain_select - Shared select function for NEXUS domains
  102. * @d: Pointer to the irq domain on which select is invoked
  103. * @fwspec: Firmware spec describing what is searched
  104. * @bus_token: The bus token for which a matching irq domain is looked up
  105. *
  106. * Returns: %0 if @d is not what is being looked for
  107. *
  108. * %1 if @d is either the domain which is directly searched for or
  109. * if @d is providing the parent MSI domain for the functionality
  110. * requested with @bus_token.
  111. */
  112. int msi_lib_irq_domain_select(struct irq_domain *d, struct irq_fwspec *fwspec,
  113. enum irq_domain_bus_token bus_token)
  114. {
  115. const struct msi_parent_ops *ops = d->msi_parent_ops;
  116. u32 busmask = BIT(bus_token);
  117. if (!ops)
  118. return 0;
  119. if (fwspec->fwnode != d->fwnode || fwspec->param_count != 0)
  120. return 0;
  121. /* Handle pure domain searches */
  122. if (bus_token == ops->bus_select_token)
  123. return 1;
  124. return !!(ops->bus_select_mask & busmask);
  125. }
  126. EXPORT_SYMBOL_GPL(msi_lib_irq_domain_select);