@@ -524,7 +551,7 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
tlbe->entry.translated_addr = gpa;
tlbe->entry.iova = ipa & ~mask;
tlbe->entry.addr_mask = mask;
- tlbe->entry.perm = s2ap;
+ tlbe->parent_perm = tlbe->entry.perm = s2ap;
tlbe->level = level;
tlbe->granule = granule_sz;
return 0;
@@ -537,6 +564,35 @@ error:
return -EINVAL;
}
+/* Combine 2 TLB enteries and return in tlbe. */
+static void combine_tlb(SMMUTLBEntry *tlbe, SMMUTLBEntry *tlbe_s2,
+ dma_addr_t iova, SMMUTransCfg *cfg)
+{
+ if (cfg->stage == SMMU_NESTED) {
+
+ /*
+ * tg and level are used from stage-1, while the addr mask can be
+ * smaller in case stage-2 size(based on granule and level) was
+ * smaller than stage-1.
+ * That should have no impact on:
+ * - lookup: as iova is properly aligned with the stage-1 level and
+ * granule.
+ * - Invalidation: as it uses the entry mask.
+ */
+ tlbe->entry.addr_mask = MIN(tlbe->entry.addr_mask,
+ tlbe_s2->entry.addr_mask);
+ tlbe->entry.translated_addr = CACHED_ENTRY_TO_ADDR(tlbe_s2,
+ tlbe->entry.translated_addr);
+
+ /* parent_perm has s2 perm while perm has s1 perm. */
+ tlbe->parent_perm = tlbe_s2->entry.perm;
+ return;
+ }
+
+ /* That was not nested, use the s2. */
+ memcpy(tlbe, tlbe_s2, sizeof(*tlbe));
+}