All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/5] iommu/arm-smmu-v3: make smmu can be enabled in kdump kernel
@ 2019-02-19  7:54 ` Zhen Lei
  0 siblings, 0 replies; 18+ messages in thread
From: Zhen Lei @ 2019-02-19  7:54 UTC (permalink / raw)
  To: Jean-Philippe Brucker, Robin Murphy, Will Deacon, Joerg Roedel,
	linux-arm-kernel, iommu, linux-kernel
  Cc: Zhen Lei

This patch series include two parts:
1. Patch1-2 use dummy STE tables with "ste abort" hardware feature to abort unexpected
   devices accessing. For more details, see the description in patch 2.
2. If the "ste abort" feature is not support, force the unexpected devices in the
   secondary kernel to use the memory maps which it used in the first kernel. For more
   details, see patch 5.


Zhen Lei (5):
  iommu/arm-smmu-v3: make sure the stale caching of L1STD are invalid
  iommu/arm-smmu-v3: make smmu can be enabled in kdump kernel
  iommu/arm-smmu-v3: add macro xxx_SIZE to replace xxx_DWORDS shift
  iommu/arm-smmu-v3: move arm_smmu_get_step_for_sid() a little ahead
  iommu/arm-smmu-v3: workaround for STE abort in kdump kernel

 drivers/iommu/arm-smmu-v3.c | 243 +++++++++++++++++++++++++++++++++++---------
 1 file changed, 194 insertions(+), 49 deletions(-)

-- 
1.8.3



^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 0/5] iommu/arm-smmu-v3: make smmu can be enabled in kdump kernel
@ 2019-02-19  7:54 ` Zhen Lei
  0 siblings, 0 replies; 18+ messages in thread
From: Zhen Lei @ 2019-02-19  7:54 UTC (permalink / raw)
  To: Jean-Philippe Brucker, Robin Murphy, Will Deacon, Joerg Roedel,
	linux-arm-kernel, iommu, linux-kernel
  Cc: Zhen Lei

This patch series include two parts:
1. Patch1-2 use dummy STE tables with "ste abort" hardware feature to abort unexpected
   devices accessing. For more details, see the description in patch 2.
2. If the "ste abort" feature is not support, force the unexpected devices in the
   secondary kernel to use the memory maps which it used in the first kernel. For more
   details, see patch 5.


Zhen Lei (5):
  iommu/arm-smmu-v3: make sure the stale caching of L1STD are invalid
  iommu/arm-smmu-v3: make smmu can be enabled in kdump kernel
  iommu/arm-smmu-v3: add macro xxx_SIZE to replace xxx_DWORDS shift
  iommu/arm-smmu-v3: move arm_smmu_get_step_for_sid() a little ahead
  iommu/arm-smmu-v3: workaround for STE abort in kdump kernel

 drivers/iommu/arm-smmu-v3.c | 243 +++++++++++++++++++++++++++++++++++---------
 1 file changed, 194 insertions(+), 49 deletions(-)

-- 
1.8.3



_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 1/5] iommu/arm-smmu-v3: make sure the stale caching of L1STD are invalid
@ 2019-02-19  7:54   ` Zhen Lei
  0 siblings, 0 replies; 18+ messages in thread
From: Zhen Lei @ 2019-02-19  7:54 UTC (permalink / raw)
  To: Jean-Philippe Brucker, Robin Murphy, Will Deacon, Joerg Roedel,
	linux-arm-kernel, iommu, linux-kernel
  Cc: Zhen Lei

Invalidate the caching of the intermediate L1ST descriptor after it has
been updated.

Signed-off-by: Zhen Lei <thunder.leizhen@huawei.com>
---
 drivers/iommu/arm-smmu-v3.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 0d28402..2072897 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -1072,13 +1072,14 @@ static void arm_smmu_write_ctx_desc(struct arm_smmu_device *smmu,
 	*dst = cpu_to_le64(val);
 }

-static void arm_smmu_sync_ste_for_sid(struct arm_smmu_device *smmu, u32 sid)
+static void
+__arm_smmu_sync_ste_for_sid(struct arm_smmu_device *smmu, u32 sid, bool leaf)
 {
 	struct arm_smmu_cmdq_ent cmd = {
 		.opcode	= CMDQ_OP_CFGI_STE,
 		.cfgi	= {
 			.sid	= sid,
-			.leaf	= true,
+			.leaf	= leaf,
 		},
 	};

@@ -1086,6 +1087,16 @@ static void arm_smmu_sync_ste_for_sid(struct arm_smmu_device *smmu, u32 sid)
 	arm_smmu_cmdq_issue_sync(smmu);
 }

+static void arm_smmu_sync_ste_for_sid(struct arm_smmu_device *smmu, u32 sid)
+{
+	__arm_smmu_sync_ste_for_sid(smmu, sid, true);
+}
+
+static void arm_smmu_sync_std_for_sid(struct arm_smmu_device *smmu, u32 sid)
+{
+	__arm_smmu_sync_ste_for_sid(smmu, sid, false);
+}
+
 static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
 				      __le64 *dst, struct arm_smmu_strtab_ent *ste)
 {
@@ -1233,6 +1244,7 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)

 	arm_smmu_init_bypass_stes(desc->l2ptr, 1 << STRTAB_SPLIT);
 	arm_smmu_write_strtab_l1_desc(strtab, desc);
+	arm_smmu_sync_std_for_sid(smmu, sid);
 	return 0;
 }

--
1.8.3



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 1/5] iommu/arm-smmu-v3: make sure the stale caching of L1STD are invalid
@ 2019-02-19  7:54   ` Zhen Lei
  0 siblings, 0 replies; 18+ messages in thread
From: Zhen Lei @ 2019-02-19  7:54 UTC (permalink / raw)
  To: Jean-Philippe Brucker, Robin Murphy, Will Deacon, Joerg Roedel,
	linux-arm-kernel, iommu, linux-kernel

Invalidate the caching of the intermediate L1ST descriptor after it has
been updated.

Signed-off-by: Zhen Lei <thunder.leizhen-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
---
 drivers/iommu/arm-smmu-v3.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 0d28402..2072897 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -1072,13 +1072,14 @@ static void arm_smmu_write_ctx_desc(struct arm_smmu_device *smmu,
 	*dst = cpu_to_le64(val);
 }

-static void arm_smmu_sync_ste_for_sid(struct arm_smmu_device *smmu, u32 sid)
+static void
+__arm_smmu_sync_ste_for_sid(struct arm_smmu_device *smmu, u32 sid, bool leaf)
 {
 	struct arm_smmu_cmdq_ent cmd = {
 		.opcode	= CMDQ_OP_CFGI_STE,
 		.cfgi	= {
 			.sid	= sid,
-			.leaf	= true,
+			.leaf	= leaf,
 		},
 	};

@@ -1086,6 +1087,16 @@ static void arm_smmu_sync_ste_for_sid(struct arm_smmu_device *smmu, u32 sid)
 	arm_smmu_cmdq_issue_sync(smmu);
 }

+static void arm_smmu_sync_ste_for_sid(struct arm_smmu_device *smmu, u32 sid)
+{
+	__arm_smmu_sync_ste_for_sid(smmu, sid, true);
+}
+
+static void arm_smmu_sync_std_for_sid(struct arm_smmu_device *smmu, u32 sid)
+{
+	__arm_smmu_sync_ste_for_sid(smmu, sid, false);
+}
+
 static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
 				      __le64 *dst, struct arm_smmu_strtab_ent *ste)
 {
@@ -1233,6 +1244,7 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)

 	arm_smmu_init_bypass_stes(desc->l2ptr, 1 << STRTAB_SPLIT);
 	arm_smmu_write_strtab_l1_desc(strtab, desc);
+	arm_smmu_sync_std_for_sid(smmu, sid);
 	return 0;
 }

--
1.8.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 1/5] iommu/arm-smmu-v3: make sure the stale caching of L1STD are invalid
@ 2019-02-19  7:54   ` Zhen Lei
  0 siblings, 0 replies; 18+ messages in thread
From: Zhen Lei @ 2019-02-19  7:54 UTC (permalink / raw)
  To: Jean-Philippe Brucker, Robin Murphy, Will Deacon, Joerg Roedel,
	linux-arm-kernel, iommu, linux-kernel
  Cc: Zhen Lei

Invalidate the caching of the intermediate L1ST descriptor after it has
been updated.

Signed-off-by: Zhen Lei <thunder.leizhen@huawei.com>
---
 drivers/iommu/arm-smmu-v3.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 0d28402..2072897 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -1072,13 +1072,14 @@ static void arm_smmu_write_ctx_desc(struct arm_smmu_device *smmu,
 	*dst = cpu_to_le64(val);
 }

-static void arm_smmu_sync_ste_for_sid(struct arm_smmu_device *smmu, u32 sid)
+static void
+__arm_smmu_sync_ste_for_sid(struct arm_smmu_device *smmu, u32 sid, bool leaf)
 {
 	struct arm_smmu_cmdq_ent cmd = {
 		.opcode	= CMDQ_OP_CFGI_STE,
 		.cfgi	= {
 			.sid	= sid,
-			.leaf	= true,
+			.leaf	= leaf,
 		},
 	};

@@ -1086,6 +1087,16 @@ static void arm_smmu_sync_ste_for_sid(struct arm_smmu_device *smmu, u32 sid)
 	arm_smmu_cmdq_issue_sync(smmu);
 }

+static void arm_smmu_sync_ste_for_sid(struct arm_smmu_device *smmu, u32 sid)
+{
+	__arm_smmu_sync_ste_for_sid(smmu, sid, true);
+}
+
+static void arm_smmu_sync_std_for_sid(struct arm_smmu_device *smmu, u32 sid)
+{
+	__arm_smmu_sync_ste_for_sid(smmu, sid, false);
+}
+
 static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
 				      __le64 *dst, struct arm_smmu_strtab_ent *ste)
 {
@@ -1233,6 +1244,7 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)

 	arm_smmu_init_bypass_stes(desc->l2ptr, 1 << STRTAB_SPLIT);
 	arm_smmu_write_strtab_l1_desc(strtab, desc);
+	arm_smmu_sync_std_for_sid(smmu, sid);
 	return 0;
 }

--
1.8.3



_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 2/5] iommu/arm-smmu-v3: make smmu can be enabled in kdump kernel
  2019-02-19  7:54 ` Zhen Lei
