Commit 46f0c579 authored by Zhang Zekun's avatar Zhang Zekun
Browse files

iommu/arm-smmu-v3: Enable iotlb_sync_map according to SMMU_IIDR

hulk inclusion
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I913T5


CVE: NA

---------------------------------------------------

SMMU pagetable prefetch features may prefetch and use a invalid PTE even
the PTE is valid at that time. This will cause the device trigger fake
pagefaults. If the SMMU works in terminate mode, transactions which occur
fake pagefaults will be aborted, and could result in unexpected errors.

To fix this problem, we need to add a SYNC command after smmu has map a
iova, then smmu will always try to get the newest PTE.

Signed-off-by: default avatarZhang Zekun <zhangzekun11@huawei.com>
parent 915a6b99
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -156,6 +156,8 @@ stable kernels.
+----------------+-----------------+-----------------+-----------------------------+
| Hisilicon      | LINXICORE9100   | #162100125      | HISILICON_ERRATUM_162100125 |
+----------------+-----------------+-----------------+-----------------------------+
| Hisilicon      | SMMUv3          | #162100602      | HISILICON_ERRATUM_162100602 |
+----------------+-----------------+-----------------+-----------------------------+
| Hisilicon      | HIP09           | #162102203      | HISILICON_ERRATUM_162102203 |
+----------------+-----------------+-----------------+-----------------------------+
| Qualcomm Tech. | Kryo/Falkor v1  | E1003           | QCOM_FALKOR_ERRATUM_1003    |
+12 −0
Original line number Diff line number Diff line
@@ -836,6 +836,18 @@ config HISILICON_ERRATUM_162102203

	  If unsure, say N.

config HISILICON_ERRATUM_162100602
	bool "Hisilicon erratum 162100602"
	depends on ARM_SMMU_V3 && ARCH_HISI
	default y
	help
	  SMMU pagetable prefetch features may prefetch and use a invalid PTE even
	  the PTE is valid at that time. This will cause the device trigger fake
	  pagefaults. If the SMMU works in terminate mode, transactions which occur
	  fake pagefaults will be aborted, and could result in unexpected errors.

	  If unsure, say Y.

config QCOM_FALKOR_ERRATUM_1003
	bool "Falkor E1003: Incorrect translation due to ASID change"
	default y
+1 −0
Original line number Diff line number Diff line
@@ -404,6 +404,7 @@ CONFIG_HISILICON_ERRATUM_1980005=y
CONFIG_HISILICON_ERRATUM_162100801=y
CONFIG_HISILICON_ERRATUM_162100125=y
CONFIG_HISILICON_ERRATUM_162102203=y
CONFIG_HISILICON_ERRATUM_162100602=y
CONFIG_QCOM_FALKOR_ERRATUM_1003=y
CONFIG_QCOM_FALKOR_ERRATUM_1009=y
CONFIG_QCOM_QDF2400_ERRATUM_0065=y
+28 −0
Original line number Diff line number Diff line
@@ -2941,6 +2941,23 @@ static void arm_smmu_iotlb_sync(struct iommu_domain *domain,
			       gather->pgsize, true, smmu_domain);
}

#ifdef CONFIG_HISILICON_ERRATUM_162100602
static void arm_smmu_iotlb_sync_map(struct iommu_domain *domain,
				unsigned long iova, size_t size)
{
	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
	size_t granule_size;

	if (!(smmu_domain->smmu->options & ARM_SMMU_OPT_SYNC_MAP))
		return;

	granule_size = 1 <<  __ffs(smmu_domain->domain.pgsize_bitmap);

	/* Add a SYNC command to sync io-pgtale to avoid errors in pgtable prefetch*/
	arm_smmu_tlb_inv_range_domain(iova, granule_size, granule_size, true, smmu_domain);
}
#endif

static phys_addr_t
arm_smmu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova)
{
@@ -3970,6 +3987,9 @@ static struct iommu_ops arm_smmu_ops = {
	.unmap			= arm_smmu_unmap,
	.flush_iotlb_all	= arm_smmu_flush_iotlb_all,
	.iotlb_sync		= arm_smmu_iotlb_sync,
#ifdef CONFIG_HISILICON_ERRATUM_162100602
	.iotlb_sync_map		= arm_smmu_iotlb_sync_map,
#endif
	.iova_to_phys		= arm_smmu_iova_to_phys,
	.probe_device		= arm_smmu_probe_device,
	.release_device		= arm_smmu_release_device,
@@ -5126,6 +5146,14 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
		smmu->oas = 48;
	}

#ifdef CONFIG_HISILICON_ERRATUM_162100602
	/* IIDR */
	reg = readl_relaxed(smmu->base + ARM_SMMU_IIDR);
	if (FIELD_GET(IIDR_VARIANT, reg) == 0x3 &&
	    FIELD_GET(IIDR_REVISON, reg) == 0x2)
		smmu->options |= ARM_SMMU_OPT_SYNC_MAP;
#endif

	if (arm_smmu_ops.pgsize_bitmap == -1UL)
		arm_smmu_ops.pgsize_bitmap = smmu->pgsize_bitmap;
	else
+5 −0
Original line number Diff line number Diff line
@@ -80,6 +80,10 @@
#define IDR5_VAX			GENMASK(11, 10)
#define IDR5_VAX_52_BIT			1

#define ARM_SMMU_IIDR			0x18
#define IIDR_VARIANT			GENMASK(19, 16)
#define IIDR_REVISON			GENMASK(15, 12)

#define ARM_SMMU_CR0			0x20
#define CR0_ATSCHK			(1 << 4)
#define CR0_CMDQEN			(1 << 3)
@@ -712,6 +716,7 @@ struct arm_smmu_device {
#define ARM_SMMU_OPT_SKIP_PREFETCH	(1 << 0)
#define ARM_SMMU_OPT_PAGE0_REGS_ONLY	(1 << 1)
#define ARM_SMMU_OPT_MSIPOLL		(1 << 2)
#define ARM_SMMU_OPT_SYNC_MAP		(1 << 3)
	u32				options;

	union {