1*a6a5006dSKan Liang // SPDX-License-Identifier: GPL-2.0-only 2*a6a5006dSKan Liang /* 3*a6a5006dSKan Liang * Support Intel IOMMU PerfMon 4*a6a5006dSKan Liang * Copyright(c) 2023 Intel Corporation. 5*a6a5006dSKan Liang */ 6*a6a5006dSKan Liang #define pr_fmt(fmt) "DMAR: " fmt 7*a6a5006dSKan Liang #define dev_fmt(fmt) pr_fmt(fmt) 8*a6a5006dSKan Liang 9*a6a5006dSKan Liang #include <linux/dmar.h> 10*a6a5006dSKan Liang #include "iommu.h" 11*a6a5006dSKan Liang #include "perfmon.h" 12*a6a5006dSKan Liang 13*a6a5006dSKan Liang static inline void __iomem * 14*a6a5006dSKan Liang get_perf_reg_address(struct intel_iommu *iommu, u32 offset) 15*a6a5006dSKan Liang { 16*a6a5006dSKan Liang u32 off = dmar_readl(iommu->reg + offset); 17*a6a5006dSKan Liang 18*a6a5006dSKan Liang return iommu->reg + off; 19*a6a5006dSKan Liang } 20*a6a5006dSKan Liang 21*a6a5006dSKan Liang int alloc_iommu_pmu(struct intel_iommu *iommu) 22*a6a5006dSKan Liang { 23*a6a5006dSKan Liang struct iommu_pmu *iommu_pmu; 24*a6a5006dSKan Liang int i, j, ret; 25*a6a5006dSKan Liang u64 perfcap; 26*a6a5006dSKan Liang u32 cap; 27*a6a5006dSKan Liang 28*a6a5006dSKan Liang if (!ecap_pms(iommu->ecap)) 29*a6a5006dSKan Liang return 0; 30*a6a5006dSKan Liang 31*a6a5006dSKan Liang /* The IOMMU PMU requires the ECMD support as well */ 32*a6a5006dSKan Liang if (!cap_ecmds(iommu->cap)) 33*a6a5006dSKan Liang return -ENODEV; 34*a6a5006dSKan Liang 35*a6a5006dSKan Liang perfcap = dmar_readq(iommu->reg + DMAR_PERFCAP_REG); 36*a6a5006dSKan Liang /* The performance monitoring is not supported. */ 37*a6a5006dSKan Liang if (!perfcap) 38*a6a5006dSKan Liang return -ENODEV; 39*a6a5006dSKan Liang 40*a6a5006dSKan Liang /* Sanity check for the number of the counters and event groups */ 41*a6a5006dSKan Liang if (!pcap_num_cntr(perfcap) || !pcap_num_event_group(perfcap)) 42*a6a5006dSKan Liang return -ENODEV; 43*a6a5006dSKan Liang 44*a6a5006dSKan Liang /* The interrupt on overflow is required */ 45*a6a5006dSKan Liang if (!pcap_interrupt(perfcap)) 46*a6a5006dSKan Liang return -ENODEV; 47*a6a5006dSKan Liang 48*a6a5006dSKan Liang iommu_pmu = kzalloc(sizeof(*iommu_pmu), GFP_KERNEL); 49*a6a5006dSKan Liang if (!iommu_pmu) 50*a6a5006dSKan Liang return -ENOMEM; 51*a6a5006dSKan Liang 52*a6a5006dSKan Liang iommu_pmu->num_cntr = pcap_num_cntr(perfcap); 53*a6a5006dSKan Liang iommu_pmu->cntr_width = pcap_cntr_width(perfcap); 54*a6a5006dSKan Liang iommu_pmu->filter = pcap_filters_mask(perfcap); 55*a6a5006dSKan Liang iommu_pmu->cntr_stride = pcap_cntr_stride(perfcap); 56*a6a5006dSKan Liang iommu_pmu->num_eg = pcap_num_event_group(perfcap); 57*a6a5006dSKan Liang 58*a6a5006dSKan Liang iommu_pmu->evcap = kcalloc(iommu_pmu->num_eg, sizeof(u64), GFP_KERNEL); 59*a6a5006dSKan Liang if (!iommu_pmu->evcap) { 60*a6a5006dSKan Liang ret = -ENOMEM; 61*a6a5006dSKan Liang goto free_pmu; 62*a6a5006dSKan Liang } 63*a6a5006dSKan Liang 64*a6a5006dSKan Liang /* Parse event group capabilities */ 65*a6a5006dSKan Liang for (i = 0; i < iommu_pmu->num_eg; i++) { 66*a6a5006dSKan Liang u64 pcap; 67*a6a5006dSKan Liang 68*a6a5006dSKan Liang pcap = dmar_readq(iommu->reg + DMAR_PERFEVNTCAP_REG + 69*a6a5006dSKan Liang i * IOMMU_PMU_CAP_REGS_STEP); 70*a6a5006dSKan Liang iommu_pmu->evcap[i] = pecap_es(pcap); 71*a6a5006dSKan Liang } 72*a6a5006dSKan Liang 73*a6a5006dSKan Liang iommu_pmu->cntr_evcap = kcalloc(iommu_pmu->num_cntr, sizeof(u32 *), GFP_KERNEL); 74*a6a5006dSKan Liang if (!iommu_pmu->cntr_evcap) { 75*a6a5006dSKan Liang ret = -ENOMEM; 76*a6a5006dSKan Liang goto free_pmu_evcap; 77*a6a5006dSKan Liang } 78*a6a5006dSKan Liang for (i = 0; i < iommu_pmu->num_cntr; i++) { 79*a6a5006dSKan Liang iommu_pmu->cntr_evcap[i] = kcalloc(iommu_pmu->num_eg, sizeof(u32), GFP_KERNEL); 80*a6a5006dSKan Liang if (!iommu_pmu->cntr_evcap[i]) { 81*a6a5006dSKan Liang ret = -ENOMEM; 82*a6a5006dSKan Liang goto free_pmu_cntr_evcap; 83*a6a5006dSKan Liang } 84*a6a5006dSKan Liang /* 85*a6a5006dSKan Liang * Set to the global capabilities, will adjust according 86*a6a5006dSKan Liang * to per-counter capabilities later. 87*a6a5006dSKan Liang */ 88*a6a5006dSKan Liang for (j = 0; j < iommu_pmu->num_eg; j++) 89*a6a5006dSKan Liang iommu_pmu->cntr_evcap[i][j] = (u32)iommu_pmu->evcap[j]; 90*a6a5006dSKan Liang } 91*a6a5006dSKan Liang 92*a6a5006dSKan Liang iommu_pmu->cfg_reg = get_perf_reg_address(iommu, DMAR_PERFCFGOFF_REG); 93*a6a5006dSKan Liang iommu_pmu->cntr_reg = get_perf_reg_address(iommu, DMAR_PERFCNTROFF_REG); 94*a6a5006dSKan Liang iommu_pmu->overflow = get_perf_reg_address(iommu, DMAR_PERFOVFOFF_REG); 95*a6a5006dSKan Liang 96*a6a5006dSKan Liang /* 97*a6a5006dSKan Liang * Check per-counter capabilities. All counters should have the 98*a6a5006dSKan Liang * same capabilities on Interrupt on Overflow Support and Counter 99*a6a5006dSKan Liang * Width. 100*a6a5006dSKan Liang */ 101*a6a5006dSKan Liang for (i = 0; i < iommu_pmu->num_cntr; i++) { 102*a6a5006dSKan Liang cap = dmar_readl(iommu_pmu->cfg_reg + 103*a6a5006dSKan Liang i * IOMMU_PMU_CFG_OFFSET + 104*a6a5006dSKan Liang IOMMU_PMU_CFG_CNTRCAP_OFFSET); 105*a6a5006dSKan Liang if (!iommu_cntrcap_pcc(cap)) 106*a6a5006dSKan Liang continue; 107*a6a5006dSKan Liang 108*a6a5006dSKan Liang /* 109*a6a5006dSKan Liang * It's possible that some counters have a different 110*a6a5006dSKan Liang * capability because of e.g., HW bug. Check the corner 111*a6a5006dSKan Liang * case here and simply drop those counters. 112*a6a5006dSKan Liang */ 113*a6a5006dSKan Liang if ((iommu_cntrcap_cw(cap) != iommu_pmu->cntr_width) || 114*a6a5006dSKan Liang !iommu_cntrcap_ios(cap)) { 115*a6a5006dSKan Liang iommu_pmu->num_cntr = i; 116*a6a5006dSKan Liang pr_warn("PMU counter capability inconsistent, counter number reduced to %d\n", 117*a6a5006dSKan Liang iommu_pmu->num_cntr); 118*a6a5006dSKan Liang } 119*a6a5006dSKan Liang 120*a6a5006dSKan Liang /* Clear the pre-defined events group */ 121*a6a5006dSKan Liang for (j = 0; j < iommu_pmu->num_eg; j++) 122*a6a5006dSKan Liang iommu_pmu->cntr_evcap[i][j] = 0; 123*a6a5006dSKan Liang 124*a6a5006dSKan Liang /* Override with per-counter event capabilities */ 125*a6a5006dSKan Liang for (j = 0; j < iommu_cntrcap_egcnt(cap); j++) { 126*a6a5006dSKan Liang cap = dmar_readl(iommu_pmu->cfg_reg + i * IOMMU_PMU_CFG_OFFSET + 127*a6a5006dSKan Liang IOMMU_PMU_CFG_CNTREVCAP_OFFSET + 128*a6a5006dSKan Liang (j * IOMMU_PMU_OFF_REGS_STEP)); 129*a6a5006dSKan Liang iommu_pmu->cntr_evcap[i][iommu_event_group(cap)] = iommu_event_select(cap); 130*a6a5006dSKan Liang /* 131*a6a5006dSKan Liang * Some events may only be supported by a specific counter. 132*a6a5006dSKan Liang * Track them in the evcap as well. 133*a6a5006dSKan Liang */ 134*a6a5006dSKan Liang iommu_pmu->evcap[iommu_event_group(cap)] |= iommu_event_select(cap); 135*a6a5006dSKan Liang } 136*a6a5006dSKan Liang } 137*a6a5006dSKan Liang 138*a6a5006dSKan Liang iommu_pmu->iommu = iommu; 139*a6a5006dSKan Liang iommu->pmu = iommu_pmu; 140*a6a5006dSKan Liang 141*a6a5006dSKan Liang return 0; 142*a6a5006dSKan Liang 143*a6a5006dSKan Liang free_pmu_cntr_evcap: 144*a6a5006dSKan Liang for (i = 0; i < iommu_pmu->num_cntr; i++) 145*a6a5006dSKan Liang kfree(iommu_pmu->cntr_evcap[i]); 146*a6a5006dSKan Liang kfree(iommu_pmu->cntr_evcap); 147*a6a5006dSKan Liang free_pmu_evcap: 148*a6a5006dSKan Liang kfree(iommu_pmu->evcap); 149*a6a5006dSKan Liang free_pmu: 150*a6a5006dSKan Liang kfree(iommu_pmu); 151*a6a5006dSKan Liang 152*a6a5006dSKan Liang return ret; 153*a6a5006dSKan Liang } 154*a6a5006dSKan Liang 155*a6a5006dSKan Liang void free_iommu_pmu(struct intel_iommu *iommu) 156*a6a5006dSKan Liang { 157*a6a5006dSKan Liang struct iommu_pmu *iommu_pmu = iommu->pmu; 158*a6a5006dSKan Liang 159*a6a5006dSKan Liang if (!iommu_pmu) 160*a6a5006dSKan Liang return; 161*a6a5006dSKan Liang 162*a6a5006dSKan Liang if (iommu_pmu->evcap) { 163*a6a5006dSKan Liang int i; 164*a6a5006dSKan Liang 165*a6a5006dSKan Liang for (i = 0; i < iommu_pmu->num_cntr; i++) 166*a6a5006dSKan Liang kfree(iommu_pmu->cntr_evcap[i]); 167*a6a5006dSKan Liang kfree(iommu_pmu->cntr_evcap); 168*a6a5006dSKan Liang } 169*a6a5006dSKan Liang kfree(iommu_pmu->evcap); 170*a6a5006dSKan Liang kfree(iommu_pmu); 171*a6a5006dSKan Liang iommu->pmu = NULL; 172*a6a5006dSKan Liang } 173