6.1-stable review patch. If anyone has any objections, please let me know. ------------------ From: Jack Wang <jinpu.wang@xxxxxxxxx> This reverts commit 586e19c88a0cb58b6ff45ae085b3dd200d862153 which is commit a6a5006dad572a53b5df3f47e1471d207ae9ba49 upstream. This commit is pulled in due to dependency for: 8c91a4bfc7f8 ("iommu: Fix compilation without CONFIG_IOMMU_INTEL") But the patch itself is part of a patchset, should not only include one, and it lead to boot hang on on Kernel 6.1.83+ with Dell PowerEdge R770 and Intel Xeon 6710E, so revert it for stable 6.1.112 Signed-off-by: Jack Wang <jinpu.wang@xxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- drivers/iommu/intel/Kconfig | 11 -- drivers/iommu/intel/Makefile | 1 drivers/iommu/intel/dmar.c | 7 - drivers/iommu/intel/iommu.h | 43 ---------- drivers/iommu/intel/perfmon.c | 172 ------------------------------------------ drivers/iommu/intel/perfmon.h | 40 --------- 6 files changed, 1 insertion(+), 273 deletions(-) delete mode 100644 drivers/iommu/intel/perfmon.c delete mode 100644 drivers/iommu/intel/perfmon.h --- a/drivers/iommu/intel/Kconfig +++ b/drivers/iommu/intel/Kconfig @@ -96,15 +96,4 @@ config INTEL_IOMMU_SCALABLE_MODE_DEFAULT passing intel_iommu=sm_on to the kernel. If not sure, please use the default value. -config INTEL_IOMMU_PERF_EVENTS - def_bool y - bool "Intel IOMMU performance events" - depends on INTEL_IOMMU && PERF_EVENTS - help - Selecting this option will enable the performance monitoring - infrastructure in the Intel IOMMU. It collects information about - key events occurring during operation of the remapping hardware, - to aid performance tuning and debug. These are available on modern - processors which support Intel VT-d 4.0 and later. - endif # INTEL_IOMMU --- a/drivers/iommu/intel/Makefile +++ b/drivers/iommu/intel/Makefile @@ -8,4 +8,3 @@ obj-$(CONFIG_INTEL_IOMMU_SVM) += svm.o ifdef CONFIG_INTEL_IOMMU obj-$(CONFIG_IRQ_REMAP) += irq_remapping.o endif -obj-$(CONFIG_INTEL_IOMMU_PERF_EVENTS) += perfmon.o --- a/drivers/iommu/intel/dmar.c +++ b/drivers/iommu/intel/dmar.c @@ -34,7 +34,6 @@ #include "../irq_remapping.h" #include "perf.h" #include "trace.h" -#include "perfmon.h" typedef int (*dmar_res_handler_t)(struct acpi_dmar_header *, void *); struct dmar_res_callback { @@ -1105,9 +1104,6 @@ static int alloc_iommu(struct dmar_drhd_ if (sts & DMA_GSTS_QIES) iommu->gcmd |= DMA_GCMD_QIE; - if (alloc_iommu_pmu(iommu)) - pr_debug("Cannot alloc PMU for iommu (seq_id = %d)\n", iommu->seq_id); - raw_spin_lock_init(&iommu->register_lock); /* @@ -1135,7 +1131,6 @@ static int alloc_iommu(struct dmar_drhd_ err_sysfs: iommu_device_sysfs_remove(&iommu->iommu); err_unmap: - free_iommu_pmu(iommu); unmap_iommu(iommu); error_free_seq_id: ida_free(&dmar_seq_ids, iommu->seq_id); @@ -1151,8 +1146,6 @@ static void free_iommu(struct intel_iomm iommu_device_sysfs_remove(&iommu->iommu); } - free_iommu_pmu(iommu); - if (iommu->irq) { if (iommu->pr_irq) { free_irq(iommu->pr_irq, iommu); --- a/drivers/iommu/intel/iommu.h +++ b/drivers/iommu/intel/iommu.h @@ -125,11 +125,6 @@ #define DMAR_MTRR_PHYSMASK8_REG 0x208 #define DMAR_MTRR_PHYSBASE9_REG 0x210 #define DMAR_MTRR_PHYSMASK9_REG 0x218 -#define DMAR_PERFCAP_REG 0x300 -#define DMAR_PERFCFGOFF_REG 0x310 -#define DMAR_PERFOVFOFF_REG 0x318 -#define DMAR_PERFCNTROFF_REG 0x31c -#define DMAR_PERFEVNTCAP_REG 0x380 #define DMAR_VCCAP_REG 0xe30 /* Virtual command capability register */ #define DMAR_VCMD_REG 0xe00 /* Virtual command register */ #define DMAR_VCRSP_REG 0xe10 /* Virtual command response register */ @@ -153,7 +148,6 @@ */ #define cap_esrtps(c) (((c) >> 63) & 1) #define cap_esirtps(c) (((c) >> 62) & 1) -#define cap_ecmds(c) (((c) >> 61) & 1) #define cap_fl5lp_support(c) (((c) >> 60) & 1) #define cap_pi_support(c) (((c) >> 59) & 1) #define cap_fl1gp_support(c) (((c) >> 56) & 1) @@ -185,8 +179,7 @@ * Extended Capability Register */ -#define ecap_pms(e) (((e) >> 51) & 0x1) -#define ecap_rps(e) (((e) >> 49) & 0x1) +#define ecap_rps(e) (((e) >> 49) & 0x1) #define ecap_smpwc(e) (((e) >> 48) & 0x1) #define ecap_flts(e) (((e) >> 47) & 0x1) #define ecap_slts(e) (((e) >> 46) & 0x1) @@ -217,22 +210,6 @@ #define ecap_max_handle_mask(e) (((e) >> 20) & 0xf) #define ecap_sc_support(e) (((e) >> 7) & 0x1) /* Snooping Control */ -/* - * Decoding Perf Capability Register - */ -#define pcap_num_cntr(p) ((p) & 0xffff) -#define pcap_cntr_width(p) (((p) >> 16) & 0x7f) -#define pcap_num_event_group(p) (((p) >> 24) & 0x1f) -#define pcap_filters_mask(p) (((p) >> 32) & 0x1f) -#define pcap_interrupt(p) (((p) >> 50) & 0x1) -/* The counter stride is calculated as 2 ^ (x+10) bytes */ -#define pcap_cntr_stride(p) (1ULL << ((((p) >> 52) & 0x7) + 10)) - -/* - * Decoding Perf Event Capability Register - */ -#define pecap_es(p) ((p) & 0xfffffff) - /* Virtual command interface capability */ #define vccap_pasid(v) (((v) & DMA_VCS_PAS)) /* PASID allocation */ @@ -584,22 +561,6 @@ struct dmar_domain { iommu core */ }; -struct iommu_pmu { - struct intel_iommu *iommu; - u32 num_cntr; /* Number of counters */ - u32 num_eg; /* Number of event group */ - u32 cntr_width; /* Counter width */ - u32 cntr_stride; /* Counter Stride */ - u32 filter; /* Bitmask of filter support */ - void __iomem *base; /* the PerfMon base address */ - void __iomem *cfg_reg; /* counter configuration base address */ - void __iomem *cntr_reg; /* counter 0 address*/ - void __iomem *overflow; /* overflow status register */ - - u64 *evcap; /* Indicates all supported events */ - u32 **cntr_evcap; /* Supported events of each counter. */ -}; - struct intel_iommu { void __iomem *reg; /* Pointer to hardware regs, virtual addr */ u64 reg_phys; /* physical address of hw register set */ @@ -647,8 +608,6 @@ struct intel_iommu { struct dmar_drhd_unit *drhd; void *perf_statistic; - - struct iommu_pmu *pmu; }; /* PCI domain-device relationship */ --- a/drivers/iommu/intel/perfmon.c +++ /dev/null @@ -1,172 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Support Intel IOMMU PerfMon - * Copyright(c) 2023 Intel Corporation. - */ -#define pr_fmt(fmt) "DMAR: " fmt -#define dev_fmt(fmt) pr_fmt(fmt) - -#include <linux/dmar.h> -#include "iommu.h" -#include "perfmon.h" - -static inline void __iomem * -get_perf_reg_address(struct intel_iommu *iommu, u32 offset) -{ - u32 off = dmar_readl(iommu->reg + offset); - - return iommu->reg + off; -} - -int alloc_iommu_pmu(struct intel_iommu *iommu) -{ - struct iommu_pmu *iommu_pmu; - int i, j, ret; - u64 perfcap; - u32 cap; - - if (!ecap_pms(iommu->ecap)) - return 0; - - /* The IOMMU PMU requires the ECMD support as well */ - if (!cap_ecmds(iommu->cap)) - return -ENODEV; - - perfcap = dmar_readq(iommu->reg + DMAR_PERFCAP_REG); - /* The performance monitoring is not supported. */ - if (!perfcap) - return -ENODEV; - - /* Sanity check for the number of the counters and event groups */ - if (!pcap_num_cntr(perfcap) || !pcap_num_event_group(perfcap)) - return -ENODEV; - - /* The interrupt on overflow is required */ - if (!pcap_interrupt(perfcap)) - return -ENODEV; - - iommu_pmu = kzalloc(sizeof(*iommu_pmu), GFP_KERNEL); - if (!iommu_pmu) - return -ENOMEM; - - iommu_pmu->num_cntr = pcap_num_cntr(perfcap); - iommu_pmu->cntr_width = pcap_cntr_width(perfcap); - iommu_pmu->filter = pcap_filters_mask(perfcap); - iommu_pmu->cntr_stride = pcap_cntr_stride(perfcap); - iommu_pmu->num_eg = pcap_num_event_group(perfcap); - - iommu_pmu->evcap = kcalloc(iommu_pmu->num_eg, sizeof(u64), GFP_KERNEL); - if (!iommu_pmu->evcap) { - ret = -ENOMEM; - goto free_pmu; - } - - /* Parse event group capabilities */ - for (i = 0; i < iommu_pmu->num_eg; i++) { - u64 pcap; - - pcap = dmar_readq(iommu->reg + DMAR_PERFEVNTCAP_REG + - i * IOMMU_PMU_CAP_REGS_STEP); - iommu_pmu->evcap[i] = pecap_es(pcap); - } - - iommu_pmu->cntr_evcap = kcalloc(iommu_pmu->num_cntr, sizeof(u32 *), GFP_KERNEL); - if (!iommu_pmu->cntr_evcap) { - ret = -ENOMEM; - goto free_pmu_evcap; - } - for (i = 0; i < iommu_pmu->num_cntr; i++) { - iommu_pmu->cntr_evcap[i] = kcalloc(iommu_pmu->num_eg, sizeof(u32), GFP_KERNEL); - if (!iommu_pmu->cntr_evcap[i]) { - ret = -ENOMEM; - goto free_pmu_cntr_evcap; - } - /* - * Set to the global capabilities, will adjust according - * to per-counter capabilities later. - */ - for (j = 0; j < iommu_pmu->num_eg; j++) - iommu_pmu->cntr_evcap[i][j] = (u32)iommu_pmu->evcap[j]; - } - - iommu_pmu->cfg_reg = get_perf_reg_address(iommu, DMAR_PERFCFGOFF_REG); - iommu_pmu->cntr_reg = get_perf_reg_address(iommu, DMAR_PERFCNTROFF_REG); - iommu_pmu->overflow = get_perf_reg_address(iommu, DMAR_PERFOVFOFF_REG); - - /* - * Check per-counter capabilities. All counters should have the - * same capabilities on Interrupt on Overflow Support and Counter - * Width. - */ - for (i = 0; i < iommu_pmu->num_cntr; i++) { - cap = dmar_readl(iommu_pmu->cfg_reg + - i * IOMMU_PMU_CFG_OFFSET + - IOMMU_PMU_CFG_CNTRCAP_OFFSET); - if (!iommu_cntrcap_pcc(cap)) - continue; - - /* - * It's possible that some counters have a different - * capability because of e.g., HW bug. Check the corner - * case here and simply drop those counters. - */ - if ((iommu_cntrcap_cw(cap) != iommu_pmu->cntr_width) || - !iommu_cntrcap_ios(cap)) { - iommu_pmu->num_cntr = i; - pr_warn("PMU counter capability inconsistent, counter number reduced to %d\n", - iommu_pmu->num_cntr); - } - - /* Clear the pre-defined events group */ - for (j = 0; j < iommu_pmu->num_eg; j++) - iommu_pmu->cntr_evcap[i][j] = 0; - - /* Override with per-counter event capabilities */ - for (j = 0; j < iommu_cntrcap_egcnt(cap); j++) { - cap = dmar_readl(iommu_pmu->cfg_reg + i * IOMMU_PMU_CFG_OFFSET + - IOMMU_PMU_CFG_CNTREVCAP_OFFSET + - (j * IOMMU_PMU_OFF_REGS_STEP)); - iommu_pmu->cntr_evcap[i][iommu_event_group(cap)] = iommu_event_select(cap); - /* - * Some events may only be supported by a specific counter. - * Track them in the evcap as well. - */ - iommu_pmu->evcap[iommu_event_group(cap)] |= iommu_event_select(cap); - } - } - - iommu_pmu->iommu = iommu; - iommu->pmu = iommu_pmu; - - return 0; - -free_pmu_cntr_evcap: - for (i = 0; i < iommu_pmu->num_cntr; i++) - kfree(iommu_pmu->cntr_evcap[i]); - kfree(iommu_pmu->cntr_evcap); -free_pmu_evcap: - kfree(iommu_pmu->evcap); -free_pmu: - kfree(iommu_pmu); - - return ret; -} - -void free_iommu_pmu(struct intel_iommu *iommu) -{ - struct iommu_pmu *iommu_pmu = iommu->pmu; - - if (!iommu_pmu) - return; - - if (iommu_pmu->evcap) { - int i; - - for (i = 0; i < iommu_pmu->num_cntr; i++) - kfree(iommu_pmu->cntr_evcap[i]); - kfree(iommu_pmu->cntr_evcap); - } - kfree(iommu_pmu->evcap); - kfree(iommu_pmu); - iommu->pmu = NULL; -} --- a/drivers/iommu/intel/perfmon.h +++ /dev/null @@ -1,40 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - -/* - * PERFCFGOFF_REG, PERFFRZOFF_REG - * PERFOVFOFF_REG, PERFCNTROFF_REG - */ -#define IOMMU_PMU_NUM_OFF_REGS 4 -#define IOMMU_PMU_OFF_REGS_STEP 4 - -#define IOMMU_PMU_CFG_OFFSET 0x100 -#define IOMMU_PMU_CFG_CNTRCAP_OFFSET 0x80 -#define IOMMU_PMU_CFG_CNTREVCAP_OFFSET 0x84 -#define IOMMU_PMU_CFG_SIZE 0x8 -#define IOMMU_PMU_CFG_FILTERS_OFFSET 0x4 - -#define IOMMU_PMU_CAP_REGS_STEP 8 - -#define iommu_cntrcap_pcc(p) ((p) & 0x1) -#define iommu_cntrcap_cw(p) (((p) >> 8) & 0xff) -#define iommu_cntrcap_ios(p) (((p) >> 16) & 0x1) -#define iommu_cntrcap_egcnt(p) (((p) >> 28) & 0xf) - -#define iommu_event_select(p) ((p) & 0xfffffff) -#define iommu_event_group(p) (((p) >> 28) & 0xf) - -#ifdef CONFIG_INTEL_IOMMU_PERF_EVENTS -int alloc_iommu_pmu(struct intel_iommu *iommu); -void free_iommu_pmu(struct intel_iommu *iommu); -#else -static inline int -alloc_iommu_pmu(struct intel_iommu *iommu) -{ - return 0; -} - -static inline void -free_iommu_pmu(struct intel_iommu *iommu) -{ -} -#endif /* CONFIG_INTEL_IOMMU_PERF_EVENTS */