@ 2019-02-19  7:54   ` Zhen Lei
  -1 siblings, 0 replies; 18+ messages in thread
From: Zhen Lei @ 2019-02-19  7:54 UTC (permalink / raw)
  To: Jean-Philippe Brucker, Robin Murphy, Will Deacon, Joerg Roedel,
	linux-arm-kernel, iommu, linux-kernel
  Cc: Zhen Lei

To reduce the risk of further crash, the device_shutdown() was not called
by the first kernel. That means some devices may still working in the
secondary kernel. For example, a netcard may still using ring buffer to
receive the broadcast messages in the kdump kernel. No events are reported
utill the related smmu reinitialized by the kdump kernel.

commit b63b3439b856 ("iommu/arm-smmu-v3: Abort all transactions if SMMU is
enabled in kdump kernel") set SMMU_GBPA.ABORT to prevent the unexpected
devices accessing, but it also prevent the devices accessing which we
needed, like hard disk, netcard.

In fact, we can use STE.config=0b000 to abort the unexpected devices
accessing only. As below:
1. In the first kernel, all buffers used by the "unexpected" devices are
   correctly mapped, and it will not be used by the secondary kernel
   because the latter has its dedicated reserved memory.
2. In the secondary kernel, set SMMU_GBPA.ABORT=1 before "disable smmu".
3. In the secondary kernel, after the smmu was disabled, preset all
   STE.config=0b000. For 2-level Stream Table, make all L1STD.l2ptr
   pointer to a dummy L2ST. The dummy L2ST is shared by all L1STDs.
4. In the secondary kernel, enable smmu. For the needed devices, allocate
   new L2STs accordingly.

For phase 1 and 2, the unexpected devices base the old mapping access
memory, it will not corrupt others. For phase 3, SMMU_GBPA abort it. For
phase 4 STE abort it.

Fixes: commit b63b3439b856 ("iommu/arm-smmu-v3: Abort all transactions ...")
Signed-off-by: Zhen Lei <thunder.leizhen@huawei.com>
---
 drivers/iommu/arm-smmu-v3.c | 72 ++++++++++++++++++++++++++++++++-------------
 1 file changed, 51 insertions(+), 21 deletions(-)

diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 2072897..c3c4ff2 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -1219,35 +1219,57 @@ static void arm_smmu_init_bypass_stes(u64 *strtab, unsigned int nent)
 	}
 }

-static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
+static int __arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid,
+				     struct arm_smmu_strtab_l1_desc *desc)
 {
-	size_t size;
 	void *strtab;
 	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
-	struct arm_smmu_strtab_l1_desc *desc = &cfg->l1_desc[sid >> STRTAB_SPLIT];

-	if (desc->l2ptr)
-		return 0;
-
-	size = 1 << (STRTAB_SPLIT + ilog2(STRTAB_STE_DWORDS) + 3);
 	strtab = &cfg->strtab[(sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS];

-	desc->span = STRTAB_SPLIT + 1;
-	desc->l2ptr = dmam_alloc_coherent(smmu->dev, size, &desc->l2ptr_dma,
-					  GFP_KERNEL | __GFP_ZERO);
 	if (!desc->l2ptr) {
-		dev_err(smmu->dev,
-			"failed to allocate l2 stream table for SID %u\n",
-			sid);
-		return -ENOMEM;
+		size_t size;
+
+		size = 1 << (STRTAB_SPLIT + ilog2(STRTAB_STE_DWORDS) + 3);
+		desc->l2ptr = dmam_alloc_coherent(smmu->dev, size,
+						  &desc->l2ptr_dma,
+						  GFP_KERNEL | __GFP_ZERO);
+		if (!desc->l2ptr) {
+			dev_err(smmu->dev,
+				"failed to allocate l2 stream table for SID %u\n",
+				sid);
+			return -ENOMEM;
+		}
+
+		desc->span = STRTAB_SPLIT + 1;
+		arm_smmu_init_bypass_stes(desc->l2ptr, 1 << STRTAB_SPLIT);
 	}

-	arm_smmu_init_bypass_stes(desc->l2ptr, 1 << STRTAB_SPLIT);
 	arm_smmu_write_strtab_l1_desc(strtab, desc);
+	return 0;
+}
+
+static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
+{
+	int ret;
+	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
+	struct arm_smmu_strtab_l1_desc *desc = &cfg->l1_desc[sid >> STRTAB_SPLIT];
+
+	ret = __arm_smmu_init_l2_strtab(smmu, sid, desc);
+	if (ret)
+		return ret;
+
 	arm_smmu_sync_std_for_sid(smmu, sid);
 	return 0;
 }

+static int arm_smmu_init_dummy_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
+{
+	static struct arm_smmu_strtab_l1_desc dummy_desc;
+
+	return __arm_smmu_init_l2_strtab(smmu, sid, &dummy_desc);
+}
+
 /* IRQ and event handlers */
 static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
 {
@@ -2150,8 +2172,12 @@ static int arm_smmu_init_l1_strtab(struct arm_smmu_device *smmu)
 	}

 	for (i = 0; i < cfg->num_l1_ents; ++i) {
-		arm_smmu_write_strtab_l1_desc(strtab, &cfg->l1_desc[i]);
-		strtab += STRTAB_L1_DESC_DWORDS << 3;
+		if (is_kdump_kernel()) {
+			arm_smmu_init_dummy_l2_strtab(smmu, i << STRTAB_SPLIT);
+		} else {
+			arm_smmu_write_strtab_l1_desc(strtab, &cfg->l1_desc[i]);
+			strtab += STRTAB_L1_DESC_DWORDS << 3;
+		}
 	}

 	return 0;
@@ -2467,11 +2493,8 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
 	/* Clear CR0 and sync (disables SMMU and queue processing) */
 	reg = readl_relaxed(smmu->base + ARM_SMMU_CR0);
 	if (reg & CR0_SMMUEN) {
-		if (is_kdump_kernel()) {
+		if (is_kdump_kernel())
 			arm_smmu_update_gbpa(smmu, GBPA_ABORT, 0);
-			arm_smmu_device_disable(smmu);
-			return -EBUSY;
-		}

 		dev_warn(smmu->dev, "SMMU currently enabled! Resetting...\n");
 	}
@@ -2859,6 +2882,13 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	bool bypass;

+	/*
+	 * Force to disable bypass for the kdump kernel, abort all incoming
+	 * transactions from the unknown devices.
+	 */
+	if (is_kdump_kernel())
+		disable_bypass = 1;
+
 	smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
 	if (!smmu) {
 		dev_err(dev, "failed to allocate arm_smmu_device\n");
--
1.8.3



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 2/5] iommu/arm-smmu-v3: make smmu can be enabled in kdump kernel
@ 2019-02-19  7:54   ` Zhen Lei
  0 siblings, 0 replies; 18+ messages in thread
From: Zhen Lei @ 2019-02-19  7:54 UTC (permalink / raw)
  To: Jean-Philippe Brucker, Robin Murphy, Will Deacon, Joerg Roedel,
	linux-arm-kernel, iommu, linux-kernel
  Cc: Zhen Lei

To reduce the risk of further crash, the device_shutdown() was not called
by the first kernel. That means some devices may still working in the
secondary kernel. For example, a netcard may still using ring buffer to
receive the broadcast messages in the kdump kernel. No events are reported
utill the related smmu reinitialized by the kdump kernel.

commit b63b3439b856 ("iommu/arm-smmu-v3: Abort all transactions if SMMU is
enabled in kdump kernel") set SMMU_GBPA.ABORT to prevent the unexpected
devices accessing, but it also prevent the devices accessing which we
needed, like hard disk, netcard.

In fact, we can use STE.config=0b000 to abort the unexpected devices
accessing only. As below:
1. In the first kernel, all buffers used by the "unexpected" devices are
   correctly mapped, and it will not be used by the secondary kernel
   because the latter has its dedicated reserved memory.
2. In the secondary kernel, set SMMU_GBPA.ABORT=1 before "disable smmu".
3. In the secondary kernel, after the smmu was disabled, preset all
   STE.config=0b000. For 2-level Stream Table, make all L1STD.l2ptr
   pointer to a dummy L2ST. The dummy L2ST is shared by all L1STDs.
4. In the secondary kernel, enable smmu. For the needed devices, allocate
   new L2STs accordingly.

For phase 1 and 2, the unexpected devices base the old mapping access
memory, it will not corrupt others. For phase 3, SMMU_GBPA abort it. For
phase 4 STE abort it.

Fixes: commit b63b3439b856 ("iommu/arm-smmu-v3: Abort all transactions ...")
Signed-off-by: Zhen Lei <thunder.leizhen@huawei.com>
---
 drivers/iommu/arm-smmu-v3.c | 72 ++++++++++++++++++++++++++++++++-------------
 1 file changed, 51 insertions(+), 21 deletions(-)

diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 2072897..c3c4ff2 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -1219,35 +1219,57 @@ static void arm_smmu_init_bypass_stes(u64 *strtab, unsigned int nent)
 	}
 }

-static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
+static int __arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid,
+				     struct arm_smmu_strtab_l1_desc *desc)
 {
-	size_t size;
 	void *strtab;
 	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
-	struct arm_smmu_strtab_l1_desc *desc = &cfg->l1_desc[sid >> STRTAB_SPLIT];

-	if (desc->l2ptr)
-		return 0;
-
-	size = 1 << (STRTAB_SPLIT + ilog2(STRTAB_STE_DWORDS) + 3);
 	strtab = &cfg->strtab[(sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS];

-	desc->span = STRTAB_SPLIT + 1;
-	desc->l2ptr = dmam_alloc_coherent(smmu->dev, size, &desc->l2ptr_dma,
-					  GFP_KERNEL | __GFP_ZERO);
 	if (!desc->l2ptr) {
-		dev_err(smmu->dev,
-			"failed to allocate l2 stream table for SID %u\n",
-			sid);
-		return -ENOMEM;
+		size_t size;
+
+		size = 1 << (STRTAB_SPLIT + ilog2(STRTAB_STE_DWORDS) + 3);
+		desc->l2ptr = dmam_alloc_coherent(smmu->dev, size,
+						  &desc->l2ptr_dma,
+						  GFP_KERNEL | __GFP_ZERO);
+		if (!desc->l2ptr) {
+			dev_err(smmu->dev,
+				"failed to allocate l2 stream table for SID %u\n",
+				sid);
+			return -ENOMEM;
+		}
+
+		desc->span = STRTAB_SPLIT + 1;
+		arm_smmu_init_bypass_stes(desc->l2ptr, 1 << STRTAB_SPLIT);
 	}

-	arm_smmu_init_bypass_stes(desc->l2ptr, 1 << STRTAB_SPLIT);
 	arm_smmu_write_strtab_l1_desc(strtab, desc);
+	return 0;
+}
+
+static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
+{
+	int ret;
+	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
+	struct arm_smmu_strtab_l1_desc *desc = &cfg->l1_desc[sid >> STRTAB_SPLIT];
+
+	ret = __arm_smmu_init_l2_strtab(smmu, sid, desc);
+	if (ret)
+		return ret;
+
 	arm_smmu_sync_std_for_sid(smmu, sid);
 	return 0;
 }

+static int arm_smmu_init_dummy_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
+{
+	static struct arm_smmu_strtab_l1_desc dummy_desc;
+
+	return __arm_smmu_init_l2_strtab(smmu, sid, &dummy_desc);
+}
+
 /* IRQ and event handlers */
 static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
 {
@@ -2150,8 +2172,12 @@ static int arm_smmu_init_l1_strtab(struct arm_smmu_device *smmu)
 	}

 	for (i = 0; i < cfg->num_l1_ents; ++i) {
-		arm_smmu_write_strtab_l1_desc(strtab, &cfg->l1_desc[i]);
-		strtab += STRTAB_L1_DESC_DWORDS << 3;
+		if (is_kdump_kernel()) {
+			arm_smmu_init_dummy_l2_strtab(smmu, i << STRTAB_SPLIT);
+		} else {
+			arm_smmu_write_strtab_l1_desc(strtab, &cfg->l1_desc[i]);
+			strtab += STRTAB_L1_DESC_DWORDS << 3;
+		}
 	}

 	return 0;
@@ -2467,11 +2493,8 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
 	/* Clear CR0 and sync (disables SMMU and queue processing) */
 	reg = readl_relaxed(smmu->base + ARM_SMMU_CR0);
 	if (reg & CR0_SMMUEN) {
-		if (is_kdump_kernel()) {
+		if (is_kdump_kernel())
 			arm_smmu_update_gbpa(smmu, GBPA_ABORT, 0);
-			arm_smmu_device_disable(smmu);
-			return -EBUSY;
-		}

 		dev_warn(smmu->dev, "SMMU currently enabled! Resetting...\n");
 	}
@@ -2859,6 +2882,13 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	bool bypass;

+	/*
+	 * Force to disable bypass for the kdump kernel, abort all incoming
+	 * transactions from the unknown devices.
+	 */
+	if (is_kdump_kernel())
+		disable_bypass = 1;
+
 	smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
 	if (!smmu) {
 		dev_err(dev, "failed to allocate arm_smmu_device\n");
--
1.8.3



_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 3/5] iommu/arm-smmu-v3: add macro xxx_SIZE to replace xxx_DWORDS shift
  2019-02-19  7:54 ` Zhen Lei
@ 2019-02-19  7:54   ` Zhen Lei
  -1 siblings, 0 replies; 18+ messages in thread
From: Zhen Lei @ 2019-02-19  7:54 UTC (permalink / raw)
  To: Jean-Philippe Brucker, Robin Murphy, Will Deacon, Joerg Roedel,
	linux-arm-kernel, iommu, linux-kernel
  Cc: Zhen Lei

The (STRTAB_L1_DESC_DWORDS << 3) appears more than 1 times, replace it
with STRTAB_L1_DESC_SIZE to eliminate the duplication. And the latter
seems more clear when it's used to calculate memory size. And the same is
true for STRTAB_STE_DWORDS and CTXDESC_CD_DWORDS.

Signed-off-by: Zhen Lei <thunder.leizhen@huawei.com>
---
 drivers/iommu/arm-smmu-v3.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index c3c4ff2..5bb5dcd 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -202,10 +202,12 @@
 #define STRTAB_SPLIT			8

 #define STRTAB_L1_DESC_DWORDS		1
+#define STRTAB_L1_DESC_SIZE		(STRTAB_L1_DESC_DWORDS << 3)
 #define STRTAB_L1_DESC_SPAN		GENMASK_ULL(4, 0)
 #define STRTAB_L1_DESC_L2PTR_MASK	GENMASK_ULL(51, 6)

 #define STRTAB_STE_DWORDS		8
+#define STRTAB_STE_SIZE			(STRTAB_STE_DWORDS << 3)
 #define STRTAB_STE_0_V			(1UL << 0)
 #define STRTAB_STE_0_CFG		GENMASK_ULL(3, 1)
 #define STRTAB_STE_0_CFG_ABORT		0
@@ -251,6 +253,7 @@

 /* Context descriptor (stage-1 only) */
 #define CTXDESC_CD_DWORDS		8
+#define CTXDESC_CD_SIZE			(CTXDESC_CD_DWORDS << 3)
 #define CTXDESC_CD_0_TCR_T0SZ		GENMASK_ULL(5, 0)
 #define ARM64_TCR_T0SZ			GENMASK_ULL(5, 0)
 #define CTXDESC_CD_0_TCR_TG0		GENMASK_ULL(7, 6)
@@ -1563,7 +1566,7 @@ static void arm_smmu_domain_free(struct iommu_domain *domain)

 		if (cfg->cdptr) {
 			dmam_free_coherent(smmu_domain->smmu->dev,
-					   CTXDESC_CD_DWORDS << 3,
+					   CTXDESC_CD_SIZE,
 					   cfg->cdptr,
 					   cfg->cdptr_dma);

@@ -1590,7 +1593,7 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain,
 	if (asid < 0)
 		return asid;

-	cfg->cdptr = dmam_alloc_coherent(smmu->dev, CTXDESC_CD_DWORDS << 3,
+	cfg->cdptr = dmam_alloc_coherent(smmu->dev, CTXDESC_CD_SIZE,
 					 &cfg->cdptr_dma,
 					 GFP_KERNEL | __GFP_ZERO);
 	if (!cfg->cdptr) {
@@ -2176,7 +2179,7 @@ static int arm_smmu_init_l1_strtab(struct arm_smmu_device *smmu)
 			arm_smmu_init_dummy_l2_strtab(smmu, i << STRTAB_SPLIT);
 		} else {
 			arm_smmu_write_strtab_l1_desc(strtab, &cfg->l1_desc[i]);
-			strtab += STRTAB_L1_DESC_DWORDS << 3;
+			strtab += STRTAB_L1_DESC_SIZE;
 		}
 	}

@@ -2201,7 +2204,7 @@ static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu)
 			 "2-level strtab only covers %u/%u bits of SID\n",
 			 size, smmu->sid_bits);

-	l1size = cfg->num_l1_ents * (STRTAB_L1_DESC_DWORDS << 3);
+	l1size = cfg->num_l1_ents * STRTAB_L1_DESC_SIZE;
 	strtab = dmam_alloc_coherent(smmu->dev, l1size, &cfg->strtab_dma,
 				     GFP_KERNEL | __GFP_ZERO);
 	if (!strtab) {
@@ -2228,7 +2231,7 @@ static int arm_smmu_init_strtab_linear(struct arm_smmu_device *smmu)
 	u32 size;
 	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;

-	size = (1 << smmu->sid_bits) * (STRTAB_STE_DWORDS << 3);
+	size = (1 << smmu->sid_bits) * STRTAB_STE_SIZE;
 	strtab = dmam_alloc_coherent(smmu->dev, size, &cfg->strtab_dma,
 				     GFP_KERNEL | __GFP_ZERO);
 	if (!strtab) {
--
1.8.3



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 3/5] iommu/arm-smmu-v3: add macro xxx_SIZE to replace xxx_DWORDS shift
@ 2019-02-19  7:54   ` Zhen Lei
  0 siblings, 0 replies; 18+ messages in thread
From: Zhen Lei @ 2019-02-19  7:54 UTC (permalink / raw)
  To: Jean-Philippe Brucker, Robin Murphy, Will Deacon, Joerg Roedel,
	linux-arm-kernel, iommu, linux-kernel
  Cc: Zhen Lei

The (STRTAB_L1_DESC_DWORDS << 3) appears more than 1 times, replace it
with STRTAB_L1_DESC_SIZE to eliminate the duplication. And the latter
seems more clear when it's used to calculate memory size. And the same is
true for STRTAB_STE_DWORDS and CTXDESC_CD_DWORDS.

Signed-off-by: Zhen Lei <thunder.leizhen@huawei.com>
---
 drivers/iommu/arm-smmu-v3.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index c3c4ff2..5bb5dcd 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -202,10 +202,12 @@
 #define STRTAB_SPLIT			8

 #define STRTAB_L1_DESC_DWORDS		1
+#define STRTAB_L1_DESC_SIZE		(STRTAB_L1_DESC_DWORDS << 3)
 #define STRTAB_L1_DESC_SPAN		GENMASK_ULL(4, 0)
 #define STRTAB_L1_DESC_L2PTR_MASK	GENMASK_ULL(51, 6)

 #define STRTAB_STE_DWORDS		8
+#define STRTAB_STE_SIZE			(STRTAB_STE_DWORDS << 3)
 #define STRTAB_STE_0_V			(1UL << 0)
 #define STRTAB_STE_0_CFG		GENMASK_ULL(3, 1)
 #define STRTAB_STE_0_CFG_ABORT		0
@@ -251,6 +253,7 @@

 /* Context descriptor (stage-1 only) */
 #define CTXDESC_CD_DWORDS		8
+#define CTXDESC_CD_SIZE			(CTXDESC_CD_DWORDS << 3)
 #define CTXDESC_CD_0_TCR_T0SZ		GENMASK_ULL(5, 0)
 #define ARM64_TCR_T0SZ			GENMASK_ULL(5, 0)
 #define CTXDESC_CD_0_TCR_TG0		GENMASK_ULL(7, 6)
@@ -1563,7 +1566,7 @@ static void arm_smmu_domain_free(struct iommu_domain *domain)

 		if (cfg->cdptr) {
 			dmam_free_coherent(smmu_domain->smmu->dev,
-					   CTXDESC_CD_DWORDS << 3,
+					   CTXDESC_CD_SIZE,
 					   cfg->cdptr,
 					   cfg->cdptr_dma);

@@ -1590,7 +1593,7 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain,
 	if (asid < 0)
 		return asid;

-	cfg->cdptr = dmam_alloc_coherent(smmu->dev, CTXDESC_CD_DWORDS << 3,
+	cfg->cdptr = dmam_alloc_coherent(smmu->dev, CTXDESC_CD_SIZE,
 					 &cfg->cdptr_dma,
 					 GFP_KERNEL | __GFP_ZERO);
 	if (!cfg->cdptr) {
@@ -2176,7 +2179,7 @@ static int arm_smmu_init_l1_strtab(struct arm_smmu_device *smmu)
 			arm_smmu_init_dummy_l2_strtab(smmu, i << STRTAB_SPLIT);
 		} else {
 			arm_smmu_write_strtab_l1_desc(strtab, &cfg->l1_desc[i]);
-			strtab += STRTAB_L1_DESC_DWORDS << 3;
+			strtab += STRTAB_L1_DESC_SIZE;
 		}
 	}

@@ -2201,7 +2204,7 @@ static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu)
 			 "2-level strtab only covers %u/%u bits of SID\n",
 			 size, smmu->sid_bits);

-	l1size = cfg->num_l1_ents * (STRTAB_L1_DESC_DWORDS << 3);
+	l1size = cfg->num_l1_ents * STRTAB_L1_DESC_SIZE;
 	strtab = dmam_alloc_coherent(smmu->dev, l1size, &cfg->strtab_dma,
 				     GFP_KERNEL | __GFP_ZERO);
 	if (!strtab) {
@@ -2228,7 +2231,7 @@ static int arm_smmu_init_strtab_linear(struct arm_smmu_device *smmu)
 	u32 size;
 	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;

-	size = (1 << smmu->sid_bits) * (STRTAB_STE_DWORDS << 3);
+	size = (1 << smmu->sid_bits) * STRTAB_STE_SIZE;
 	strtab = dmam_alloc_coherent(smmu->dev, size, &cfg->strtab_dma,
 				     GFP_KERNEL | __GFP_ZERO);
 	if (!strtab) {
--
1.8.3



_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 4/5] iommu/arm-smmu-v3: move arm_smmu_get_step_for_sid() a little ahead
  2019-02-19  7:54 ` Zhen Lei
@ 2019-02-19  7:54   ` Zhen Lei
  -1 siblings, 0 replies; 18+ messages in thread
From: Zhen Lei @ 2019-02-19  7:54 UTC (permalink / raw)
  To: Jean-Philippe Brucker, Robin Murphy, Will Deacon, Joerg Roedel,
	linux-arm-kernel, iommu, linux-kernel
  Cc: Zhen Lei

No functional change, just prepare for the next patch.

Signed-off-by: Zhen Lei <thunder.leizhen@huawei.com>
---
 drivers/iommu/arm-smmu-v3.c | 44 ++++++++++++++++++++++----------------------
 1 file changed, 22 insertions(+), 22 deletions(-)

diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 5bb5dcd..84adecc 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -1273,6 +1273,28 @@ static int arm_smmu_init_dummy_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
 	return __arm_smmu_init_l2_strtab(smmu, sid, &dummy_desc);
 }

+static __le64 *arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid)
+{
+	__le64 *step;
+	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
+
+	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
+		struct arm_smmu_strtab_l1_desc *l1_desc;
+		int idx;
+
+		/* Two-level walk */
+		idx = (sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS;
+		l1_desc = &cfg->l1_desc[idx];
+		idx = (sid & ((1 << STRTAB_SPLIT) - 1)) * STRTAB_STE_DWORDS;
+		step = &l1_desc->l2ptr[idx];
+	} else {
+		/* Simple linear lookup */
+		step = &cfg->strtab[sid * STRTAB_STE_DWORDS];
+	}
+
+	return step;
+}
+
 /* IRQ and event handlers */
 static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
 {
@@ -1704,28 +1726,6 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain)
 	return 0;
 }

-static __le64 *arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid)
-{
-	__le64 *step;
-	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
-
-	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
-		struct arm_smmu_strtab_l1_desc *l1_desc;
-		int idx;
-
-		/* Two-level walk */
-		idx = (sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS;
-		l1_desc = &cfg->l1_desc[idx];
-		idx = (sid & ((1 << STRTAB_SPLIT) - 1)) * STRTAB_STE_DWORDS;
-		step = &l1_desc->l2ptr[idx];
-	} else {
-		/* Simple linear lookup */
-		step = &cfg->strtab[sid * STRTAB_STE_DWORDS];
-	}
-
-	return step;
-}
-
 static void arm_smmu_install_ste_for_dev(struct iommu_fwspec *fwspec)
 {
 	int i, j;
--
1.8.3



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 4/5] iommu/arm-smmu-v3: move arm_smmu_get_step_for_sid() a little ahead
@ 2019-02-19  7:54   ` Zhen Lei
  0 siblings, 0 replies; 18+ messages in thread
From: Zhen Lei @ 2019-02-19  7:54 UTC (permalink / raw)
  To: Jean-Philippe Brucker, Robin Murphy, Will Deacon, Joerg Roedel,
	linux-arm-kernel, iommu, linux-kernel
  Cc: Zhen Lei

No functional change, just prepare for the next patch.

Signed-off-by: Zhen Lei <thunder.leizhen@huawei.com>
---
 drivers/iommu/arm-smmu-v3.c | 44 ++++++++++++++++++++++----------------------
 1 file changed, 22 insertions(+), 22 deletions(-)

diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 5bb5dcd..84adecc 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -1273,6 +1273,28 @@ static int arm_smmu_init_dummy_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
 	return __arm_smmu_init_l2_strtab(smmu, sid, &dummy_desc);
 }

+static __le64 *arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid)
+{
+	__le64 *step;
+	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
+
+	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
+		struct arm_smmu_strtab_l1_desc *l1_desc;
+		int idx;
+
+		/* Two-level walk */
+		idx = (sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS;
+		l1_desc = &cfg->l1_desc[idx];
+		idx = (sid & ((1 << STRTAB_SPLIT) - 1)) * STRTAB_STE_DWORDS;
+		step = &l1_desc->l2ptr[idx];
+	} else {
+		/* Simple linear lookup */
+		step = &cfg->strtab[sid * STRTAB_STE_DWORDS];
+	}
+
+	return step;
+}
+
 /* IRQ and event handlers */
 static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
 {
@@ -1704,28 +1726,6 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain)
 	return 0;
 }

-static __le64 *arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid)
-{
-	__le64 *step;
-	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
-
-	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
-		struct arm_smmu_strtab_l1_desc *l1_desc;
-		int idx;
-
-		/* Two-level walk */
-		idx = (sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS;
-		l1_desc = &cfg->l1_desc[idx];
-		idx = (sid & ((1 << STRTAB_SPLIT) - 1)) * STRTAB_STE_DWORDS;
-		step = &l1_desc->l2ptr[idx];
-	} else {
-		/* Simple linear lookup */
-		step = &cfg->strtab[sid * STRTAB_STE_DWORDS];
-	}
-
-	return step;
-}
-
 static void arm_smmu_install_ste_for_dev(struct iommu_fwspec *fwspec)
 {
 	int i, j;
--
1.8.3



_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 5/5] iommu/arm-smmu-v3: workaround for STE abort in kdump kernel
  2019-02-19  7:54 ` Zhen Lei
@ 2019-02-19  7:54   ` Zhen Lei
  -1 siblings, 0 replies; 18+ messages in thread
From: Zhen Lei @ 2019-02-19  7:54 UTC (permalink / raw)
  To: Jean-Philippe Brucker, Robin Murphy, Will Deacon, Joerg Roedel,
	linux-arm-kernel, iommu, linux-kernel
  Cc: Zhen Lei

Some boards may not implement the STE.config=0b000 correctly, it also
reports event C_BAD_STE when a transaction incoming. To make kdump kernel
can be worked well in this situation, backup the strtab_base which is used
in the first kernel, to make the unexpected devices can reuse the old
mapping if we detected the STE.config=0b000 take no effect.

Signed-off-by: Zhen Lei <thunder.leizhen@huawei.com>
---
 drivers/iommu/arm-smmu-v3.c | 100 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 100 insertions(+)

diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 84adecc..4e95710 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -335,6 +335,9 @@
 #define EVTQ_MAX_SZ_SHIFT		7

 #define EVTQ_0_ID			GENMASK_ULL(7, 0)
+#define EVTQ_0_ID_C_BAD_STE		0x4
+#define EVTQ_0_SSV			GENMASK_ULL(11, 11)
+#define EVTQ_0_SID			GENMASK_ULL(63, 32)

 /* PRI queue */
 #define PRIQ_ENT_DWORDS			2
@@ -525,6 +528,7 @@ struct arm_smmu_strtab_ent {
 struct arm_smmu_strtab_cfg {
 	__le64				*strtab;
 	dma_addr_t			strtab_dma;
+	dma_addr_t			former_strtab_dma;
 	struct arm_smmu_strtab_l1_desc	*l1_desc;
 	unsigned int			num_l1_ents;

@@ -1295,6 +1299,95 @@ static __le64 *arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid)
 	return step;
 }

+/*
+ * This function is only called in the kdump kernel, and mainly because of the
+ * smmu hardware feature "ste abort" is not effective.
+ *
+ * The first kernel flushed all cache before start the secondary kernel, so
+ * it's safe base on ioremap() to access the former smmu tables.
+ *
+ * If any error detected, just simply give up the attempt, directly return
+ * without any error reported.
+ */
+static void arm_smmu_ste_abort_quirks(struct arm_smmu_device *smmu, u64 evt0)
+{
+	int i;
+	__le64 *dst, *src;
+	u64 val, paddr;
+	u32 sid = FIELD_GET(EVTQ_0_SID, evt0);
+	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
+
+	/* SubStreamID is not support yet */
+	if (FIELD_GET(EVTQ_0_SSV, evt0))
+		return;
+
+	/*
+	 * If no device within this L2ST range has been added, the L1STD.L2Ptr
+	 * still point to the dummy L2ST, we should allocate one now.
+	 */
+	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
+		int idx, ret;
+
+		idx = (sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS;
+		if (!cfg->l1_desc[idx].l2ptr) {
+			ret = arm_smmu_init_l2_strtab(smmu, sid);
+			if (ret)
+				return;
+		}
+	}
+
+	dst = arm_smmu_get_step_for_sid(smmu, sid);
+	val = le64_to_cpu(dst[0]);
+	if (FIELD_GET(STRTAB_STE_0_CFG, val) != STRTAB_STE_0_CFG_ABORT)
+		return;
+
+	/* The value of SMMU_STRTAB_BASE maybe corrupted, sanity check it */
+	if (cfg->former_strtab_dma & ~(STRTAB_BASE_RA | STRTAB_BASE_ADDR_MASK))
+		return;
+
+	/* Find the STE base address of "sid" */
+	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
+		u32 span;
+
+		paddr = cfg->former_strtab_dma +
+			(sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_SIZE;
+		src = ioremap(paddr, STRTAB_L1_DESC_SIZE);
+		if (!src)
+			return;
+
+		val   = le64_to_cpu(*src);
+		paddr = val & STRTAB_L1_DESC_L2PTR_MASK;
+		span  = val & STRTAB_L1_DESC_SPAN;
+		iounmap(src);
+
+		/* The content of L1STD maybe corrupted, sanity check it */
+		if (val & ~(STRTAB_L1_DESC_L2PTR_MASK | STRTAB_L1_DESC_SPAN))
+			return;
+		paddr += (sid & ((1 << STRTAB_SPLIT) - 1)) * STRTAB_STE_SIZE;
+	} else {
+		paddr = cfg->former_strtab_dma + (sid * STRTAB_STE_SIZE);
+	}
+
+	src = ioremap(paddr, STRTAB_STE_SIZE);
+	if (!src)
+		return;
+
+	/*
+	 * Copy the former STE content, so that the device can base the former
+	 * mapping to access "memory", and does not report any event again.
+	 *
+	 * Please note that, the "memory" is legally allocated in the first
+	 * kernel, so that it will not corrupt the memory of current secondary
+	 * kernel.
+	 */
+	for (i = 1; i < STRTAB_STE_DWORDS; i++)
+		dst[i] = src[i];
+	arm_smmu_sync_ste_for_sid(smmu, sid);
+	dst[0] = src[0];
+	arm_smmu_sync_ste_for_sid(smmu, sid);
+	iounmap(src);
+}
+
 /* IRQ and event handlers */
 static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
 {
@@ -1312,6 +1405,8 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
 				dev_info(smmu->dev, "\t0x%016llx\n",
 					 (unsigned long long)evt[i]);

+			if ((id == EVTQ_0_ID_C_BAD_STE) && is_kdump_kernel())
+				arm_smmu_ste_abort_quirks(smmu, evt[0]);
 		}

 		/*
@@ -2491,6 +2586,7 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
 {
 	int ret;
 	u32 reg, enables;
+	u64 reg64;
 	struct arm_smmu_cmdq_ent cmd;

 	/* Clear CR0 and sync (disables SMMU and queue processing) */
@@ -2519,6 +2615,10 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
 	reg = CR2_PTM | CR2_RECINVSID | CR2_E2H;
 	writel_relaxed(reg, smmu->base + ARM_SMMU_CR2);

+	/* save the former strtab base */
+	reg64 = readq_relaxed(smmu->base + ARM_SMMU_STRTAB_BASE);
+	smmu->strtab_cfg.former_strtab_dma = reg64 & STRTAB_BASE_ADDR_MASK;
+
 	/* Stream table */
 	writeq_relaxed(smmu->strtab_cfg.strtab_base,
 		       smmu->base + ARM_SMMU_STRTAB_BASE);
--
1.8.3



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 5/5] iommu/arm-smmu-v3: workaround for STE abort in kdump kernel
@ 2019-02-19  7:54   ` Zhen Lei
  0 siblings, 0 replies; 18+ messages in thread
From: Zhen Lei @ 2019-02-19  7:54 UTC (permalink / raw)
  To: Jean-Philippe Brucker, Robin Murphy, Will Deacon, Joerg Roedel,
	linux-arm-kernel, iommu, linux-kernel
  Cc: Zhen Lei

Some boards may not implement the STE.config=0b000 correctly, it also
reports event C_BAD_STE when a transaction incoming. To make kdump kernel
can be worked well in this situation, backup the strtab_base which is used
in the first kernel, to make the unexpected devices can reuse the old
mapping if we detected the STE.config=0b000 take no effect.

Signed-off-by: Zhen Lei <thunder.leizhen@huawei.com>
---
 drivers/iommu/arm-smmu-v3.c | 100 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 100 insertions(+)

diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 84adecc..4e95710 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -335,6 +335,9 @@
 #define EVTQ_MAX_SZ_SHIFT		7

 #define EVTQ_0_ID			GENMASK_ULL(7, 0)
+#define EVTQ_0_ID_C_BAD_STE		0x4
+#define EVTQ_0_SSV			GENMASK_ULL(11, 11)
+#define EVTQ_0_SID			GENMASK_ULL(63, 32)

 /* PRI queue */
 #define PRIQ_ENT_DWORDS			2
@@ -525,6 +528,7 @@ struct arm_smmu_strtab_ent {
 struct arm_smmu_strtab_cfg {
 	__le64				*strtab;
 	dma_addr_t			strtab_dma;
+	dma_addr_t			former_strtab_dma;
 	struct arm_smmu_strtab_l1_desc	*l1_desc;
 	unsigned int			num_l1_ents;

@@ -1295,6 +1299,95 @@ static __le64 *arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid)
 	return step;
 }

+/*
+ * This function is only called in the kdump kernel, and mainly because of the
+ * smmu hardware feature "ste abort" is not effective.
+ *
+ * The first kernel flushed all cache before start the secondary kernel, so
+ * it's safe base on ioremap() to access the former smmu tables.
+ *
+ * If any error detected, just simply give up the attempt, directly return
+ * without any error reported.
+ */
+static void arm_smmu_ste_abort_quirks(struct arm_smmu_device *smmu, u64 evt0)
+{
+	int i;
+	__le64 *dst, *src;
+	u64 val, paddr;
+	u32 sid = FIELD_GET(EVTQ_0_SID, evt0);
+	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
+
+	/* SubStreamID is not support yet */
+	if (FIELD_GET(EVTQ_0_SSV, evt0))
+		return;
+
+	/*
+	 * If no device within this L2ST range has been added, the L1STD.L2Ptr
+	 * still point to the dummy L2ST, we should allocate one now.
+	 */
+	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
+		int idx, ret;
+
+		idx = (sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS;
+		if (!cfg->l1_desc[idx].l2ptr) {
+			ret = arm_smmu_init_l2_strtab(smmu, sid);
+			if (ret)
+				return;
+		}
+	}
+
+	dst = arm_smmu_get_step_for_sid(smmu, sid);
+	val = le64_to_cpu(dst[0]);
+	if (FIELD_GET(STRTAB_STE_0_CFG, val) != STRTAB_STE_0_CFG_ABORT)
+		return;
+
+	/* The value of SMMU_STRTAB_BASE maybe corrupted, sanity check it */
+	if (cfg->former_strtab_dma & ~(STRTAB_BASE_RA | STRTAB_BASE_ADDR_MASK))
+		return;
+
+	/* Find the STE base address of "sid" */
+	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
+		u32 span;
+
+		paddr = cfg->former_strtab_dma +
+			(sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_SIZE;
+		src = ioremap(paddr, STRTAB_L1_DESC_SIZE);
+		if (!src)
+			return;
+
+		val   = le64_to_cpu(*src);
+		paddr = val & STRTAB_L1_DESC_L2PTR_MASK;
+		span  = val & STRTAB_L1_DESC_SPAN;
+		iounmap(src);
+
+		/* The content of L1STD maybe corrupted, sanity check it */
+		if (val & ~(STRTAB_L1_DESC_L2PTR_MASK | STRTAB_L1_DESC_SPAN))
+			return;
+		paddr += (sid & ((1 << STRTAB_SPLIT) - 1)) * STRTAB_STE_SIZE;
+	} else {
+		paddr = cfg->former_strtab_dma + (sid * STRTAB_STE_SIZE);
+	}
+
+	src = ioremap(paddr, STRTAB_STE_SIZE);
+	if (!src)
+		return;
+
+	/*
+	 * Copy the former STE content, so that the device can base the former
+	 * mapping to access "memory", and does not report any event again.
+	 *
+	 * Please note that, the "memory" is legally allocated in the first
+	 * kernel, so that it will not corrupt the memory of current secondary
+	 * kernel.
+	 */
+	for (i = 1; i < STRTAB_STE_DWORDS; i++)
+		dst[i] = src[i];
+	arm_smmu_sync_ste_for_sid(smmu, sid);
+	dst[0] = src[0];
+	arm_smmu_sync_ste_for_sid(smmu, sid);
+	iounmap(src);
+}
+
 /* IRQ and event handlers */
 static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
 {
@@ -1312,6 +1405,8 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
 				dev_info(smmu->dev, "\t0x%016llx\n",
 					 (unsigned long long)evt[i]);

+			if ((id == EVTQ_0_ID_C_BAD_STE) && is_kdump_kernel())
+				arm_smmu_ste_abort_quirks(smmu, evt[0]);
 		}

 		/*
@@ -2491,6 +2586,7 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
 {
 	int ret;
 	u32 reg, enables;
+	u64 reg64;
 	struct arm_smmu_cmdq_ent cmd;

 	/* Clear CR0 and sync (disables SMMU and queue processing) */
@@ -2519,6 +2615,10 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
 	reg = CR2_PTM | CR2_RECINVSID | CR2_E2H;
 	writel_relaxed(reg, smmu->base + ARM_SMMU_CR2);

+	/* save the former strtab base */
+	reg64 = readq_relaxed(smmu->base + ARM_SMMU_STRTAB_BASE);
+	smmu->strtab_cfg.former_strtab_dma = reg64 & STRTAB_BASE_ADDR_MASK;
+
 	/* Stream table */
 	writeq_relaxed(smmu->strtab_cfg.strtab_base,
 		       smmu->base + ARM_SMMU_STRTAB_BASE);
--
1.8.3



_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH 0/5] iommu/arm-smmu-v3: make smmu can be enabled in kdump kernel
  2019-02-19  7:54 ` Zhen Lei
