diff options
Diffstat (limited to 'drivers/iommu/intel/perfmon.c')
-rw-r--r-- | drivers/iommu/intel/perfmon.c | 172 |
1 files changed, 0 insertions, 172 deletions
diff --git a/drivers/iommu/intel/perfmon.c b/drivers/iommu/intel/perfmon.c deleted file mode 100644 index db5791a544551..0000000000000 --- 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; -} |