Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.9.
  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
 13#include "iommu.h"
 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}