| From 685957ba7b0ff9a28d2129cfae1ce90aabacf42e Mon Sep 17 00:00:00 2001 |
| From: Shuah Khan <skhan@linuxfoundation.org> |
| Date: Thu, 23 Jan 2020 15:32:14 -0700 |
| Subject: [PATCH] iommu/amd: Fix IOMMU perf counter clobbering during init |
| |
| commit 8c17bbf6c8f70058a66305f2e1982552e6ea7f47 upstream. |
| |
| init_iommu_perf_ctr() clobbers the register when it checks write access |
| to IOMMU perf counters and fails to restore when they are writable. |
| |
| Add save and restore to fix it. |
| |
| Signed-off-by: Shuah Khan <skhan@linuxfoundation.org> |
| Fixes: 30861ddc9cca4 ("perf/x86/amd: Add IOMMU Performance Counter resource management") |
| Reviewed-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com> |
| Tested-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com> |
| Signed-off-by: Joerg Roedel <jroedel@suse.de> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c |
| index 6469f5128242..a0e6d1bb1437 100644 |
| --- a/drivers/iommu/amd_iommu_init.c |
| +++ b/drivers/iommu/amd_iommu_init.c |
| @@ -1650,27 +1650,39 @@ static int iommu_pc_get_set_reg(struct amd_iommu *iommu, u8 bank, u8 cntr, |
| static void init_iommu_perf_ctr(struct amd_iommu *iommu) |
| { |
| struct pci_dev *pdev = iommu->dev; |
| - u64 val = 0xabcd, val2 = 0; |
| + u64 val = 0xabcd, val2 = 0, save_reg = 0; |
| |
| if (!iommu_feature(iommu, FEATURE_PC)) |
| return; |
| |
| amd_iommu_pc_present = true; |
| |
| + /* save the value to restore, if writable */ |
| + if (iommu_pc_get_set_reg(iommu, 0, 0, 0, &save_reg, false)) |
| + goto pc_false; |
| + |
| /* Check if the performance counters can be written to */ |
| if ((iommu_pc_get_set_reg(iommu, 0, 0, 0, &val, true)) || |
| (iommu_pc_get_set_reg(iommu, 0, 0, 0, &val2, false)) || |
| - (val != val2)) { |
| - pci_err(pdev, "Unable to write to IOMMU perf counter.\n"); |
| - amd_iommu_pc_present = false; |
| - return; |
| - } |
| + (val != val2)) |
| + goto pc_false; |
| + |
| + /* restore */ |
| + if (iommu_pc_get_set_reg(iommu, 0, 0, 0, &save_reg, true)) |
| + goto pc_false; |
| |
| pci_info(pdev, "IOMMU performance counters supported\n"); |
| |
| val = readl(iommu->mmio_base + MMIO_CNTR_CONF_OFFSET); |
| iommu->max_banks = (u8) ((val >> 12) & 0x3f); |
| iommu->max_counters = (u8) ((val >> 7) & 0xf); |
| + |
| + return; |
| + |
| +pc_false: |
| + pci_err(pdev, "Unable to read/write to IOMMU perf counter.\n"); |
| + amd_iommu_pc_present = false; |
| + return; |
| } |
| |
| static ssize_t amd_iommu_show_cap(struct device *dev, |
| -- |
| 2.7.4 |
| |