* [PATCH v2 1/9] iommu/vt-d: Fix no_iommu to disable platform optin
2026-07-02 6:12 [PATCH v2 0/9] iommu/vt-d: Support a new DMAR flag Kevin Tian
@ 2026-07-02 6:12 ` Kevin Tian
2026-07-02 6:12 ` [PATCH v2 2/9] iommu/vt-d: Force requesting ACS when tboot is enabled Kevin Tian
` (8 subsequent siblings)
9 siblings, 0 replies; 12+ messages in thread
From: Kevin Tian @ 2026-07-02 6:12 UTC (permalink / raw)
To: Lu Baolu, Joerg Roedel, Will Deacon, Robin Murphy
Cc: Kevin Tian, Mika Westerberg, Ashok Raj, Chris Wright,
Jesse Barnes, Asit Mallick, iommu, linux-kernel, stable
If user explicitly requests to disable iommu (via "iommu=off" or
"intel_iommu=off"), there is no reason to force enabling it due
to platform optin (for external-facing devices). User should be
aware of any security implication of doing so.
"intel_iommu=off" implements this policy by setting no_platform_optin
to skip platform optin in platform_optin_force_iommu().
However, "iommu=off" (no_iommu=1) doesn't set no_platform_optin
hence is broken in this aspect:
- detect_intel_iommu() doesn't request ACS if no_iommu=1
- platform_optin_force_iommu() forces iommu on if external-facing
devices exist and no_platform_optin is not set
This leads to a bad configuration with ACS disabled while DMA
remapping is enabled.
Instead of setting no_platform_optin (will soon be removed) for
no_iommu=1, directly check no_iommu in platform_optin_force_iommu().
Fixes: 89a6079df791 ("iommu/vt-d: Force IOMMU on for platform opt in hint")
Cc: stable@vger.kernel.org
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
---
drivers/iommu/intel/iommu.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 849d06dfe1ae..8668565e5781 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -2482,10 +2482,11 @@ static bool has_external_pci(void)
static int __init platform_optin_force_iommu(void)
{
- if (!dmar_platform_optin() || no_platform_optin || !has_external_pci())
+ if (no_iommu || !dmar_platform_optin() || no_platform_optin ||
+ !has_external_pci())
return 0;
- if (no_iommu || dmar_disabled)
+ if (dmar_disabled)
pr_info("Intel-IOMMU force enabled due to platform opt in\n");
/*
@@ -2496,7 +2497,6 @@ static int __init platform_optin_force_iommu(void)
iommu_set_default_passthrough(false);
dmar_disabled = 0;
- no_iommu = 0;
return 1;
}
--
2.43.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v2 2/9] iommu/vt-d: Force requesting ACS when tboot is enabled
2026-07-02 6:12 [PATCH v2 0/9] iommu/vt-d: Support a new DMAR flag Kevin Tian
2026-07-02 6:12 ` [PATCH v2 1/9] iommu/vt-d: Fix no_iommu to disable platform optin Kevin Tian
@ 2026-07-02 6:12 ` Kevin Tian
2026-07-02 6:50 ` Tian, Kevin
2026-07-02 6:12 ` [PATCH v2 3/9] iommu/vt-d: Remove dead code when CONFIG_INTEL_IOMMU is not set Kevin Tian
` (7 subsequent siblings)
9 siblings, 1 reply; 12+ messages in thread
From: Kevin Tian @ 2026-07-02 6:12 UTC (permalink / raw)
To: Lu Baolu, Joerg Roedel, Will Deacon, Robin Murphy
Cc: Kevin Tian, Mika Westerberg, Ashok Raj, Chris Wright,
Jesse Barnes, Asit Mallick, iommu, linux-kernel, stable
Currently the conditions of requesting ACS in detect_intel_iommu()
don't include tboot, leading to a possible misconfiguration with ACS
disabled (e.g. due to user opts) while iommu is later forced on by
tboot_force_iommu().
Fix it by checking tboot in detect_intel_iommu().
Fixes: 5d990b627537 ("PCI: add pci_request_acs")
Cc: stable@vger.kernel.org
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
---
drivers/iommu/intel/dmar.c | 15 +++++++++++++--
drivers/iommu/intel/iommu.c | 2 +-
drivers/iommu/intel/iommu.h | 2 ++
3 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c
index 767ec092accd..e32685402f74 100644
--- a/drivers/iommu/intel/dmar.c
+++ b/drivers/iommu/intel/dmar.c
@@ -915,6 +915,18 @@ dmar_validate_one_drhd(struct acpi_dmar_header *entry, void *arg)
return 0;
}
+static bool dmar_required(void)
+{
+ /* tboot supersedes any user/platform opt */
+ if (!intel_iommu_tboot_noforce && tboot_enabled())
+ return true;
+
+ if (!no_iommu && (!dmar_disabled || dmar_platform_optin()))
+ return true;
+
+ return false;
+}
+
void __init detect_intel_iommu(void)
{
int ret;
@@ -928,8 +940,7 @@ void __init detect_intel_iommu(void)
if (!ret)
ret = dmar_walk_dmar_table((struct acpi_table_dmar *)dmar_tbl,
&validate_drhd_cb);
- if (!ret && !no_iommu && !iommu_detected &&
- (!dmar_disabled || dmar_platform_optin())) {
+ if (!ret && !iommu_detected && dmar_required()) {
iommu_detected = 1;
/* Make sure ACS will be enabled */
pci_request_acs();
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 8668565e5781..4e7ba60f3a0a 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -57,7 +57,7 @@ static int rwbf_quirk;
* (used when kernel is launched w/ TXT)
*/
static int force_on = 0;
-static int intel_iommu_tboot_noforce;
+int intel_iommu_tboot_noforce;
static int no_platform_optin;
#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))
diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h
index 775f1c4ae346..2cee36138d6e 100644
--- a/drivers/iommu/intel/iommu.h
+++ b/drivers/iommu/intel/iommu.h
@@ -1354,6 +1354,7 @@ static inline bool ecmd_has_pmu_essential(struct intel_iommu *iommu)
extern int dmar_disabled;
extern int intel_iommu_enabled;
+extern int intel_iommu_tboot_noforce;
#else
static inline int iommu_calculate_agaw(struct intel_iommu *iommu)
{
@@ -1366,6 +1367,7 @@ static inline int iommu_calculate_max_sagaw(struct intel_iommu *iommu)
#define dmar_disabled (1)
#define intel_iommu_enabled (0)
#define intel_iommu_sm (0)
+#define intel_iommu_tboot_noforce (0)
#endif
static inline const char *decode_prq_descriptor(char *str, size_t size,
--
2.43.0
^ permalink raw reply [flat|nested] 12+ messages in thread* RE: [PATCH v2 2/9] iommu/vt-d: Force requesting ACS when tboot is enabled
2026-07-02 6:12 ` [PATCH v2 2/9] iommu/vt-d: Force requesting ACS when tboot is enabled Kevin Tian
@ 2026-07-02 6:50 ` Tian, Kevin
0 siblings, 0 replies; 12+ messages in thread
From: Tian, Kevin @ 2026-07-02 6:50 UTC (permalink / raw)
To: Lu Baolu, Joerg Roedel, Will Deacon, Robin Murphy
Cc: Mika Westerberg, Ashok Raj, Chris Wright, Jesse Barnes, Mallick,
Asit K, iommu, linux-kernel, stable
> From: Tian, Kevin <kevin.tian@intel.com>
> Sent: Thursday, July 2, 2026 2:12 PM
>
> +static bool dmar_required(void)
> +{
> + /* tboot supersedes any user/platform opt */
> + if (!intel_iommu_tboot_noforce && tboot_enabled())
> + return true;
> +
> + if (!no_iommu && (!dmar_disabled || dmar_platform_optin()))
> + return true;
> +
> + return false;
> +}
> +
Sashiko [1] questions that parse_args() is called after detect_intel_iommu()
so above check of intel_iommu_tboot_noforce is always false.
But actually parse_args() is called in start_kernel() way earlier:
parse_early_param();
parse_args("Booting kernel", ...); // where __setup() is parsed
...
mm_core_init();
-> detect_intel_iommu() -> dmar_required()
so this comment is invalid.
[1] https://sashiko.dev/#/patchset/20260702061216.388743-1-kevin.tian%40intel.com
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v2 3/9] iommu/vt-d: Remove dead code when CONFIG_INTEL_IOMMU is not set
2026-07-02 6:12 [PATCH v2 0/9] iommu/vt-d: Support a new DMAR flag Kevin Tian
2026-07-02 6:12 ` [PATCH v2 1/9] iommu/vt-d: Fix no_iommu to disable platform optin Kevin Tian
2026-07-02 6:12 ` [PATCH v2 2/9] iommu/vt-d: Force requesting ACS when tboot is enabled Kevin Tian
@ 2026-07-02 6:12 ` Kevin Tian
2026-07-02 6:12 ` [PATCH v2 4/9] iommu/vt-d: Consolidate dmar policy management and force_on logic Kevin Tian
` (6 subsequent siblings)
9 siblings, 0 replies; 12+ messages in thread
From: Kevin Tian @ 2026-07-02 6:12 UTC (permalink / raw)
To: Lu Baolu, Joerg Roedel, Will Deacon, Robin Murphy
Cc: Kevin Tian, Mika Westerberg, Ashok Raj, Chris Wright,
Jesse Barnes, Asit Mallick, iommu, linux-kernel
Those are leftovers and unreachable now: the entire intel directory
is built only when CONFIG_INTEL_IOMMU is set.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
---
drivers/iommu/intel/iommu.h | 15 ---------------
1 file changed, 15 deletions(-)
diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h
index 2cee36138d6e..785aa3b62055 100644
--- a/drivers/iommu/intel/iommu.h
+++ b/drivers/iommu/intel/iommu.h
@@ -1340,7 +1340,6 @@ static inline bool intel_domain_is_ss_paging(struct dmar_domain *domain)
return domain->domain.ops == &intel_ss_paging_domain_ops;
}
-#ifdef CONFIG_INTEL_IOMMU
extern int intel_iommu_sm;
int iommu_calculate_agaw(struct intel_iommu *iommu);
int iommu_calculate_max_sagaw(struct intel_iommu *iommu);
@@ -1355,20 +1354,6 @@ static inline bool ecmd_has_pmu_essential(struct intel_iommu *iommu)
extern int dmar_disabled;
extern int intel_iommu_enabled;
extern int intel_iommu_tboot_noforce;
-#else
-static inline int iommu_calculate_agaw(struct intel_iommu *iommu)
-{
- return 0;
-}
-static inline int iommu_calculate_max_sagaw(struct intel_iommu *iommu)
-{
- return 0;
-}
-#define dmar_disabled (1)
-#define intel_iommu_enabled (0)
-#define intel_iommu_sm (0)
-#define intel_iommu_tboot_noforce (0)
-#endif
static inline const char *decode_prq_descriptor(char *str, size_t size,
u64 dw0, u64 dw1, u64 dw2, u64 dw3)
--
2.43.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v2 4/9] iommu/vt-d: Consolidate dmar policy management and force_on logic
2026-07-02 6:12 [PATCH v2 0/9] iommu/vt-d: Support a new DMAR flag Kevin Tian
` (2 preceding siblings ...)
2026-07-02 6:12 ` [PATCH v2 3/9] iommu/vt-d: Remove dead code when CONFIG_INTEL_IOMMU is not set Kevin Tian
@ 2026-07-02 6:12 ` Kevin Tian
2026-07-02 6:12 ` [PATCH v2 5/9] iommu/vt-d: Use dmar_can_force_on() for platform optin Kevin Tian
` (5 subsequent siblings)
9 siblings, 0 replies; 12+ messages in thread
From: Kevin Tian @ 2026-07-02 6:12 UTC (permalink / raw)
To: Lu Baolu, Joerg Roedel, Will Deacon, Robin Murphy
Cc: Kevin Tian, Mika Westerberg, Ashok Raj, Chris Wright,
Jesse Barnes, Asit Mallick, iommu, linux-kernel
Currently the dmar on/off is carried by multiple variables (no_iommu,
dmar_disabled, no_platform_optin, etc.) with error-prone force_on logic
scattered in multiple places.
Unify/centralize the policy/priority management for various force_on
scenarios.
No functional impact except one case - "intel_iommu=off" sets
no_platform_optin which is checked in platform_optin_force_iommu()
but not in detect_intel_iommu(), leading to ACS unnecessarily requested
when iommu could not be forced on later. Now with the unified logic
this becomes more consistent.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
---
drivers/iommu/intel/dmar.c | 58 ++++++++++++++++++++++++++++++++++---
drivers/iommu/intel/iommu.c | 7 +++++
drivers/iommu/intel/iommu.h | 45 ++++++++++++++++++++++++++++
3 files changed, 106 insertions(+), 4 deletions(-)
diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c
index e32685402f74..bc2f6597eb27 100644
--- a/drivers/iommu/intel/dmar.c
+++ b/drivers/iommu/intel/dmar.c
@@ -915,14 +915,61 @@ dmar_validate_one_drhd(struct acpi_dmar_header *entry, void *arg)
return 0;
}
+/*
+ * Centralized helper for deciding the force_on policy
+ *
+ * dmar off policies (for DMA Remapping) are defined from stronger
+ * (more negative values) to weaker (less negative values).
+ *
+ * When a force_on type is passed in, it is associated to a reference
+ * level for comparison. force_on is permitted when dmar is in a
+ * off policy less negative than the reference level (if the policy is
+ * on then the check is always true).
+ *
+ * For supported force_on types:
+ *
+ * - DMAR_FORCEON_TBOOT: tboot strictly requires DMA remapping for secure
+ * boot hence supersedes any user opts ("iommu=off" or "intel_iommu=off")
+ * and weaker off policies.
+ *
+ * - DMAR_FORCEON_PLATFORM: external-facing devices requires DMA
+ * remapping to prevent malicious downstream external devices from
+ * composing DMA attacks. force_on is permitted only if dmar policy is
+ * off by build configurations (CONFIG_INTEL_IOMMU_DEFAULT_ON=off).
+ *
+ * In a nutshell, "trusted boot environment" is considered stronger than
+ * "user choices", which in turn is stronger than "platform opt-in hint".
+ */
+bool dmar_can_force_on(enum dmar_force_on force_on)
+{
+ int level;
+
+ switch (force_on) {
+ case DMAR_FORCEON_TBOOT:
+ level = DMAR_USER_OFF;
+ break;
+ case DMAR_FORCEON_PLATFORM:
+ level = DMAR_DEFAULT_OFF;
+ break;
+ default:
+ level = INT_MAX;
+ pr_warn("Unsupported force_on type (%d)\n", force_on);
+ break;
+ }
+
+ return dmar_policy >= level;
+}
+
static bool dmar_required(void)
{
- /* tboot supersedes any user/platform opt */
- if (!intel_iommu_tboot_noforce && tboot_enabled())
+ if (dmar_policy_on())
return true;
- if (!no_iommu && (!dmar_disabled || dmar_platform_optin()))
- return true;
+ if (!intel_iommu_tboot_noforce && tboot_enabled())
+ return dmar_can_force_on(DMAR_FORCEON_TBOOT);
+
+ if (dmar_platform_optin())
+ return dmar_can_force_on(DMAR_FORCEON_PLATFORM);
return false;
}
@@ -936,6 +983,9 @@ void __init detect_intel_iommu(void)
};
down_write(&dmar_global_lock);
+ if (no_iommu)
+ dmar_policy = DMAR_USER_OFF;
+
ret = dmar_table_detect();
if (!ret)
ret = dmar_walk_dmar_table((struct acpi_table_dmar *)dmar_tbl,
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 4e7ba60f3a0a..c66909b8e33b 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -199,6 +199,11 @@ static LIST_HEAD(dmar_satc_units);
static void intel_iommu_domain_free(struct iommu_domain *domain);
+#ifdef CONFIG_INTEL_IOMMU_DEFAULT_ON
+int dmar_policy = DMAR_ON;
+#else
+int dmar_policy = DMAR_DEFAULT_OFF;
+#endif
int dmar_disabled = !IS_ENABLED(CONFIG_INTEL_IOMMU_DEFAULT_ON);
int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON);
@@ -240,9 +245,11 @@ static int __init intel_iommu_setup(char *str)
while (*str) {
if (!strncmp(str, "on", 2)) {
+ dmar_policy = DMAR_ON;
dmar_disabled = 0;
pr_info("IOMMU enabled\n");
} else if (!strncmp(str, "off", 3)) {
+ dmar_policy = DMAR_USER_OFF;
dmar_disabled = 1;
no_platform_optin = 1;
pr_info("IOMMU disabled\n");
diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h
index 785aa3b62055..d2e787243532 100644
--- a/drivers/iommu/intel/iommu.h
+++ b/drivers/iommu/intel/iommu.h
@@ -1351,6 +1351,51 @@ static inline bool ecmd_has_pmu_essential(struct intel_iommu *iommu)
DMA_ECMD_ECCAP3_ESSENTIAL;
}
+enum dmar_force_on {
+ DMAR_FORCEON_PLATFORM,
+ DMAR_FORCEON_TBOOT
+};
+
+/*
+ * On policies are positive, with more positive value being stronger.
+ * Off policies are negative, with more negative value being stronger.
+ *
+ * 'dmar' here refers to DMA remapping instead of the dmar/iommu unit.
+ *
+ * - DMAR_FORCE_ON:
+ * force to turn on (e.g. by tboot or platform optin).
+ *
+ * - DMAR_ON:
+ * turn on by build configuration (CONFIG_INTEL_IOMMU_DEFAULT_ON=on)
+ * or user opts ("intel_iommu=on").
+ *
+ * - DMAR_DEFAULT_OFF
+ * turn off by build configuration (CONFIG_INTEL_IOMMU_DEFAULT_ON=off).
+ *
+ * - DMAR_USER_OFF
+ * turn off by user opts ("intel_iommu=off" or "iommu=off").
+ *
+ * - '0' is invalid, compared to decide the on/off policy
+ *
+ */
+#define DMAR_FORCE_ON 2
+#define DMAR_ON 1
+#define DMAR_DEFAULT_OFF -1
+#define DMAR_USER_OFF -2
+extern int dmar_policy;
+
+static inline bool dmar_policy_on(void)
+{
+ return dmar_policy > 0;
+}
+
+static inline bool dmar_policy_off(void)
+{
+ return dmar_policy < 0;
+}
+
+bool dmar_can_force_on(enum dmar_force_on force_on);
+
extern int dmar_disabled;
extern int intel_iommu_enabled;
extern int intel_iommu_tboot_noforce;
--
2.43.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v2 5/9] iommu/vt-d: Use dmar_can_force_on() for platform optin
2026-07-02 6:12 [PATCH v2 0/9] iommu/vt-d: Support a new DMAR flag Kevin Tian
` (3 preceding siblings ...)
2026-07-02 6:12 ` [PATCH v2 4/9] iommu/vt-d: Consolidate dmar policy management and force_on logic Kevin Tian
@ 2026-07-02 6:12 ` Kevin Tian
2026-07-02 6:12 ` [PATCH v2 6/9] iommu/vt-d: Call dmar_can_force_on() for tboot optin Kevin Tian
` (4 subsequent siblings)
9 siblings, 0 replies; 12+ messages in thread
From: Kevin Tian @ 2026-07-02 6:12 UTC (permalink / raw)
To: Lu Baolu, Joerg Roedel, Will Deacon, Robin Murphy
Cc: Kevin Tian, Mika Westerberg, Ashok Raj, Chris Wright,
Jesse Barnes, Asit Mallick, iommu, linux-kernel
So the policy of requesting ACS in detect_intel_iommu() is consistent
with that in platform_optin_force_iommu().
While at it, remove no_platform_optin which is unnecessary now.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
---
drivers/iommu/intel/iommu.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index c66909b8e33b..94cf144b4b70 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -58,7 +58,6 @@ static int rwbf_quirk;
*/
static int force_on = 0;
int intel_iommu_tboot_noforce;
-static int no_platform_optin;
#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))
@@ -251,7 +250,6 @@ static int __init intel_iommu_setup(char *str)
} else if (!strncmp(str, "off", 3)) {
dmar_policy = DMAR_USER_OFF;
dmar_disabled = 1;
- no_platform_optin = 1;
pr_info("IOMMU disabled\n");
} else if (!strncmp(str, "igfx_off", 8)) {
disable_igfx_iommu = 1;
@@ -2489,20 +2487,23 @@ static bool has_external_pci(void)
static int __init platform_optin_force_iommu(void)
{
- if (no_iommu || !dmar_platform_optin() || no_platform_optin ||
- !has_external_pci())
+ if (!dmar_platform_optin() || !dmar_can_force_on(DMAR_FORCEON_PLATFORM))
return 0;
- if (dmar_disabled)
- pr_info("Intel-IOMMU force enabled due to platform opt in\n");
+ if (!has_external_pci())
+ return 0;
/*
* If Intel-IOMMU is disabled by default, we will apply identity
* map for all devices except those marked as being untrusted.
*/
- if (dmar_disabled)
+ if (dmar_policy_off()) {
+ pr_info("Intel-IOMMU force enabled due to platform opt in\n");
iommu_set_default_passthrough(false);
+ }
+ /* No concurrent access to dmar_policy at this point. */
+ dmar_policy = DMAR_FORCE_ON;
dmar_disabled = 0;
return 1;
--
2.43.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v2 6/9] iommu/vt-d: Call dmar_can_force_on() for tboot optin
2026-07-02 6:12 [PATCH v2 0/9] iommu/vt-d: Support a new DMAR flag Kevin Tian
` (4 preceding siblings ...)
2026-07-02 6:12 ` [PATCH v2 5/9] iommu/vt-d: Use dmar_can_force_on() for platform optin Kevin Tian
@ 2026-07-02 6:12 ` Kevin Tian
2026-07-02 6:12 ` [PATCH v2 7/9] iommu/vt-d: Remove the 'force_on' variable Kevin Tian
` (3 subsequent siblings)
9 siblings, 0 replies; 12+ messages in thread
From: Kevin Tian @ 2026-07-02 6:12 UTC (permalink / raw)
To: Lu Baolu, Joerg Roedel, Will Deacon, Robin Murphy
Cc: Kevin Tian, Mika Westerberg, Ashok Raj, Chris Wright,
Jesse Barnes, Asit Mallick, iommu, linux-kernel
So the policy of requesting ACS in detect_intel_iommu() is consistent
with that in tboot_force_iommu().
Though tboot is the strongest override so far, dmar_can_force_on() may
return false due to future extensions. In this case panic the kernel,
as is already done when failing to initialize DMA remapping for tboot.
No functional impact at this point.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
---
drivers/iommu/intel/iommu.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 94cf144b4b70..cddd3ab215cf 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -2548,12 +2548,17 @@ static int __init probe_acpi_namespace_devices(void)
static __init int tboot_force_iommu(void)
{
- if (!tboot_enabled())
+ if (!tboot_enabled() || intel_iommu_tboot_noforce)
return 0;
- if (no_iommu || dmar_disabled)
+ if (!dmar_can_force_on(DMAR_FORCEON_TBOOT))
+ panic("tboot: Failed to force IOMMU on\n");
+
+ if (dmar_policy_off())
pr_warn("Forcing Intel-IOMMU to enabled\n");
+ /* No concurrent access to dmar_policy at this point. */
+ dmar_policy = DMAR_FORCE_ON;
dmar_disabled = 0;
no_iommu = 0;
@@ -2570,8 +2575,7 @@ int __init intel_iommu_init(void)
* Intel IOMMU is required for a TXT/tboot launch or platform
* opt in, so enforce that.
*/
- force_on = (!intel_iommu_tboot_noforce && tboot_force_iommu()) ||
- platform_optin_force_iommu();
+ force_on = tboot_force_iommu() || platform_optin_force_iommu();
down_write(&dmar_global_lock);
if (dmar_table_init()) {
--
2.43.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v2 7/9] iommu/vt-d: Remove the 'force_on' variable
2026-07-02 6:12 [PATCH v2 0/9] iommu/vt-d: Support a new DMAR flag Kevin Tian
` (5 preceding siblings ...)
2026-07-02 6:12 ` [PATCH v2 6/9] iommu/vt-d: Call dmar_can_force_on() for tboot optin Kevin Tian
@ 2026-07-02 6:12 ` Kevin Tian
2026-07-02 6:12 ` [PATCH v2 8/9] iommu/vt-d: Remove dmar_disabled Kevin Tian
` (2 subsequent siblings)
9 siblings, 0 replies; 12+ messages in thread
From: Kevin Tian @ 2026-07-02 6:12 UTC (permalink / raw)
To: Lu Baolu, Joerg Roedel, Will Deacon, Robin Murphy
Cc: Kevin Tian, Mika Westerberg, Ashok Raj, Chris Wright,
Jesse Barnes, Asit Mallick, iommu, linux-kernel
The force_on variable is now redundant - same information captured
by "dmar_policy == DMAR_FORCE_ON". Replace all force_on checks
with dmar_policy_force_on().
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
---
drivers/iommu/intel/iommu.c | 37 +++++++++++++++++--------------------
drivers/iommu/intel/iommu.h | 5 +++++
2 files changed, 22 insertions(+), 20 deletions(-)
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index cddd3ab215cf..50dfe426322f 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -53,10 +53,9 @@ static int rwbf_quirk;
#define rwbf_required(iommu) (rwbf_quirk || cap_rwbf((iommu)->cap))
/*
- * set to 1 to panic kernel if can't successfully enable VT-d
- * (used when kernel is launched w/ TXT)
+ * Skip forcing iommu on and avoid tboot-related kernel panics during
+ * initialization when set to 1 (via intel_iommu=tboot_noforce).
*/
-static int force_on = 0;
int intel_iommu_tboot_noforce;
#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))
@@ -1711,7 +1710,7 @@ static int __init init_dmars(void)
* we always have to disable PMRs or DMA may fail on
* this device
*/
- if (force_on)
+ if (dmar_policy_force_on())
iommu_disable_protect_mem_regions(iommu);
continue;
}
@@ -1803,7 +1802,7 @@ static int init_iommu_hw(void)
* we always have to disable PMRs or DMA may fail on
* this device
*/
- if (force_on)
+ if (dmar_policy_force_on())
iommu_disable_protect_mem_regions(iommu);
continue;
}
@@ -1864,7 +1863,7 @@ static void iommu_resume(void *data)
unsigned long flag;
if (init_iommu_hw()) {
- if (force_on)
+ if (dmar_policy_force_on())
panic("tboot: IOMMU setup failed, DMAR can not resume!\n");
else
WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
@@ -2132,7 +2131,7 @@ static int intel_iommu_add(struct dmar_drhd_unit *dmaru)
/*
* we always have to disable PMRs or DMA may fail on this device
*/
- if (force_on)
+ if (dmar_policy_force_on())
iommu_disable_protect_mem_regions(iommu);
return 0;
}
@@ -2485,13 +2484,13 @@ static bool has_external_pci(void)
return false;
}
-static int __init platform_optin_force_iommu(void)
+static void __init platform_optin_force_iommu(void)
{
if (!dmar_platform_optin() || !dmar_can_force_on(DMAR_FORCEON_PLATFORM))
- return 0;
+ return;
if (!has_external_pci())
- return 0;
+ return;
/*
* If Intel-IOMMU is disabled by default, we will apply identity
@@ -2505,8 +2504,6 @@ static int __init platform_optin_force_iommu(void)
/* No concurrent access to dmar_policy at this point. */
dmar_policy = DMAR_FORCE_ON;
dmar_disabled = 0;
-
- return 1;
}
static int __init probe_acpi_namespace_devices(void)
@@ -2546,10 +2543,10 @@ static int __init probe_acpi_namespace_devices(void)
return 0;
}
-static __init int tboot_force_iommu(void)
+static __init void tboot_force_iommu(void)
{
if (!tboot_enabled() || intel_iommu_tboot_noforce)
- return 0;
+ return;
if (!dmar_can_force_on(DMAR_FORCEON_TBOOT))
panic("tboot: Failed to force IOMMU on\n");
@@ -2561,8 +2558,6 @@ static __init int tboot_force_iommu(void)
dmar_policy = DMAR_FORCE_ON;
dmar_disabled = 0;
no_iommu = 0;
-
- return 1;
}
int __init intel_iommu_init(void)
@@ -2575,17 +2570,19 @@ int __init intel_iommu_init(void)
* Intel IOMMU is required for a TXT/tboot launch or platform
* opt in, so enforce that.
*/
- force_on = tboot_force_iommu() || platform_optin_force_iommu();
+ tboot_force_iommu();
+ if (!dmar_policy_force_on())
+ platform_optin_force_iommu();
down_write(&dmar_global_lock);
if (dmar_table_init()) {
- if (force_on)
+ if (dmar_policy_force_on())
panic("tboot: Failed to initialize DMAR table\n");
goto out_free_dmar;
}
if (dmar_dev_scope_init() < 0) {
- if (force_on)
+ if (dmar_policy_force_on())
panic("tboot: Failed to initialize DMAR device scope\n");
goto out_free_dmar;
}
@@ -2639,7 +2636,7 @@ int __init intel_iommu_init(void)
ret = init_dmars();
if (ret) {
- if (force_on)
+ if (dmar_policy_force_on())
panic("tboot: Failed to initialize DMARs\n");
pr_err("Initialization failed\n");
goto out_free_dmar;
diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h
index d2e787243532..95962a45ac36 100644
--- a/drivers/iommu/intel/iommu.h
+++ b/drivers/iommu/intel/iommu.h
@@ -1394,6 +1394,11 @@ static inline bool dmar_policy_off(void)
return dmar_policy < 0;
}
+static inline bool dmar_policy_force_on(void)
+{
+ return dmar_policy == DMAR_FORCE_ON;
+}
+
bool dmar_can_force_on(enum dmar_force_on force_on);
extern int dmar_disabled;
--
2.43.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v2 8/9] iommu/vt-d: Remove dmar_disabled
2026-07-02 6:12 [PATCH v2 0/9] iommu/vt-d: Support a new DMAR flag Kevin Tian
` (6 preceding siblings ...)
2026-07-02 6:12 ` [PATCH v2 7/9] iommu/vt-d: Remove the 'force_on' variable Kevin Tian
@ 2026-07-02 6:12 ` Kevin Tian
2026-07-02 6:12 ` [PATCH v2 9/9] iommu/vt-d: Support the new DMA_REMAP_OPT_OUT flag bit Kevin Tian
2026-07-27 3:04 ` [PATCH v2 0/9] iommu/vt-d: Support a new DMAR flag Baolu Lu
9 siblings, 0 replies; 12+ messages in thread
From: Kevin Tian @ 2026-07-02 6:12 UTC (permalink / raw)
To: Lu Baolu, Joerg Roedel, Will Deacon, Robin Murphy
Cc: Kevin Tian, Mika Westerberg, Ashok Raj, Chris Wright,
Jesse Barnes, Asit Mallick, iommu, linux-kernel
It's replaced by dmar_policy_off() now, covering both "iommu=off"
and "intel_iommu=off". Also remove unnecessary checks on no_iommu,
leaving only one exception in intel_iommu_init() which skips debugfs
init for "iommu=off" but not "intel_iommu=off". Keep it to avoid
surprise for now.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
---
drivers/iommu/intel/iommu.c | 9 ++-------
drivers/iommu/intel/iommu.h | 1 -
drivers/iommu/intel/svm.c | 2 +-
3 files changed, 3 insertions(+), 9 deletions(-)
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 50dfe426322f..3312ee28db11 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -202,7 +202,6 @@ int dmar_policy = DMAR_ON;
#else
int dmar_policy = DMAR_DEFAULT_OFF;
#endif
-int dmar_disabled = !IS_ENABLED(CONFIG_INTEL_IOMMU_DEFAULT_ON);
int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON);
int intel_iommu_enabled = 0;
@@ -244,11 +243,9 @@ static int __init intel_iommu_setup(char *str)
while (*str) {
if (!strncmp(str, "on", 2)) {
dmar_policy = DMAR_ON;
- dmar_disabled = 0;
pr_info("IOMMU enabled\n");
} else if (!strncmp(str, "off", 3)) {
dmar_policy = DMAR_USER_OFF;
- dmar_disabled = 1;
pr_info("IOMMU disabled\n");
} else if (!strncmp(str, "igfx_off", 8)) {
disable_igfx_iommu = 1;
@@ -2369,7 +2366,7 @@ void intel_iommu_shutdown(void)
struct dmar_drhd_unit *drhd;
struct intel_iommu *iommu = NULL;
- if (no_iommu || dmar_disabled)
+ if (dmar_policy_off())
return;
/*
@@ -2503,7 +2500,6 @@ static void __init platform_optin_force_iommu(void)
/* No concurrent access to dmar_policy at this point. */
dmar_policy = DMAR_FORCE_ON;
- dmar_disabled = 0;
}
static int __init probe_acpi_namespace_devices(void)
@@ -2556,7 +2552,6 @@ static __init void tboot_force_iommu(void)
/* No concurrent access to dmar_policy at this point. */
dmar_policy = DMAR_FORCE_ON;
- dmar_disabled = 0;
no_iommu = 0;
}
@@ -2600,7 +2595,7 @@ int __init intel_iommu_init(void)
if (!no_iommu)
intel_iommu_debugfs_init();
- if (no_iommu || dmar_disabled) {
+ if (dmar_policy_off()) {
/*
* We exit the function here to ensure IOMMU's remapping and
* mempool aren't setup, which means that the IOMMU's PMRs
diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h
index 95962a45ac36..ad4d1aafd12c 100644
--- a/drivers/iommu/intel/iommu.h
+++ b/drivers/iommu/intel/iommu.h
@@ -1401,7 +1401,6 @@ static inline bool dmar_policy_force_on(void)
bool dmar_can_force_on(enum dmar_force_on force_on);
-extern int dmar_disabled;
extern int intel_iommu_enabled;
extern int intel_iommu_tboot_noforce;
diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index fea10acd4f02..0636987f03c8 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -115,7 +115,7 @@ static int intel_iommu_sva_supported(struct device *dev)
struct device_domain_info *info = dev_iommu_priv_get(dev);
struct intel_iommu *iommu;
- if (!info || dmar_disabled)
+ if (!info || dmar_policy_off())
return -EINVAL;
iommu = info->iommu;
--
2.43.0
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH v2 9/9] iommu/vt-d: Support the new DMA_REMAP_OPT_OUT flag bit
2026-07-02 6:12 [PATCH v2 0/9] iommu/vt-d: Support a new DMAR flag Kevin Tian
` (7 preceding siblings ...)
2026-07-02 6:12 ` [PATCH v2 8/9] iommu/vt-d: Remove dmar_disabled Kevin Tian
@ 2026-07-02 6:12 ` Kevin Tian
2026-07-27 3:04 ` [PATCH v2 0/9] iommu/vt-d: Support a new DMAR flag Baolu Lu
9 siblings, 0 replies; 12+ messages in thread
From: Kevin Tian @ 2026-07-02 6:12 UTC (permalink / raw)
To: Lu Baolu, Joerg Roedel, Will Deacon, Robin Murphy
Cc: Kevin Tian, Mika Westerberg, Ashok Raj, Chris Wright,
Jesse Barnes, Asit Mallick, iommu, linux-kernel
Some BIOS already provides config options to expose/hide VT-d units
as a whole to/from system software. A new demand is to allow exposing
VT-d units but requesting system software to disable DMA remapping
while sustaining interrupt remapping. This can be communicated now by
setting the new DMA_REMAP_OPT_OUT flag bit in the DMAR table, as
introduced in VT-d spec v5.2 (section 8.1, DMA Remapping Reporting
Structure).
Introduce a new off policy (DMAR_FW_OFF) for DMA_REMAP_OPT_OUT. As
the strongest off policy, it cannot be overridden by user opts or
any force_on types. If tboot is enabled in the meantime, kernel will
panic. It is user responsibility to configure BIOS properly.
One cleanup is left for future - the DMAR flag is parsed multiple
times, in detect_intel_iommu(), dmar_platform_optin() (which can be
called at run-time), etc. Caching it is a cleaner way.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
---
drivers/iommu/intel/dmar.c | 34 ++++++++++++++++++++++++----------
drivers/iommu/intel/iommu.h | 4 ++++
include/linux/dmar.h | 1 +
3 files changed, 29 insertions(+), 10 deletions(-)
diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c
index bc2f6597eb27..33bfaeafa7c6 100644
--- a/drivers/iommu/intel/dmar.c
+++ b/drivers/iommu/intel/dmar.c
@@ -930,7 +930,9 @@ dmar_validate_one_drhd(struct acpi_dmar_header *entry, void *arg)
*
* - DMAR_FORCEON_TBOOT: tboot strictly requires DMA remapping for secure
* boot hence supersedes any user opts ("iommu=off" or "intel_iommu=off")
- * and weaker off policies.
+ * and weaker off policies. But if firmware forces DMA remapping off (by
+ * setting DMAR_REMAP_OPT_OUT in the DMAR table), no force_on is allowed.
+ * Firmware settings must be changed to unblock tboot.
*
* - DMAR_FORCEON_PLATFORM: external-facing devices requires DMA
* remapping to prevent malicious downstream external devices from
@@ -939,6 +941,7 @@ dmar_validate_one_drhd(struct acpi_dmar_header *entry, void *arg)
*
* In a nutshell, "trusted boot environment" is considered stronger than
* "user choices", which in turn is stronger than "platform opt-in hint".
+ * But they are all meaningless when it's forced off by "firmware".
*/
bool dmar_can_force_on(enum dmar_force_on force_on)
{
@@ -976,31 +979,42 @@ static bool dmar_required(void)
void __init detect_intel_iommu(void)
{
- int ret;
struct dmar_res_callback validate_drhd_cb = {
.cb[ACPI_DMAR_TYPE_HARDWARE_UNIT] = &dmar_validate_one_drhd,
.ignore_unhandled = true,
};
+ struct acpi_table_dmar *dmar;
+ int ret;
down_write(&dmar_global_lock);
if (no_iommu)
dmar_policy = DMAR_USER_OFF;
ret = dmar_table_detect();
- if (!ret)
- ret = dmar_walk_dmar_table((struct acpi_table_dmar *)dmar_tbl,
- &validate_drhd_cb);
- if (!ret && !iommu_detected && dmar_required()) {
+ if (!ret) {
+ dmar = (struct acpi_table_dmar *)dmar_tbl;
+ ret = dmar_walk_dmar_table(dmar, &validate_drhd_cb);
+ }
+
+ if (ret)
+ goto out;
+
+ if (dmar->flags & DMAR_REMAP_OPT_OUT) {
+ dmar_policy = DMAR_FW_OFF;
+ pr_info("Firmware forces DMA remapping off\n");
+ pr_info("Any user opt or tboot/platform force_on will be ignored\n");
+ }
+
+ if (!iommu_detected && dmar_required()) {
iommu_detected = 1;
/* Make sure ACS will be enabled */
pci_request_acs();
}
- if (!ret) {
- x86_init.iommu.iommu_init = intel_iommu_init;
- x86_platform.iommu_shutdown = intel_iommu_shutdown;
- }
+ x86_init.iommu.iommu_init = intel_iommu_init;
+ x86_platform.iommu_shutdown = intel_iommu_shutdown;
+out:
if (dmar_tbl) {
acpi_put_table(dmar_tbl);
dmar_tbl = NULL;
diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h
index ad4d1aafd12c..bad7db37d899 100644
--- a/drivers/iommu/intel/iommu.h
+++ b/drivers/iommu/intel/iommu.h
@@ -1375,6 +1375,9 @@ enum dmar_force_on {
* - DMAR_USER_OFF
* turn off by user opts ("intel_iommu=off" or "iommu=off").
*
+ * - DMAR_FW_OFF
+ * turn off due to firmware opt-out (DMAR_REMAP_OPT_OUT)
+ *
* - '0' is invalid, compared to decide the on/off policy
*
*/
@@ -1382,6 +1385,7 @@ enum dmar_force_on {
#define DMAR_ON 1
#define DMAR_DEFAULT_OFF -1
#define DMAR_USER_OFF -2
+#define DMAR_FW_OFF -3
extern int dmar_policy;
static inline bool dmar_policy_on(void)
diff --git a/include/linux/dmar.h b/include/linux/dmar.h
index 692b2b445761..63e35df2cef4 100644
--- a/include/linux/dmar.h
+++ b/include/linux/dmar.h
@@ -24,6 +24,7 @@ struct acpi_dmar_header;
#define DMAR_INTR_REMAP 0x1
#define DMAR_X2APIC_OPT_OUT 0x2
#define DMAR_PLATFORM_OPT_IN 0x4
+#define DMAR_REMAP_OPT_OUT 0x8
struct intel_iommu;
--
2.43.0
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH v2 0/9] iommu/vt-d: Support a new DMAR flag
2026-07-02 6:12 [PATCH v2 0/9] iommu/vt-d: Support a new DMAR flag Kevin Tian
` (8 preceding siblings ...)
2026-07-02 6:12 ` [PATCH v2 9/9] iommu/vt-d: Support the new DMA_REMAP_OPT_OUT flag bit Kevin Tian
@ 2026-07-27 3:04 ` Baolu Lu
9 siblings, 0 replies; 12+ messages in thread
From: Baolu Lu @ 2026-07-27 3:04 UTC (permalink / raw)
To: Kevin Tian, Joerg Roedel, Will Deacon, Robin Murphy
Cc: Mika Westerberg, Ashok Raj, Chris Wright, Jesse Barnes,
Asit Mallick, iommu, linux-kernel
On 7/2/26 14:12, Kevin Tian wrote:
> VT-d spec v5.2 introduces a new DMA_REMAP_OPT_OUT flag in the DMAR
> table, adding another knob to affect whether the DMA remapping
> capability should be turned on or off.
>
> While at it, first clean up the existing on/off policy messed with
> user opts and various force_on conditions in the first 8 patches.
>
> On top of the improved framework, the last patch introduces the
> support of the new bit.
>
> Some cleanups will be done after this series:
> - Cache dmar->flags instead of reading ACPI table multiple times
> - Check intel_iommu_enabled at runtime instead of using dmar_policy
> - Clean up existing warning messages (e.g. force_on panic message
> always has the "tboot:" prefix)
>
> v2:
> - Rebase to 7.2-rc1
> - Policy-oriented renaming to avoid confusion with runtime state (Baolu)
> - Warning message/comment improvements (Baolu)
> - Always return error for unsupported force_on type
> - No need to do platform optin if tboot already forces on (old behavior)
>
> v1:
> https://lore.kernel.org/linux-iommu/20260604051540.592925-1-
> kevin.tian@intel.com/
>
> Kevin Tian (9):
> iommu/vt-d: Fix no_iommu to disable platform optin
> iommu/vt-d: Force requesting ACS when tboot is enabled
> iommu/vt-d: Remove dead code when CONFIG_INTEL_IOMMU is not set
> iommu/vt-d: Consolidate dmar policy management and force_on logic
> iommu/vt-d: Use dmar_can_force_on() for platform optin
> iommu/vt-d: Call dmar_can_force_on() for tboot optin
> iommu/vt-d: Remove the 'force_on' variable
> iommu/vt-d: Remove dmar_disabled
> iommu/vt-d: Support the new DMA_REMAP_OPT_OUT flag bit
>
> drivers/iommu/intel/dmar.c | 95 +++++++++++++++++++++++++++++++++----
> drivers/iommu/intel/iommu.c | 78 +++++++++++++++---------------
> drivers/iommu/intel/iommu.h | 64 ++++++++++++++++++++-----
> drivers/iommu/intel/svm.c | 2 +-
> include/linux/dmar.h | 1 +
> 5 files changed, 180 insertions(+), 60 deletions(-)
Patch series queued for v7.3-rc1. Thanks a lot, Kevin.
^ permalink raw reply [flat|nested] 12+ messages in thread