@ 2019-02-27  3:25   ` Leizhen (ThunderTown)
  -1 siblings, 0 replies; 18+ messages in thread
From: Leizhen (ThunderTown) @ 2019-02-27  3:25 UTC (permalink / raw)
  To: Jean-Philippe Brucker, Robin Murphy, Will Deacon, Joerg Roedel,
	linux-arm-kernel, iommu, linux-kernel

Hi Will, Robin:
   Do you have time to review these patches? Hope you can give me some opinions.


On 2019/2/19 15:54, Zhen Lei wrote:
> This patch series include two parts:
> 1. Patch1-2 use dummy STE tables with "ste abort" hardware feature to abort unexpected
>    devices accessing. For more details, see the description in patch 2.
> 2. If the "ste abort" feature is not support, force the unexpected devices in the
>    secondary kernel to use the memory maps which it used in the first kernel. For more
>    details, see patch 5.
> 
> 
> Zhen Lei (5):
>   iommu/arm-smmu-v3: make sure the stale caching of L1STD are invalid
>   iommu/arm-smmu-v3: make smmu can be enabled in kdump kernel
>   iommu/arm-smmu-v3: add macro xxx_SIZE to replace xxx_DWORDS shift
>   iommu/arm-smmu-v3: move arm_smmu_get_step_for_sid() a little ahead
>   iommu/arm-smmu-v3: workaround for STE abort in kdump kernel
> 
>  drivers/iommu/arm-smmu-v3.c | 243 +++++++++++++++++++++++++++++++++++---------
>  1 file changed, 194 insertions(+), 49 deletions(-)
> 

-- 
Thanks!
BestRegards


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 0/5] iommu/arm-smmu-v3: make smmu can be enabled in kdump kernel
@ 2019-02-27  3:25   ` Leizhen (ThunderTown)
  0 siblings, 0 replies; 18+ messages in thread
From: Leizhen (ThunderTown) @ 2019-02-27  3:25 UTC (permalink / raw)
  To: Jean-Philippe Brucker, Robin Murphy, Will Deacon, Joerg Roedel,
	linux-arm-kernel, iommu, linux-kernel

Hi Will, Robin:
   Do you have time to review these patches? Hope you can give me some opinions.


On 2019/2/19 15:54, Zhen Lei wrote:
> This patch series include two parts:
> 1. Patch1-2 use dummy STE tables with "ste abort" hardware feature to abort unexpected
>    devices accessing. For more details, see the description in patch 2.
> 2. If the "ste abort" feature is not support, force the unexpected devices in the
>    secondary kernel to use the memory maps which it used in the first kernel. For more
>    details, see patch 5.
> 
> 
> Zhen Lei (5):
>   iommu/arm-smmu-v3: make sure the stale caching of L1STD are invalid
>   iommu/arm-smmu-v3: make smmu can be enabled in kdump kernel
>   iommu/arm-smmu-v3: add macro xxx_SIZE to replace xxx_DWORDS shift
>   iommu/arm-smmu-v3: move arm_smmu_get_step_for_sid() a little ahead
>   iommu/arm-smmu-v3: workaround for STE abort in kdump kernel
> 
>  drivers/iommu/arm-smmu-v3.c | 243 +++++++++++++++++++++++++++++++++++---------
>  1 file changed, 194 insertions(+), 49 deletions(-)
> 

-- 
Thanks!
BestRegards


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/5] iommu/arm-smmu-v3: make smmu can be enabled in kdump kernel
  2019-02-19  7:54   ` Zhen Lei
  (?)
@ 2019-03-01  9:02   ` Leizhen (ThunderTown)
  2019-03-01  9:18       ` Leizhen (ThunderTown)
  -1 siblings, 1 reply; 18+ messages in thread
From: Leizhen (ThunderTown) @ 2019-03-01  9:02 UTC (permalink / raw)
  To: Jean-Philippe Brucker, Robin Murphy, Will Deacon, Joerg Roedel,
	linux-arm-kernel, iommu, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 5841 bytes --]

Hi All,
    I drew a flowchart, hope this can help you to understand my method.

On 2019/2/19 15:54, Zhen Lei wrote:
> To reduce the risk of further crash, the device_shutdown() was not called
> by the first kernel. That means some devices may still working in the
> secondary kernel. For example, a netcard may still using ring buffer to
> receive the broadcast messages in the kdump kernel. No events are reported
> utill the related smmu reinitialized by the kdump kernel.
> 
> commit b63b3439b856 ("iommu/arm-smmu-v3: Abort all transactions if SMMU is
> enabled in kdump kernel") set SMMU_GBPA.ABORT to prevent the unexpected
> devices accessing, but it also prevent the devices accessing which we
> needed, like hard disk, netcard.
> 
> In fact, we can use STE.config=0b000 to abort the unexpected devices
> accessing only. As below:
> 1. In the first kernel, all buffers used by the "unexpected" devices are
>    correctly mapped, and it will not be used by the secondary kernel
>    because the latter has its dedicated reserved memory.
> 2. In the secondary kernel, set SMMU_GBPA.ABORT=1 before "disable smmu".
> 3. In the secondary kernel, after the smmu was disabled, preset all
>    STE.config=0b000. For 2-level Stream Table, make all L1STD.l2ptr
>    pointer to a dummy L2ST. The dummy L2ST is shared by all L1STDs.
> 4. In the secondary kernel, enable smmu. For the needed devices, allocate
>    new L2STs accordingly.
> 
> For phase 1 and 2, the unexpected devices base the old mapping access
> memory, it will not corrupt others. For phase 3, SMMU_GBPA abort it. For
> phase 4 STE abort it.
> 
> Fixes: commit b63b3439b856 ("iommu/arm-smmu-v3: Abort all transactions ...")
> Signed-off-by: Zhen Lei <thunder.leizhen@huawei.com>
> ---
>  drivers/iommu/arm-smmu-v3.c | 72 ++++++++++++++++++++++++++++++++-------------
>  1 file changed, 51 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
> index 2072897..c3c4ff2 100644
> --- a/drivers/iommu/arm-smmu-v3.c
> +++ b/drivers/iommu/arm-smmu-v3.c
> @@ -1219,35 +1219,57 @@ static void arm_smmu_init_bypass_stes(u64 *strtab, unsigned int nent)
>  	}
>  }
> 
> -static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
> +static int __arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid,
> +				     struct arm_smmu_strtab_l1_desc *desc)
>  {
> -	size_t size;
>  	void *strtab;
>  	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
> -	struct arm_smmu_strtab_l1_desc *desc = &cfg->l1_desc[sid >> STRTAB_SPLIT];
> 
> -	if (desc->l2ptr)
> -		return 0;
> -
> -	size = 1 << (STRTAB_SPLIT + ilog2(STRTAB_STE_DWORDS) + 3);
>  	strtab = &cfg->strtab[(sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS];
> 
> -	desc->span = STRTAB_SPLIT + 1;
> -	desc->l2ptr = dmam_alloc_coherent(smmu->dev, size, &desc->l2ptr_dma,
> -					  GFP_KERNEL | __GFP_ZERO);
>  	if (!desc->l2ptr) {
> -		dev_err(smmu->dev,
> -			"failed to allocate l2 stream table for SID %u\n",
> -			sid);
> -		return -ENOMEM;
> +		size_t size;
> +
> +		size = 1 << (STRTAB_SPLIT + ilog2(STRTAB_STE_DWORDS) + 3);
> +		desc->l2ptr = dmam_alloc_coherent(smmu->dev, size,
> +						  &desc->l2ptr_dma,
> +						  GFP_KERNEL | __GFP_ZERO);
> +		if (!desc->l2ptr) {
> +			dev_err(smmu->dev,
> +				"failed to allocate l2 stream table for SID %u\n",
> +				sid);
> +			return -ENOMEM;
> +		}
> +
> +		desc->span = STRTAB_SPLIT + 1;
> +		arm_smmu_init_bypass_stes(desc->l2ptr, 1 << STRTAB_SPLIT);
>  	}
> 
> -	arm_smmu_init_bypass_stes(desc->l2ptr, 1 << STRTAB_SPLIT);
>  	arm_smmu_write_strtab_l1_desc(strtab, desc);
> +	return 0;
> +}
> +
> +static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
> +{
> +	int ret;
> +	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
> +	struct arm_smmu_strtab_l1_desc *desc = &cfg->l1_desc[sid >> STRTAB_SPLIT];
> +
> +	ret = __arm_smmu_init_l2_strtab(smmu, sid, desc);
> +	if (ret)
> +		return ret;
> +
>  	arm_smmu_sync_std_for_sid(smmu, sid);
>  	return 0;
>  }
> 
> +static int arm_smmu_init_dummy_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
> +{
> +	static struct arm_smmu_strtab_l1_desc dummy_desc;
> +
> +	return __arm_smmu_init_l2_strtab(smmu, sid, &dummy_desc);
> +}
> +
>  /* IRQ and event handlers */
>  static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
>  {
> @@ -2150,8 +2172,12 @@ static int arm_smmu_init_l1_strtab(struct arm_smmu_device *smmu)
>  	}
> 
>  	for (i = 0; i < cfg->num_l1_ents; ++i) {
> -		arm_smmu_write_strtab_l1_desc(strtab, &cfg->l1_desc[i]);
> -		strtab += STRTAB_L1_DESC_DWORDS << 3;
> +		if (is_kdump_kernel()) {
> +			arm_smmu_init_dummy_l2_strtab(smmu, i << STRTAB_SPLIT);
> +		} else {
> +			arm_smmu_write_strtab_l1_desc(strtab, &cfg->l1_desc[i]);
> +			strtab += STRTAB_L1_DESC_DWORDS << 3;
> +		}
>  	}
> 
>  	return 0;
> @@ -2467,11 +2493,8 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
>  	/* Clear CR0 and sync (disables SMMU and queue processing) */
>  	reg = readl_relaxed(smmu->base + ARM_SMMU_CR0);
>  	if (reg & CR0_SMMUEN) {
> -		if (is_kdump_kernel()) {
> +		if (is_kdump_kernel())
>  			arm_smmu_update_gbpa(smmu, GBPA_ABORT, 0);
> -			arm_smmu_device_disable(smmu);
> -			return -EBUSY;
> -		}
> 
>  		dev_warn(smmu->dev, "SMMU currently enabled! Resetting...\n");
>  	}
> @@ -2859,6 +2882,13 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
>  	struct device *dev = &pdev->dev;
>  	bool bypass;
> 
> +	/*
> +	 * Force to disable bypass for the kdump kernel, abort all incoming
> +	 * transactions from the unknown devices.
> +	 */
> +	if (is_kdump_kernel())
> +		disable_bypass = 1;
> +
>  	smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
>  	if (!smmu) {
>  		dev_err(dev, "failed to allocate arm_smmu_device\n");
> --
> 1.8.3
> 
> 
> 
> .
> 

-- 
Thanks!
BestRegards

[-- Attachment #2: kdump_smmu.jpg --]
[-- Type: image/jpeg, Size: 134954 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/5] iommu/arm-smmu-v3: make smmu can be enabled in kdump kernel
  2019-03-01  9:02   ` Leizhen (ThunderTown)
