mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-07 12:25:00 -04:00
Merge "iommu/arm-smmu: Record page table configuration in debug structures"
This commit is contained in:
commit
03de949cee
3 changed files with 148 additions and 38 deletions
|
|
@ -1820,23 +1820,18 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
|
|||
struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
|
||||
unsigned long quirks = 0;
|
||||
struct iommu_group *group;
|
||||
struct io_pgtable *iop;
|
||||
|
||||
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_logger;
|
||||
goto out_unlock;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1893,7 +1888,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
|
|||
|
||||
if (cfg->fmt == ARM_SMMU_CTX_FMT_NONE) {
|
||||
ret = -EINVAL;
|
||||
goto out_logger;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
switch (smmu_domain->stage) {
|
||||
|
|
@ -1941,7 +1936,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
|
|||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto out_logger;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IOMMU_IO_PGTABLE_FAST
|
||||
|
|
@ -1955,7 +1950,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_logger;
|
||||
goto out_unlock;
|
||||
|
||||
cfg->cbndx = ret;
|
||||
|
||||
|
|
@ -1985,6 +1980,13 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
|
|||
goto out_clear_smmu;
|
||||
}
|
||||
|
||||
group = iommu_group_get_for_dev(smmu_domain->dev);
|
||||
iop = container_of(smmu_domain->pgtbl_ops, struct io_pgtable, ops);
|
||||
ret = iommu_logger_register(&smmu_domain->logger, domain, group, iop);
|
||||
iommu_group_put(group);
|
||||
if (ret)
|
||||
goto out_clear_smmu;
|
||||
|
||||
/*
|
||||
* assign any page table memory that might have been allocated
|
||||
* during alloc_io_pgtable_ops
|
||||
|
|
@ -1998,23 +2000,23 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
|
|||
domain->geometry.aperture_end = (1UL << ias) - 1;
|
||||
ret = arm_smmu_adjust_domain_geometry(dev, domain);
|
||||
if (ret)
|
||||
goto out_clear_smmu;
|
||||
goto out_logger;
|
||||
domain->geometry.force_aperture = true;
|
||||
|
||||
if (domain->type == IOMMU_DOMAIN_DMA) {
|
||||
ret = arm_smmu_get_dma_cookie(dev, smmu_domain);
|
||||
if (ret)
|
||||
goto out_clear_smmu;
|
||||
goto out_logger;
|
||||
}
|
||||
|
||||
/* Assign an asid */
|
||||
ret = arm_smmu_init_asid(domain, smmu);
|
||||
if (ret)
|
||||
goto out_clear_smmu;
|
||||
goto out_logger;
|
||||
|
||||
ret = arm_smmu_setup_context_bank(smmu_domain, smmu, dev);
|
||||
if (ret)
|
||||
goto out_clear_smmu;
|
||||
goto out_logger;
|
||||
|
||||
strlcpy(smmu_domain->domain.name, dev_name(dev),
|
||||
sizeof(smmu_domain->domain.name));
|
||||
|
|
@ -2022,12 +2024,12 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
|
|||
|
||||
return 0;
|
||||
|
||||
out_clear_smmu:
|
||||
arm_smmu_destroy_domain_context(domain);
|
||||
smmu_domain->smmu = NULL;
|
||||
out_logger:
|
||||
iommu_logger_unregister(smmu_domain->logger);
|
||||
smmu_domain->logger = NULL;
|
||||
out_clear_smmu:
|
||||
arm_smmu_destroy_domain_context(domain);
|
||||
smmu_domain->smmu = NULL;
|
||||
out_unlock:
|
||||
mutex_unlock(&smmu_domain->init_mutex);
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -12,47 +13,126 @@
|
|||
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 unsigned int iommu_logger_pgtable_levels(struct iommu_domain *domain,
|
||||
struct io_pgtable *iop)
|
||||
{
|
||||
unsigned int va_bits, pte_size, bits_per_level, pg_shift;
|
||||
unsigned long ias = iop->cfg.ias;
|
||||
|
||||
switch (iop->fmt) {
|
||||
case ARM_32_LPAE_S1:
|
||||
case ARM_64_LPAE_S1:
|
||||
#ifdef CONFIG_IOMMU_IO_PGTABLE_FAST
|
||||
case ARM_V8L_FAST:
|
||||
#endif
|
||||
pte_size = sizeof(u64);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
pg_shift = __ffs(domain->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 (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
|
||||
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, ttbr1;
|
||||
|
||||
switch (iop->fmt) {
|
||||
case ARM_32_LPAE_S1:
|
||||
case ARM_64_LPAE_S1:
|
||||
ttbr0 = iop->cfg.arm_lpae_s1_cfg.ttbr[0];
|
||||
ttbr1 = iop->cfg.arm_lpae_s1_cfg.ttbr[1];
|
||||
ret = 0;
|
||||
break;
|
||||
#ifdef CONFIG_IOMMU_IO_PGTABLE_FAST
|
||||
case ARM_V8L_FAST:
|
||||
ttbr0 = iop->cfg.av8l_fast_cfg.ttbr[0];
|
||||
ttbr1 = iop->cfg.av8l_fast_cfg.ttbr[1];
|
||||
ret = 0;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
*ttbr0_ptr = phys_to_virt(ttbr0);
|
||||
*ttbr1_ptr = ttbr1 ? phys_to_virt(ttbr1) : NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct iommu_debug_attachment *iommu_logger_init(
|
||||
struct iommu_domain *domain,
|
||||
struct iommu_group *group)
|
||||
struct iommu_group *group,
|
||||
struct io_pgtable *iop)
|
||||
{
|
||||
struct iommu_debug_attachment *logger;
|
||||
unsigned int levels = iommu_logger_pgtable_levels(domain, 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 NULL;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
INIT_LIST_HEAD(&logger->list);
|
||||
logger->domain = domain;
|
||||
logger->group = group;
|
||||
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 iommu_group *group)
|
||||
struct iommu_group *group,
|
||||
struct io_pgtable *iop)
|
||||
{
|
||||
struct iommu_debug_attachment *logger;
|
||||
|
||||
if (!logger_out)
|
||||
if (!logger_out || !domain || !group || !iop ||
|
||||
iop->fmt >= IO_PGTABLE_NUM_FMTS)
|
||||
return -EINVAL;
|
||||
|
||||
logger = iommu_logger_init(domain, group);
|
||||
if (!logger)
|
||||
return -ENOMEM;
|
||||
logger = iommu_logger_init(domain, group, iop);
|
||||
if (IS_ERR(logger))
|
||||
return PTR_ERR(logger);
|
||||
|
||||
mutex_lock(&iommu_debug_attachments_lock);
|
||||
list_add(&logger->list, &iommu_debug_attachments);
|
||||
|
|
|
|||
|
|
@ -4,18 +4,46 @@
|
|||
#ifndef __LINUX_QTI_IOMMU_LOGGER_H
|
||||
#define __LINUX_QTI_IOMMU_LOGGER_H
|
||||
|
||||
struct iommu_debug_attachment;
|
||||
#include <linux/io-pgtable.h>
|
||||
|
||||
enum iommu_logger_pgtable_fmt {
|
||||
IOMMU_LOGGER_ARM_32_LPAE_S1,
|
||||
IOMMU_LOGGER_ARM_64_LPAE_S1,
|
||||
IOMMU_LOGGER_MAX_PGTABLE_FMTS,
|
||||
};
|
||||
|
||||
/*
|
||||
* 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;
|
||||
enum iommu_logger_pgtable_fmt fmt;
|
||||
unsigned int levels;
|
||||
/*
|
||||
* Virtual addresses of the top-level page tables are stored here,
|
||||
* as they are more useful for debug tools than physical addresses.
|
||||
*/
|
||||
void *ttbr0;
|
||||
void *ttbr1;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_QTI_IOMMU_SUPPORT)
|
||||
|
||||
int iommu_logger_register(struct iommu_debug_attachment **a,
|
||||
struct iommu_domain *domain,
|
||||
struct iommu_group *group);
|
||||
struct iommu_group *group,
|
||||
struct io_pgtable *iop);
|
||||
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)
|
||||
struct iommu_group *group,
|
||||
struct io_pgtable *iop)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue