Re: [PATCH] arm64/io: Don't use WZR in writel

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 03/05/2019 12:36, Marc Gonzalez wrote:
On 02/05/2019 18:50, Marc Gonzalez wrote:

Are you saying that when writing to any of

	gr0_base + ARM_SMMU_GR0_TLBIALLH
	gr0_base + ARM_SMMU_GR0_TLBIALLNSNH
	base + ARM_SMMU_GR0_sTLBGSYNC

the actual value written does not matter? Is it ignored by the HW?

We could write 0xdeadbeef?


http://infocenter.arm.com/help/topic/com.arm.doc.ihi0062d.c/IHI0062D_c_system_mmu_architecture_specification.pdf

0x068	SMMU_TLBIALLNSNH	WO	32	TLB Invalidate All Non-secure Non-Hyp
0x06C	SMMU_TLBIALLH		WO	32	TLB Invalidate All Hyp
0x070	SMMU_sTLBGSYNC		WO	32	Global Synchronize TLB Invalidate

The SMMU_TLBIALLNSNH	bit assignments are reserved.
The SMMU_TLBIALLH	bit assignments are reserved.
The SMMU_sTLBGSYNC	bit assignments are reserved.


Reserved:

Unless otherwise stated in the architecture or product documentation, reserved:
o Instruction and 32-bit system control register encodings are UNPREDICTABLE.
o 64-bit system control register encodings are UNDEFINED.
o Register bit fields are UNK/SBZP.


UNK/SBZP:

Hardware must implement the field as Read-As-Zero, and must ignore writes to the field.

That "Hardware [...] must ignore writes to the field" is the crux of the matter here.
Software must not rely on the field reading as all 0s, and except for writing back to the register
it must treat the value as if it is UNKNOWN. Software must use an SBZP policy to write to the field.

In practice, this is a forwards-compatibility provision - the architecture is effectively making a promise that if a previously-reserved field becomes meaningful in a future version, 0 will remain a "safe" value which does not enable any new and unexpected behaviour that current software won't understand.

In this case, however, there is zero chance of fields in these particular registers ever being defined, so I'm happy to take advantage of assumptions about hardware's end of the bargain. Note that even the architecture spec itself provides this example:

MOV	R0,#SMMU_CBn_TLBSYNC
STR	R0,[R0] ; Initiate TLB SYNC

This description can apply to a single bit that should be written as its preserved value or as 0,
or to a field that should be written as its preserved value or as all 0s.

See also Read-As-Zero (RAZ), Should-Be-Zero-or-Preserved (SBZP), and UNKNOWN.


UNKNOWN:

An UNKNOWN value does not contain valid data, and can vary from moment to moment,
instruction to instruction, and implementation to implementation.

An UNKNOWN value must not be a security hole. An UNKNOWN value must not be documented
or promoted as having a defined value or effect.

When UNKNOWN appears in body text, it is always in SMALL CAPITALS.


Should-Be-Zero-or-Preserved (SBZP)

 From the introduction of ARMv7 Large Physical Address Extension, the definition of SBZP is modified
for register bits that are SBZP in some but not all contexts. The generic definition of SBZP given
here applies only to bits that are not affected by this modification.

Hardware must ignore writes to the field.

If software has read the field since the PE implementing the field was last reset and initialized,
it must preserve the value of the field by writing the value that it previously read from the field.
Otherwise, it must write the field as all 0s.

If software writes a value to the field that is not a value previously read for the field and is
not all 0s, it must expect an UNPREDICTABLE result.


Considering the above, instead of writing any random value, what do
you think of writing back the current value, as in:

They're defined as write-only registers...

Even if the bits *within* a register nominally behave as RAZ/WI, I don't think that gives you any guarantee that the register itself will actually be readable (for starters, consider that the register as a whole does *not* ignore writes, because its fundamental reason for existing is to trigger an operation when written to).

Anyway, I'll clean up my patch and post it properly - thanks to you and Bjorn for testing.

Robin.



diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 930c07635956..fe27908d5295 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -417,13 +417,18 @@ static void __arm_smmu_free_bitmap(unsigned long *map, int idx)
  	clear_bit(idx, map);
  }
+static inline void sbzp_writel(void __iomem *reg)
+{
+	writel_relaxed(readl_relaxed(reg), reg);
+}
+
  /* Wait for any pending TLB invalidations to complete */
  static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu,
  				void __iomem *sync, void __iomem *status)
  {
  	unsigned int spin_cnt, delay;
- writel_relaxed(0, sync);
+	sbzp_writel(sync);
  	for (delay = 1; delay < TLB_LOOP_TIMEOUT; delay *= 2) {
  		for (spin_cnt = TLB_SPIN_COUNT; spin_cnt > 0; spin_cnt--) {
  			if (!(readl_relaxed(status) & sTLBGSTATUS_GSACTIVE))
@@ -1761,8 +1766,8 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
  	}
/* Invalidate the TLB, just in case */
-	writel_relaxed(0, gr0_base + ARM_SMMU_GR0_TLBIALLH);
-	writel_relaxed(0, gr0_base + ARM_SMMU_GR0_TLBIALLNSNH);
+	sbzp_writel(gr0_base + ARM_SMMU_GR0_TLBIALLH);
+	sbzp_writel(gr0_base + ARM_SMMU_GR0_TLBIALLNSNH);
reg = readl_relaxed(ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0);
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@xxxxxxxxxxxxxxxxxxx
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [Linux for Sparc]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux