aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu
diff options
context:
space:
mode:
authorHiroshi Doyu <hdoyu@nvidia.com>2012-08-02 04:46:40 -0400
committerJoerg Roedel <joerg.roedel@amd.com>2012-08-03 11:53:55 -0400
commit39abf8aa7dfad0badb4741373023cda369aacc8e (patch)
treeb1e845941ab5a29f4907922a6406d2db13bc38e5 /drivers/iommu
parent0d7614f09c1ebdbaa1599a5aba7593f147bf96ee (diff)
iommu/tegra: smmu: debugfs for TLB/PTC statistics
Add debugfs entries to collect TLB/PTC statistics. $ echo "reset" > /sys/kernel/debug/smmu/mc/{tlb,ptc} $ echo "on" > /sys/kernel/debug/smmu/mc/{tlb,ptc} $ echo "off" > /sys/kernel/debug/smmu/mc/{tlb,ptc} $ cat /sys/kernel/debug/smmu/mc/{tlb,ptc} hit:0014910c miss:00014d22 The above format is: hit:<HIT count><SPC>miss:<MISS count><SPC><CR+LF> fscanf(fp, "hit:%lx miss:%lx", &hit, &miss); Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com> Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Diffstat (limited to 'drivers/iommu')
-rw-r--r--drivers/iommu/tegra-smmu.c202
1 files changed, 190 insertions, 12 deletions
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 4ba325ab6262..95b4698abd3e 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -32,6 +32,8 @@
32#include <linux/io.h> 32#include <linux/io.h>
33#include <linux/of.h> 33#include <linux/of.h>
34#include <linux/of_iommu.h> 34#include <linux/of_iommu.h>
35#include <linux/debugfs.h>
36#include <linux/seq_file.h>
35 37
36#include <asm/page.h> 38#include <asm/page.h>
37#include <asm/cacheflush.h> 39#include <asm/cacheflush.h>
@@ -47,16 +49,29 @@
47#define SMMU_CONFIG_DISABLE 0 49#define SMMU_CONFIG_DISABLE 0
48#define SMMU_CONFIG_ENABLE 1 50#define SMMU_CONFIG_ENABLE 1
49 51
50#define SMMU_TLB_CONFIG 0x14 52/* REVISIT: To support multiple MCs */
51#define SMMU_TLB_CONFIG_STATS__MASK (1 << 31) 53enum {
52#define SMMU_TLB_CONFIG_STATS__ENABLE (1 << 31) 54 _MC = 0,
55};
56
57enum {
58 _TLB = 0,
59 _PTC,
60};
61
62#define SMMU_CACHE_CONFIG_BASE 0x14
63#define __SMMU_CACHE_CONFIG(mc, cache) (SMMU_CACHE_CONFIG_BASE + 4 * cache)
64#define SMMU_CACHE_CONFIG(cache) __SMMU_CACHE_CONFIG(_MC, cache)
65
66#define SMMU_CACHE_CONFIG_STATS_SHIFT 31
67#define SMMU_CACHE_CONFIG_STATS_ENABLE (1 << SMMU_CACHE_CONFIG_STATS_SHIFT)
68#define SMMU_CACHE_CONFIG_STATS_TEST_SHIFT 30
69#define SMMU_CACHE_CONFIG_STATS_TEST (1 << SMMU_CACHE_CONFIG_STATS_TEST_SHIFT)
70
53#define SMMU_TLB_CONFIG_HIT_UNDER_MISS__ENABLE (1 << 29) 71#define SMMU_TLB_CONFIG_HIT_UNDER_MISS__ENABLE (1 << 29)
54#define SMMU_TLB_CONFIG_ACTIVE_LINES__VALUE 0x10 72#define SMMU_TLB_CONFIG_ACTIVE_LINES__VALUE 0x10
55#define SMMU_TLB_CONFIG_RESET_VAL 0x20000010 73#define SMMU_TLB_CONFIG_RESET_VAL 0x20000010
56 74
57#define SMMU_PTC_CONFIG 0x18
58#define SMMU_PTC_CONFIG_STATS__MASK (1 << 31)
59#define SMMU_PTC_CONFIG_STATS__ENABLE (1 << 31)
60#define SMMU_PTC_CONFIG_CACHE__ENABLE (1 << 29) 75#define SMMU_PTC_CONFIG_CACHE__ENABLE (1 << 29)
61#define SMMU_PTC_CONFIG_INDEX_MAP__PATTERN 0x3f 76#define SMMU_PTC_CONFIG_INDEX_MAP__PATTERN 0x3f
62#define SMMU_PTC_CONFIG_RESET_VAL 0x2000003f 77#define SMMU_PTC_CONFIG_RESET_VAL 0x2000003f
@@ -86,10 +101,10 @@
86 101
87#define SMMU_ASID_SECURITY 0x38 102#define SMMU_ASID_SECURITY 0x38
88 103
89#define SMMU_STATS_TLB_HIT_COUNT 0x1f0 104#define SMMU_STATS_CACHE_COUNT_BASE 0x1f0
90#define SMMU_STATS_TLB_MISS_COUNT 0x1f4 105
91#define SMMU_STATS_PTC_HIT_COUNT 0x1f8 106#define SMMU_STATS_CACHE_COUNT(mc, cache, hitmiss) \
92#define SMMU_STATS_PTC_MISS_COUNT 0x1fc 107 (SMMU_STATS_CACHE_COUNT_BASE + 8 * cache + 4 * hitmiss)
93 108
94#define SMMU_TRANSLATION_ENABLE_0 0x228 109#define SMMU_TRANSLATION_ENABLE_0 0x228
95#define SMMU_TRANSLATION_ENABLE_1 0x22c 110#define SMMU_TRANSLATION_ENABLE_1 0x22c
@@ -251,6 +266,8 @@ struct smmu_device {
251 unsigned long translation_enable_2; 266 unsigned long translation_enable_2;
252 unsigned long asid_security; 267 unsigned long asid_security;
253 268
269 struct dentry *debugfs_root;
270
254 struct device_node *ahb; 271 struct device_node *ahb;
255 272
256 int num_as; 273 int num_as;
@@ -412,8 +429,8 @@ static int smmu_setup_regs(struct smmu_device *smmu)
412 smmu_write(smmu, smmu->translation_enable_1, SMMU_TRANSLATION_ENABLE_1); 429 smmu_write(smmu, smmu->translation_enable_1, SMMU_TRANSLATION_ENABLE_1);
413 smmu_write(smmu, smmu->translation_enable_2, SMMU_TRANSLATION_ENABLE_2); 430 smmu_write(smmu, smmu->translation_enable_2, SMMU_TRANSLATION_ENABLE_2);
414 smmu_write(smmu, smmu->asid_security, SMMU_ASID_SECURITY); 431 smmu_write(smmu, smmu->asid_security, SMMU_ASID_SECURITY);
415 smmu_write(smmu, SMMU_TLB_CONFIG_RESET_VAL, SMMU_TLB_CONFIG); 432 smmu_write(smmu, SMMU_TLB_CONFIG_RESET_VAL, SMMU_CACHE_CONFIG(_TLB));
416 smmu_write(smmu, SMMU_PTC_CONFIG_RESET_VAL, SMMU_PTC_CONFIG); 433 smmu_write(smmu, SMMU_PTC_CONFIG_RESET_VAL, SMMU_CACHE_CONFIG(_PTC));
417 434
418 smmu_flush_regs(smmu, 1); 435 smmu_flush_regs(smmu, 1);
419 436
@@ -892,6 +909,164 @@ static struct iommu_ops smmu_iommu_ops = {
892 .pgsize_bitmap = SMMU_IOMMU_PGSIZES, 909 .pgsize_bitmap = SMMU_IOMMU_PGSIZES,
893}; 910};
894 911
912/* Should be in the order of enum */
913static const char * const smmu_debugfs_mc[] = { "mc", };
914static const char * const smmu_debugfs_cache[] = { "tlb", "ptc", };
915
916static ssize_t smmu_debugfs_stats_write(struct file *file,
917 const char __user *buffer,
918 size_t count, loff_t *pos)
919{
920 struct smmu_device *smmu;
921 struct dentry *dent;
922 int i, cache, mc;
923 enum {
924 _OFF = 0,
925 _ON,
926 _RESET,
927 };
928 const char * const command[] = {
929 [_OFF] = "off",
930 [_ON] = "on",
931 [_RESET] = "reset",
932 };
933 char str[] = "reset";
934 u32 val;
935 size_t offs;
936
937 count = min_t(size_t, count, sizeof(str));
938 if (copy_from_user(str, buffer, count))
939 return -EINVAL;
940
941 for (i = 0; i < ARRAY_SIZE(command); i++)
942 if (strncmp(str, command[i],
943 strlen(command[i])) == 0)
944 break;
945
946 if (i == ARRAY_SIZE(command))
947 return -EINVAL;
948
949 dent = file->f_dentry;
950 cache = (int)dent->d_inode->i_private;
951 mc = (int)dent->d_parent->d_inode->i_private;
952 smmu = dent->d_parent->d_parent->d_inode->i_private;
953
954 offs = SMMU_CACHE_CONFIG(cache);
955 val = smmu_read(smmu, offs);
956 switch (i) {
957 case _OFF:
958 val &= ~SMMU_CACHE_CONFIG_STATS_ENABLE;
959 val &= ~SMMU_CACHE_CONFIG_STATS_TEST;
960 smmu_write(smmu, val, offs);
961 break;
962 case _ON:
963 val |= SMMU_CACHE_CONFIG_STATS_ENABLE;
964 val &= ~SMMU_CACHE_CONFIG_STATS_TEST;
965 smmu_write(smmu, val, offs);
966 break;
967 case _RESET:
968 val |= SMMU_CACHE_CONFIG_STATS_TEST;
969 smmu_write(smmu, val, offs);
970 val &= ~SMMU_CACHE_CONFIG_STATS_TEST;
971 smmu_write(smmu, val, offs);
972 break;
973 default:
974 BUG();
975 break;
976 }
977
978 dev_dbg(smmu->dev, "%s() %08x, %08x @%08x\n", __func__,
979 val, smmu_read(smmu, offs), offs);
980
981 return count;
982}
983
984static int smmu_debugfs_stats_show(struct seq_file *s, void *v)
985{
986 struct smmu_device *smmu;
987 struct dentry *dent;
988 int i, cache, mc;
989 const char * const stats[] = { "hit", "miss", };
990
991 dent = d_find_alias(s->private);
992 cache = (int)dent->d_inode->i_private;
993 mc = (int)dent->d_parent->d_inode->i_private;
994 smmu = dent->d_parent->d_parent->d_inode->i_private;
995
996 for (i = 0; i < ARRAY_SIZE(stats); i++) {
997 u32 val;
998 size_t offs;
999
1000 offs = SMMU_STATS_CACHE_COUNT(mc, cache, i);
1001 val = smmu_read(smmu, offs);
1002 seq_printf(s, "%s:%08x ", stats[i], val);
1003
1004 dev_dbg(smmu->dev, "%s() %s %08x @%08x\n", __func__,
1005 stats[i], val, offs);
1006 }
1007 seq_printf(s, "\n");
1008
1009 return 0;
1010}
1011
1012static int smmu_debugfs_stats_open(struct inode *inode, struct file *file)
1013{
1014 return single_open(file, smmu_debugfs_stats_show, inode);
1015}
1016
1017static const struct file_operations smmu_debugfs_stats_fops = {
1018 .open = smmu_debugfs_stats_open,
1019 .read = seq_read,
1020 .llseek = seq_lseek,
1021 .release = single_release,
1022 .write = smmu_debugfs_stats_write,
1023};
1024
1025static void smmu_debugfs_delete(struct smmu_device *smmu)
1026{
1027 debugfs_remove_recursive(smmu->debugfs_root);
1028}
1029
1030static void smmu_debugfs_create(struct smmu_device *smmu)
1031{
1032 int i;
1033 struct dentry *root;
1034
1035 root = debugfs_create_file(dev_name(smmu->dev),
1036 S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
1037 NULL, smmu, NULL);
1038 if (!root)
1039 goto err_out;
1040 smmu->debugfs_root = root;
1041
1042 for (i = 0; i < ARRAY_SIZE(smmu_debugfs_mc); i++) {
1043 int j;
1044 struct dentry *mc;
1045
1046 mc = debugfs_create_file(smmu_debugfs_mc[i],
1047 S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
1048 root, (void *)i, NULL);
1049 if (!mc)
1050 goto err_out;
1051
1052 for (j = 0; j < ARRAY_SIZE(smmu_debugfs_cache); j++) {
1053 struct dentry *cache;
1054
1055 cache = debugfs_create_file(smmu_debugfs_cache[j],
1056 S_IWUGO | S_IRUGO, mc,
1057 (void *)j,
1058 &smmu_debugfs_stats_fops);
1059 if (!cache)
1060 goto err_out;
1061 }
1062 }
1063
1064 return;
1065
1066err_out:
1067 smmu_debugfs_delete(smmu);
1068}
1069
895static int tegra_smmu_suspend(struct device *dev) 1070static int tegra_smmu_suspend(struct device *dev)
896{ 1071{
897 struct smmu_device *smmu = dev_get_drvdata(dev); 1072 struct smmu_device *smmu = dev_get_drvdata(dev);
@@ -996,6 +1171,7 @@ static int tegra_smmu_probe(struct platform_device *pdev)
996 if (!smmu->avp_vector_page) 1171 if (!smmu->avp_vector_page)
997 return -ENOMEM; 1172 return -ENOMEM;
998 1173
1174 smmu_debugfs_create(smmu);
999 smmu_handle = smmu; 1175 smmu_handle = smmu;
1000 return 0; 1176 return 0;
1001} 1177}
@@ -1005,6 +1181,8 @@ static int tegra_smmu_remove(struct platform_device *pdev)
1005 struct smmu_device *smmu = platform_get_drvdata(pdev); 1181 struct smmu_device *smmu = platform_get_drvdata(pdev);
1006 int i; 1182 int i;
1007 1183
1184 smmu_debugfs_delete(smmu);
1185
1008 smmu_write(smmu, SMMU_CONFIG_DISABLE, SMMU_CONFIG); 1186 smmu_write(smmu, SMMU_CONFIG_DISABLE, SMMU_CONFIG);
1009 for (i = 0; i < smmu->num_as; i++) 1187 for (i = 0; i < smmu->num_as; i++)
1010 free_pdir(&smmu->as[i]); 1188 free_pdir(&smmu->as[i]);