0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/spinlock.h>
0012
0013 #include "iommu.h"
0014 #include "perf.h"
0015
0016 static DEFINE_SPINLOCK(latency_lock);
0017
0018 bool dmar_latency_enabled(struct intel_iommu *iommu, enum latency_type type)
0019 {
0020 struct latency_statistic *lstat = iommu->perf_statistic;
0021
0022 return lstat && lstat[type].enabled;
0023 }
0024
0025 int dmar_latency_enable(struct intel_iommu *iommu, enum latency_type type)
0026 {
0027 struct latency_statistic *lstat;
0028 unsigned long flags;
0029 int ret = -EBUSY;
0030
0031 if (dmar_latency_enabled(iommu, type))
0032 return 0;
0033
0034 spin_lock_irqsave(&latency_lock, flags);
0035 if (!iommu->perf_statistic) {
0036 iommu->perf_statistic = kzalloc(sizeof(*lstat) * DMAR_LATENCY_NUM,
0037 GFP_ATOMIC);
0038 if (!iommu->perf_statistic) {
0039 ret = -ENOMEM;
0040 goto unlock_out;
0041 }
0042 }
0043
0044 lstat = iommu->perf_statistic;
0045
0046 if (!lstat[type].enabled) {
0047 lstat[type].enabled = true;
0048 lstat[type].counter[COUNTS_MIN] = UINT_MAX;
0049 ret = 0;
0050 }
0051 unlock_out:
0052 spin_unlock_irqrestore(&latency_lock, flags);
0053
0054 return ret;
0055 }
0056
0057 void dmar_latency_disable(struct intel_iommu *iommu, enum latency_type type)
0058 {
0059 struct latency_statistic *lstat = iommu->perf_statistic;
0060 unsigned long flags;
0061
0062 if (!dmar_latency_enabled(iommu, type))
0063 return;
0064
0065 spin_lock_irqsave(&latency_lock, flags);
0066 memset(&lstat[type], 0, sizeof(*lstat) * DMAR_LATENCY_NUM);
0067 spin_unlock_irqrestore(&latency_lock, flags);
0068 }
0069
0070 void dmar_latency_update(struct intel_iommu *iommu, enum latency_type type, u64 latency)
0071 {
0072 struct latency_statistic *lstat = iommu->perf_statistic;
0073 unsigned long flags;
0074 u64 min, max;
0075
0076 if (!dmar_latency_enabled(iommu, type))
0077 return;
0078
0079 spin_lock_irqsave(&latency_lock, flags);
0080 if (latency < 100)
0081 lstat[type].counter[COUNTS_10e2]++;
0082 else if (latency < 1000)
0083 lstat[type].counter[COUNTS_10e3]++;
0084 else if (latency < 10000)
0085 lstat[type].counter[COUNTS_10e4]++;
0086 else if (latency < 100000)
0087 lstat[type].counter[COUNTS_10e5]++;
0088 else if (latency < 1000000)
0089 lstat[type].counter[COUNTS_10e6]++;
0090 else if (latency < 10000000)
0091 lstat[type].counter[COUNTS_10e7]++;
0092 else
0093 lstat[type].counter[COUNTS_10e8_plus]++;
0094
0095 min = lstat[type].counter[COUNTS_MIN];
0096 max = lstat[type].counter[COUNTS_MAX];
0097 lstat[type].counter[COUNTS_MIN] = min_t(u64, min, latency);
0098 lstat[type].counter[COUNTS_MAX] = max_t(u64, max, latency);
0099 lstat[type].counter[COUNTS_SUM] += latency;
0100 lstat[type].samples++;
0101 spin_unlock_irqrestore(&latency_lock, flags);
0102 }
0103
0104 static char *latency_counter_names[] = {
0105 " <0.1us",
0106 " 0.1us-1us", " 1us-10us", " 10us-100us",
0107 " 100us-1ms", " 1ms-10ms", " >=10ms",
0108 " min(us)", " max(us)", " average(us)"
0109 };
0110
0111 static char *latency_type_names[] = {
0112 " inv_iotlb", " inv_devtlb", " inv_iec",
0113 " svm_prq"
0114 };
0115
0116 int dmar_latency_snapshot(struct intel_iommu *iommu, char *str, size_t size)
0117 {
0118 struct latency_statistic *lstat = iommu->perf_statistic;
0119 unsigned long flags;
0120 int bytes = 0, i, j;
0121
0122 memset(str, 0, size);
0123
0124 for (i = 0; i < COUNTS_NUM; i++)
0125 bytes += snprintf(str + bytes, size - bytes,
0126 "%s", latency_counter_names[i]);
0127
0128 spin_lock_irqsave(&latency_lock, flags);
0129 for (i = 0; i < DMAR_LATENCY_NUM; i++) {
0130 if (!dmar_latency_enabled(iommu, i))
0131 continue;
0132
0133 bytes += snprintf(str + bytes, size - bytes,
0134 "\n%s", latency_type_names[i]);
0135
0136 for (j = 0; j < COUNTS_NUM; j++) {
0137 u64 val = lstat[i].counter[j];
0138
0139 switch (j) {
0140 case COUNTS_MIN:
0141 if (val == UINT_MAX)
0142 val = 0;
0143 else
0144 val = div_u64(val, 1000);
0145 break;
0146 case COUNTS_MAX:
0147 val = div_u64(val, 1000);
0148 break;
0149 case COUNTS_SUM:
0150 if (lstat[i].samples)
0151 val = div_u64(val, (lstat[i].samples * 1000));
0152 else
0153 val = 0;
0154 break;
0155 default:
0156 break;
0157 }
0158
0159 bytes += snprintf(str + bytes, size - bytes,
0160 "%12lld", val);
0161 }
0162 }
0163 spin_unlock_irqrestore(&latency_lock, flags);
0164
0165 return bytes;
0166 }