Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f1746fc8 authored by Patrick Daly's avatar Patrick Daly
Browse files

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: default avatarPatrick Daly <pdaly@codeaurora.org>
parent 3313f94b
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -367,6 +367,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
	bool "ARM Ltd. System MMU (SMMU) Support"
@@ -375,6 +383,7 @@ config ARM_SMMU
	select IOMMU_IO_PGTABLE_LPAE
	select ARM_DMA_USE_IOMMU if ARM
	select ARM64_DMA_USE_IOMMU if ARM64
	select QTI_IOMMU_SUPPORT
	help
	  Support for implementations of the ARM System MMU architecture
	  versions 1 and 2.
+1 −0
Original line number Diff line number Diff line
@@ -34,4 +34,5 @@ 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
+16 −4
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@
#include "io-pgtable.h"
#include "arm-smmu-regs.h"
#include "arm-smmu-debug.h"
#include "iommu-logger.h"
#include <linux/debugfs.h>
#include <linux/uaccess.h>

@@ -394,6 +395,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 iommu_domain		domain;
};

@@ -2079,17 +2081,24 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
	struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
	unsigned long quirks = 0;
	bool dynamic;
	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;
		}
	}

@@ -2147,7 +2156,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) {
@@ -2195,7 +2204,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
		break;
	default:
		ret = -EINVAL;
		goto out_unlock;
		goto out_logger;
	}

	if (smmu_domain->attributes & (1 << DOMAIN_ATTR_FAST))
@@ -2217,7 +2226,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;

@@ -2325,6 +2334,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;
@@ -2448,6 +2459,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);
}

+77 −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>

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");
+25 −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. */

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