Skip to content

Commit 36b7200

Browse files
Stuart Hayesjoergroedel
authored andcommitted
iommu/amd: Flush old domains in kdump kernel
When devices are attached to the amd_iommu in a kdump kernel, the old device table entries (DTEs), which were copied from the crashed kernel, will be overwritten with a new domain number. When the new DTE is written, the IOMMU is told to flush the DTE from its internal cache--but it is not told to flush the translation cache entries for the old domain number. Without this patch, AMD systems using the tg3 network driver fail when kdump tries to save the vmcore to a network system, showing network timeouts and (sometimes) IOMMU errors in the kernel log. This patch will flush IOMMU translation cache entries for the old domain when a DTE gets overwritten with a new domain number. Signed-off-by: Stuart Hayes <[email protected]> Fixes: 3ac3e5e ('iommu/amd: Copy old trans table from old kernel') Signed-off-by: Joerg Roedel <[email protected]>
1 parent 8744daf commit 36b7200

File tree

1 file changed

+24
-0
lines changed

1 file changed

+24
-0
lines changed

drivers/iommu/amd_iommu.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,6 +1143,17 @@ static void amd_iommu_flush_tlb_all(struct amd_iommu *iommu)
11431143
iommu_completion_wait(iommu);
11441144
}
11451145

1146+
static void amd_iommu_flush_tlb_domid(struct amd_iommu *iommu, u32 dom_id)
1147+
{
1148+
struct iommu_cmd cmd;
1149+
1150+
build_inv_iommu_pages(&cmd, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS,
1151+
dom_id, 1);
1152+
iommu_queue_command(iommu, &cmd);
1153+
1154+
iommu_completion_wait(iommu);
1155+
}
1156+
11461157
static void amd_iommu_flush_all(struct amd_iommu *iommu)
11471158
{
11481159
struct iommu_cmd cmd;
@@ -1873,6 +1884,7 @@ static void set_dte_entry(u16 devid, struct protection_domain *domain,
18731884
{
18741885
u64 pte_root = 0;
18751886
u64 flags = 0;
1887+
u32 old_domid;
18761888

18771889
if (domain->mode != PAGE_MODE_NONE)
18781890
pte_root = iommu_virt_to_phys(domain->pt_root);
@@ -1922,8 +1934,20 @@ static void set_dte_entry(u16 devid, struct protection_domain *domain,
19221934
flags &= ~DEV_DOMID_MASK;
19231935
flags |= domain->id;
19241936

1937+
old_domid = amd_iommu_dev_table[devid].data[1] & DEV_DOMID_MASK;
19251938
amd_iommu_dev_table[devid].data[1] = flags;
19261939
amd_iommu_dev_table[devid].data[0] = pte_root;
1940+
1941+
/*
1942+
* A kdump kernel might be replacing a domain ID that was copied from
1943+
* the previous kernel--if so, it needs to flush the translation cache
1944+
* entries for the old domain ID that is being overwritten
1945+
*/
1946+
if (old_domid) {
1947+
struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
1948+
1949+
amd_iommu_flush_tlb_domid(iommu, old_domid);
1950+
}
19271951
}
19281952

19291953
static void clear_dte_entry(u16 devid)

0 commit comments

Comments
 (0)