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

Commit d574893a authored by Magnus Damm's avatar Magnus Damm Committed by Alex Williamson
Browse files

iommu/ipmmu-vmsa: Write IMCTR twice



Write IMCTR both in the root device and the leaf node.

To allow access of IMCTR introduce the following function:
 - ipmmu_ctx_write_all()

While at it also rename context functions:
 - ipmmu_ctx_read() -> ipmmu_ctx_read_root()
 - ipmmu_ctx_write() -> ipmmu_ctx_write_root()

Signed-off-by: default avatarMagnus Damm <damm+renesas@opensource.se>
Signed-off-by: default avatarAlex Williamson <alex.williamson@redhat.com>
parent 1c894225
Loading
Loading
Loading
Loading
+35 −21
Original line number Original line Diff line number Diff line
@@ -248,15 +248,27 @@ static void ipmmu_write(struct ipmmu_vmsa_device *mmu, unsigned int offset,
	iowrite32(data, mmu->base + offset);
	iowrite32(data, mmu->base + offset);
}
}


static u32 ipmmu_ctx_read(struct ipmmu_vmsa_domain *domain, unsigned int reg)
static u32 ipmmu_ctx_read_root(struct ipmmu_vmsa_domain *domain,
			       unsigned int reg)
{
{
	return ipmmu_read(domain->mmu->root,
	return ipmmu_read(domain->mmu->root,
			  domain->context_id * IM_CTX_SIZE + reg);
			  domain->context_id * IM_CTX_SIZE + reg);
}
}


static void ipmmu_ctx_write(struct ipmmu_vmsa_domain *domain, unsigned int reg,
static void ipmmu_ctx_write_root(struct ipmmu_vmsa_domain *domain,
			    u32 data)
				 unsigned int reg, u32 data)
{
	ipmmu_write(domain->mmu->root,
		    domain->context_id * IM_CTX_SIZE + reg, data);
}

