x86/amd-iommu: Work around S3 BIOS bug

This patch adds a workaround for an IOMMU BIOS problem to
the AMD IOMMU driver. The result of the bug is that the
IOMMU does not execute commands anymore when the system
comes out of the S3 state resulting in system failure. The
bug in the BIOS is that is does not restore certain hardware
specific registers correctly. This workaround reads out the
contents of these registers at boot time and restores them
on resume from S3. The workaround is limited to the specific
IOMMU chipset where this problem occurs.

Cc: stable@kernel.org
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
This commit is contained in:
Joerg Roedel
2010-09-23 15:15:19 +02:00
parent e9bf519711
commit 4c894f47bb
4 changed files with 36 additions and 0 deletions

View File

@ -632,6 +632,13 @@ static void __init init_iommu_from_pci(struct amd_iommu *iommu)
iommu->last_device = calc_devid(MMIO_GET_BUS(range),
MMIO_GET_LD(range));
iommu->evt_msi_num = MMIO_MSI_NUM(misc);
if (is_rd890_iommu(iommu->dev)) {
pci_read_config_dword(iommu->dev, 0xf0, &iommu->cache_cfg[0]);
pci_read_config_dword(iommu->dev, 0xf4, &iommu->cache_cfg[1]);
pci_read_config_dword(iommu->dev, 0xf8, &iommu->cache_cfg[2]);
pci_read_config_dword(iommu->dev, 0xfc, &iommu->cache_cfg[3]);
}
}
/*
@ -1120,6 +1127,16 @@ static void iommu_init_flags(struct amd_iommu *iommu)
iommu_feature_enable(iommu, CONTROL_COHERENT_EN);
}
static void iommu_apply_quirks(struct amd_iommu *iommu)
{
if (is_rd890_iommu(iommu->dev)) {
pci_write_config_dword(iommu->dev, 0xf0, iommu->cache_cfg[0]);
pci_write_config_dword(iommu->dev, 0xf4, iommu->cache_cfg[1]);
pci_write_config_dword(iommu->dev, 0xf8, iommu->cache_cfg[2]);
pci_write_config_dword(iommu->dev, 0xfc, iommu->cache_cfg[3]);
}
}
/*
* This function finally enables all IOMMUs found in the system after
* they have been initialized
@ -1130,6 +1147,7 @@ static void enable_iommus(void)
for_each_iommu(iommu) {
iommu_disable(iommu);
iommu_apply_quirks(iommu);
iommu_init_flags(iommu);
iommu_set_device_table(iommu);
iommu_enable_command_buffer(iommu);