linux/drivers/iommu/intel/perf.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * perf.c - performance monitor
   4 *
   5 * Copyright (C) 2021 Intel Corporation
   6 *
   7 * Author: Lu Baolu <baolu.lu@linux.intel.com>
   8 *         Fenghua Yu <fenghua.yu@intel.com>
   9 */
  10
  11#include <linux/spinlock.h>
  12#include <linux/intel-iommu.h>
  13
  14#include "perf.h"
  15
  16static DEFINE_SPINLOCK(latency_lock);
  17
  18bool dmar_latency_enabled(struct intel_iommu *iommu, enum latency_type type)
  19{
  20        struct latency_statistic *lstat = iommu->perf_statistic;
  21
  22        return lstat && lstat[type].enabled;
  23}
  24
  25int dmar_latency_enable(struct intel_iommu *iommu, enum latency_type type)
  26{
  27        struct latency_statistic *lstat;
  28        unsigned long flags;
  29        int ret = -EBUSY;
  30
  31        if (dmar_latency_enabled(iommu, type))
  32                return 0;
  33
  34        spin_lock_irqsave(&latency_lock, flags);
  35        if (!iommu->perf_statistic) {
  36                iommu->perf_statistic = kzalloc(sizeof(*lstat) * DMAR_LATENCY_NUM,
  37                                                GFP_ATOMIC);
  38                if (!iommu->perf_statistic) {
  39                        ret = -ENOMEM;
  40                        goto unlock_out;
  41                }
  42        }
  43
  44        lstat = iommu->perf_statistic;
  45
  46        if (!lstat[type].enabled) {
  47                lstat[type].enabled = true;
  48                lstat[type].counter[COUNTS_MIN] = UINT_MAX;
  49                ret = 0;
  50        }
  51unlock_out:
  52        spin_unlock_irqrestore(&latency_lock, flags);
  53
  54        return ret;
  55}
  56
  57void dmar_latency_disable(struct intel_iommu *iommu, enum latency_type type)
  58{
  59        struct latency_statistic *lstat = iommu->perf_statistic;
  60        unsigned long flags;
  61
  62        if (!dmar_latency_enabled(iommu, type))
  63                return;
  64
  65        spin_lock_irqsave(&latency_lock, flags);
  66        memset(&lstat[type], 0, sizeof(*lstat) * DMAR_LATENCY_NUM);
  67        spin_unlock_irqrestore(&latency_lock, flags);
  68}
  69
  70void dmar_latency_update(struct intel_iommu *iommu, enum latency_type type, u64 latency)
  71{
  72        struct latency_statistic *lstat = iommu->perf_statistic;
  73        unsigned long flags;
  74        u64 min, max;
  75
  76        if (!dmar_latency_enabled(iommu, type))
  77                return;
  78
  79        spin_lock_irqsave(&latency_lock, flags);
  80        if (latency < 100)
  81                lstat[type].counter[COUNTS_10e2]++;
  82        else if (latency < 1000)
  83                lstat[type].counter[COUNTS_10e3]++;
  84        else if (latency < 10000)
  85                lstat[type].counter[COUNTS_10e4]++;
  86        else if (latency < 100000)
  87                lstat[type].counter[COUNTS_10e5]++;
  88        else if (latency < 1000000)
  89                lstat[type].counter[COUNTS_10e6]++;
  90        else if (latency < 10000000)
  91                lstat[type].counter[COUNTS_10e7]++;
  92        else
  93                lstat[type].counter[COUNTS_10e8_plus]++;
  94
  95        min = lstat[type].counter[COUNTS_MIN];
  96        max = lstat[type].counter[COUNTS_MAX];
  97        lstat[type].counter[COUNTS_MIN] = min_t(u64, min, latency);
  98        lstat[type].counter[COUNTS_MAX] = max_t(u64, max, latency);
  99        lstat[type].counter[COUNTS_SUM] += latency;
 100        lstat[type].samples++;
 101        spin_unlock_irqrestore(&latency_lock, flags);
 102}
 103
 104static char *latency_counter_names[] = {
 105        "                  <0.1us",
 106        "   0.1us-1us", "    1us-10us", "  10us-100us",
 107        "   100us-1ms", "    1ms-10ms", "      >=10ms",
 108        "     min(us)", "     max(us)", " average(us)"
 109};
 110
 111static char *latency_type_names[] = {
 112        "   inv_iotlb", "  inv_devtlb", "     inv_iec",
 113        "     svm_prq"
 114};
 115
 116int dmar_latency_snapshot(struct intel_iommu *iommu, char *str, size_t size)
 117{
 118        struct latency_statistic *lstat = iommu->perf_statistic;
 119        unsigned long flags;
 120        int bytes = 0, i, j;
 121
 122        memset(str, 0, size);
 123
 124        for (i = 0; i < COUNTS_NUM; i++)
 125                bytes += snprintf(str + bytes, size - bytes,
 126                                  "%s", latency_counter_names[i]);
 127
 128        spin_lock_irqsave(&latency_lock, flags);
 129        for (i = 0; i < DMAR_LATENCY_NUM; i++) {
 130                if (!dmar_latency_enabled(iommu, i))
 131                        continue;
 132
 133                bytes += snprintf(str + bytes, size - bytes,
 134                                  "\n%s", latency_type_names[i]);
 135
 136                for (j = 0; j < COUNTS_NUM; j++) {
 137                        u64 val = lstat[i].counter[j];
 138
 139                        switch (j) {
 140                        case COUNTS_MIN:
 141                                if (val == UINT_MAX)
 142                                        val = 0;
 143                                else
 144                                        val = div_u64(val, 1000);
 145                                break;
 146                        case COUNTS_MAX:
 147                                val = div_u64(val, 1000);
 148                                break;
 149                        case COUNTS_SUM:
 150                                if (lstat[i].samples)
 151                                        val = div_u64(val, (lstat[i].samples * 1000));
 152                                else
 153                                        val = 0;
 154                                break;
 155                        default:
 156                                break;
 157                        }
 158
 159                        bytes += snprintf(str + bytes, size - bytes,
 160                                          "%12lld", val);
 161                }
 162        }
 163        spin_unlock_irqrestore(&latency_lock, flags);
 164
 165        return bytes;
 166}
 167