irq-gic-v3-its-fsl-mc-msi.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  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 <German.Rivera@freescale.com>
  7. *
  8. */
  9. #include <linux/of_device.h>
  10. #include <linux/of_address.h>
  11. #include <linux/irq.h>
  12. #include <linux/msi.h>
  13. #include <linux/of.h>
  14. #include <linux/of_irq.h>
  15. #include <linux/fsl/mc.h>
  16. static struct irq_chip its_msi_irq_chip = {
  17. .name = "ITS-fMSI",
  18. .irq_mask = irq_chip_mask_parent,
  19. .irq_unmask = irq_chip_unmask_parent,
  20. .irq_eoi = irq_chip_eoi_parent,
  21. .irq_set_affinity = msi_domain_set_affinity
  22. };
  23. static int its_fsl_mc_msi_prepare(struct irq_domain *msi_domain,
  24. struct device *dev,
  25. int nvec, msi_alloc_info_t *info)
  26. {
  27. struct fsl_mc_device *mc_bus_dev;
  28. struct msi_domain_info *msi_info;
  29. if (!dev_is_fsl_mc(dev))
  30. return -EINVAL;
  31. mc_bus_dev = to_fsl_mc_device(dev);
  32. if (!(mc_bus_dev->flags & FSL_MC_IS_DPRC))
  33. return -EINVAL;
  34. /*
  35. * Set the device Id to be passed to the GIC-ITS:
  36. *
  37. * NOTE: This device id corresponds to the IOMMU stream ID
  38. * associated with the DPRC object (ICID).
  39. */
  40. info->scratchpad[0].ul = mc_bus_dev->icid;
  41. msi_info = msi_get_domain_info(msi_domain->parent);
  42. /* Allocate at least 32 MSIs, and always as a power of 2 */
  43. nvec = max_t(int, 32, roundup_pow_of_two(nvec));
  44. return msi_info->ops->msi_prepare(msi_domain->parent, dev, nvec, info);
  45. }
  46. static struct msi_domain_ops its_fsl_mc_msi_ops __ro_after_init = {
  47. .msi_prepare = its_fsl_mc_msi_prepare,
  48. };
  49. static struct msi_domain_info its_fsl_mc_msi_domain_info = {
  50. .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS),
  51. .ops = &its_fsl_mc_msi_ops,
  52. .chip = &its_msi_irq_chip,
  53. };
  54. static const struct of_device_id its_device_id[] = {
  55. { .compatible = "arm,gic-v3-its", },
  56. {},
  57. };
  58. static int __init its_fsl_mc_msi_init(void)
  59. {
  60. struct device_node *np;
  61. struct irq_domain *parent;
  62. struct irq_domain *mc_msi_domain;
  63. for (np = of_find_matching_node(NULL, its_device_id); np;
  64. np = of_find_matching_node(np, its_device_id)) {
  65. if (!of_device_is_available(np))
  66. continue;
  67. if (!of_property_read_bool(np, "msi-controller"))
  68. continue;
  69. parent = irq_find_matching_host(np, DOMAIN_BUS_NEXUS);
  70. if (!parent || !msi_get_domain_info(parent)) {
  71. pr_err("%pOF: unable to locate ITS domain\n", np);
  72. continue;
  73. }
  74. mc_msi_domain = fsl_mc_msi_create_irq_domain(
  75. of_node_to_fwnode(np),
  76. &its_fsl_mc_msi_domain_info,
  77. parent);
  78. if (!mc_msi_domain) {
  79. pr_err("%pOF: unable to create fsl-mc domain\n", np);
  80. continue;
  81. }
  82. pr_info("fsl-mc MSI: %pOF domain created\n", np);
  83. }
  84. return 0;
  85. }
  86. early_initcall(its_fsl_mc_msi_init);