Loading drivers/iommu/Kconfig +9 −0 Original line number Diff line number Diff line Loading @@ -399,6 +399,14 @@ config SPAPR_TCE_IOMMU Enables bits of IOMMU API required by VFIO. The iommu_ops is not implemented as it is not necessary for VFIO. config QTI_IOMMU_SUPPORT tristate "Support for QTI iommu drivers" help The QTI GPU device may switch between multiple iommu domains, depending on usecase. This introduces a need to track all such domains in a non-driver specific manner. If in doubt say N. # ARM IOMMU support config ARM_SMMU tristate "ARM Ltd. System MMU (SMMU) Support" Loading @@ -406,6 +414,7 @@ config ARM_SMMU select IOMMU_API select IOMMU_IO_PGTABLE_LPAE select ARM_DMA_USE_IOMMU if ARM select QTI_IOMMU_SUPPORT help Support for implementations of the ARM System MMU architecture versions 1 and 2. Loading drivers/iommu/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ obj-$(CONFIG_TEGRA_IOMMU_SMMU) += tegra-smmu.o obj-$(CONFIG_EXYNOS_IOMMU) += exynos-iommu.o obj-$(CONFIG_FSL_PAMU) += fsl_pamu.o fsl_pamu_domain.o obj-$(CONFIG_S390_IOMMU) += s390-iommu.o obj-$(CONFIG_QTI_IOMMU_SUPPORT) += iommu-logger.o obj-$(CONFIG_QCOM_IOMMU) += qcom_iommu.o obj-$(CONFIG_HYPERV_IOMMU) += hyperv-iommu.o obj-$(CONFIG_VIRTIO_IOMMU) += virtio-iommu.o drivers/iommu/arm-smmu.c +15 −4 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ #include <linux/qcom_scm.h> #include "arm-smmu.h" #include "iommu-logger.h" #define CREATE_TRACE_POINTS #include "arm-smmu-trace.h" Loading Loading @@ -1872,17 +1873,24 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, struct msm_io_pgtable_info *pgtbl_info = &smmu_domain->pgtbl_info; struct arm_smmu_cfg *cfg = &smmu_domain->cfg; unsigned long quirks = 0; struct iommu_group *group; mutex_lock(&smmu_domain->init_mutex); if (smmu_domain->smmu) goto out_unlock; group = iommu_group_get(dev); ret = iommu_logger_register(&smmu_domain->logger, domain, group); iommu_group_put(group); if (ret) goto out_unlock; if (domain->type == IOMMU_DOMAIN_DMA) { ret = arm_smmu_setup_default_domain(dev, domain); if (ret) { dev_err(dev, "%s: default domain setup failed\n", __func__); goto out_unlock; goto out_logger; } } Loading Loading @@ -1939,7 +1947,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, if (cfg->fmt == ARM_SMMU_CTX_FMT_NONE) { ret = -EINVAL; goto out_unlock; goto out_logger; } switch (smmu_domain->stage) { Loading Loading @@ -1987,7 +1995,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, break; default: ret = -EINVAL; goto out_unlock; goto out_logger; } #ifdef CONFIG_IOMMU_IO_PGTABLE_FAST Loading @@ -2001,7 +2009,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, ret = arm_smmu_alloc_cb(domain, smmu, dev); if (ret < 0) goto out_unlock; goto out_logger; cfg->cbndx = ret; Loading Loading @@ -2071,6 +2079,8 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, out_clear_smmu: arm_smmu_destroy_domain_context(domain); smmu_domain->smmu = NULL; out_logger: iommu_logger_unregister(smmu_domain->logger); out_unlock: mutex_unlock(&smmu_domain->init_mutex); return ret; Loading Loading @@ -2186,6 +2196,7 @@ static void arm_smmu_domain_free(struct iommu_domain *domain) */ arm_smmu_put_dma_cookie(domain); arm_smmu_destroy_domain_context(domain); iommu_logger_unregister(smmu_domain->logger); kfree(smmu_domain); } Loading drivers/iommu/arm-smmu.h +1 −0 Original line number Diff line number Diff line Loading @@ -433,6 +433,7 @@ struct arm_smmu_domain { struct list_head secure_pool_list; /* nonsecure pool protected by pgtbl_lock */ struct list_head nonsecure_pool; struct iommu_debug_attachment *logger; struct msm_iommu_domain domain; }; Loading drivers/iommu/iommu-logger.c 0 → 100644 +79 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2020, The Linux Foundation. All rights reserved. */ #include <linux/module.h> #include <linux/iommu.h> #include <linux/slab.h> #include "iommu-logger.h" static DEFINE_MUTEX(iommu_debug_attachments_lock); static LIST_HEAD(iommu_debug_attachments); /* * Each group may have more than one domain; but each domain may * only have one group. * Used by debug tools to display the name of the device(s) associated * with a particular domain. */ struct iommu_debug_attachment { struct iommu_domain *domain; struct iommu_group *group; struct list_head list; }; static struct iommu_debug_attachment *iommu_logger_init( struct iommu_domain *domain, struct iommu_group *group) { struct iommu_debug_attachment *logger; logger = kzalloc(sizeof(*logger), GFP_KERNEL); if (!logger) return NULL; INIT_LIST_HEAD(&logger->list); logger->domain = domain; logger->group = group; return logger; } int iommu_logger_register(struct iommu_debug_attachment **logger_out, struct iommu_domain *domain, struct iommu_group *group) { struct iommu_debug_attachment *logger; if (!logger_out) return -EINVAL; logger = iommu_logger_init(domain, group); if (!logger) return -ENOMEM; mutex_lock(&iommu_debug_attachments_lock); list_add(&logger->list, &iommu_debug_attachments); mutex_unlock(&iommu_debug_attachments_lock); *logger_out = logger; return 0; } EXPORT_SYMBOL(iommu_logger_register); void iommu_logger_unregister(struct iommu_debug_attachment *logger) { if (!logger) return; mutex_lock(&iommu_debug_attachments_lock); list_del(&logger->list); mutex_unlock(&iommu_debug_attachments_lock); kfree(logger); } EXPORT_SYMBOL(iommu_logger_unregister); MODULE_DESCRIPTION("QTI IOMMU SUPPORT"); MODULE_LICENSE("GPL v2"); Loading
drivers/iommu/Kconfig +9 −0 Original line number Diff line number Diff line Loading @@ -399,6 +399,14 @@ config SPAPR_TCE_IOMMU Enables bits of IOMMU API required by VFIO. The iommu_ops is not implemented as it is not necessary for VFIO. config QTI_IOMMU_SUPPORT tristate "Support for QTI iommu drivers" help The QTI GPU device may switch between multiple iommu domains, depending on usecase. This introduces a need to track all such domains in a non-driver specific manner. If in doubt say N. # ARM IOMMU support config ARM_SMMU tristate "ARM Ltd. System MMU (SMMU) Support" Loading @@ -406,6 +414,7 @@ config ARM_SMMU select IOMMU_API select IOMMU_IO_PGTABLE_LPAE select ARM_DMA_USE_IOMMU if ARM select QTI_IOMMU_SUPPORT help Support for implementations of the ARM System MMU architecture versions 1 and 2. Loading
drivers/iommu/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ obj-$(CONFIG_TEGRA_IOMMU_SMMU) += tegra-smmu.o obj-$(CONFIG_EXYNOS_IOMMU) += exynos-iommu.o obj-$(CONFIG_FSL_PAMU) += fsl_pamu.o fsl_pamu_domain.o obj-$(CONFIG_S390_IOMMU) += s390-iommu.o obj-$(CONFIG_QTI_IOMMU_SUPPORT) += iommu-logger.o obj-$(CONFIG_QCOM_IOMMU) += qcom_iommu.o obj-$(CONFIG_HYPERV_IOMMU) += hyperv-iommu.o obj-$(CONFIG_VIRTIO_IOMMU) += virtio-iommu.o
drivers/iommu/arm-smmu.c +15 −4 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ #include <linux/qcom_scm.h> #include "arm-smmu.h" #include "iommu-logger.h" #define CREATE_TRACE_POINTS #include "arm-smmu-trace.h" Loading Loading @@ -1872,17 +1873,24 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, struct msm_io_pgtable_info *pgtbl_info = &smmu_domain->pgtbl_info; struct arm_smmu_cfg *cfg = &smmu_domain->cfg; unsigned long quirks = 0; struct iommu_group *group; mutex_lock(&smmu_domain->init_mutex); if (smmu_domain->smmu) goto out_unlock; group = iommu_group_get(dev); ret = iommu_logger_register(&smmu_domain->logger, domain, group); iommu_group_put(group); if (ret) goto out_unlock; if (domain->type == IOMMU_DOMAIN_DMA) { ret = arm_smmu_setup_default_domain(dev, domain); if (ret) { dev_err(dev, "%s: default domain setup failed\n", __func__); goto out_unlock; goto out_logger; } } Loading Loading @@ -1939,7 +1947,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, if (cfg->fmt == ARM_SMMU_CTX_FMT_NONE) { ret = -EINVAL; goto out_unlock; goto out_logger; } switch (smmu_domain->stage) { Loading Loading @@ -1987,7 +1995,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, break; default: ret = -EINVAL; goto out_unlock; goto out_logger; } #ifdef CONFIG_IOMMU_IO_PGTABLE_FAST Loading @@ -2001,7 +2009,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, ret = arm_smmu_alloc_cb(domain, smmu, dev); if (ret < 0) goto out_unlock; goto out_logger; cfg->cbndx = ret; Loading Loading @@ -2071,6 +2079,8 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, out_clear_smmu: arm_smmu_destroy_domain_context(domain); smmu_domain->smmu = NULL; out_logger: iommu_logger_unregister(smmu_domain->logger); out_unlock: mutex_unlock(&smmu_domain->init_mutex); return ret; Loading Loading @@ -2186,6 +2196,7 @@ static void arm_smmu_domain_free(struct iommu_domain *domain) */ arm_smmu_put_dma_cookie(domain); arm_smmu_destroy_domain_context(domain); iommu_logger_unregister(smmu_domain->logger); kfree(smmu_domain); } Loading
drivers/iommu/arm-smmu.h +1 −0 Original line number Diff line number Diff line Loading @@ -433,6 +433,7 @@ struct arm_smmu_domain { struct list_head secure_pool_list; /* nonsecure pool protected by pgtbl_lock */ struct list_head nonsecure_pool; struct iommu_debug_attachment *logger; struct msm_iommu_domain domain; }; Loading
drivers/iommu/iommu-logger.c 0 → 100644 +79 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2020, The Linux Foundation. All rights reserved. */ #include <linux/module.h> #include <linux/iommu.h> #include <linux/slab.h> #include "iommu-logger.h" static DEFINE_MUTEX(iommu_debug_attachments_lock); static LIST_HEAD(iommu_debug_attachments); /* * Each group may have more than one domain; but each domain may * only have one group. * Used by debug tools to display the name of the device(s) associated * with a particular domain. */ struct iommu_debug_attachment { struct iommu_domain *domain; struct iommu_group *group; struct list_head list; }; static struct iommu_debug_attachment *iommu_logger_init( struct iommu_domain *domain, struct iommu_group *group) { struct iommu_debug_attachment *logger; logger = kzalloc(sizeof(*logger), GFP_KERNEL); if (!logger) return NULL; INIT_LIST_HEAD(&logger->list); logger->domain = domain; logger->group = group; return logger; } int iommu_logger_register(struct iommu_debug_attachment **logger_out, struct iommu_domain *domain, struct iommu_group *group) { struct iommu_debug_attachment *logger; if (!logger_out) return -EINVAL; logger = iommu_logger_init(domain, group); if (!logger) return -ENOMEM; mutex_lock(&iommu_debug_attachments_lock); list_add(&logger->list, &iommu_debug_attachments); mutex_unlock(&iommu_debug_attachments_lock); *logger_out = logger; return 0; } EXPORT_SYMBOL(iommu_logger_register); void iommu_logger_unregister(struct iommu_debug_attachment *logger) { if (!logger) return; mutex_lock(&iommu_debug_attachments_lock); list_del(&logger->list); mutex_unlock(&iommu_debug_attachments_lock); kfree(logger); } EXPORT_SYMBOL(iommu_logger_unregister); MODULE_DESCRIPTION("QTI IOMMU SUPPORT"); MODULE_LICENSE("GPL v2");