gator: Merge gator version 5.23.1
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / drivers / gator / gator_pmu.c
1 struct gator_cpu {
2         struct list_head list;
3         unsigned long cpuid;
4         unsigned long pmnc_counters;
5         /* Human readable name */
6         char core_name[MAXSIZE_CORE_NAME];
7         /* gatorfs event and Perf PMU name */
8         char pmnc_name[MAXSIZE_CORE_NAME];
9         /* compatible from Documentation/devicetree/bindings/arm/cpus.txt */
10         char dt_name[MAXSIZE_CORE_NAME];
11 };
12
13 struct uncore_pmu {
14         struct list_head list;
15         unsigned long pmnc_counters;
16         unsigned long has_cycles_counter;
17         /* Perf PMU name */
18         char pmnc_name[MAXSIZE_CORE_NAME];
19         /* gatorfs event name */
20         char core_name[MAXSIZE_CORE_NAME];
21 };
22
23 static LIST_HEAD(uncore_pmus);
24 static LIST_HEAD(gator_cpus);
25 static DEFINE_MUTEX(pmu_mutex);
26
27 static struct super_block *gator_sb;
28 static struct dentry *gator_events_dir;
29
30 static const struct gator_cpu *gator_find_cpu_by_cpuid(const u32 cpuid)
31 {
32         const struct gator_cpu *gator_cpu;
33
34         list_for_each_entry(gator_cpu, &gator_cpus, list) {
35                 if (gator_cpu->cpuid == cpuid)
36                         return gator_cpu;
37         }
38
39         return NULL;
40 }
41
42 static const char OLD_PMU_PREFIX[] = "ARMv7 Cortex-";
43 static const char NEW_PMU_PREFIX[] = "ARMv7_Cortex_";
44
45 __maybe_unused
46 static const struct gator_cpu *gator_find_cpu_by_pmu_name(const char *const name)
47 {
48         const struct gator_cpu *gator_cpu;
49
50         list_for_each_entry(gator_cpu, &gator_cpus, list) {
51                 if (gator_cpu->pmnc_name != NULL &&
52                     /* Do the names match exactly? */
53                     (strcasecmp(gator_cpu->pmnc_name, name) == 0 ||
54                      /* Do these names match but have the old vs new prefix? */
55                      ((strncasecmp(name, OLD_PMU_PREFIX, sizeof(OLD_PMU_PREFIX) - 1) == 0 &&
56                        strncasecmp(gator_cpu->pmnc_name, NEW_PMU_PREFIX, sizeof(NEW_PMU_PREFIX) - 1) == 0 &&
57                        strcasecmp(name + sizeof(OLD_PMU_PREFIX) - 1, gator_cpu->pmnc_name + sizeof(NEW_PMU_PREFIX) - 1) == 0))))
58                         return gator_cpu;
59         }
60
61         return NULL;
62 }
63
64 __maybe_unused
65 static const struct uncore_pmu *gator_find_uncore_pmu(const char *const name)
66 {
67         const struct uncore_pmu *uncore_pmu;
68
69         list_for_each_entry(uncore_pmu, &uncore_pmus, list) {
70                 if (uncore_pmu->pmnc_name != NULL && strcasecmp(uncore_pmu->pmnc_name, name) == 0)
71                         return uncore_pmu;
72         }
73
74         return NULL;
75 }
76
77 static bool gator_pmu_initialized;
78
79 static ssize_t gator_pmu_init_write(struct file *file, char const __user *buf, size_t count, loff_t *offset)
80 {
81         if (gator_pmu_initialized)
82                 return -EINVAL;
83         gator_pmu_initialized = true;
84         if (gator_events_perf_pmu_reread() != 0 ||
85                         gator_events_perf_pmu_create_files(gator_sb, gator_events_dir) != 0)
86                 return -EINVAL;
87         return count;
88 }
89
90 static const struct file_operations gator_pmu_init_fops = {
91         .write = gator_pmu_init_write,
92 };
93
94 static ssize_t gator_pmu_str_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset)
95 {
96         char *const val = file->private_data;
97
98         return simple_read_from_buffer(buf, count, offset, val, strlen(val));
99 }
100
101 static ssize_t gator_pmu_str_write_file(struct file *file, char const __user *buf, size_t count, loff_t *offset)
102 {
103         char *value = file->private_data;
104
105         if (*offset)
106                 return -EINVAL;
107
108         if (count >= MAXSIZE_CORE_NAME)
109                 return -EINVAL;
110         if (copy_from_user(value, buf, count))
111                 return -EFAULT;
112         value[count] = 0;
113         value = strstrip(value);
114
115         return count;
116 }
117
118 static const struct file_operations gator_pmu_str_fops = {
119         .read = gator_pmu_str_read_file,
120         .write = gator_pmu_str_write_file,
121         .open = default_open,
122 };
123
124 static int gator_pmu_create_str(struct super_block *sb, struct dentry *root, char const *name, char *const val)
125 {
126         struct dentry *d = __gatorfs_create_file(sb, root, name, &gator_pmu_str_fops, 0644);
127         if (!d)
128                 return -EFAULT;
129
130         d->d_inode->i_private = val;
131         return 0;
132 }
133
134 static ssize_t gator_pmu_export_write(struct file *file, char const __user *ubuf, size_t count, loff_t *offset)
135 {
136         struct dentry *dir;
137         struct dentry *parent;
138         char buf[MAXSIZE_CORE_NAME];
139         const char *str;
140
141         if (*offset)
142                 return -EINVAL;
143
144         if (count >= sizeof(buf))
145                 return -EINVAL;
146         if (copy_from_user(&buf, ubuf, count))
147                 return -EFAULT;
148         buf[count] = 0;
149         str = strstrip(buf);
150
151         parent = file->f_path.dentry->d_parent;
152         dir = gatorfs_mkdir(gator_sb, parent, buf);
153         if (!dir)
154                 return -EINVAL;
155
156         if (strcmp("pmu", parent->d_name.name) == 0) {
157                 struct gator_cpu *gator_cpu;
158
159                 gator_cpu = kmalloc(sizeof(*gator_cpu), GFP_KERNEL);
160                 if (gator_cpu == NULL)
161                         return -ENOMEM;
162                 memset(gator_cpu, 0, sizeof(*gator_cpu));
163
164                 gatorfs_create_ulong(gator_sb, dir, "cpuid", &gator_cpu->cpuid);
165                 gator_pmu_create_str(gator_sb, dir, "core_name", gator_cpu->core_name);
166                 strcpy(gator_cpu->pmnc_name, str);
167                 gator_pmu_create_str(gator_sb, dir, "dt_name", gator_cpu->dt_name);
168                 gatorfs_create_ulong(gator_sb, dir, "pmnc_counters", &gator_cpu->pmnc_counters);
169
170                 mutex_lock(&pmu_mutex);
171                 list_add_tail(&gator_cpu->list, &gator_cpus); /* mutex */
172                 mutex_unlock(&pmu_mutex);
173         } else {
174                 struct uncore_pmu *uncore_pmu;
175
176                 uncore_pmu = kmalloc(sizeof(*uncore_pmu), GFP_KERNEL);
177                 if (uncore_pmu == NULL)
178                         return -ENOMEM;
179                 memset(uncore_pmu, 0, sizeof(*uncore_pmu));
180
181                 strcpy(uncore_pmu->pmnc_name, str);
182                 gator_pmu_create_str(gator_sb, dir, "core_name", uncore_pmu->core_name);
183                 gatorfs_create_ulong(gator_sb, dir, "pmnc_counters", &uncore_pmu->pmnc_counters);
184                 gatorfs_create_ulong(gator_sb, dir, "has_cycles_counter", &uncore_pmu->has_cycles_counter);
185
186                 mutex_lock(&pmu_mutex);
187                 list_add_tail(&uncore_pmu->list, &uncore_pmus); /* mutex */
188                 mutex_unlock(&pmu_mutex);
189         }
190
191         return count;
192 }
193
194 static const struct file_operations export_fops = {
195         .write = gator_pmu_export_write,
196 };
197
198 static int gator_pmu_create_files(struct super_block *sb, struct dentry *root, struct dentry *events)
199 {
200         struct dentry *dir;
201
202         gator_sb = sb;
203         gator_events_dir = events;
204
205         gatorfs_create_file(sb, root, "pmu_init", &gator_pmu_init_fops);
206
207         dir = gatorfs_mkdir(sb, root, "pmu");
208         if (!dir)
209                 return -1;
210
211         gatorfs_create_file(sb, dir, "export", &export_fops);
212
213         dir = gatorfs_mkdir(sb, root, "uncore_pmu");
214         if (!dir)
215                 return -1;
216
217         gatorfs_create_file(sb, dir, "export", &export_fops);
218
219         return 0;
220 }
221
222 static void gator_pmu_exit(void)
223 {
224         mutex_lock(&pmu_mutex);
225         {
226                 struct gator_cpu *gator_cpu;
227                 struct gator_cpu *next;
228
229                 list_for_each_entry_safe(gator_cpu, next, &gator_cpus, list) {
230                         kfree(gator_cpu);
231                 }
232         }
233         {
234                 struct uncore_pmu *uncore_pmu;
235                 struct uncore_pmu *next;
236
237                 list_for_each_entry_safe(uncore_pmu, next, &uncore_pmus, list) {
238                         kfree(uncore_pmu);
239                 }
240         }
241         mutex_unlock(&pmu_mutex);
242 }