Skip to content

Commit f32fe7c

Browse files
ashkalrajoergroedel
authored andcommitted
iommu/amd: Add support to remap/unmap IOMMU buffers for kdump
After a panic if SNP is enabled in the previous kernel then the kdump kernel boots with IOMMU SNP enforcement still enabled. IOMMU completion wait buffers (CWBs), command buffers and event buffer registers remain locked and exclusive to the previous kernel. Attempts to allocate and use new buffers in the kdump kernel fail, as hardware ignores writes to the locked MMIO registers as per AMD IOMMU spec Section 2.12.2.1. This results in repeated "Completion-Wait loop timed out" errors and a second kernel panic: "Kernel panic - not syncing: timer doesn't work through Interrupt-remapped IO-APIC" The list of MMIO registers locked and which ignore writes after failed SNP shutdown are mentioned in the AMD IOMMU specifications below: Section 2.12.2.1. https://docs.amd.com/v/u/en-US/48882_3.10_PUB Reuse the pages of the previous kernel for completion wait buffers, command buffers, event buffers and memremap them during kdump boot and essentially work with an already enabled IOMMU configuration and re-using the previous kernel’s data structures. Reusing of command buffers and event buffers is now done for kdump boot irrespective of SNP being enabled during kdump. Re-use of completion wait buffers is only done when SNP is enabled as the exclusion base register is used for the completion wait buffer (CWB) address only when SNP is enabled. Reviewed-by: Vasant Hegde <[email protected]> Tested-by: Sairaj Kodilkar <[email protected]> Signed-off-by: Ashish Kalra <[email protected]> Link: https://lore.kernel.org/r/ff04b381a8fe774b175c23c1a336b28bc1396511.1756157913.git.ashish.kalra@amd.com Signed-off-by: Joerg Roedel <[email protected]>
1 parent d3d3b60 commit f32fe7c

File tree

3 files changed

+146
-13
lines changed

3 files changed

+146
-13
lines changed

drivers/iommu/amd/amd_iommu_types.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,11 @@ struct amd_iommu {
791791
u32 flags;
792792
volatile u64 *cmd_sem;
793793
atomic64_t cmd_sem_val;
794+
/*
795+
* Track physical address to directly use it in build_completion_wait()
796+
* and avoid adding any special checks and handling for kdump.
797+
*/
798+
u64 cmd_sem_paddr;
794799

795800
#ifdef CONFIG_AMD_IOMMU_DEBUGFS
796801
/* DebugFS Info */

drivers/iommu/amd/init.c

Lines changed: 140 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,26 @@ static void __init free_alias_table(struct amd_iommu_pci_seg *pci_seg)
710710
pci_seg->alias_table = NULL;
711711
}
712712

713+
static inline void *iommu_memremap(unsigned long paddr, size_t size)
714+
{
715+
phys_addr_t phys;
716+
717+
if (!paddr)
718+
return NULL;
719+
720+
/*
721+
* Obtain true physical address in kdump kernel when SME is enabled.
722+
* Currently, previous kernel with SME enabled and kdump kernel
723+
* with SME support disabled is not supported.
724+
*/
725+
phys = __sme_clr(paddr);
726+
727+
if (cc_platform_has(CC_ATTR_HOST_MEM_ENCRYPT))
728+
return (__force void *)ioremap_encrypted(phys, size);
729+
else
730+
return memremap(phys, size, MEMREMAP_WB);
731+
}
732+
713733
/*
714734
* Allocates the command buffer. This buffer is per AMD IOMMU. We can
715735
* write commands to that buffer later and the IOMMU will execute them
@@ -942,15 +962,130 @@ static int iommu_init_ga_log(struct amd_iommu *iommu)
942962
static int __init alloc_cwwb_sem(struct amd_iommu *iommu)
943963
{
944964
iommu->cmd_sem = iommu_alloc_4k_pages(iommu, GFP_KERNEL, 1);
965+
if (!iommu->cmd_sem)
966+
return -ENOMEM;
967+
iommu->cmd_sem_paddr = iommu_virt_to_phys((void *)iommu->cmd_sem);
968+
return 0;
969+
}
970+
971+
static int __init remap_event_buffer(struct amd_iommu *iommu)
972+
{
973+
u64 paddr;
974+
975+
pr_info_once("Re-using event buffer from the previous kernel\n");
976+
paddr = readq(iommu->mmio_base + MMIO_EVT_BUF_OFFSET) & PM_ADDR_MASK;
977+
iommu->evt_buf = iommu_memremap(paddr, EVT_BUFFER_SIZE);
978+
979+
return iommu->evt_buf ? 0 : -ENOMEM;
980+
}
981+
982+
static int __init remap_command_buffer(struct amd_iommu *iommu)
983+
{
984+
u64 paddr;
945985

946-
return iommu->cmd_sem ? 0 : -ENOMEM;
986+
pr_info_once("Re-using command buffer from the previous kernel\n");
987+
paddr = readq(iommu->mmio_base + MMIO_CMD_BUF_OFFSET) & PM_ADDR_MASK;
988+
iommu->cmd_buf = iommu_memremap(paddr, CMD_BUFFER_SIZE);
989+
990+
return iommu->cmd_buf ? 0 : -ENOMEM;
991+
}
992+
993+
static int __init remap_or_alloc_cwwb_sem(struct amd_iommu *iommu)
994+
{
995+
u64 paddr;
996+
997+
if (check_feature(FEATURE_SNP)) {
998+
/*
999+
* When SNP is enabled, the exclusion base register is used for the
1000+
* completion wait buffer (CWB) address. Read and re-use it.
1001+
*/
1002+
pr_info_once("Re-using CWB buffers from the previous kernel\n");
1003+
paddr = readq(iommu->mmio_base + MMIO_EXCL_BASE_OFFSET) & PM_ADDR_MASK;
1004+
iommu->cmd_sem = iommu_memremap(paddr, PAGE_SIZE);
1005+
if (!iommu->cmd_sem)
1006+
return -ENOMEM;
1007+
iommu->cmd_sem_paddr = paddr;
1008+
} else {
1009+
return alloc_cwwb_sem(iommu);
1010+
}
1011+
1012+
return 0;
1013+
}
1014+
1015+
static int __init alloc_iommu_buffers(struct amd_iommu *iommu)
1016+
{
1017+
int ret;
1018+
1019+
/*
1020+
* Reuse/Remap the previous kernel's allocated completion wait
1021+
* command and event buffers for kdump boot.
1022+
*/
1023+
if (is_kdump_kernel()) {
1024+
ret = remap_or_alloc_cwwb_sem(iommu);
1025+
if (ret)
1026+
return ret;
1027+
1028+
ret = remap_command_buffer(iommu);
1029+
if (ret)
1030+
return ret;
1031+
1032+
ret = remap_event_buffer(iommu);
1033+
if (ret)
1034+
return ret;
1035+
} else {
1036+
ret = alloc_cwwb_sem(iommu);
1037+
if (ret)
1038+
return ret;
1039+
1040+
ret = alloc_command_buffer(iommu);
1041+
if (ret)
1042+
return ret;
1043+
1044+
ret = alloc_event_buffer(iommu);
1045+
if (ret)
1046+
return ret;
1047+
}
1048+
1049+
return 0;
9471050
}
9481051

