diff options
author | Ashish Kalra <ashish.kalra@amd.com> | 2024-01-25 22:11:19 -0600 |
---|---|---|
committer | Borislav Petkov (AMD) <bp@alien8.de> | 2024-01-29 20:34:18 +0100 |
commit | f366a8dac1b8fef28a470d4e67b9843ebb8e2a1f (patch) | |
tree | aa462024ab41a438123bd2be9090c497ead9783c /drivers/iommu | |
parent | a867ad6b340f47b7333b80a54b8507fc2cd80aa4 (diff) | |
download | linux-stable-f366a8dac1b8fef28a470d4e67b9843ebb8e2a1f.tar.gz linux-stable-f366a8dac1b8fef28a470d4e67b9843ebb8e2a1f.tar.bz2 linux-stable-f366a8dac1b8fef28a470d4e67b9843ebb8e2a1f.zip |
iommu/amd: Clean up RMP entries for IOMMU pages during SNP shutdown
Add a new IOMMU API interface amd_iommu_snp_disable() to transition
IOMMU pages to Hypervisor state from Reclaim state after SNP_SHUTDOWN_EX
command. Invoke this API from the CCP driver after SNP_SHUTDOWN_EX
command.
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Link: https://lore.kernel.org/r/20240126041126.1927228-20-michael.roth@amd.com
Diffstat (limited to 'drivers/iommu')
-rw-r--r-- | drivers/iommu/amd/init.c | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index 3a4eeb26d515..88bb08ae39b2 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -30,6 +30,7 @@ #include <asm/io_apic.h> #include <asm/irq_remapping.h> #include <asm/set_memory.h> +#include <asm/sev.h> #include <linux/crash_dump.h> @@ -3797,3 +3798,81 @@ int amd_iommu_pc_set_reg(struct amd_iommu *iommu, u8 bank, u8 cntr, u8 fxn, u64 return iommu_pc_get_set_reg(iommu, bank, cntr, fxn, value, true); } + +#ifdef CONFIG_KVM_AMD_SEV +static int iommu_page_make_shared(void *page) +{ + unsigned long paddr, pfn; + + paddr = iommu_virt_to_phys(page); + /* Cbit maybe set in the paddr */ + pfn = __sme_clr(paddr) >> PAGE_SHIFT; + + if (!(pfn % PTRS_PER_PMD)) { + int ret, level; + bool assigned; + + ret = snp_lookup_rmpentry(pfn, &assigned, &level); + if (ret) + pr_warn("IOMMU PFN %lx RMP lookup failed, ret %d\n", + pfn, ret); + + if (!assigned) + pr_warn("IOMMU PFN %lx not assigned in RMP table\n", + pfn); + + if (level > PG_LEVEL_4K) { + ret = psmash(pfn); + if (ret) { + pr_warn("IOMMU PFN %lx had a huge RMP entry, but attempted psmash failed, ret: %d, level: %d\n", + pfn, ret, level); + } + } + } + + return rmp_make_shared(pfn, PG_LEVEL_4K); +} + +static int iommu_make_shared(void *va, size_t size) +{ + void *page; + int ret; + + if (!va) + return 0; + + for (page = va; page < (va + size); page += PAGE_SIZE) { + ret = iommu_page_make_shared(page); + if (ret) + return ret; + } + + return 0; +} + +int amd_iommu_snp_disable(void) +{ + struct amd_iommu *iommu; + int ret; + + if (!amd_iommu_snp_en) + return 0; + + for_each_iommu(iommu) { + ret = iommu_make_shared(iommu->evt_buf, EVT_BUFFER_SIZE); + if (ret) + return ret; + + ret = iommu_make_shared(iommu->ppr_log, PPR_LOG_SIZE); + if (ret) + return ret; + + ret = iommu_make_shared((void *)iommu->cmd_sem, PAGE_SIZE); + if (ret) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(amd_iommu_snp_disable); +#endif |