iommu/vt-d: Consolidate dmar policy management and force_on logic

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>
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
This commit is contained in:
Kevin Tian 2026-08-05 07:43:02 +08:00 committed by Joerg Roedel
parent a4bd40c7e2
commit 7e6bd2211e
3 changed files with 106 additions and 4 deletions

View File

@ -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,

View File

@ -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");

View File

@ -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 opt-in).
*
* - 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;