|
12 | 12 | #include <linux/acpi.h>
|
13 | 13 | #include <linux/list.h>
|
14 | 14 | #include <linux/bitmap.h>
|
| 15 | +#include <linux/delay.h> |
15 | 16 | #include <linux/slab.h>
|
16 | 17 | #include <linux/syscore_ops.h>
|
17 | 18 | #include <linux/interrupt.h>
|
@@ -256,6 +257,8 @@ static enum iommu_init_state init_state = IOMMU_START_STATE;
|
256 | 257 | static int amd_iommu_enable_interrupts(void);
|
257 | 258 | static int __init iommu_go_to_state(enum iommu_init_state state);
|
258 | 259 | 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); |
259 | 262 |
|
260 | 263 | static bool amd_iommu_pre_enabled = true;
|
261 | 264 |
|
@@ -1697,31 +1700,51 @@ static int __init init_iommu_all(struct acpi_table_header *table)
|
1697 | 1700 | return 0;
|
1698 | 1701 | }
|
1699 | 1702 |
|
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) |
1704 | 1704 | {
|
| 1705 | + int retry; |
1705 | 1706 | 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; |
1707 | 1708 |
|
1708 | 1709 | if (!iommu_feature(iommu, FEATURE_PC))
|
1709 | 1710 | return;
|
1710 | 1711 |
|
1711 | 1712 | amd_iommu_pc_present = true;
|
1712 | 1713 |
|
1713 | 1714 | /* 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)) |
1715 | 1717 | goto pc_false;
|
1716 | 1718 |
|
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)) |
1721 | 1728 | goto pc_false;
|
1722 | 1729 |
|
| 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 | + |
1723 | 1742 | /* 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) |
1725 | 1748 | goto pc_false;
|
1726 | 1749 |
|
1727 | 1750 | pci_info(pdev, "IOMMU performance counters supported\n");
|
|
0 commit comments