9491052
static void __init free_cwwb_sem(struct amd_iommu *iommu)
9501053
{
9511054
if (iommu->cmd_sem)
9521055
iommu_free_pages((void *)iommu->cmd_sem);
9531056
}
1057+
static void __init unmap_cwwb_sem(struct amd_iommu *iommu)
1058+
{
1059+
if (iommu->cmd_sem) {
1060+
if (check_feature(FEATURE_SNP))
1061+
memunmap((void *)iommu->cmd_sem);
1062+
else
1063+
iommu_free_pages((void *)iommu->cmd_sem);
1064+
}
1065+
}
1066+
1067+
static void __init unmap_command_buffer(struct amd_iommu *iommu)
1068+
{
1069+
memunmap((void *)iommu->cmd_buf);
1070+
}
1071+
1072+
static void __init unmap_event_buffer(struct amd_iommu *iommu)
1073+
{
1074+
memunmap(iommu->evt_buf);
1075+
}
1076+
1077+
static void __init free_iommu_buffers(struct amd_iommu *iommu)
1078+
{
1079+
if (is_kdump_kernel()) {
1080+
unmap_cwwb_sem(iommu);
1081+
unmap_command_buffer(iommu);
1082+
unmap_event_buffer(iommu);
1083+
} else {
1084+
free_cwwb_sem(iommu);
1085+
free_command_buffer(iommu);
1086+
free_event_buffer(iommu);
1087+
}
1088+
}
9541089

9551090
static void iommu_enable_xt(struct amd_iommu *iommu)
9561091
{
@@ -1655,9 +1790,7 @@ static void __init free_sysfs(struct amd_iommu *iommu)
16551790
static void __init free_iommu_one(struct amd_iommu *iommu)
16561791
{
16571792
free_sysfs(iommu);
1658-
free_cwwb_sem(iommu);
1659-
free_command_buffer(iommu);
1660-
free_event_buffer(iommu);
1793+
free_iommu_buffers(iommu);
16611794
amd_iommu_free_ppr_log(iommu);
16621795
free_ga_log(iommu);
16631796
iommu_unmap_mmio_space(iommu);
@@ -1821,14 +1954,9 @@ static int __init init_iommu_one_late(struct amd_iommu *iommu)
18211954
{
18221955
int ret;
18231956

1824-
if (alloc_cwwb_sem(iommu))
1825-
return -ENOMEM;
1826-
1827-
if (alloc_command_buffer(iommu))
1828-
return -ENOMEM;
1829-
1830-
if (alloc_event_buffer(iommu))
1831-
return -ENOMEM;
1957+
ret = alloc_iommu_buffers(iommu);
1958+
if (ret)
1959+
return ret;
18321960

18331961
iommu->int_enabled = false;
18341962

drivers/iommu/amd/iommu.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1196,7 +1196,7 @@ static void build_completion_wait(struct iommu_cmd *cmd,
11961196
struct amd_iommu *iommu,
11971197
u64 data)
11981198
{
1199-
u64 paddr = iommu_virt_to_phys((void *)iommu->cmd_sem);
1199+
u64 paddr = iommu->cmd_sem_paddr;
12001200

12011201
memset(cmd, 0, sizeof(*cmd));
12021202
cmd->data[0] = lower_32_bits(paddr) | CMD_COMPL_WAIT_STORE_MASK;

0 commit comments

Comments
 (0)