@ 2019-03-01  9:18       ` Leizhen (ThunderTown)
  0 siblings, 0 replies; 18+ messages in thread
From: Leizhen (ThunderTown) @ 2019-03-01  9:18 UTC (permalink / raw)
  To: Jean-Philippe Brucker, Robin Murphy, Will Deacon, Joerg Roedel,
	linux-arm-kernel, iommu, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 6110 bytes --]

It seems that the picture is too big, I change it from jpg to png.


On 2019/3/1 17:02, Leizhen (ThunderTown) wrote:
> Hi All,
>     I drew a flowchart, hope this can help you to understand my method.
> 
> On 2019/2/19 15:54, Zhen Lei wrote:
>> To reduce the risk of further crash, the device_shutdown() was not called
>> by the first kernel. That means some devices may still working in the
>> secondary kernel. For example, a netcard may still using ring buffer to
>> receive the broadcast messages in the kdump kernel. No events are reported
>> utill the related smmu reinitialized by the kdump kernel.
>>
>> commit b63b3439b856 ("iommu/arm-smmu-v3: Abort all transactions if SMMU is
>> enabled in kdump kernel") set SMMU_GBPA.ABORT to prevent the unexpected
>> devices accessing, but it also prevent the devices accessing which we
>> needed, like hard disk, netcard.
>>
>> In fact, we can use STE.config=0b000 to abort the unexpected devices
>> accessing only. As below:
>> 1. In the first kernel, all buffers used by the "unexpected" devices are
>>    correctly mapped, and it will not be used by the secondary kernel
>>    because the latter has its dedicated reserved memory.
>> 2. In the secondary kernel, set SMMU_GBPA.ABORT=1 before "disable smmu".
>> 3. In the secondary kernel, after the smmu was disabled, preset all
>>    STE.config=0b000. For 2-level Stream Table, make all L1STD.l2ptr
>>    pointer to a dummy L2ST. The dummy L2ST is shared by all L1STDs.
>> 4. In the secondary kernel, enable smmu. For the needed devices, allocate
>>    new L2STs accordingly.
>>
>> For phase 1 and 2, the unexpected devices base the old mapping access
>> memory, it will not corrupt others. For phase 3, SMMU_GBPA abort it. For
>> phase 4 STE abort it.
>>
>> Fixes: commit b63b3439b856 ("iommu/arm-smmu-v3: Abort all transactions ...")
>> Signed-off-by: Zhen Lei <thunder.leizhen@huawei.com>
>> ---
>>  drivers/iommu/arm-smmu-v3.c | 72 ++++++++++++++++++++++++++++++++-------------
>>  1 file changed, 51 insertions(+), 21 deletions(-)
>>
>> diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
>> index 2072897..c3c4ff2 100644
>> --- a/drivers/iommu/arm-smmu-v3.c
>> +++ b/drivers/iommu/arm-smmu-v3.c
>> @@ -1219,35 +1219,57 @@ static void arm_smmu_init_bypass_stes(u64 *strtab, unsigned int nent)
>>  	}
>>  }
>>
>> -static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
>> +static int __arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid,
>> +				     struct arm_smmu_strtab_l1_desc *desc)
>>  {
>> -	size_t size;
>>  	void *strtab;
>>  	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
>> -	struct arm_smmu_strtab_l1_desc *desc = &cfg->l1_desc[sid >> STRTAB_SPLIT];
>>
>> -	if (desc->l2ptr)
>> -		return 0;
>> -
>> -	size = 1 << (STRTAB_SPLIT + ilog2(STRTAB_STE_DWORDS) + 3);
>>  	strtab = &cfg->strtab[(sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS];
>>
>> -	desc->span = STRTAB_SPLIT + 1;
>> -	desc->l2ptr = dmam_alloc_coherent(smmu->dev, size, &desc->l2ptr_dma,
>> -					  GFP_KERNEL | __GFP_ZERO);
>>  	if (!desc->l2ptr) {
>> -		dev_err(smmu->dev,
>> -			"failed to allocate l2 stream table for SID %u\n",
>> -			sid);
>> -		return -ENOMEM;
>> +		size_t size;
>> +
>> +		size = 1 << (STRTAB_SPLIT + ilog2(STRTAB_STE_DWORDS) + 3);
>> +		desc->l2ptr = dmam_alloc_coherent(smmu->dev, size,
>> +						  &desc->l2ptr_dma,
>> +						  GFP_KERNEL | __GFP_ZERO);
>> +		if (!desc->l2ptr) {
>> +			dev_err(smmu->dev,
>> +				"failed to allocate l2 stream table for SID %u\n",
>> +				sid);
>> +			return -ENOMEM;
>> +		}
>> +
>> +		desc->span = STRTAB_SPLIT + 1;
>> +		arm_smmu_init_bypass_stes(desc->l2ptr, 1 << STRTAB_SPLIT);
>>  	}
>>
>> -	arm_smmu_init_bypass_stes(desc->l2ptr, 1 << STRTAB_SPLIT);
>>  	arm_smmu_write_strtab_l1_desc(strtab, desc);
>> +	return 0;
>> +}
>> +
>> +static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
>> +{
>> +	int ret;
>> +	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
>> +	struct arm_smmu_strtab_l1_desc *desc = &cfg->l1_desc[sid >> STRTAB_SPLIT];
>> +
>> +	ret = __arm_smmu_init_l2_strtab(smmu, sid, desc);
>> +	if (ret)
>> +		return ret;
>> +
>>  	arm_smmu_sync_std_for_sid(smmu, sid);
>>  	return 0;
>>  }
>>
>> +static int arm_smmu_init_dummy_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
>> +{
>> +	static struct arm_smmu_strtab_l1_desc dummy_desc;
>> +
>> +	return __arm_smmu_init_l2_strtab(smmu, sid, &dummy_desc);
>> +}
>> +
>>  /* IRQ and event handlers */
>>  static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
>>  {
>> @@ -2150,8 +2172,12 @@ static int arm_smmu_init_l1_strtab(struct arm_smmu_device *smmu)
>>  	}
>>
>>  	for (i = 0; i < cfg->num_l1_ents; ++i) {
>> -		arm_smmu_write_strtab_l1_desc(strtab, &cfg->l1_desc[i]);
>> -		strtab += STRTAB_L1_DESC_DWORDS << 3;
>> +		if (is_kdump_kernel()) {
>> +			arm_smmu_init_dummy_l2_strtab(smmu, i << STRTAB_SPLIT);
>> +		} else {
>> +			arm_smmu_write_strtab_l1_desc(strtab, &cfg->l1_desc[i]);
>> +			strtab += STRTAB_L1_DESC_DWORDS << 3;
>> +		}
>>  	}
>>
>>  	return 0;
>> @@ -2467,11 +2493,8 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
>>  	/* Clear CR0 and sync (disables SMMU and queue processing) */
>>  	reg = readl_relaxed(smmu->base + ARM_SMMU_CR0);
>>  	if (reg & CR0_SMMUEN) {
>> -		if (is_kdump_kernel()) {
>> +		if (is_kdump_kernel())
>>  			arm_smmu_update_gbpa(smmu, GBPA_ABORT, 0);
>> -			arm_smmu_device_disable(smmu);
>> -			return -EBUSY;
>> -		}
>>
>>  		dev_warn(smmu->dev, "SMMU currently enabled! Resetting...\n");
>>  	}
>> @@ -2859,6 +2882,13 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
>>  	struct device *dev = &pdev->dev;
>>  	bool bypass;
>>
>> +	/*
>> +	 * Force to disable bypass for the kdump kernel, abort all incoming
>> +	 * transactions from the unknown devices.
>> +	 */
>> +	if (is_kdump_kernel())
>> +		disable_bypass = 1;
>> +
>>  	smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
>>  	if (!smmu) {
>>  		dev_err(dev, "failed to allocate arm_smmu_device\n");
>> --
>> 1.8.3
>>
>>
>>
>> .
>>
> 

-- 
Thanks!
BestRegards

[-- Attachment #2: kdump_smmu.png --]
[-- Type: image/png, Size: 47852 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/5] iommu/arm-smmu-v3: make smmu can be enabled in kdump kernel
@ 2019-03-01  9:18       ` Leizhen (ThunderTown)
  0 siblings, 0 replies; 18+ messages in thread
