iommu-logger.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
  4. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  5. */
  6. #include <linux/bitfield.h>
  7. #include <linux/module.h>
  8. #include <linux/iommu.h>
  9. #include <linux/qcom-io-pgtable.h>
  10. #include <linux/slab.h>
  11. #include "iommu-logger.h"
  12. static DEFINE_MUTEX(iommu_debug_attachments_lock);
  13. static LIST_HEAD(iommu_debug_attachments);
  14. static unsigned int iommu_logger_pgtable_levels(struct io_pgtable *iop)
  15. {
  16. unsigned int va_bits, pte_size, bits_per_level, pg_shift;
  17. unsigned long ias = iop->cfg.ias;
  18. switch ((u32)iop->fmt) {
  19. case ARM_32_LPAE_S1:
  20. case ARM_64_LPAE_S1:
  21. #ifdef CONFIG_IOMMU_IO_PGTABLE_FAST
  22. case ARM_V8L_FAST:
  23. #endif
  24. case QCOM_ARM_64_LPAE_S1:
  25. pte_size = sizeof(u64);
  26. break;
  27. default:
  28. return 0;
  29. }
  30. pg_shift = __ffs(iop->cfg.pgsize_bitmap);
  31. bits_per_level = pg_shift - ilog2(pte_size);
  32. va_bits = ias - pg_shift;
  33. return DIV_ROUND_UP(va_bits, bits_per_level);
  34. }
  35. static enum iommu_logger_pgtable_fmt iommu_logger_pgtable_fmt_lut(
  36. enum io_pgtable_fmt fmt)
  37. {
  38. switch ((u32)fmt) {
  39. case ARM_32_LPAE_S1:
  40. return IOMMU_LOGGER_ARM_32_LPAE_S1;
  41. case ARM_64_LPAE_S1:
  42. #ifdef CONFIG_IOMMU_IO_PGTABLE_FAST
  43. case ARM_V8L_FAST:
  44. #endif
  45. case QCOM_ARM_64_LPAE_S1:
  46. return IOMMU_LOGGER_ARM_64_LPAE_S1;
  47. default:
  48. return IOMMU_LOGGER_MAX_PGTABLE_FMTS;
  49. }
  50. }
  51. static int iommu_logger_domain_ttbrs(struct io_pgtable *iop, void **ttbr0_ptr,
  52. void **ttbr1_ptr)
  53. {
  54. int ret;
  55. u64 ttbr0;
  56. switch ((u32)iop->fmt) {
  57. case ARM_32_LPAE_S1:
  58. case ARM_64_LPAE_S1:
  59. #ifdef CONFIG_IOMMU_IO_PGTABLE_FAST
  60. case ARM_V8L_FAST:
  61. #endif
  62. case QCOM_ARM_64_LPAE_S1:
  63. ttbr0 = iop->cfg.arm_lpae_s1_cfg.ttbr;
  64. ret = 0;
  65. break;
  66. default:
  67. ret = -EINVAL;
  68. }
  69. if (!ret) {
  70. *ttbr0_ptr = phys_to_virt(ttbr0);
  71. /*
  72. * FIXME - fix ttbr1 retrieval later. In this kernel version
  73. * struct io_pgtable no longer contains this information.
  74. */
  75. *ttbr1_ptr = NULL;
  76. }
  77. return ret;
  78. }
  79. static struct iommu_debug_attachment *iommu_logger_init(
  80. struct iommu_domain *domain,
  81. struct device *dev,
  82. struct io_pgtable *iop)
  83. {
  84. struct iommu_debug_attachment *logger;
  85. char *client_name;
  86. struct iommu_group *group;
  87. unsigned int levels = iommu_logger_pgtable_levels(iop);
  88. enum iommu_logger_pgtable_fmt fmt = iommu_logger_pgtable_fmt_lut(
  89. iop->fmt);
  90. void *ttbr0, *ttbr1;
  91. int ret;
  92. if (!levels || fmt == IOMMU_LOGGER_MAX_PGTABLE_FMTS)
  93. return ERR_PTR(-EINVAL);
  94. ret = iommu_logger_domain_ttbrs(iop, &ttbr0, &ttbr1);
  95. if (ret)
  96. return ERR_PTR(ret);
  97. logger = kzalloc(sizeof(*logger), GFP_KERNEL);
  98. if (!logger)
  99. return ERR_PTR(-ENOMEM);
  100. client_name = kasprintf(GFP_KERNEL, "%s", kobject_name(&dev->kobj));
  101. if (!client_name) {
  102. kfree(logger);
  103. return ERR_PTR(-ENOMEM);
  104. }
  105. group = iommu_group_get(dev);
  106. iommu_group_put(group);
  107. INIT_LIST_HEAD(&logger->list);
  108. logger->domain = domain;
  109. logger->group = group;
  110. logger->client_name = client_name;
  111. logger->fmt = fmt;
  112. logger->levels = levels;
  113. logger->ttbr0 = ttbr0;
  114. logger->ttbr1 = ttbr1;
  115. return logger;
  116. }
  117. int iommu_logger_register(struct iommu_debug_attachment **logger_out,
  118. struct iommu_domain *domain, struct device *dev,
  119. struct io_pgtable *iop)
  120. {
  121. struct iommu_debug_attachment *logger;
  122. if (!logger_out || !dev || !iop)
  123. return -EINVAL;
  124. logger = iommu_logger_init(domain, dev, iop);
  125. if (IS_ERR(logger))
  126. return PTR_ERR(logger);
  127. mutex_lock(&iommu_debug_attachments_lock);
  128. list_add(&logger->list, &iommu_debug_attachments);
  129. mutex_unlock(&iommu_debug_attachments_lock);
  130. *logger_out = logger;
  131. return 0;
  132. }
  133. EXPORT_SYMBOL(iommu_logger_register);
  134. void iommu_logger_unregister(struct iommu_debug_attachment *logger)
  135. {
  136. if (!logger)
  137. return;
  138. mutex_lock(&iommu_debug_attachments_lock);
  139. list_del(&logger->list);
  140. mutex_unlock(&iommu_debug_attachments_lock);
  141. kfree(logger->client_name);
  142. kfree(logger);
  143. }
  144. EXPORT_SYMBOL(iommu_logger_unregister);
  145. MODULE_DESCRIPTION("QTI IOMMU SUPPORT");
  146. MODULE_LICENSE("GPL v2");