iommu/io-pgtable-arm: Add support to use system cache
authorVivek Gautam <vivek.gautam@codeaurora.org>
Thu, 16 May 2019 09:30:20 +0000 (15:00 +0530)
committerWill Deacon <will.deacon@arm.com>
Tue, 18 Jun 2019 18:27:37 +0000 (19:27 +0100)
Few Qualcomm platforms such as, sdm845 have an additional outer
cache called as System cache, aka. Last level cache (LLC) that
allows non-coherent devices to upgrade to using caching.
This cache sits right before the DDR, and is tightly coupled
with the memory controller. The clients using this cache request
their slices from this system cache, make it active, and can then
start using it.

There is a fundamental assumption that non-coherent devices can't
access caches. This change adds an exception where they *can* use
some level of cache despite still being non-coherent overall.
The coherent devices that use cacheable memory, and CPU make use of
this system cache by default.

Looking at memory types, we have following -
a) Normal uncached :- MAIR 0x44, inner non-cacheable,
                      outer non-cacheable;
b) Normal cached :-   MAIR 0xff, inner read write-back non-transient,
                      outer read write-back non-transient;
                      attribute setting for coherenet I/O devices.
and, for non-coherent i/o devices that can allocate in system cache
another type gets added -
c) Normal sys-cached :- MAIR 0xf4, inner non-cacheable,
                        outer read write-back non-transient

Coherent I/O devices use system cache by marking the memory as
normal cached.
Non-coherent I/O devices should mark the memory as normal
sys-cached in page tables to use system cache.

Acked-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Vivek Gautam <vivek.gautam@codeaurora.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
drivers/iommu/io-pgtable-arm.c
include/linux/iommu.h

index 4e21efbc4459596f3744fea1a80cd912a2d1eb39..2454ac11aa97f848e447c434adc4b4971b145ac2 100644 (file)
 #define ARM_LPAE_MAIR_ATTR_MASK                0xff
 #define ARM_LPAE_MAIR_ATTR_DEVICE      0x04
 #define ARM_LPAE_MAIR_ATTR_NC          0x44
 #define ARM_LPAE_MAIR_ATTR_MASK                0xff
 #define ARM_LPAE_MAIR_ATTR_DEVICE      0x04
 #define ARM_LPAE_MAIR_ATTR_NC          0x44
+#define ARM_LPAE_MAIR_ATTR_INC_OWBRWA  0xf4
 #define ARM_LPAE_MAIR_ATTR_WBRWA       0xff
 #define ARM_LPAE_MAIR_ATTR_IDX_NC      0
 #define ARM_LPAE_MAIR_ATTR_IDX_CACHE   1
 #define ARM_LPAE_MAIR_ATTR_IDX_DEV     2
 #define ARM_LPAE_MAIR_ATTR_WBRWA       0xff
 #define ARM_LPAE_MAIR_ATTR_IDX_NC      0
 #define ARM_LPAE_MAIR_ATTR_IDX_CACHE   1
 #define ARM_LPAE_MAIR_ATTR_IDX_DEV     2
+#define ARM_LPAE_MAIR_ATTR_IDX_INC_OCACHE      3
 
 #define ARM_MALI_LPAE_TTBR_ADRMODE_TABLE (3u << 0)
 #define ARM_MALI_LPAE_TTBR_READ_INNER  BIT(2)
 
 #define ARM_MALI_LPAE_TTBR_ADRMODE_TABLE (3u << 0)
 #define ARM_MALI_LPAE_TTBR_READ_INNER  BIT(2)
@@ -470,6 +472,9 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct arm_lpae_io_pgtable *data,
                else if (prot & IOMMU_CACHE)
                        pte |= (ARM_LPAE_MAIR_ATTR_IDX_CACHE
                                << ARM_LPAE_PTE_ATTRINDX_SHIFT);
                else if (prot & IOMMU_CACHE)
                        pte |= (ARM_LPAE_MAIR_ATTR_IDX_CACHE
                                << ARM_LPAE_PTE_ATTRINDX_SHIFT);
+               else if (prot & IOMMU_QCOM_SYS_CACHE)
+                       pte |= (ARM_LPAE_MAIR_ATTR_IDX_INC_OCACHE
+                               << ARM_LPAE_PTE_ATTRINDX_SHIFT);
        }
 
        if (prot & IOMMU_NOEXEC)
        }
 
        if (prot & IOMMU_NOEXEC)
@@ -857,7 +862,9 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie)
              (ARM_LPAE_MAIR_ATTR_WBRWA
               << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_CACHE)) |
              (ARM_LPAE_MAIR_ATTR_DEVICE
              (ARM_LPAE_MAIR_ATTR_WBRWA
               << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_CACHE)) |
              (ARM_LPAE_MAIR_ATTR_DEVICE
-              << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_DEV));
+              << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_DEV)) |
+             (ARM_LPAE_MAIR_ATTR_INC_OWBRWA
+              << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_INC_OCACHE));
 
        cfg->arm_lpae_s1_cfg.mair[0] = reg;
        cfg->arm_lpae_s1_cfg.mair[1] = 0;
 
        cfg->arm_lpae_s1_cfg.mair[0] = reg;
        cfg->arm_lpae_s1_cfg.mair[1] = 0;
index a815cf6f6f47a8611b70b886d15da0f003ac5a01..8ee3fbaf58553059641db89448194c8d448a550d 100644 (file)
  * if the IOMMU page table format is equivalent.
  */
 #define IOMMU_PRIV     (1 << 5)
  * if the IOMMU page table format is equivalent.
  */
 #define IOMMU_PRIV     (1 << 5)
+/*
+ * Non-coherent masters on few Qualcomm SoCs can use this page protection flag
+ * to set correct cacheability attributes to use an outer level of cache -
+ * last level cache, aka system cache.
+ */
+#define IOMMU_QCOM_SYS_CACHE   (1 << 6)
 
 struct iommu_ops;
 struct iommu_group;
 
 struct iommu_ops;
 struct iommu_group;