From: Leizhen (ThunderTown) @ 2019-03-01  9:18 UTC (permalink / raw)
  To: Jean-Philippe Brucker, Robin Murphy, Will Deacon, Joerg Roedel,
	linux-arm-kernel, iommu, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 6110 bytes --]

It seems that the picture is too big, I change it from jpg to png.


On 2019/3/1 17:02, Leizhen (ThunderTown) wrote:
> Hi All,
>     I drew a flowchart, hope this can help you to understand my method.
> 
> On 2019/2/19 15:54, Zhen Lei wrote:
>> To reduce the risk of further crash, the device_shutdown() was not called
>> by the first kernel. That means some devices may still working in the
>> secondary kernel. For example, a netcard may still using ring buffer to
>> receive the broadcast messages in the kdump kernel. No events are reported
>> utill the related smmu reinitialized by the kdump kernel.
>>
>> commit b63b3439b856 ("iommu/arm-smmu-v3: Abort all transactions if SMMU is
>> enabled in kdump kernel") set SMMU_GBPA.ABORT to prevent the unexpected
>> devices accessing, but it also prevent the devices accessing which we
>> needed, like hard disk, netcard.
>>
>> In fact, we can use STE.config=0b000 to abort the unexpected devices
>> accessing only. As below:
>> 1. In the first kernel, all buffers used by the "unexpected" devices are
>>    correctly mapped, and it will not be used by the secondary kernel
>>    because the latter has its dedicated reserved memory.
>> 2. In the secondary kernel, set SMMU_GBPA.ABORT=1 before "disable smmu".
>> 3. In the secondary kernel, after the smmu was disabled, preset all
>>    STE.config=0b000. For 2-level Stream Table, make all L1STD.l2ptr
>>    pointer to a dummy L2ST. The dummy L2ST is shared by all L1STDs.
>> 4. In the secondary kernel, enable smmu. For the needed devices, allocate
>>    new L2STs accordingly.
>>
>> For phase 1 and 2, the unexpected devices base the old mapping access
>> memory, it will not corrupt others. For phase 3, SMMU_GBPA abort it. For
>> phase 4 STE abort it.
>>
>> Fixes: commit b63b3439b856 ("iommu/arm-smmu-v3: Abort all transactions ...")
>> Signed-off-by: Zhen Lei <thunder.leizhen@huawei.com>
>> ---
>>  drivers/iommu/arm-smmu-v3.c | 72 ++++++++++++++++++++++++++++++++-------------
>>  1 file changed, 51 insertions(+), 21 deletions(-)
>>
>> diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
>> index 2072897..c3c4ff2 100644
>> --- a/drivers/iommu/arm-smmu-v3.c
>> +++ b/drivers/iommu/arm-smmu-v3.c
>> @@ -1219,35 +1219,57 @@ static void arm_smmu_init_bypass_stes(u64 *strtab, unsigned int nent)
>>  	}
>>  }
>>
>> -static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
>> +static int __arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid,
>> +				     struct arm_smmu_strtab_l1_desc *desc)
>>  {
>> -	size_t size;
>>  	void *strtab;
>>  	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
>> -	struct arm_smmu_strtab_l1_desc *desc = &cfg->l1_desc[sid >> STRTAB_SPLIT];
>>
>> -	if (desc->l2ptr)
>> -		return 0;
>> -
>> -	size = 1 << (STRTAB_SPLIT + ilog2(STRTAB_STE_DWORDS) + 3);
>>  	strtab = &cfg->strtab[(sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS];
>>
>> -	desc->span = STRTAB_SPLIT + 1;
>> -	desc->l2ptr = dmam_alloc_coherent(smmu->dev, size, &desc->l2ptr_dma,
>> -					  GFP_KERNEL | __GFP_ZERO);
>>  	if (!desc->l2ptr) {
>> -		dev_err(smmu->dev,
>> -			"failed to allocate l2 stream table for SID %u\n",
>> -			sid);
>> -		return -ENOMEM;
>> +		size_t size;
>> +
>> +		size = 1 << (STRTAB_SPLIT + ilog2(STRTAB_STE_DWORDS) + 3);
>> +		desc->l2ptr = dmam_alloc_coherent(smmu->dev, size,
>> +						  &desc->l2ptr_dma,
>> +						  GFP_KERNEL | __GFP_ZERO);
>> +		if (!desc->l2ptr) {
>> +			dev_err(smmu->dev,
>> +				"failed to allocate l2 stream table for SID %u\n",
>> +				sid);
>> +			return -ENOMEM;
>> +		}
>> +
>> +		desc->span = STRTAB_SPLIT + 1;
>> +		arm_smmu_init_bypass_stes(desc->l2ptr, 1 << STRTAB_SPLIT);
>>  	}
>>
>> -	arm_smmu_init_bypass_stes(desc->l2ptr, 1 << STRTAB_SPLIT);
>>  	arm_smmu_write_strtab_l1_desc(strtab, desc);
>> +	return 0;
>> +}
>> +
>> +static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
>> +{
>> +	int ret;
>> +	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
>> +	struct arm_smmu_strtab_l1_desc *desc = &cfg->l1_desc[sid >> STRTAB_SPLIT];
>> +
>> +	ret = __arm_smmu_init_l2_strtab(smmu, sid, desc);
>> +	if (ret)
>> +		return ret;
>> +
>>  	arm_smmu_sync_std_for_sid(smmu, sid);
>>  	return 0;
>>  }
>>
>> +static int arm_smmu_init_dummy_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
>> +{
>> +	static struct arm_smmu_strtab_l1_desc dummy_desc;
>> +
>> +	return __arm_smmu_init_l2_strtab(smmu, sid, &dummy_desc);
>> +}
>> +
>>  /* IRQ and event handlers */
>>  static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
>>  {
>> @@ -2150,8 +2172,12 @@ static int arm_smmu_init_l1_strtab(struct arm_smmu_device *smmu)
>>  	}
>>
>>  	for (i = 0; i < cfg->num_l1_ents; ++i) {
>> -		arm_smmu_write_strtab_l1_desc(strtab, &cfg->l1_desc[i]);
>> -		strtab += STRTAB_L1_DESC_DWORDS << 3;
>> +		if (is_kdump_kernel()) {
>> +			arm_smmu_init_dummy_l2_strtab(smmu, i << STRTAB_SPLIT);
>> +		} else {
>> +			arm_smmu_write_strtab_l1_desc(strtab, &cfg->l1_desc[i]);
>> +			strtab += STRTAB_L1_DESC_DWORDS << 3;
>> +		}
>>  	}
>>
>>  	return 0;
>> @@ -2467,11 +2493,8 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
>>  	/* Clear CR0 and sync (disables SMMU and queue processing) */
>>  	reg = readl_relaxed(smmu->base + ARM_SMMU_CR0);
>>  	if (reg & CR0_SMMUEN) {
>> -		if (is_kdump_kernel()) {
>> +		if (is_kdump_kernel())
>>  			arm_smmu_update_gbpa(smmu, GBPA_ABORT, 0);
>> -			arm_smmu_device_disable(smmu);
>> -			return -EBUSY;
>> -		}
>>
>>  		dev_warn(smmu->dev, "SMMU currently enabled! Resetting...\n");
>>  	}
>> @@ -2859,6 +2882,13 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
>>  	struct device *dev = &pdev->dev;
>>  	bool bypass;
>>
>> +	/*
>> +	 * Force to disable bypass for the kdump kernel, abort all incoming
>> +	 * transactions from the unknown devices.
>> +	 */
>> +	if (is_kdump_kernel())
>> +		disable_bypass = 1;
>> +
>>  	smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
>>  	if (!smmu) {
>>  		dev_err(dev, "failed to allocate arm_smmu_device\n");
>> --
>> 1.8.3
>>
>>
>>
>> .
>>
> 

-- 
Thanks!
BestRegards

[-- Attachment #2: kdump_smmu.png --]
[-- Type: image/png, Size: 47852 bytes --]

[-- Attachment #3: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2019-03-01  9:19 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-19  7:54 [PATCH 0/5] iommu/arm-smmu-v3: make smmu can be enabled in kdump kernel Zhen Lei
2019-02-19  7:54 ` Zhen Lei
2019-02-19  7:54 ` [PATCH 1/5] iommu/arm-smmu-v3: make sure the stale caching of L1STD are invalid Zhen Lei
2019-02-19  7:54   ` Zhen Lei
2019-02-19  7:54   ` Zhen Lei
2019-02-19  7:54 ` [PATCH 2/5] iommu/arm-smmu-v3: make smmu can be enabled in kdump kernel Zhen Lei
2019-02-19  7:54   ` Zhen Lei
2019-03-01  9:02   ` Leizhen (ThunderTown)
2019-03-01  9:18     ` Leizhen (ThunderTown)
2019-03-01  9:18       ` Leizhen (ThunderTown)
2019-02-19  7:54 ` [PATCH 3/5] iommu/arm-smmu-v3: add macro xxx_SIZE to replace xxx_DWORDS shift Zhen Lei
2019-02-19  7:54   ` Zhen Lei
2019-02-19  7:54 ` [PATCH 4/5] iommu/arm-smmu-v3: move arm_smmu_get_step_for_sid() a little ahead Zhen Lei
2019-02-19  7:54   ` Zhen Lei
2019-02-19  7:54 ` [PATCH 5/5] iommu/arm-smmu-v3: workaround for STE abort in kdump kernel Zhen Lei
2019-02-19  7:54   ` Zhen Lei
2019-02-27  3:25 ` [PATCH 0/5] iommu/arm-smmu-v3: make smmu can be enabled " Leizhen (ThunderTown)
2019-02-27  3:25   ` Leizhen (ThunderTown)

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.