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

Commit 03ea9668 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "iommu/arm-smmu: Adopt bitfield model for remaining SMMU registers"

parents 1578f169 9fa87fcf
Loading
Loading
Loading
Loading
+38 −4
Original line number Diff line number Diff line
@@ -48,25 +48,60 @@ const struct arm_smmu_impl calxeda_impl = {
};


struct cavium_smmu {
	struct arm_smmu_device smmu;
	u32 id_base;
};

static int cavium_cfg_probe(struct arm_smmu_device *smmu)
{
	static atomic_t context_count = ATOMIC_INIT(0);
	struct cavium_smmu *cs = container_of(smmu, struct cavium_smmu, smmu);
	/*
	 * Cavium CN88xx erratum #27704.
	 * Ensure ASID and VMID allocation is unique across all SMMUs in
	 * the system.
	 */
	smmu->cavium_id_base = atomic_fetch_add(smmu->num_context_banks,
						   &context_count);
	cs->id_base = atomic_fetch_add(smmu->num_context_banks, &context_count);
	dev_notice(smmu->dev, "\tenabling workaround for Cavium erratum 27704\n");

	return 0;
}

int cavium_init_context(struct arm_smmu_domain *smmu_domain)
{
	struct cavium_smmu *cs = container_of(smmu_domain->smmu,
					      struct cavium_smmu, smmu);

	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S2)
		smmu_domain->cfg.vmid += cs->id_base;
	else
		smmu_domain->cfg.asid += cs->id_base;

	return 0;
}

const struct arm_smmu_impl cavium_impl = {
	.cfg_probe = cavium_cfg_probe,
	.init_context = cavium_init_context,
};

struct arm_smmu_device *cavium_smmu_impl_init(struct arm_smmu_device *smmu)
{
	struct cavium_smmu *cs;

	cs = devm_kzalloc(smmu->dev, sizeof(*cs), GFP_KERNEL);
	if (!cs)
		return ERR_PTR(-ENOMEM);

	cs->smmu = *smmu;
	cs->smmu.impl = &cavium_impl;

	devm_kfree(smmu->dev, smmu);

	return &cs->smmu;
}


#define ARM_MMU500_ACTLR_CPRE		(1 << 1)

@@ -126,8 +161,7 @@ struct arm_smmu_device *arm_smmu_impl_init(struct arm_smmu_device *smmu)
		smmu->impl = &arm_mmu500_impl;
		break;
	case CAVIUM_SMMUV2:
		smmu->impl = &cavium_impl;
		break;
		return cavium_smmu_impl_init(smmu);
	default:
		break;
	}
