fsl-mc-msi.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Freescale Management Complex (MC) bus driver MSI support
  4. *
  5. * Copyright (C) 2015-2016 Freescale Semiconductor, Inc.
  6. * Author: German Rivera <[email protected]>
  7. *
  8. */
  9. #include <linux/of_device.h>
  10. #include <linux/of_address.h>
  11. #include <linux/of_irq.h>
  12. #include <linux/irq.h>
  13. #include <linux/irqdomain.h>
  14. #include <linux/msi.h>
  15. #include <linux/acpi_iort.h>
  16. #include "fsl-mc-private.h"
  17. #ifdef GENERIC_MSI_DOMAIN_OPS
  18. /*
  19. * Generate a unique ID identifying the interrupt (only used within the MSI
  20. * irqdomain. Combine the icid with the interrupt index.
  21. */
  22. static irq_hw_number_t fsl_mc_domain_calc_hwirq(struct fsl_mc_device *dev,
  23. struct msi_desc *desc)
  24. {
  25. /*
  26. * Make the base hwirq value for ICID*10000 so it is readable
  27. * as a decimal value in /proc/interrupts.
  28. */
  29. return (irq_hw_number_t)(desc->msi_index + (dev->icid * 10000));
  30. }
  31. static void fsl_mc_msi_set_desc(msi_alloc_info_t *arg,
  32. struct msi_desc *desc)
  33. {
  34. arg->desc = desc;
  35. arg->hwirq = fsl_mc_domain_calc_hwirq(to_fsl_mc_device(desc->dev),
  36. desc);
  37. }
  38. #else
  39. #define fsl_mc_msi_set_desc NULL
  40. #endif
  41. static void fsl_mc_msi_update_dom_ops(struct msi_domain_info *info)
  42. {
  43. struct msi_domain_ops *ops = info->ops;
  44. if (!ops)
  45. return;
  46. /*
  47. * set_desc should not be set by the caller
  48. */
  49. if (!ops->set_desc)
  50. ops->set_desc = fsl_mc_msi_set_desc;
  51. }
  52. static void __fsl_mc_msi_write_msg(struct fsl_mc_device *mc_bus_dev,
  53. struct fsl_mc_device_irq *mc_dev_irq,
  54. struct msi_desc *msi_desc)
  55. {
  56. int error;
  57. struct fsl_mc_device *owner_mc_dev = mc_dev_irq->mc_dev;
  58. struct dprc_irq_cfg irq_cfg;
  59. /*
  60. * msi_desc->msg.address is 0x0 when this function is invoked in
  61. * the free_irq() code path. In this case, for the MC, we don't
  62. * really need to "unprogram" the MSI, so we just return.
  63. */
  64. if (msi_desc->msg.address_lo == 0x0 && msi_desc->msg.address_hi == 0x0)
  65. return;
  66. if (!owner_mc_dev)
  67. return;
  68. irq_cfg.paddr = ((u64)msi_desc->msg.address_hi << 32) |
  69. msi_desc->msg.address_lo;
  70. irq_cfg.val = msi_desc->msg.data;
  71. irq_cfg.irq_num = msi_desc->irq;
  72. if (owner_mc_dev == mc_bus_dev) {
  73. /*
  74. * IRQ is for the mc_bus_dev's DPRC itself
  75. */
  76. error = dprc_set_irq(mc_bus_dev->mc_io,
  77. MC_CMD_FLAG_INTR_DIS | MC_CMD_FLAG_PRI,
  78. mc_bus_dev->mc_handle,
  79. mc_dev_irq->dev_irq_index,
  80. &irq_cfg);
  81. if (error < 0) {
  82. dev_err(&owner_mc_dev->dev,
  83. "dprc_set_irq() failed: %d\n", error);
  84. }
  85. } else {
  86. /*
  87. * IRQ is for for a child device of mc_bus_dev
  88. */
  89. error = dprc_set_obj_irq(mc_bus_dev->mc_io,
  90. MC_CMD_FLAG_INTR_DIS | MC_CMD_FLAG_PRI,
  91. mc_bus_dev->mc_handle,
  92. owner_mc_dev->obj_desc.type,
  93. owner_mc_dev->obj_desc.id,
  94. mc_dev_irq->dev_irq_index,
  95. &irq_cfg);
  96. if (error < 0) {
  97. dev_err(&owner_mc_dev->dev,
  98. "dprc_obj_set_irq() failed: %d\n", error);
  99. }
  100. }
  101. }
  102. /*
  103. * NOTE: This function is invoked with interrupts disabled
  104. */
  105. static void fsl_mc_msi_write_msg(struct irq_data *irq_data,
  106. struct msi_msg *msg)
  107. {
  108. struct msi_desc *msi_desc = irq_data_get_msi_desc(irq_data);
  109. struct fsl_mc_device *mc_bus_dev = to_fsl_mc_device(msi_desc->dev);
  110. struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev);
  111. struct fsl_mc_device_irq *mc_dev_irq =
  112. &mc_bus->irq_resources[msi_desc->msi_index];
  113. msi_desc->msg = *msg;
  114. /*
  115. * Program the MSI (paddr, value) pair in the device:
  116. */
  117. __fsl_mc_msi_write_msg(mc_bus_dev, mc_dev_irq, msi_desc);
  118. }
  119. static void fsl_mc_msi_update_chip_ops(struct msi_domain_info *info)
  120. {
  121. struct irq_chip *chip = info->chip;
  122. if (!chip)
  123. return;
  124. /*
  125. * irq_write_msi_msg should not be set by the caller
  126. */
  127. if (!chip->irq_write_msi_msg)
  128. chip->irq_write_msi_msg = fsl_mc_msi_write_msg;
  129. }
  130. /**
  131. * fsl_mc_msi_create_irq_domain - Create a fsl-mc MSI interrupt domain
  132. * @fwnode: Optional firmware node of the interrupt controller
  133. * @info: MSI domain info
  134. * @parent: Parent irq domain
  135. *
  136. * Updates the domain and chip ops and creates a fsl-mc MSI
  137. * interrupt domain.
  138. *
  139. * Returns:
  140. * A domain pointer or NULL in case of failure.
  141. */
  142. struct irq_domain *fsl_mc_msi_create_irq_domain(struct fwnode_handle *fwnode,
  143. struct msi_domain_info *info,
  144. struct irq_domain *parent)
  145. {
  146. struct irq_domain *domain;
  147. if (WARN_ON((info->flags & MSI_FLAG_LEVEL_CAPABLE)))
  148. info->flags &= ~MSI_FLAG_LEVEL_CAPABLE;
  149. if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS)
  150. fsl_mc_msi_update_dom_ops(info);
  151. if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
  152. fsl_mc_msi_update_chip_ops(info);
  153. info->flags |= MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS | MSI_FLAG_FREE_MSI_DESCS;
  154. domain = msi_create_irq_domain(fwnode, info, parent);
  155. if (domain)
  156. irq_domain_update_bus_token(domain, DOMAIN_BUS_FSL_MC_MSI);
  157. return domain;
  158. }
  159. struct irq_domain *fsl_mc_find_msi_domain(struct device *dev)
  160. {
  161. struct device *root_dprc_dev;
  162. struct device *bus_dev;
  163. struct irq_domain *msi_domain;
  164. struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
  165. fsl_mc_get_root_dprc(dev, &root_dprc_dev);
  166. bus_dev = root_dprc_dev->parent;
  167. if (bus_dev->of_node) {
  168. msi_domain = of_msi_map_get_device_domain(dev,
  169. mc_dev->icid,
  170. DOMAIN_BUS_FSL_MC_MSI);
  171. /*
  172. * if the msi-map property is missing assume that all the
  173. * child containers inherit the domain from the parent
  174. */
  175. if (!msi_domain)
  176. msi_domain = of_msi_get_domain(bus_dev,
  177. bus_dev->of_node,
  178. DOMAIN_BUS_FSL_MC_MSI);
  179. } else {
  180. msi_domain = iort_get_device_domain(dev, mc_dev->icid,
  181. DOMAIN_BUS_FSL_MC_MSI);
  182. }
  183. return msi_domain;
  184. }
  185. int fsl_mc_msi_domain_alloc_irqs(struct device *dev, unsigned int irq_count)
  186. {
  187. struct irq_domain *msi_domain;
  188. int error;
  189. msi_domain = dev_get_msi_domain(dev);
  190. if (!msi_domain)
  191. return -EINVAL;
  192. error = msi_setup_device_data(dev);
  193. if (error)
  194. return error;
  195. msi_lock_descs(dev);
  196. if (msi_first_desc(dev, MSI_DESC_ALL))
  197. error = -EINVAL;
  198. msi_unlock_descs(dev);
  199. if (error)
  200. return error;
  201. /*
  202. * NOTE: Calling this function will trigger the invocation of the
  203. * its_fsl_mc_msi_prepare() callback
  204. */
  205. error = msi_domain_alloc_irqs(msi_domain, dev, irq_count);
  206. if (error)
  207. dev_err(dev, "Failed to allocate IRQs\n");
  208. return error;
  209. }
  210. void fsl_mc_msi_domain_free_irqs(struct device *dev)
  211. {
  212. struct irq_domain *msi_domain;
  213. msi_domain = dev_get_msi_domain(dev);
  214. if (!msi_domain)
  215. return;
  216. msi_domain_free_irqs(msi_domain, dev);
  217. }