cdx_msi.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * AMD CDX bus driver MSI support
  4. *
  5. * Copyright (C) 2022-2023, Advanced Micro Devices, Inc.
  6. */
  7. #include <linux/of.h>
  8. #include <linux/of_device.h>
  9. #include <linux/of_address.h>
  10. #include <linux/of_irq.h>
  11. #include <linux/irq.h>
  12. #include <linux/irqdomain.h>
  13. #include <linux/msi.h>
  14. #include <linux/cdx/cdx_bus.h>
  15. #include "cdx.h"
  16. static void cdx_msi_write_msg(struct irq_data *irq_data, struct msi_msg *msg)
  17. {
  18. struct msi_desc *msi_desc = irq_data_get_msi_desc(irq_data);
  19. struct cdx_device *cdx_dev = to_cdx_device(msi_desc->dev);
  20. /* We would not operate on msg here rather we wait for irq_bus_sync_unlock()
  21. * to be called from preemptible task context.
  22. */
  23. msi_desc->msg = *msg;
  24. cdx_dev->msi_write_pending = true;
  25. }
  26. static void cdx_msi_write_irq_lock(struct irq_data *irq_data)
  27. {
  28. struct msi_desc *msi_desc = irq_data_get_msi_desc(irq_data);
  29. struct cdx_device *cdx_dev = to_cdx_device(msi_desc->dev);
  30. mutex_lock(&cdx_dev->irqchip_lock);
  31. }
  32. static void cdx_msi_write_irq_unlock(struct irq_data *irq_data)
  33. {
  34. struct msi_desc *msi_desc = irq_data_get_msi_desc(irq_data);
  35. struct cdx_device *cdx_dev = to_cdx_device(msi_desc->dev);
  36. struct cdx_controller *cdx = cdx_dev->cdx;
  37. struct cdx_device_config dev_config;
  38. if (!cdx_dev->msi_write_pending) {
  39. mutex_unlock(&cdx_dev->irqchip_lock);
  40. return;
  41. }
  42. cdx_dev->msi_write_pending = false;
  43. mutex_unlock(&cdx_dev->irqchip_lock);
  44. dev_config.msi.msi_index = msi_desc->msi_index;
  45. dev_config.msi.data = msi_desc->msg.data;
  46. dev_config.msi.addr = ((u64)(msi_desc->msg.address_hi) << 32) | msi_desc->msg.address_lo;
  47. /*
  48. * dev_configure() is a controller callback which can interact with
  49. * Firmware or other entities, and can sleep, so invoke this function
  50. * outside of the mutex held region.
  51. */
  52. dev_config.type = CDX_DEV_MSI_CONF;
  53. if (cdx->ops->dev_configure)
  54. cdx->ops->dev_configure(cdx, cdx_dev->bus_num, cdx_dev->dev_num, &dev_config);
  55. }
  56. int cdx_enable_msi(struct cdx_device *cdx_dev)
  57. {
  58. struct cdx_controller *cdx = cdx_dev->cdx;
  59. struct cdx_device_config dev_config;
  60. dev_config.type = CDX_DEV_MSI_ENABLE;
  61. dev_config.msi_enable = true;
  62. if (cdx->ops->dev_configure) {
  63. return cdx->ops->dev_configure(cdx, cdx_dev->bus_num, cdx_dev->dev_num,
  64. &dev_config);
  65. }
  66. return -EOPNOTSUPP;
  67. }
  68. EXPORT_SYMBOL_GPL(cdx_enable_msi);
  69. void cdx_disable_msi(struct cdx_device *cdx_dev)
  70. {
  71. struct cdx_controller *cdx = cdx_dev->cdx;
  72. struct cdx_device_config dev_config;
  73. dev_config.type = CDX_DEV_MSI_ENABLE;
  74. dev_config.msi_enable = false;
  75. if (cdx->ops->dev_configure)
  76. cdx->ops->dev_configure(cdx, cdx_dev->bus_num, cdx_dev->dev_num, &dev_config);
  77. }
  78. EXPORT_SYMBOL_GPL(cdx_disable_msi);
  79. static struct irq_chip cdx_msi_irq_chip = {
  80. .name = "CDX-MSI",
  81. .irq_mask = irq_chip_mask_parent,
  82. .irq_unmask = irq_chip_unmask_parent,
  83. .irq_eoi = irq_chip_eoi_parent,
  84. .irq_set_affinity = msi_domain_set_affinity,
  85. .irq_write_msi_msg = cdx_msi_write_msg,
  86. .irq_bus_lock = cdx_msi_write_irq_lock,
  87. .irq_bus_sync_unlock = cdx_msi_write_irq_unlock
  88. };
  89. /* Convert an msi_desc to a unique identifier within the domain. */
  90. static irq_hw_number_t cdx_domain_calc_hwirq(struct cdx_device *dev,
  91. struct msi_desc *desc)
  92. {
  93. return ((irq_hw_number_t)dev->msi_dev_id << 10) | desc->msi_index;
  94. }
  95. static void cdx_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
  96. {
  97. arg->desc = desc;
  98. arg->hwirq = cdx_domain_calc_hwirq(to_cdx_device(desc->dev), desc);
  99. }
  100. static int cdx_msi_prepare(struct irq_domain *msi_domain,
  101. struct device *dev,
  102. int nvec, msi_alloc_info_t *info)
  103. {
  104. struct cdx_device *cdx_dev = to_cdx_device(dev);
  105. struct device *parent = cdx_dev->cdx->dev;
  106. struct msi_domain_info *msi_info;
  107. u32 dev_id;
  108. int ret;
  109. /* Retrieve device ID from requestor ID using parent device */
  110. ret = of_map_id(parent->of_node, cdx_dev->msi_dev_id, "msi-map", "msi-map-mask",
  111. NULL, &dev_id);
  112. if (ret) {
  113. dev_err(dev, "of_map_id failed for MSI: %d\n", ret);
  114. return ret;
  115. }
  116. #ifdef GENERIC_MSI_DOMAIN_OPS
  117. /* Set the device Id to be passed to the GIC-ITS */
  118. info->scratchpad[0].ul = dev_id;
  119. #endif
  120. msi_info = msi_get_domain_info(msi_domain->parent);
  121. return msi_info->ops->msi_prepare(msi_domain->parent, dev, nvec, info);
  122. }
  123. static struct msi_domain_ops cdx_msi_ops = {
  124. .msi_prepare = cdx_msi_prepare,
  125. .set_desc = cdx_msi_set_desc
  126. };
  127. static struct msi_domain_info cdx_msi_domain_info = {
  128. .ops = &cdx_msi_ops,
  129. .chip = &cdx_msi_irq_chip,
  130. .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
  131. MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS | MSI_FLAG_FREE_MSI_DESCS
  132. };
  133. struct irq_domain *cdx_msi_domain_init(struct device *dev)
  134. {
  135. struct device_node *np = dev->of_node;
  136. struct fwnode_handle *fwnode_handle;
  137. struct irq_domain *cdx_msi_domain;
  138. struct device_node *parent_node;
  139. struct irq_domain *parent;
  140. fwnode_handle = of_fwnode_handle(np);
  141. parent_node = of_parse_phandle(np, "msi-map", 1);
  142. if (!parent_node) {
  143. dev_err(dev, "msi-map not present on cdx controller\n");
  144. return NULL;
  145. }
  146. parent = irq_find_matching_fwnode(of_fwnode_handle(parent_node), DOMAIN_BUS_NEXUS);
  147. of_node_put(parent_node);
  148. if (!parent || !msi_get_domain_info(parent)) {
  149. dev_err(dev, "unable to locate ITS domain\n");
  150. return NULL;
  151. }
  152. cdx_msi_domain = msi_create_irq_domain(fwnode_handle, &cdx_msi_domain_info, parent);
  153. if (!cdx_msi_domain) {
  154. dev_err(dev, "unable to create CDX-MSI domain\n");
  155. return NULL;
  156. }
  157. dev_dbg(dev, "CDX-MSI domain created\n");
  158. return cdx_msi_domain;
  159. }
  160. EXPORT_SYMBOL_NS_GPL(cdx_msi_domain_init, "CDX_BUS_CONTROLLER");