iommu/vt-d: Expose latency monitor data through debugfs
A debugfs interface /sys/kernel/debug/iommu/intel/dmar_perf_latency is created to control and show counts of execution time ranges for various types per DMAR. The interface may help debug any potential performance issue. By default, the interface is disabled. Possible write value of /sys/kernel/debug/iommu/intel/dmar_perf_latency 0 - disable sampling all latency data 1 - enable sampling IOTLB invalidation latency data 2 - enable sampling devTLB invalidation latency data 3 - enable sampling intr entry cache invalidation latency data 4 - enable sampling prq handling latency data Read /sys/kernel/debug/iommu/intel/dmar_perf_latency gives a snapshot of sampling result of all enabled monitors. Signed-off-by: Fenghua Yu <fenghua.yu@intel.com> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com> Link: https://lore.kernel.org/r/20210520031531.712333-1-baolu.lu@linux.intel.com Link: https://lore.kernel.org/r/20210610020115.1637656-15-baolu.lu@linux.intel.com Signed-off-by: Joerg Roedel <jroedel@suse.de>
This commit is contained in:
Родитель
55ee5e67a5
Коммит
456bb0b97f
|
@ -28,6 +28,7 @@ config INTEL_IOMMU
|
|||
config INTEL_IOMMU_DEBUGFS
|
||||
bool "Export Intel IOMMU internals in Debugfs"
|
||||
depends on INTEL_IOMMU && IOMMU_DEBUGFS
|
||||
select DMAR_PERF
|
||||
help
|
||||
!!!WARNING!!!
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <asm/irq_remapping.h>
|
||||
|
||||
#include "pasid.h"
|
||||
#include "perf.h"
|
||||
|
||||
struct tbl_walk {
|
||||
u16 bus;
|
||||
|
@ -31,6 +32,9 @@ struct iommu_regset {
|
|||
const char *regs;
|
||||
};
|
||||
|
||||
#define DEBUG_BUFFER_SIZE 1024
|
||||
static char debug_buf[DEBUG_BUFFER_SIZE];
|
||||
|
||||
#define IOMMU_REGSET_ENTRY(_reg_) \
|
||||
{ DMAR_##_reg_##_REG, __stringify(_reg_) }
|
||||
|
||||
|
@ -538,6 +542,111 @@ static int ir_translation_struct_show(struct seq_file *m, void *unused)
|
|||
DEFINE_SHOW_ATTRIBUTE(ir_translation_struct);
|
||||
#endif
|
||||
|
||||
static void latency_show_one(struct seq_file *m, struct intel_iommu *iommu,
|
||||
struct dmar_drhd_unit *drhd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
seq_printf(m, "IOMMU: %s Register Base Address: %llx\n",
|
||||
iommu->name, drhd->reg_base_addr);
|
||||
|
||||
ret = dmar_latency_snapshot(iommu, debug_buf, DEBUG_BUFFER_SIZE);
|
||||
if (ret < 0)
|
||||
seq_puts(m, "Failed to get latency snapshot");
|
||||
else
|
||||
seq_puts(m, debug_buf);
|
||||
seq_puts(m, "\n");
|
||||
}
|
||||
|
||||
static int latency_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct dmar_drhd_unit *drhd;
|
||||
struct intel_iommu *iommu;
|
||||
|
||||
rcu_read_lock();
|
||||
for_each_active_iommu(iommu, drhd)
|
||||
latency_show_one(m, iommu, drhd);
|
||||
rcu_read_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dmar_perf_latency_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return single_open(filp, latency_show, NULL);
|
||||
}
|
||||
|
||||
static ssize_t dmar_perf_latency_write(struct file *filp,
|
||||
const char __user *ubuf,
|
||||
size_t cnt, loff_t *ppos)
|
||||
{
|
||||
struct dmar_drhd_unit *drhd;
|
||||
struct intel_iommu *iommu;
|
||||
int counting;
|
||||
char buf[64];
|
||||
|
||||
if (cnt > 63)
|
||||
cnt = 63;
|
||||
|
||||
if (copy_from_user(&buf, ubuf, cnt))
|
||||
return -EFAULT;
|
||||
|
||||
buf[cnt] = 0;
|
||||
|
||||
if (kstrtoint(buf, 0, &counting))
|
||||
return -EINVAL;
|
||||
|
||||
switch (counting) {
|
||||
case 0:
|
||||
rcu_read_lock();
|
||||
for_each_active_iommu(iommu, drhd) {
|
||||
dmar_latency_disable(iommu, DMAR_LATENCY_INV_IOTLB);
|
||||
dmar_latency_disable(iommu, DMAR_LATENCY_INV_DEVTLB);
|
||||
dmar_latency_disable(iommu, DMAR_LATENCY_INV_IEC);
|
||||
dmar_latency_disable(iommu, DMAR_LATENCY_PRQ);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
break;
|
||||
case 1:
|
||||
rcu_read_lock();
|
||||
for_each_active_iommu(iommu, drhd)
|
||||
dmar_latency_enable(iommu, DMAR_LATENCY_INV_IOTLB);
|
||||
rcu_read_unlock();
|
||||
break;
|
||||
case 2:
|
||||
rcu_read_lock();
|
||||
for_each_active_iommu(iommu, drhd)
|
||||
dmar_latency_enable(iommu, DMAR_LATENCY_INV_DEVTLB);
|
||||
rcu_read_unlock();
|
||||
break;
|
||||
case 3:
|
||||
rcu_read_lock();
|
||||
for_each_active_iommu(iommu, drhd)
|
||||
dmar_latency_enable(iommu, DMAR_LATENCY_INV_IEC);
|
||||
rcu_read_unlock();
|
||||
break;
|
||||
case 4:
|
||||
rcu_read_lock();
|
||||
for_each_active_iommu(iommu, drhd)
|
||||
dmar_latency_enable(iommu, DMAR_LATENCY_PRQ);
|
||||
rcu_read_unlock();
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*ppos += cnt;
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static const struct file_operations dmar_perf_latency_fops = {
|
||||
.open = dmar_perf_latency_open,
|
||||
.write = dmar_perf_latency_write,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
void __init intel_iommu_debugfs_init(void)
|
||||
{
|
||||
struct dentry *intel_iommu_debug = debugfs_create_dir("intel",
|
||||
|
@ -556,4 +665,6 @@ void __init intel_iommu_debugfs_init(void)
|
|||
debugfs_create_file("ir_translation_struct", 0444, intel_iommu_debug,
|
||||
NULL, &ir_translation_struct_fops);
|
||||
#endif
|
||||
debugfs_create_file("dmar_perf_latency", 0644, intel_iommu_debug,
|
||||
NULL, &dmar_perf_latency_fops);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче