android_kernel_samsung_sm8650/drivers/iommu/iommu-logger.c
Kamal Agrawal 219674c5f8 arm-smmu-qcom: Export QCOM io-pagetables for adreno smmu
Do the groundwork for kgsl to be able to use QCOM io-pagetables
to make maps/unmaps faster.

Change-Id: Ib1b484e1e0ba21aaf8e9c0cac1c100cc981a6825
Signed-off-by: Harshdeep Dhatt <quic_hdhatt@quicinc.com>
Signed-off-by: Kamal Agrawal <quic_kamaagra@quicinc.com>
2023-02-06 11:01:22 -08:00

174 lines
3.9 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/bitfield.h>
#include <linux/module.h>
#include <linux/iommu.h>
#include <linux/qcom-io-pgtable.h>
#include <linux/slab.h>
#include "iommu-logger.h"
static DEFINE_MUTEX(iommu_debug_attachments_lock);
static LIST_HEAD(iommu_debug_attachments);
static unsigned int iommu_logger_pgtable_levels(struct io_pgtable *iop)
{
unsigned int va_bits, pte_size, bits_per_level, pg_shift;
unsigned long ias = iop->cfg.ias;
switch ((u32)iop->fmt) {
case ARM_32_LPAE_S1:
case ARM_64_LPAE_S1:
#ifdef CONFIG_IOMMU_IO_PGTABLE_FAST
case ARM_V8L_FAST:
#endif
case QCOM_ARM_64_LPAE_S1:
pte_size = sizeof(u64);
break;
default:
return 0;
}
pg_shift = __ffs(iop->cfg.pgsize_bitmap);
bits_per_level = pg_shift - ilog2(pte_size);
va_bits = ias - pg_shift;
return DIV_ROUND_UP(va_bits, bits_per_level);
}
static enum iommu_logger_pgtable_fmt iommu_logger_pgtable_fmt_lut(
enum io_pgtable_fmt fmt)
{
switch ((u32)fmt) {
case ARM_32_LPAE_S1:
return IOMMU_LOGGER_ARM_32_LPAE_S1;
case ARM_64_LPAE_S1:
#ifdef CONFIG_IOMMU_IO_PGTABLE_FAST
case ARM_V8L_FAST:
#endif
case QCOM_ARM_64_LPAE_S1:
return IOMMU_LOGGER_ARM_64_LPAE_S1;
default:
return IOMMU_LOGGER_MAX_PGTABLE_FMTS;
}
}
static int iommu_logger_domain_ttbrs(struct io_pgtable *iop, void **ttbr0_ptr,
void **ttbr1_ptr)
{
int ret;
u64 ttbr0;
switch ((u32)iop->fmt) {
case ARM_32_LPAE_S1:
case ARM_64_LPAE_S1:
#ifdef CONFIG_IOMMU_IO_PGTABLE_FAST
case ARM_V8L_FAST:
#endif
case QCOM_ARM_64_LPAE_S1:
ttbr0 = iop->cfg.arm_lpae_s1_cfg.ttbr;
ret = 0;
break;
default:
ret = -EINVAL;
}
if (!ret) {
*ttbr0_ptr = phys_to_virt(ttbr0);
/*
* FIXME - fix ttbr1 retrieval later. In this kernel version
* struct io_pgtable no longer contains this information.
*/
*ttbr1_ptr = NULL;
}
return ret;
}
static struct iommu_debug_attachment *iommu_logger_init(
struct iommu_domain *domain,
struct device *dev,
struct io_pgtable *iop)
{
struct iommu_debug_attachment *logger;
char *client_name;
struct iommu_group *group;
unsigned int levels = iommu_logger_pgtable_levels(iop);
enum iommu_logger_pgtable_fmt fmt = iommu_logger_pgtable_fmt_lut(
iop->fmt);
void *ttbr0, *ttbr1;
int ret;
if (!levels || fmt == IOMMU_LOGGER_MAX_PGTABLE_FMTS)
return ERR_PTR(-EINVAL);
ret = iommu_logger_domain_ttbrs(iop, &ttbr0, &ttbr1);
if (ret)
return ERR_PTR(ret);
logger = kzalloc(sizeof(*logger), GFP_KERNEL);
if (!logger)
return ERR_PTR(-ENOMEM);
client_name = kasprintf(GFP_KERNEL, "%s", kobject_name(&dev->kobj));
if (!client_name) {
kfree(logger);
return ERR_PTR(-ENOMEM);
}
group = iommu_group_get(dev);
iommu_group_put(group);
INIT_LIST_HEAD(&logger->list);
logger->domain = domain;
logger->group = group;
logger->client_name = client_name;
logger->fmt = fmt;
logger->levels = levels;
logger->ttbr0 = ttbr0;
logger->ttbr1 = ttbr1;
return logger;
}
int iommu_logger_register(struct iommu_debug_attachment **logger_out,
struct iommu_domain *domain, struct device *dev,
struct io_pgtable *iop)
{
struct iommu_debug_attachment *logger;
if (!logger_out || !dev || !iop)
return -EINVAL;
logger = iommu_logger_init(domain, dev, iop);
if (IS_ERR(logger))
return PTR_ERR(logger);
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->client_name);
kfree(logger);
}
EXPORT_SYMBOL(iommu_logger_unregister);
MODULE_DESCRIPTION("QTI IOMMU SUPPORT");
MODULE_LICENSE("GPL v2");