Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Mostafa Saleh <smostafa@google.com>
To: Nicolin Chen <nicolinc@nvidia.com>
Cc: will@kernel.org, robin.murphy@arm.com, joro@8bytes.org,
	jgg@nvidia.com, praan@google.com, kevin.tian@intel.com,
	linux-arm-kernel@lists.infradead.org, iommu@lists.linux.dev,
	linux-kernel@vger.kernel.org, jamien@nvidia.com, kas@kernel.org,
	Cristian Prundeanu <cpru@amazon.com>,
	Breno Leitao <leitao@kernel.org>
Subject: Re: [PATCH v11 06/11] iommu/arm-smmu-v3: Add ARM_SMMU_OPT_KDUMP_ADOPT for kdump kernel
Date: Tue, 20 Oct 2026 11:38:21 +0000	[thread overview]
Message-ID: <atdSrRwrphdI9ZQA@google.com> (raw)
In-Reply-To: <ee4257b62324aa75d7140f1f4a49aa0f78586fff.1791226953.git.nicolinc@nvidia.com>

On Mon, Oct 05, 2026 at 12:30:49PM -0700, Nicolin Chen wrote:
> When transitioning to a kdump kernel, the primary kernel might have crashed
> while endpoint devices were actively bus-mastering DMA. Currently, the SMMU
> driver aggressively resets the hardware during probe by clearing CR0_SMMUEN
> and setting the Global Bypass Attribute (GBPA) to ABORT.
> 
> In a kdump scenario, this aggressive reset is highly destructive:
> a) If GBPA is set to ABORT, in-flight DMA will be aborted, generating fatal
>    PCIe AER or SErrors that may panic the kdump kernel
> b) If GBPA is set to BYPASS, in-flight DMA targeting some IOVAs will bypass
>    the SMMU and corrupt the physical memory at those 1:1 mapped IOVAs.
> 
> To safely absorb in-flight DMAs, a kdump kernel will have to leave SMMUEN=1
> intact and avoid modifying STRTAB_BASE, allowing HW to continue translating
> in-flight DMAs reusing the crashed kernel's page tables until the endpoint
> device drivers probe and quiesce their respective hardware.
> 
> However, the ARM SMMUv3 architecture specification states that updating the
> SMMU_STRTAB_BASE register while SMMUEN == 1 is UNPREDICTABLE or ignored.
> 
> This leaves a kdump kernel no choice but to adopt the stream table from the
> crashed kernel.
> 
> Introduce ARM_SMMU_OPT_KDUMP_ADOPT and adoption functions that memremap the
> stream tables extracted from STRTAB_BASE and STRTAB_BASE_CFG.
> 
> Note that the adoption of the crashed kernel's stream table follows certain
> strict rules, since the old stream table might be compromised. Thus, apply
> some basic validations against the values read from the registers. If tests
> fail, it means the stream table cannot be trusted, so toss it entirely. To
> avoid OOM due to a potentially corrupted stream table, the memremap for l2
> tables is done lazily on the kdump kernel's demand.
> 
> The new option will be set in a following change, once the device reset and
> the RMR setup are reworked not to overwrite the adopted stream table, and
> the crashed kernel's in-use ASIDs and VMIDs are reserved.
> 
> Keep all kdump functions and kexec helpers in a new arm-smmu-v3-kexec file,
> which will be shared with the liveupdate series in the future.
> 
> Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
> Suggested-by: Pranjal Shrivastava <praan@google.com>
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
> Tested-by: Breno Leitao <leitao@kernel.org>
> Tested-by: Cristian Prundeanu <cpru@amazon.com>
> Assisted-by: LLM
> Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
> ---
>  drivers/iommu/arm/Kconfig                     |   3 +
>  drivers/iommu/arm/arm-smmu-v3/Makefile        |   1 +
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h   |  21 +
>  .../iommu/arm/arm-smmu-v3/arm-smmu-v3-kexec.c | 398 ++++++++++++++++++
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c   |  21 +-
>  5 files changed, 441 insertions(+), 3 deletions(-)
>  create mode 100644 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-kexec.c
> 
> diff --git a/drivers/iommu/arm/Kconfig b/drivers/iommu/arm/Kconfig
> index 5fac08b89deea..9a7bebe16f395 100644
> --- a/drivers/iommu/arm/Kconfig
> +++ b/drivers/iommu/arm/Kconfig
> @@ -109,6 +109,9 @@ config ARM_SMMU_V3_IOMMUFD
>  
>  	  Say Y here if you are doing development and testing on this feature.
>  
> +config ARM_SMMU_V3_KEXEC
> +	def_bool CRASH_DUMP
> +
>  config ARM_SMMU_V3_KUNIT_TEST
>  	tristate "KUnit tests for arm-smmu-v3 driver"  if !KUNIT_ALL_TESTS
>  	depends on KUNIT
> diff --git a/drivers/iommu/arm/arm-smmu-v3/Makefile b/drivers/iommu/arm/arm-smmu-v3/Makefile
> index 493a659cc66bb..89a27de8dd2f0 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/Makefile
> +++ b/drivers/iommu/arm/arm-smmu-v3/Makefile
> @@ -3,6 +3,7 @@ obj-$(CONFIG_ARM_SMMU_V3) += arm_smmu_v3.o
>  arm_smmu_v3-y := arm-smmu-v3.o
>  arm_smmu_v3-$(CONFIG_ARM_SMMU_V3_IOMMUFD) += arm-smmu-v3-iommufd.o
>  arm_smmu_v3-$(CONFIG_ARM_SMMU_V3_SVA) += arm-smmu-v3-sva.o
> +arm_smmu_v3-$(CONFIG_ARM_SMMU_V3_KEXEC) += arm-smmu-v3-kexec.o
>  arm_smmu_v3-$(CONFIG_TEGRA241_CMDQV) += tegra241-cmdqv.o
>  
>  obj-$(CONFIG_ARM_SMMU_V3_KUNIT_TEST) += arm-smmu-v3-test.o
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> index 559bfa8cbc5e0..a1f947e7d9fe4 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> @@ -986,6 +986,7 @@ struct arm_smmu_device {
>   * invalidated CONT
>   */
>  #define ARM_SMMU_OPT_FULL_CONT_RANGE_INV (1 << 6)
> +#define ARM_SMMU_OPT_KDUMP_ADOPT	(1 << 7)
>  	u32				options;
>  
>  	struct arm_smmu_cmdq		cmdq;
> @@ -1312,6 +1313,26 @@ tegra241_cmdqv_probe(struct arm_smmu_device *smmu)
>  }
>  #endif /* CONFIG_TEGRA241_CMDQV */
>  
> +#ifdef CONFIG_CRASH_DUMP
> +int arm_smmu_kdump_adopt_strtab(struct arm_smmu_device *smmu);
> +int arm_smmu_kdump_adopt_deferred_l2_strtab(struct arm_smmu_device *smmu,
> +					    u32 sid, phys_addr_t base, u32 span,
> +					    struct arm_smmu_strtab_l2 **l2table);
> +#else /* CONFIG_CRASH_DUMP */
> +static inline int arm_smmu_kdump_adopt_strtab(struct arm_smmu_device *smmu)
> +{
> +	return -EOPNOTSUPP;
> +}
> +
> +static inline int
> +arm_smmu_kdump_adopt_deferred_l2_strtab(struct arm_smmu_device *smmu, u32 sid,
> +					phys_addr_t base, u32 span,
> +					struct arm_smmu_strtab_l2 **l2table)
> +{
> +	return -EOPNOTSUPP;
> +}
> +#endif /* CONFIG_CRASH_DUMP */
> +
>  struct arm_vsmmu {
>  	struct iommufd_viommu core;
>  	struct arm_smmu_device *smmu;
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-kexec.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-kexec.c
> new file mode 100644
> index 0000000000000..6bbc369df86bb
> --- /dev/null
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-kexec.c
> @@ -0,0 +1,398 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES
> + */
> +
> +#define dev_fmt(fmt) "kexec: " fmt
> +
> +#include <linux/io.h>
> +#include <linux/slab.h>
> +
> +#include "arm-smmu-v3.h"
> +
> +/*
> + * Common helpers for a kexec'd kernel to parse, validate, and walk through the
> + * previous kernel's SMMU table structures, shared by the kdump adoption and a
> + * future live-update restoration.
> + *
> + * The common helpers are read-only against the previous kernel's structures: a
> + * table that is not yet mapped by this kernel gets a transient memremap during
> + * a walk, followed by an immediate memunmap. They never allocate memory or take
> + * ownership of the previous kernel's tables; the callers make those decisions.
> + */
> +
> +/**
> + * arm_smmu_kexec_parse_strtab_2lvl() - Validate a 2-level stream table
> + * @smmu: SMMU device of this kernel
> + * @cfg_reg: STRTAB_BASE_CFG register value set by the previous kernel
> + * @base: stream table base address extracted from the STRTAB_BASE register
> + * @num_l1_ents: pointer to return the number of L1 entries
> + *
> + * Validate the 2-level stream table geometry in @cfg_reg and @base's alignment
> + * against this kernel's hardware limits.
> + *
> + * Return: 0 on success with @num_l1_ents set, or -EINVAL on a bad geometry
> + */
> +static int arm_smmu_kexec_parse_strtab_2lvl(struct arm_smmu_device *smmu,
> +					    u32 cfg_reg, phys_addr_t base,
> +					    u32 *num_l1_ents)
> +{
> +	u32 log2size = FIELD_GET(STRTAB_BASE_CFG_LOG2SIZE, cfg_reg);
> +	u32 split = FIELD_GET(STRTAB_BASE_CFG_SPLIT, cfg_reg);
> +	u32 num_ents;
> +	size_t size;
> +
> +	if (log2size < split || log2size > smmu->sid_bits) {
> +		dev_err(smmu->dev, "log2size %u out of range [%u, %u]\n",
> +			log2size, split, smmu->sid_bits);
> +		return -EINVAL;
> +	}
> +	if (split != STRTAB_SPLIT) {
> +		dev_err(smmu->dev,
> +			"unsupported STRTAB_SPLIT %u (expected %u)\n", split,
> +			STRTAB_SPLIT);
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * Bound the entry count before the shift, as a log2size wider than what
> +	 * this kernel itself supports would overflow it.
> +	 */
> +	if (log2size - split > ilog2(STRTAB_MAX_L1_ENTRIES)) {
> +		dev_err(smmu->dev, "l1 entries 2^%u exceeds max %u\n",
> +			log2size - split, STRTAB_MAX_L1_ENTRIES);
> +		return -EINVAL;
> +	}
> +
> +	num_ents = 1U << (log2size - split);
> +
> +	size = num_ents * sizeof(struct arm_smmu_strtab_l1);
> +	/*
> +	 * According to spec (6.3.24), HW aligns the base down to the L1 table
> +	 * size, i.e. min 64 bytes, so an unaligned base would make this kernel
> +	 * read another table.
> +	 */
> +	if (!IS_ALIGNED(base, size)) {
> +		dev_err(smmu->dev, "unaligned l1 stream table base %pa\n",
> +			&base);
> +		return -EINVAL;
> +	}
> +
> +	*num_l1_ents = num_ents;
> +	return 0;
> +}
> +
> +/**
> + * arm_smmu_kexec_parse_strtab_linear() - Validate a linear stream table
> + * @smmu: SMMU device of this kernel
> + * @cfg_reg: STRTAB_BASE_CFG register value set by the previous kernel
> + * @base: stream table base address extracted from the STRTAB_BASE register
> + * @num_ents: pointer to return the number of STEs
> + *
> + * Validate the linear stream table geometry in @cfg_reg and @base's alignment
> + * against this kernel's own limits.
> + *
> + * Return: 0 on success with @num_ents set, or -EINVAL on a bad geometry
> + */
> +static int arm_smmu_kexec_parse_strtab_linear(struct arm_smmu_device *smmu,
> +					      u32 cfg_reg, phys_addr_t base,
> +					      u32 *num_ents)
> +{
> +	u32 log2size = FIELD_GET(STRTAB_BASE_CFG_LOG2SIZE, cfg_reg);
> +	unsigned int max_log2size = smmu->sid_bits;
> +	size_t size;
> +
> +	/* Cap the size at what this kernel itself would have allocated */
> +	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB)
> +		max_log2size = min_t(
> +			unsigned int, max_log2size,
> +			ilog2(STRTAB_MAX_L1_ENTRIES * STRTAB_NUM_L2_STES));
> +
> +	/* num_ents is limited to a u32, so cap log2size at 31 */
> +	max_log2size = min(max_log2size, 31U);
> +	if (log2size > max_log2size) {
> +		dev_err(smmu->dev, "unsupported log2size %u (> %u)\n", log2size,
> +			max_log2size);
> +		return -EINVAL;
> +	}
> +
> +	size = (1U << log2size) * sizeof(struct arm_smmu_ste);
> +	/*
> +	 * According to spec (6.3.24), HW aligns the base down to the table size
> +	 * and ignores the low bits, so an unaligned base would make this kernel
> +	 * read a different table.
> +	 */
> +	if (!IS_ALIGNED(base, size)) {
> +		dev_err(smmu->dev, "unaligned stream table base %pa\n", &base);

I understand these are best effort, but what happens if the address
corrupted and happens to be aligned?

> +		return -EINVAL;
> +	}
> +
> +	*num_ents = 1U << log2size;
> +	return 0;
> +}
> +
> +/**
> + * arm_smmu_kexec_check_strtab_l1_desc() - Check one stream table L1 descriptor
> + * @smmu: SMMU device of this kernel
> + * @l1_desc: L1 descriptor value from the previous kernel's stream table
> + * @idx: index of the L1 descriptor, for diagnostics
> + * @l2_base: pointer to return the L2 table's physical address
> + *
> + * Return: 1 if the descriptor is unused, 0 if it is valid with @l2_base set, or
> + * -EINVAL if it is malformed
> + */
> +static int arm_smmu_kexec_check_strtab_l1_desc(struct arm_smmu_device *smmu,
> +					       u64 l1_desc, u32 idx,
> +					       phys_addr_t *l2_base)
> +{
> +	phys_addr_t base = l1_desc & STRTAB_L1_DESC_L2PTR_MASK;
> +	u32 span = FIELD_GET(STRTAB_L1_DESC_SPAN, l1_desc);
> +
> +	/* L1STD.L2Ptr is invalid */
> +	if (!span)
> +		return 1;
> +
> +	if (span != STRTAB_SPLIT + 1) {
> +		dev_err(smmu->dev, "L1[%u] unsupported span %u (vs %u)\n", idx,
> +			span, STRTAB_SPLIT + 1);
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * A valid descriptor never carries a null pointer. Also, HW aligns the
> +	 * pointer down to the L2 table size, so an unaligned pointer would make
> +	 * this kernel read a different table.
> +	 */
> +	if (!base || !IS_ALIGNED(base, sizeof(struct arm_smmu_strtab_l2))) {
> +		dev_err(smmu->dev, "L1[%u] bad l2 table base %pa\n", idx,
> +			&base);
> +		return -EINVAL;
> +	}
> +
> +	*l2_base = base;
> +	return 0;
> +}
> +
> +#ifdef CONFIG_CRASH_DUMP
> +/*
> + * Helper functions of the kdump stream table adoption for ARM SMMUv3
> + *
> + * When the crashed kernel left the SMMU enabled with in-flight DMAs, the kdump
> + * kernel adopts the crashed kernel's stream tables, instead of doing a regular
> + * reset, to keep in-flight DMAs translating until the endpoint device drivers
> + * re-probe and quiesce their devices.
> + *
> + * Note:
> + *  - Adoption only starts on an SMMU that the crashed kernel left enabled, as a
> + *    disabled SMMU (CR0_SMMUEN=0) could hold meaningless register values.
> + *  - Values read from the crashed kernel's registers get structural validation
> + *    only (format, size, span, alignment, and ID range); the physical addresses
> + *    are not vetted, as the kdump kernel has no record of which pages held the
> + *    tables.
> + *  - A structural inconsistency at adoption time tosses the entire adoption and
> + *    makes the SMMU fall back to a full reset blocking in-flight DMAs.
> + *  - L2 stream tables are adopted lazily at master-inserting time, to bound the
> + *    peak memory use against a corrupted L1 table; any lazy L2 adoption failure
> + *    rejects that device alone, as its blast radius is bounded to the bus.
> + *  - Only a coherent SMMU (ARM_SMMU_FEAT_COHERENCY) is supported, as the stream
> + *    table adoption is done by memremap with MEMREMAP_WB, which is verified on
> + *    the real hardware. Callers of these functions are responsible for gating
> + *    ARM_SMMU_FEAT_COHERENCY once during the probe.
> + */
> +
> +int arm_smmu_kdump_adopt_deferred_l2_strtab(struct arm_smmu_device *smmu,
> +					    u32 sid, phys_addr_t base, u32 span,
> +					    struct arm_smmu_strtab_l2 **l2table)
> +{
> +	struct arm_smmu_strtab_l2 *table;
> +	size_t size;
> +
> +	/*
> +	 * Retest the span in case the L1 descriptor has been overwritten since
> +	 * the adopt. Reject this master's insert; panic or SMMU-disable would
> +	 * either lose the vmcore or cascade aborts. Do not try to fix it, as it
> +	 * would break all other SIDs in the same bus (PCI case). The corruption
> +	 * blast radius is already bounded to that bus range.
> +	 */
> +	if (span != STRTAB_SPLIT + 1) {
> +		dev_err(smmu->dev,
> +			"L1[%u] span %u changed since adopt (was %u)\n",
> +			arm_smmu_strtab_l1_idx(sid), span, STRTAB_SPLIT + 1);
> +		return -EINVAL;
> +	}
> +
> +	size = (1UL << (span - 1)) * sizeof(struct arm_smmu_ste);
> +
> +	/* Same live-corruption check as the span; reject an overwritten base */
> +	if (!base || !IS_ALIGNED(base, size)) {
> +		dev_err(smmu->dev, "L1[%u] bad l2 table base %pa\n",
> +			arm_smmu_strtab_l1_idx(sid), &base);
> +		return -EINVAL;
> +	}
> +

Those are a bit similar to arm_smmu_kexec_parse_strtab_2lvl() is it
possible to have some helpers instead?

> +	/*
> +	 * This L2 table is mapped lazily per master; devres frees it at unbind,
> +	 * as with the dmam_alloc_coherent() used for a fresh L2.
> +	 */
> +	table = devm_memremap(smmu->dev, base, size, MEMREMAP_WB);
> +	if (IS_ERR(table)) {
> +		dev_err(smmu->dev,
> +			"failed to adopt l2 stream table for SID %u\n", sid);
> +		return PTR_ERR(table);
> +	}
> +
> +	*l2table = table;
> +	return 0;
> +}
> +
> +static int arm_smmu_kdump_adopt_strtab_2lvl(struct arm_smmu_device *smmu,
> +					    u32 cfg_reg, phys_addr_t base)
> +{
> +	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
> +	u32 num_l1_ents;
> +	size_t size;
> +	int ret, i;
> +
> +	ret = arm_smmu_kexec_parse_strtab_2lvl(smmu, cfg_reg, base,
> +					       &num_l1_ents);
> +	if (ret)
> +		return ret;
> +
> +	cfg->l2.num_l1_ents = num_l1_ents;
> +
> +	size = num_l1_ents * sizeof(struct arm_smmu_strtab_l1);
> +	cfg->l2.l1tab = memremap(base, size, MEMREMAP_WB);
> +	if (!cfg->l2.l1tab)
> +		return -ENOMEM;
> +
> +	cfg->l2.l2ptrs =
> +		kcalloc(num_l1_ents, sizeof(*cfg->l2.l2ptrs), GFP_KERNEL);
> +	if (!cfg->l2.l2ptrs)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < num_l1_ents; i++) {
> +		u64 l2ptr = le64_to_cpu(cfg->l2.l1tab[i].l2ptr);
> +		phys_addr_t l2_base;
> +
> +		ret = arm_smmu_kexec_check_strtab_l1_desc(smmu, l2ptr, i,
> +							  &l2_base);
> +		if (ret < 0)
> +			return ret;
> +
> +		/*
> +		 * If the crashed kernel's l1 descriptors are deeply corrupted,
> +		 * blindly memremapping every l2 table here could lead to OOM.
> +		 *
> +		 * Defer the l2 memremap to arm_smmu_init_l2_strtab(), so peak
> +		 * memory is bounded by the kdump kernel's actual demand.
> +		 */
> +	}
> +
> +	return 0;
> +}
> +
> +static int arm_smmu_kdump_adopt_strtab_linear(struct arm_smmu_device *smmu,
> +					      u32 cfg_reg, phys_addr_t base)
> +{
> +	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
> +	u32 num_ents;
> +	size_t size;
> +	int ret;
> +
> +	ret = arm_smmu_kexec_parse_strtab_linear(smmu, cfg_reg, base,
> +						 &num_ents);
> +	if (ret)
> +		return ret;
> +
> +	/*
> +	 * We might end up with a num_ents != sid_bits, which is fine, since the
> +	 * ARM_SMMU_OPT_KDUMP_ADOPT case bypasses arm_smmu_write_strtab().
> +	 */
> +	cfg->linear.num_ents = num_ents;
> +
> +	size = num_ents * sizeof(struct arm_smmu_ste);
> +	cfg->linear.table = memremap(base, size, MEMREMAP_WB);
> +	if (!cfg->linear.table)
> +		return -ENOMEM;
> +	return 0;
> +}
> +
> +static void arm_smmu_kdump_adopt_cleanup(void *data)
> +{
> +	struct arm_smmu_device *smmu = data;
> +	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
> +
> +	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
> +		kfree(cfg->l2.l2ptrs);
> +		if (cfg->l2.l1tab)
> +			memunmap(cfg->l2.l1tab);
> +	} else {
> +		if (cfg->linear.table)
> +			memunmap(cfg->linear.table);
> +	}
> +}
> +
> +int arm_smmu_kdump_adopt_strtab(struct arm_smmu_device *smmu)
> +{
> +	u32 cfg_reg = readl_relaxed(smmu->base + ARM_SMMU_STRTAB_BASE_CFG);
> +	u64 base_reg = readq_relaxed(smmu->base + ARM_SMMU_STRTAB_BASE);
> +	bool was_2lvl = smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB;
> +	phys_addr_t base = base_reg & STRTAB_BASE_ADDR_MASK;
> +	u32 fmt = FIELD_GET(STRTAB_BASE_CFG_FMT, cfg_reg);
> +	int ret;
> +
> +	dev_dbg(smmu->dev, "adopting crashed kernel's stream table\n");
> +
> +	if (fmt == STRTAB_BASE_CFG_FMT_2LVL) {
> +		/*
> +		 * Both kernels run on the same hardware, so it's impossible for
> +		 * kdump kernel to see the support for linear stream table only.
> +		 */

STRTAB_SPLIT which influences ARM_SMMU_FEAT_2_LVL_STRTAB is a SW choice, so it is
possible to get such mismatch if STRTAB_SPLIT of the newer kernel is larger than the
older kernel.
However, I agree that in that case it's better to refuse the adoption.

> +		if (WARN_ON(!(smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB)))
> +			ret = -EINVAL;
> +		else
> +			ret = arm_smmu_kdump_adopt_strtab_2lvl(smmu, cfg_reg,
> +							       base);
> +	} else if (fmt == STRTAB_BASE_CFG_FMT_LINEAR) {
> +		/*
> +		 * The kdump kernel need not match the crashed kernel. An older
> +		 * crashed kernel that predates two-level stream table support
> +		 * may have used a linear table on 2-level-capable hardware, so
> +		 * enforce the same format here to match the adopted table.
> +		 */
> +		ret = arm_smmu_kdump_adopt_strtab_linear(smmu, cfg_reg, base);
> +		if (!ret)
> +			smmu->features &= ~ARM_SMMU_FEAT_2_LVL_STRTAB;

For simplicity, it is better to enforce the same table formats between
kernels as the rest of the file, for example,
arm_smmu_kexec_parse_strtab_2lvl() refuses different STRTAB_SPLIT.
Some checks can be removed and the was_2lvl error path. It's
very unlikely to hit such case anyway.

> +	} else {
> +		dev_err(smmu->dev, "invalid STRTAB format %u\n", fmt);
> +		ret = -EINVAL;
> +	}
> +
> +	if (ret) {
> +		arm_smmu_kdump_adopt_cleanup(smmu);

Probably easier to inline the error handling after each call and remove this?

Thanks,
Mostafa



  reply	other threads:[~2026-10-20 11:38 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-05 19:30 [PATCH v11 00/11] iommu/arm-smmu-v3: Adopt the crashed kernel's stream table for kdump Nicolin Chen
2026-10-05 19:30 ` [PATCH v11 01/11] iommu/arm-smmu-v3: Init the vmid_map ida before the stream table setup Nicolin Chen
2026-10-20 11:13   ` Mostafa Saleh
2026-10-05 19:30 ` [PATCH v11 02/11] iommu/arm-smmu-v3: Make the ASID space per SMMU instance Nicolin Chen
2026-10-20 11:14   ` Mostafa Saleh
2026-10-05 19:30 ` [PATCH v11 03/11] iommu/arm-smmu-v3: Swap EVTQ_MSI_INDEX and GERROR_MSI_INDEX Nicolin Chen
2026-10-13 14:49   ` Jason Gunthorpe
2026-10-13 17:41     ` Nicolin Chen
2026-10-20 14:26       ` Jason Gunthorpe
2026-10-05 19:30 ` [PATCH v11 04/11] iommu/arm-smmu-v3: Add ARM_SMMU_FEAT_EVTQ for the event queue Nicolin Chen
2026-10-20 11:16   ` Mostafa Saleh
2026-10-20 16:49     ` Nicolin Chen
2026-10-05 19:30 ` [PATCH v11 05/11] iommu/arm-smmu-v3: Disable the EVTQ and the PRIQ in a kdump kernel Nicolin Chen
2026-10-20 11:22   ` Mostafa Saleh
2026-10-20 16:59     ` Nicolin Chen
2026-10-05 19:30 ` [PATCH v11 06/11] iommu/arm-smmu-v3: Add ARM_SMMU_OPT_KDUMP_ADOPT for " Nicolin Chen
2026-10-20 11:38   ` Mostafa Saleh [this message]
2026-10-20 14:25     ` Jason Gunthorpe
2026-10-20 17:36     ` Nicolin Chen
2026-10-20 17:47       ` Nicolin Chen
2026-10-05 19:30 ` [PATCH v11 07/11] iommu/arm-smmu-v3-kexec: Reserve crashed kernel's ASIDs and VMIDs Nicolin Chen
2026-10-05 19:30 ` [PATCH v11 08/11] iommu/arm-smmu-v3-kexec: Implement is_attach_deferred() Nicolin Chen
2026-10-05 19:30 ` [PATCH v11 09/11] iommu/arm-smmu-v3: Retain CR0_SMMUEN during kdump device reset Nicolin Chen
2026-10-13 14:49   ` Jason Gunthorpe
2026-10-05 19:30 ` [PATCH v11 10/11] iommu/arm-smmu-v3: Skip RMR bypass for kdump adoption Nicolin Chen
2026-10-05 19:30 ` [PATCH v11 11/11] iommu/arm-smmu-v3: Detect ARM_SMMU_OPT_KDUMP_ADOPT in probe() Nicolin Chen
2026-10-05 20:48 ` [PATCH v11 00/11] iommu/arm-smmu-v3: Adopt the crashed kernel's stream table for kdump Nicolin Chen
2026-10-17  8:19 ` Shuai Xue
2026-10-17 11:40   ` Jason Gunthorpe
2026-10-17 18:52   ` Nicolin Chen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=atdSrRwrphdI9ZQA@google.com \
    --to=smostafa@google.com \
    --cc=cpru@amazon.com \
    --cc=iommu@lists.linux.dev \
    --cc=jamien@nvidia.com \
    --cc=jgg@nvidia.com \
    --cc=joro@8bytes.org \
    --cc=kas@kernel.org \
    --cc=kevin.tian@intel.com \
    --cc=leitao@kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nicolinc@nvidia.com \
    --cc=praan@google.com \
    --cc=robin.murphy@arm.com \
    --cc=will@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox