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 <pdaly@codeaurora.org>
[isaacm@codeaurora.org: resolved trivial merge conflicts]
Signed-off-by: Isaac J. Manjarres <isaacm@codeaurora.org>
This commit is contained in:
Patrick Daly 2020-01-20 16:47:10 -08:00 • committed by Isaac J. Manjarres
commit 39cc9a4594
6 changed files with 130 additions and 4 deletions

View file

@ -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.

View file

@ -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

View file

@ -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"
@ -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);
}

View file

@ -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;
};

View file

@ -0,0 +1,79 @@
// 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");

View file

@ -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 */