+15 −59
Original line number Diff line number Diff line
@@ -30,7 +30,6 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/io-64-nonatomic-hi-lo.h>
#include <linux/io-pgtable.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/interconnect.h>
@@ -144,25 +143,6 @@ struct arm_smmu_master_cfg {
#define for_each_cfg_sme(fw, i, idx) \
	for (i = 0; idx = fwspec_smendx(fw, i), i < fw->num_ids; ++i)

enum arm_smmu_context_fmt {
	ARM_SMMU_CTX_FMT_NONE,
	ARM_SMMU_CTX_FMT_AARCH64,
	ARM_SMMU_CTX_FMT_AARCH32_L,
	ARM_SMMU_CTX_FMT_AARCH32_S,
};

struct arm_smmu_cfg {
	u8				cbndx;
	u8				irptndx;
	union {
		u16			asid;
		u16			vmid;
	};
	u32				procid;
	enum arm_smmu_cbar_type		cbar;
	enum arm_smmu_context_fmt	fmt;
};
#define INVALID_IRPTNDX			0xff
#define INVALID_CBNDX			0xff
#define INVALID_ASID			0xffff
/*
@@ -175,42 +155,12 @@ struct arm_smmu_cfg {
#define ARM_SMMU_CB_VMID(smmu, cfg) ((u16)(smmu)->cavium_id_base + \
							(cfg)->cbndx + 1)

enum arm_smmu_domain_stage {
	ARM_SMMU_DOMAIN_S1 = 0,
	ARM_SMMU_DOMAIN_S2,
	ARM_SMMU_DOMAIN_NESTED,
	ARM_SMMU_DOMAIN_BYPASS,
};

struct arm_smmu_pte_info {
	void *virt_addr;
	size_t size;
	struct list_head entry;
};

struct arm_smmu_domain {
	struct arm_smmu_device		*smmu;
	struct device			*dev;
	struct io_pgtable_ops		*pgtbl_ops;
	const struct iommu_gather_ops	*tlb_ops;
	struct arm_smmu_cfg		cfg;
	enum arm_smmu_domain_stage	stage;
	bool				non_strict;
	struct mutex			init_mutex; /* Protects smmu pointer */
	spinlock_t			cb_lock; /* Serialises ATS1* ops */
	spinlock_t			sync_lock; /* Serialises TLB syncs */
	struct msm_io_pgtable_info	pgtbl_info;
	u64 attributes;
	u32				secure_vmid;
	struct list_head		pte_info_list;
	struct list_head		unassign_list;
	struct mutex			assign_lock;
	struct list_head		secure_pool_list;
	/* nonsecure pool protected by pgtbl_lock */
	struct list_head		nonsecure_pool;
	struct msm_iommu_domain		domain;
};

static bool using_legacy_binding, using_generic_binding;

