From 39cc9a4594fa46aa833de2a1e6eab02a7d6d5eff Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Mon, 20 Jan 2020 16:47:10 -0800 Subject: [PATCH] iommu: qti: Track iommu domains Add a new module to track iommu domains, including those which may not currently be active. Supports multiple types of smmu drivers. Change-Id: Iacb98d823db8a87a2cf0868c467914847351950b Signed-off-by: Patrick Daly [isaacm@codeaurora.org: resolved trivial merge conflicts] Signed-off-by: Isaac J. Manjarres --- drivers/iommu/Kconfig | 9 ++++ drivers/iommu/Makefile | 1 + drivers/iommu/arm-smmu.c | 19 +++++++-- drivers/iommu/arm-smmu.h | 1 + drivers/iommu/iommu-logger.c | 79 ++++++++++++++++++++++++++++++++++++ drivers/iommu/iommu-logger.h | 25 ++++++++++++ 6 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 drivers/iommu/iommu-logger.c create mode 100644 drivers/iommu/iommu-logger.h diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index c9c9ee5182d6..38c4ee46ddb3 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -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" @@ -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. diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile index 8e85bce4fb84..b7df29893d8f 100644 --- a/drivers/iommu/Makefile +++ b/drivers/iommu/Makefile @@ -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 diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 13c6c8dd7f26..0589f3022544 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -51,6 +51,7 @@ #include #include "arm-smmu.h" +#include "iommu-logger.h" #define CREATE_TRACE_POINTS #include "arm-smmu-trace.h" @@ -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; } } @@ -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) { @@ -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 @@ -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; @@ -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; @@ -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); } diff --git a/drivers/iommu/arm-smmu.h b/drivers/iommu/arm-smmu.h index 534dd8286356..9ad4db0c5082 100644 --- a/drivers/iommu/arm-smmu.h +++ b/drivers/iommu/arm-smmu.h @@ -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; }; diff --git a/drivers/iommu/iommu-logger.c b/drivers/iommu/iommu-logger.c new file mode 100644 index 000000000000..483c9c4be897 --- /dev/null +++ b/drivers/iommu/iommu-logger.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include + +#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"); diff --git a/drivers/iommu/iommu-logger.h b/drivers/iommu/iommu-logger.h new file mode 100644 index 000000000000..3afe1872a201 --- /dev/null +++ b/drivers/iommu/iommu-logger.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. */ + +#ifndef __LINUX_QTI_IOMMU_LOGGER_H +#define __LINUX_QTI_IOMMU_LOGGER_H + +struct iommu_debug_attachment; + +#if IS_ENABLED(CONFIG_QTI_IOMMU_SUPPORT) + +int iommu_logger_register(struct iommu_debug_attachment **a, + struct iommu_domain *domain, + struct iommu_group *group); +void iommu_logger_unregister(struct iommu_debug_attachment *a); +#else +static inline int iommu_logger_register(struct iommu_debug_attachment **a, + struct iommu_domain *domain, + struct iommu_group *group) +{ + return 0; +} + +static inline void iommu_logger_unregister(struct iommu_debug_attachment *a) {} +#endif /* CONFIG_QTI_IOMMU_LOGGER */ +#endif /* __LINUX_QTI_IOMMU_LOGGER_H */