Commit 3a93c841 authored by Takao Indoh's avatar Takao Indoh Committed by Joerg Roedel

iommu/vt-d: Disable translation if already enabled

This patch disables translation(dma-remapping) before its initialization
if it is already enabled.

This is needed for kexec/kdump boot. If dma-remapping is enabled in the
first kernel, it need to be disabled before initializing its page table
during second kernel boot. Wei Hu also reported that this is needed
when second kernel boots with intel_iommu=off.

Basically iommu->gcmd is used to know whether translation is enabled or
disabled, but it is always zero at boot time even when translation is
enabled since iommu->gcmd is initialized without considering such a
case. Therefor this patch synchronizes iommu->gcmd value with global
command register when iommu structure is allocated.
Signed-off-by: default avatarTakao Indoh <indou.takao@jp.fujitsu.com>
Signed-off-by: default avatarJoerg Roedel <joro@8bytes.org>
parent 35d3d814
...@@ -645,7 +645,7 @@ static int map_iommu(struct intel_iommu *iommu, u64 phys_addr) ...@@ -645,7 +645,7 @@ static int map_iommu(struct intel_iommu *iommu, u64 phys_addr)
int alloc_iommu(struct dmar_drhd_unit *drhd) int alloc_iommu(struct dmar_drhd_unit *drhd)
{ {
struct intel_iommu *iommu; struct intel_iommu *iommu;
u32 ver; u32 ver, sts;
static int iommu_allocated = 0; static int iommu_allocated = 0;
int agaw = 0; int agaw = 0;
int msagaw = 0; int msagaw = 0;
...@@ -695,6 +695,15 @@ int alloc_iommu(struct dmar_drhd_unit *drhd) ...@@ -695,6 +695,15 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
(unsigned long long)iommu->cap, (unsigned long long)iommu->cap,
(unsigned long long)iommu->ecap); (unsigned long long)iommu->ecap);
/* Reflect status in gcmd */
sts = readl(iommu->reg + DMAR_GSTS_REG);
if (sts & DMA_GSTS_IRES)
iommu->gcmd |= DMA_GCMD_IRE;
if (sts & DMA_GSTS_TES)
iommu->gcmd |= DMA_GCMD_TE;
if (sts & DMA_GSTS_QIES)
iommu->gcmd |= DMA_GCMD_QIE;
raw_spin_lock_init(&iommu->register_lock); raw_spin_lock_init(&iommu->register_lock);
drhd->iommu = iommu; drhd->iommu = iommu;
......
...@@ -3665,6 +3665,7 @@ static struct notifier_block device_nb = { ...@@ -3665,6 +3665,7 @@ static struct notifier_block device_nb = {
int __init intel_iommu_init(void) int __init intel_iommu_init(void)
{ {
int ret = 0; int ret = 0;
struct dmar_drhd_unit *drhd;
/* VT-d is required for a TXT/tboot launch, so enforce that */ /* VT-d is required for a TXT/tboot launch, so enforce that */
force_on = tboot_force_iommu(); force_on = tboot_force_iommu();
...@@ -3675,6 +3676,20 @@ int __init intel_iommu_init(void) ...@@ -3675,6 +3676,20 @@ int __init intel_iommu_init(void)
return -ENODEV; return -ENODEV;
} }
/*
* Disable translation if already enabled prior to OS handover.
*/
for_each_drhd_unit(drhd) {
struct intel_iommu *iommu;
if (drhd->ignored)
continue;
iommu = drhd->iommu;
if (iommu->gcmd & DMA_GCMD_TE)
iommu_disable_translation(iommu);
}
if (dmar_dev_scope_init() < 0) { if (dmar_dev_scope_init() < 0) {
if (force_on) if (force_on)
panic("tboot: Failed to initialize DMAR device scope\n"); panic("tboot: Failed to initialize DMAR device scope\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment