From: Kunkun Jiang <jiangkun...@huawei.com>

As nested mode is not upstreamed now, we just aim to support dirty
log tracking for stage1 with io-pgtable mapping (means not support
SVA mapping). If HTTU is supported, we enable HA/HD bits in the SMMU
CD, and set DBM bit for writable TTD.

The dirty state information is encoded using the access permission
bits AP[2] (stage 1) or S2AP[1] (stage 2) in conjunction with the
DBM (Dirty Bit Modifier) bit, where DBM means writable and AP[2]/
S2AP[1] means dirty.

Co-developed-by: Keqian Zhu <zhukeqi...@huawei.com>
Signed-off-by: Kunkun Jiang <jiangkun...@huawei.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 3 +++
 drivers/iommu/io-pgtable-arm.c              | 7 ++++++-
 include/linux/io-pgtable.h                  | 3 +++
 3 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c 
b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index b6d965504f44..369c0ea7a104 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1921,6 +1921,7 @@ static int arm_smmu_domain_finalise_s1(struct 
arm_smmu_domain *smmu_domain,
                          FIELD_PREP(CTXDESC_CD_0_TCR_ORGN0, tcr->orgn) |
                          FIELD_PREP(CTXDESC_CD_0_TCR_SH0, tcr->sh) |
                          FIELD_PREP(CTXDESC_CD_0_TCR_IPS, tcr->ips) |
+                         CTXDESC_CD_0_TCR_HA | CTXDESC_CD_0_TCR_HD |
                          CTXDESC_CD_0_TCR_EPD1 | CTXDESC_CD_0_AA64;
        cfg->cd.mair    = pgtbl_cfg->arm_lpae_s1_cfg.mair;
 
@@ -2026,6 +2027,8 @@ static int arm_smmu_domain_finalise(struct iommu_domain 
*domain,
 
        if (smmu_domain->non_strict)
                pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_NON_STRICT;
+       if (smmu->features & ARM_SMMU_FEAT_HD)
+               pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_ARM_HD;
 
        pgtbl_ops = alloc_io_pgtable_ops(fmt, &pgtbl_cfg, smmu_domain);
        if (!pgtbl_ops)
diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
index 87def58e79b5..94d790b8ed27 100644
--- a/drivers/iommu/io-pgtable-arm.c
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -72,6 +72,7 @@
 
 #define ARM_LPAE_PTE_NSTABLE           (((arm_lpae_iopte)1) << 63)
 #define ARM_LPAE_PTE_XN                        (((arm_lpae_iopte)3) << 53)
+#define ARM_LPAE_PTE_DBM               (((arm_lpae_iopte)1) << 51)
 #define ARM_LPAE_PTE_AF                        (((arm_lpae_iopte)1) << 10)
 #define ARM_LPAE_PTE_SH_NS             (((arm_lpae_iopte)0) << 8)
 #define ARM_LPAE_PTE_SH_OS             (((arm_lpae_iopte)2) << 8)
@@ -81,7 +82,7 @@
 
 #define ARM_LPAE_PTE_ATTR_LO_MASK      (((arm_lpae_iopte)0x3ff) << 2)
 /* Ignore the contiguous bit for block splitting */
-#define ARM_LPAE_PTE_ATTR_HI_MASK      (((arm_lpae_iopte)6) << 52)
+#define ARM_LPAE_PTE_ATTR_HI_MASK      (((arm_lpae_iopte)13) << 51)
 #define ARM_LPAE_PTE_ATTR_MASK         (ARM_LPAE_PTE_ATTR_LO_MASK |    \
                                         ARM_LPAE_PTE_ATTR_HI_MASK)
 /* Software bit for solving coherency races */
@@ -379,6 +380,7 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, 
unsigned long iova,
 static arm_lpae_iopte arm_lpae_prot_to_pte(struct arm_lpae_io_pgtable *data,
                                           int prot)
 {
+       struct io_pgtable_cfg *cfg = &data->iop.cfg;
        arm_lpae_iopte pte;
 
        if (data->iop.fmt == ARM_64_LPAE_S1 ||
@@ -386,6 +388,9 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct 
arm_lpae_io_pgtable *data,
                pte = ARM_LPAE_PTE_nG;
                if (!(prot & IOMMU_WRITE) && (prot & IOMMU_READ))
                        pte |= ARM_LPAE_PTE_AP_RDONLY;
+               else if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_HD)
+                       pte |= ARM_LPAE_PTE_DBM;
+
                if (!(prot & IOMMU_PRIV))
                        pte |= ARM_LPAE_PTE_AP_UNPRIV;
        } else {
diff --git a/include/linux/io-pgtable.h b/include/linux/io-pgtable.h
index a4c9ca2c31f1..64cee6831c97 100644
--- a/include/linux/io-pgtable.h
+++ b/include/linux/io-pgtable.h
@@ -82,6 +82,8 @@ struct io_pgtable_cfg {
         *
         * IO_PGTABLE_QUIRK_ARM_OUTER_WBWA: Override the outer-cacheability
         *      attributes set in the TCR for a non-coherent page-table walker.
+        *
+        * IO_PGTABLE_QUIRK_ARM_HD: Support hardware management of dirty status.
         */
        #define IO_PGTABLE_QUIRK_ARM_NS         BIT(0)
        #define IO_PGTABLE_QUIRK_NO_PERMS       BIT(1)
@@ -89,6 +91,7 @@ struct io_pgtable_cfg {
        #define IO_PGTABLE_QUIRK_NON_STRICT     BIT(4)
        #define IO_PGTABLE_QUIRK_ARM_TTBR1      BIT(5)
        #define IO_PGTABLE_QUIRK_ARM_OUTER_WBWA BIT(6)
+       #define IO_PGTABLE_QUIRK_ARM_HD         BIT(7)
        unsigned long                   quirks;
        unsigned long                   pgsize_bitmap;
        unsigned int                    ias;
-- 
2.19.1

Reply via email to