On 03.07.2020 11:03, Robin Murphy wrote:
On 2020-07-02 21:16, Tomasz Nowicki wrote:
From: Hanna Hawa <[email protected]>

Due to erratum #582743, the Marvell Armada-AP806 can't access 64bit to
ARM SMMUv2 registers.

Provide implementation relevant hooks:
- split the writeq/readq to two accesses of writel/readl.
- mask the MMU_IDR2.PTFSv8 fields to not use AArch64 format (but
only AARCH32_L) since with AArch64 format 32 bits access is not supported.

Note that separate writes/reads to 2 is not problem regards to
atomicity, because the driver use the readq/writeq while initialize
the SMMU, report for SMMU fault, and use spinlock in one
case (iova_to_phys).

The comment about the spinlock seems to be out of date, and TBH that whole sentence is a bit unclear - how about something like:

"Note that most 64-bit registers like TTBRn can be accessed as two 32-bit halves without issue, and AArch32 format ensures that the register writes which must be atomic (for TLBI etc.) need only be 32-bit."

Signed-off-by: Hanna Hawa <[email protected]>
Signed-off-by: Gregory CLEMENT <[email protected]>
Signed-off-by: Tomasz Nowicki <[email protected]>
---
  Documentation/arm64/silicon-errata.rst |  3 ++
  drivers/iommu/arm-smmu-impl.c          | 52 ++++++++++++++++++++++++++
  2 files changed, 55 insertions(+)

diff --git a/Documentation/arm64/silicon-errata.rst b/Documentation/arm64/silicon-errata.rst
index 936cf2a59ca4..157214d3abe1 100644
--- a/Documentation/arm64/silicon-errata.rst
+++ b/Documentation/arm64/silicon-errata.rst
@@ -125,6 +125,9 @@ stable kernels.
  | Cavium         | ThunderX2 Core  | #219            | CAVIUM_TX2_ERRATUM_219      | +----------------+-----------------+-----------------+-----------------------------+ +----------------+-----------------+-----------------+-----------------------------+ +| Marvell        | ARM-MMU-500     | #582743         | N/A                         | ++----------------+-----------------+-----------------+-----------------------------+ ++----------------+-----------------+-----------------+-----------------------------+   | Freescale/NXP  | LS2080A/LS1043A | A-008585        | FSL_ERRATUM_A008585         | +----------------+-----------------+-----------------+-----------------------------+ +----------------+-----------------+-----------------+-----------------------------+ diff --git a/drivers/iommu/arm-smmu-impl.c b/drivers/iommu/arm-smmu-impl.c
index c75b9d957b70..c1fc5e1b8193 100644
--- a/drivers/iommu/arm-smmu-impl.c
+++ b/drivers/iommu/arm-smmu-impl.c
@@ -147,6 +147,53 @@ static const struct arm_smmu_impl arm_mmu500_impl = {
      .reset = arm_mmu500_reset,
  };
+static u64 mrvl_mmu500_readq(struct arm_smmu_device *smmu, int page, int off)
+{
+    u64 val;
+
+    /*
+     * Marvell Armada-AP806 erratum #582743.
+     * Split all the readq to double readl
+     */
+    val = (u64)readl_relaxed(arm_smmu_page(smmu, page) + off + 4) << 32;
+    val |= readl_relaxed(arm_smmu_page(smmu, page) + off);

Even though io-64-nonatomic-hi-lo.h doesn't override readq() etc. for 64-bit builds, you can still use hi_lo_readq_relaxed() directly.

+
+    return val;
+}
+
+static void mrvl_mmu500_writeq(struct arm_smmu_device *smmu, int page, int off,
+                   u64 val)
+{
+    /*
+     * Marvell Armada-AP806 erratum #582743.
+     * Split all the writeq to double writel
+     */
+    writel_relaxed(upper_32_bits(val), arm_smmu_page(smmu, page) + off + 4);
+    writel_relaxed(lower_32_bits(val), arm_smmu_page(smmu, page) + off);

Similarly, hi_lo_writeq_relaxed().

+}
+
+static u32 mrvl_mmu500_cfg_id2_fixup(u32 id)
+{
+
+    /*
+     * Armada-AP806 erratum #582743.
+     * Hide the SMMU_IDR2.PTFSv8 fields to sidestep the AArch64
+     * formats altogether and allow using 32 bits access on the
+     * interconnect.
+     */
+    id &= ~(ARM_SMMU_ID2_PTFS_4K | ARM_SMMU_ID2_PTFS_16K |
+        ARM_SMMU_ID2_PTFS_64K);
+
+    return id;
+}
+
+static const struct arm_smmu_impl mrvl_mmu500_impl = {
+    .read_reg64 = mrvl_mmu500_readq,
+    .write_reg64 = mrvl_mmu500_writeq,
+    .cfg_id2_fixup = mrvl_mmu500_cfg_id2_fixup,
+    .reset = arm_mmu500_reset,
+};
+
  struct arm_smmu_device *arm_smmu_impl_init(struct arm_smmu_device *smmu)
  {
@@ -160,6 +207,11 @@ struct arm_smmu_device *arm_smmu_impl_init(struct arm_smmu_device *smmu)
       */
      switch (smmu->model) {
      case ARM_MMU500:
+        if (of_device_is_compatible(smmu->dev->of_node,

Nit: there's a local "np" variable now.

+                        "marvell,ap806-smmu-500")) {
+            smmu->impl = &mrvl_mmu500_impl;
+            return smmu;
+        }

Please put this with the other integration checks below the switch statement. Yes, it means we'll end up assigning smmu->impl twice for this particular case, but that's the intended pattern.


Thanks, all above comments do make sense and will be fixed in next spin.

Thanks,
Tomasz

Reply via email to