struct arm_smmu_option_prop {
@@ -1600,12 +1550,12 @@ static void arm_smmu_write_context_bank(struct arm_smmu_device *smmu, int idx,
	 */
	if (of_dma_is_coherent(smmu_domain->dev->of_node)) {

		reg |= SCTLR_RACFG_RA << SCTLR_RACFG_SHIFT;
		reg |= SCTLR_WACFG_WA << SCTLR_WACFG_SHIFT;
		reg |= SCTLR_MTCFG;
		reg |= SCTLR_MEM_ATTR_OISH_WB_CACHE << SCTLR_MEM_ATTR_SHIFT;
		reg |= FIELD_PREP(SCTLR_WACFG, SCTLR_WACFG_WA) |
		       FIELD_PREP(SCTLR_RACFG, SCTLR_RACFG_RA) |
		       SCTLR_MTCFG |
		       FIELD_PREP(SCTLR_MEM_ATTR, SCTLR_MEM_ATTR_OISH_WB_CACHE);
	} else
		reg |= SCTLR_SHCFG_NSH << SCTLR_SHCFG_SHIFT;
		reg |= FIELD_PREP(SCTLR_SHCFG, SCTLR_SHCFG_NSH);

	if (attributes & (1ULL << DOMAIN_ATTR_CB_STALL_DISABLE)) {
		reg &= ~SCTLR_CFCFG;
@@ -1958,6 +1908,13 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,

	cfg->cbndx = ret;

	smmu_domain->smmu = smmu;
	if (smmu->impl && smmu->impl->init_context) {
		ret = smmu->impl->init_context(smmu_domain);
		if (ret)
			goto out_clear_smmu;
	}

	pgtbl_info->pgtbl_cfg = (struct io_pgtable_cfg) {
		.quirks		= quirks,
		.pgsize_bitmap	= smmu->pgsize_bitmap,
@@ -1968,7 +1925,6 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
		.iommu_dev	= smmu->dev,
	};

	smmu_domain->smmu = smmu;
	smmu_domain->dev = dev;
	smmu_domain->pgtbl_ops = alloc_io_pgtable_ops(fmt,
						      &pgtbl_info->pgtbl_cfg,
@@ -2152,7 +2108,7 @@ static void arm_smmu_write_s2cr(struct arm_smmu_device *smmu, int idx)
	u32 reg = FIELD_PREP(S2CR_TYPE, s2cr->type) |
		  FIELD_PREP(S2CR_CBNDX, s2cr->cbndx) |
		  FIELD_PREP(S2CR_PRIVCFG, s2cr->privcfg) |
		  S2CR_SHCFG_NSH << S2CR_SHCFG_SHIFT;
		  FIELD_PREP(S2CR_SHCFG, S2CR_SHCFG_NSH);

	if (smmu->features & ARM_SMMU_FEAT_EXIDS && smmu->smrs &&
	    smmu->smrs[idx].valid)
@@ -3919,8 +3875,8 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
		reg |= sCR0_EXIDENABLE;

	/* Force bypass transaction to be Non-Shareable & not io-coherent */
	reg &= ~(sCR0_SHCFG_MASK << sCR0_SHCFG_SHIFT);
	reg |= sCR0_SHCFG_NSH << sCR0_SHCFG_SHIFT;
	reg &= ~sCR0_SHCFG;
	reg |= FIELD_PREP(sCR0_SHCFG, sCR0_SHCFG_NSH);

	if (smmu->impl && smmu->impl->reset)
		smmu->impl->reset(smmu);
+68 −22
Original line number Diff line number Diff line
@@ -15,16 +15,16 @@
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/iommu.h>
#include <linux/io-pgtable.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/types.h>

/* Configuration registers */
#define ARM_SMMU_GR0_sCR0		0x0
#define sCR0_SHCFG_SHIFT		22
#define sCR0_SHCFG_MASK			0x3
#define sCR0_SHCFG_NSH			3
#define sCR0_VMID16EN			BIT(31)
#define sCR0_SHCFG			GENMASK(23, 22)
#define sCR0_SHCFG_NSH			0x3
#define sCR0_BSU			GENMASK(15, 14)
#define sCR0_FB				BIT(13)
#define sCR0_PTM			BIT(12)
@@ -95,15 +95,14 @@

/* Stream mapping registers */
#define ARM_SMMU_GR0_SMR(n)		(0x800 + ((n) << 2))
#define SMR_MASK_MASK			0x7FFF
#define SID_MASK			0x7FFF
#define SMR_MASK_MASK			GENMASK(14, 0)
#define SID_MASK			GENMASK(14, 0)
#define SMR_VALID			BIT(31)
#define SMR_MASK			GENMASK(31, 16)
#define SMR_ID				GENMASK(15, 0)

#define ARM_SMMU_GR0_S2CR(n)		(0xc00 + ((n) << 2))
#define S2CR_SHCFG_SHIFT		8
#define S2CR_SHCFG_MASK			0x3
#define S2CR_SHCFG			GENMASK(9, 8)
#define S2CR_SHCFG_NSH			0x3

#define S2CR_PRIVCFG			GENMASK(25, 24)
@@ -146,7 +145,17 @@ enum arm_smmu_cbar_type {
#define CBA2R_VA64			BIT(0)

#define ARM_SMMU_CB_SCTLR		0x0
#define SCTLR_WACFG			GENMASK(27, 26)
#define SCTLR_WACFG_WA			0x2
#define SCTLR_RACFG			GENMASK(25, 24)
#define SCTLR_RACFG_RA			0x2
#define SCTLR_SHCFG			GENMASK(23, 22)
#define SCTLR_SHCFG_NSH			0x3
#define SCTLR_MTCFG			BIT(20)
#define SCTLR_MEM_ATTR			GENMASK(19, 16)
#define SCTLR_MEM_ATTR_OISH_WB_CACHE	0xf
#define SCTLR_S1_ASIDPNE		BIT(12)
#define SCTLR_HUPCF			BIT(8)
#define SCTLR_CFCFG			BIT(7)
#define SCTLR_CFIE			BIT(6)
#define SCTLR_CFRE			BIT(5)
@@ -209,24 +218,12 @@ enum arm_smmu_cbar_type {
#define ARM_SMMU_CB_S2_TLBIIPAS2L	0x638
#define ARM_SMMU_CB_TLBSYNC		0x7f0
#define ARM_SMMU_CB_TLBSTATUS		0x7f4
#define TLBSTATUS_SACTIVE		(1 << 0)
#define TLBSTATUS_SACTIVE		BIT(0)
#define ARM_SMMU_CB_ATS1PR		0x800
#define ARM_SMMU_STATS_SYNC_INV_TBU_ACK 0x25dc
#define ARM_SMMU_TBU_PWR_STATUS         0x2204
#define ARM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR 0x2670

#define SCTLR_MEM_ATTR_SHIFT		16
#define SCTLR_SHCFG_SHIFT		22
#define SCTLR_RACFG_SHIFT		24
#define SCTLR_WACFG_SHIFT		26
#define SCTLR_SHCFG_MASK		0x3
#define SCTLR_SHCFG_NSH			0x3
#define SCTLR_RACFG_RA			0x2
#define SCTLR_WACFG_WA			0x2
#define SCTLR_MEM_ATTR_OISH_WB_CACHE	0xf
#define SCTLR_MTCFG			(1 << 20)
#define SCTLR_HUPCF			(1 << 8)

#define ARM_SMMU_CB_ATSR		0x8f0
#define ATSR_ACTIVE			BIT(0)

@@ -341,8 +338,6 @@ struct arm_smmu_device {

	struct list_head		list;

	u32				cavium_id_base; /* Specific to Cavium */

	spinlock_t			global_sync_lock;

	/* IOMMU core code handle */
@@ -364,6 +359,56 @@ struct arm_smmu_device {
	void				*archdata;
};

enum arm_smmu_context_fmt {
	ARM_SMMU_CTX_FMT_NONE,
	ARM_SMMU_CTX_FMT_AARCH64,
	ARM_SMMU_CTX_FMT_AARCH32_L,
	ARM_SMMU_CTX_FMT_AARCH32_S,
};

struct arm_smmu_cfg {
	u8				cbndx;
	u8				irptndx;
	union {
		u16			asid;
		u16			vmid;
	};
	u32				procid;
	enum arm_smmu_cbar_type		cbar;
	enum arm_smmu_context_fmt	fmt;
};
#define INVALID_IRPTNDX			0xff

enum arm_smmu_domain_stage {
	ARM_SMMU_DOMAIN_S1 = 0,
	ARM_SMMU_DOMAIN_S2,
	ARM_SMMU_DOMAIN_NESTED,
	ARM_SMMU_DOMAIN_BYPASS,
};

struct arm_smmu_domain {
	struct arm_smmu_device		*smmu;
	struct device			*dev;
	struct io_pgtable_ops		*pgtbl_ops;
	const struct iommu_gather_ops	*tlb_ops;
	struct arm_smmu_cfg		cfg;
	enum arm_smmu_domain_stage	stage;
	bool				non_strict;
	struct mutex			init_mutex; /* Protects smmu pointer */
	spinlock_t			cb_lock; /* Serialises ATS1* ops */
	spinlock_t			sync_lock; /* Serialises TLB syncs */
	struct msm_io_pgtable_info	pgtbl_info;
	u64 attributes;
	u32				secure_vmid;
	struct list_head		pte_info_list;
	struct list_head		unassign_list;
	struct mutex			assign_lock;
	struct list_head		secure_pool_list;
	/* nonsecure pool protected by pgtbl_lock */
	struct list_head		nonsecure_pool;
	struct msm_iommu_domain		domain;
};


/* Implementation details, yay! */
struct arm_smmu_impl {
@@ -375,6 +420,7 @@ struct arm_smmu_impl {
			    u64 val);
	int (*cfg_probe)(struct arm_smmu_device *smmu);
	int (*reset)(struct arm_smmu_device *smmu);
	int (*init_context)(struct arm_smmu_domain *smmu_domain);
};

static inline void __iomem *arm_smmu_page(struct arm_smmu_device *smmu, int n)