Skip to content

Commit 6778ff5

Browse files
ssuthiku-amdjoergroedel
authored andcommitted
iommu/amd: Fix performance counter initialization
Certain AMD platforms enable power gating feature for IOMMU PMC, which prevents the IOMMU driver from updating the counter while trying to validate the PMC functionality in the init_iommu_perf_ctr(). This results in disabling PMC support and the following error message: "AMD-Vi: Unable to read/write to IOMMU perf counter" To workaround this issue, disable power gating temporarily by programming the counter source to non-zero value while validating the counter, and restore the prior state afterward. Signed-off-by: Suravee Suthikulpanit <[email protected]> Tested-by: Tj (Elloe Linux) <[email protected]> Link: https://lore.kernel.org/r/[email protected] Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=201753 Signed-off-by: Joerg Roedel <[email protected]>
1 parent 89c9a09 commit 6778ff5

File tree

1 file changed

+34
-11
lines changed

1 file changed

+34
-11
lines changed

drivers/iommu/amd/init.c

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/acpi.h>
1313
#include <linux/list.h>
1414
#include <linux/bitmap.h>
15+
#include <linux/delay.h>
1516
#include <linux/slab.h>
1617
#include <linux/syscore_ops.h>
1718
#include <linux/interrupt.h>
@@ -256,6 +257,8 @@ static enum iommu_init_state init_state = IOMMU_START_STATE;
256257
static int amd_iommu_enable_interrupts(void);
257258
static int __init iommu_go_to_state(enum iommu_init_state state);
258259
static void init_device_table_dma(void);
260+
static int iommu_pc_get_set_reg(struct amd_iommu *iommu, u8 bank, u8 cntr,
261+
u8 fxn, u64 *value, bool is_write);
259262

260263
static bool amd_iommu_pre_enabled = true;
261264

@@ -1697,31 +1700,51 @@ static int __init init_iommu_all(struct acpi_table_header *table)
16971700
return 0;
16981701
}
16991702

1700-
static int iommu_pc_get_set_reg(struct amd_iommu *iommu, u8 bank, u8 cntr,
1701-
u8 fxn, u64 *value, bool is_write);
1702-
1703-
static void init_iommu_perf_ctr(struct amd_iommu *iommu)
1703+
static void __init init_iommu_perf_ctr(struct amd_iommu *iommu)
17041704
{
1705+
int retry;
17051706
struct pci_dev *pdev = iommu->dev;
1706-
u64 val = 0xabcd, val2 = 0, save_reg = 0;
1707+
u64 val = 0xabcd, val2 = 0, save_reg, save_src;
17071708

17081709
if (!iommu_feature(iommu, FEATURE_PC))
17091710
return;
17101711

17111712
amd_iommu_pc_present = true;
17121713

17131714
/* save the value to restore, if writable */
1714-
if (iommu_pc_get_set_reg(iommu, 0, 0, 0, &save_reg, false))
1715+
if (iommu_pc_get_set_reg(iommu, 0, 0, 0, &save_reg, false) ||
1716+
iommu_pc_get_set_reg(iommu, 0, 0, 8, &save_src, false))
17151717
goto pc_false;
17161718

1717-
/* Check if the performance counters can be written to */
1718-
if ((iommu_pc_get_set_reg(iommu, 0, 0, 0, &val, true)) ||
1719-
(iommu_pc_get_set_reg(iommu, 0, 0, 0, &val2, false)) ||
1720-
(val != val2))
1719+
/*
1720+
* Disable power gating by programing the performance counter
1721+
* source to 20 (i.e. counts the reads and writes from/to IOMMU
1722+
* Reserved Register [MMIO Offset 1FF8h] that are ignored.),
1723+
* which never get incremented during this init phase.
1724+
* (Note: The event is also deprecated.)
1725+
*/
1726+
val = 20;
1727+
if (iommu_pc_get_set_reg(iommu, 0, 0, 8, &val, true))
17211728
goto pc_false;
17221729

1730+
/* Check if the performance counters can be written to */
1731+
val = 0xabcd;
1732+
for (retry = 5; retry; retry--) {
1733+
if (iommu_pc_get_set_reg(iommu, 0, 0, 0, &val, true) ||
1734+
iommu_pc_get_set_reg(iommu, 0, 0, 0, &val2, false) ||
1735+
val2)
1736+
break;
1737+
1738+
/* Wait about 20 msec for power gating to disable and retry. */
1739+
msleep(20);
1740+
}
1741+
17231742
/* restore */
1724-
if (iommu_pc_get_set_reg(iommu, 0, 0, 0, &save_reg, true))
1743+
if (iommu_pc_get_set_reg(iommu, 0, 0, 0, &save_reg, true) ||
1744+
iommu_pc_get_set_reg(iommu, 0, 0, 8, &save_src, true))
1745+
goto pc_false;
1746+
1747+
if (val != val2)
17251748
goto pc_false;
17261749

17271750
pci_info(pdev, "IOMMU performance counters supported\n");

0 commit comments

Comments
 (0)