static void ipmmu_ctx_write_all(struct ipmmu_vmsa_domain *domain,
				unsigned int reg, u32 data)
{
{
	if (domain->mmu != domain->mmu->root)
		ipmmu_write(domain->mmu,
			    domain->context_id * IM_CTX_SIZE + reg, data);

	ipmmu_write(domain->mmu->root,
	ipmmu_write(domain->mmu->root,
		    domain->context_id * IM_CTX_SIZE + reg, data);
		    domain->context_id * IM_CTX_SIZE + reg, data);
}
}
@@ -270,7 +282,7 @@ static void ipmmu_tlb_sync(struct ipmmu_vmsa_domain *domain)
{
{
	unsigned int count = 0;
	unsigned int count = 0;


	while (ipmmu_ctx_read(domain, IMCTR) & IMCTR_FLUSH) {
	while (ipmmu_ctx_read_root(domain, IMCTR) & IMCTR_FLUSH) {
		cpu_relax();
		cpu_relax();
		if (++count == TLB_LOOP_TIMEOUT) {
		if (++count == TLB_LOOP_TIMEOUT) {
			dev_err_ratelimited(domain->mmu->dev,
			dev_err_ratelimited(domain->mmu->dev,
@@ -285,9 +297,9 @@ static void ipmmu_tlb_invalidate(struct ipmmu_vmsa_domain *domain)
{
{
	u32 reg;
	u32 reg;


	reg = ipmmu_ctx_read(domain, IMCTR);
	reg = ipmmu_ctx_read_root(domain, IMCTR);
	reg |= IMCTR_FLUSH;
	reg |= IMCTR_FLUSH;
	ipmmu_ctx_write(domain, IMCTR, reg);
	ipmmu_ctx_write_all(domain, IMCTR, reg);


	ipmmu_tlb_sync(domain);
	ipmmu_tlb_sync(domain);
}
}
@@ -428,31 +440,32 @@ static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain)


	/* TTBR0 */
	/* TTBR0 */
	ttbr = domain->cfg.arm_lpae_s1_cfg.ttbr[0];
	ttbr = domain->cfg.arm_lpae_s1_cfg.ttbr[0];
	ipmmu_ctx_write(domain, IMTTLBR0, ttbr);
	ipmmu_ctx_write_root(domain, IMTTLBR0, ttbr);
	ipmmu_ctx_write(domain, IMTTUBR0, ttbr >> 32);
	ipmmu_ctx_write_root(domain, IMTTUBR0, ttbr >> 32);


	/*
	/*
	 * TTBCR
	 * TTBCR
	 * We use long descriptors with inner-shareable WBWA tables and allocate
	 * We use long descriptors with inner-shareable WBWA tables and allocate
	 * the whole 32-bit VA space to TTBR0.
	 * the whole 32-bit VA space to TTBR0.
	 */
	 */
	ipmmu_ctx_write(domain, IMTTBCR, IMTTBCR_EAE |
	ipmmu_ctx_write_root(domain, IMTTBCR, IMTTBCR_EAE |
			     IMTTBCR_SH0_INNER_SHAREABLE | IMTTBCR_ORGN0_WB_WA |
			     IMTTBCR_SH0_INNER_SHAREABLE | IMTTBCR_ORGN0_WB_WA |
			     IMTTBCR_IRGN0_WB_WA | IMTTBCR_SL0_LVL_1);
			     IMTTBCR_IRGN0_WB_WA | IMTTBCR_SL0_LVL_1);


	/* MAIR0 */
	/* MAIR0 */
	ipmmu_ctx_write(domain, IMMAIR0, domain->cfg.arm_lpae_s1_cfg.mair[0]);
	ipmmu_ctx_write_root(domain, IMMAIR0,
			     domain->cfg.arm_lpae_s1_cfg.mair[0]);


	/* IMBUSCR */
	/* IMBUSCR */
	ipmmu_ctx_write(domain, IMBUSCR,
	ipmmu_ctx_write_root(domain, IMBUSCR,
			ipmmu_ctx_read(domain, IMBUSCR) &
			     ipmmu_ctx_read_root(domain, IMBUSCR) &
			     ~(IMBUSCR_DVM | IMBUSCR_BUSSEL_MASK));
			     ~(IMBUSCR_DVM | IMBUSCR_BUSSEL_MASK));


	/*
	/*
	 * IMSTR
	 * IMSTR
	 * Clear all interrupt flags.
	 * Clear all interrupt flags.
	 */
	 */
	ipmmu_ctx_write(domain, IMSTR, ipmmu_ctx_read(domain, IMSTR));
	ipmmu_ctx_write_root(domain, IMSTR, ipmmu_ctx_read_root(domain, IMSTR));


	/*
	/*
	 * IMCTR
	 * IMCTR
@@ -461,7 +474,8 @@ static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain)
	 * software management as we have no use for it. Flush the TLB as
	 * software management as we have no use for it. Flush the TLB as
	 * required when modifying the context registers.
	 * required when modifying the context registers.
	 */
	 */
	ipmmu_ctx_write(domain, IMCTR, IMCTR_INTEN | IMCTR_FLUSH | IMCTR_MMUEN);
	ipmmu_ctx_write_all(domain, IMCTR,
			    IMCTR_INTEN | IMCTR_FLUSH | IMCTR_MMUEN);


	return 0;
	return 0;
}
}
@@ -474,7 +488,7 @@ static void ipmmu_domain_destroy_context(struct ipmmu_vmsa_domain *domain)
	 *
	 *
	 * TODO: Is TLB flush really needed ?
	 * TODO: Is TLB flush really needed ?
	 */
	 */
	ipmmu_ctx_write(domain, IMCTR, IMCTR_FLUSH);
	ipmmu_ctx_write_all(domain, IMCTR, IMCTR_FLUSH);
	ipmmu_tlb_sync(domain);
	ipmmu_tlb_sync(domain);
	ipmmu_domain_free_context(domain->mmu->root, domain->context_id);
	ipmmu_domain_free_context(domain->mmu->root, domain->context_id);
}
}
@@ -490,11 +504,11 @@ static irqreturn_t ipmmu_domain_irq(struct ipmmu_vmsa_domain *domain)
	u32 status;
	u32 status;
	u32 iova;
	u32 iova;


	status = ipmmu_ctx_read(domain, IMSTR);
	status = ipmmu_ctx_read_root(domain, IMSTR);
	if (!(status & err_mask))
	if (!(status & err_mask))
		return IRQ_NONE;
		return IRQ_NONE;


	iova = ipmmu_ctx_read(domain, IMEAR);
	iova = ipmmu_ctx_read_root(domain, IMEAR);


	/*
	/*
	 * Clear the error status flags. Unlike traditional interrupt flag
	 * Clear the error status flags. Unlike traditional interrupt flag
@@ -502,7 +516,7 @@ static irqreturn_t ipmmu_domain_irq(struct ipmmu_vmsa_domain *domain)
	 * seems to require 0. The error address register must be read before,
	 * seems to require 0. The error address register must be read before,
	 * otherwise its value will be 0.
	 * otherwise its value will be 0.
	 */
	 */
	ipmmu_ctx_write(domain, IMSTR, 0);
	ipmmu_ctx_write_root(domain, IMSTR, 0);


	/* Log fatal errors. */
	/* Log fatal errors. */
	if (status & IMSTR_MHIT)
	if (status & IMSTR_MHIT)