]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/staging/ccree/ssi_sysfs.c
Merge branches 'for-4.13/multitouch', 'for-4.13/retrode', 'for-4.13/transport-open...
[mirror_ubuntu-artful-kernel.git] / drivers / staging / ccree / ssi_sysfs.c
CommitLineData
abefd674
GBY
1/*
2 * Copyright (C) 2012-2017 ARM Limited or its affiliates.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <linux/kernel.h>
18#include "ssi_config.h"
19#include "ssi_driver.h"
20#include "cc_crypto_ctx.h"
21#include "ssi_sysfs.h"
22
23#ifdef ENABLE_CC_SYSFS
24
25static struct ssi_drvdata *sys_get_drvdata(void);
26
27#ifdef CC_CYCLE_COUNT
28
29#include <asm/timex.h>
30
31struct stat_item {
32 unsigned int min;
33 unsigned int max;
34 cycles_t sum;
35 unsigned int count;
36};
37
38struct stat_name {
39 const char *op_type_name;
40 const char *stat_phase_name[MAX_STAT_PHASES];
41};
42
43static struct stat_name stat_name_db[MAX_STAT_OP_TYPES] =
44{
45 {
46 /* STAT_OP_TYPE_NULL */
47 .op_type_name = "NULL",
48 .stat_phase_name = {NULL},
49 },
50 {
51 .op_type_name = "Encode",
52 .stat_phase_name[STAT_PHASE_0] = "Init and sanity checks",
53 .stat_phase_name[STAT_PHASE_1] = "Map buffers",
54 .stat_phase_name[STAT_PHASE_2] = "Create sequence",
55 .stat_phase_name[STAT_PHASE_3] = "Send Request",
56 .stat_phase_name[STAT_PHASE_4] = "HW-Q push",
57 .stat_phase_name[STAT_PHASE_5] = "Sequence completion",
58 .stat_phase_name[STAT_PHASE_6] = "HW cycles",
59 },
60 { .op_type_name = "Decode",
61 .stat_phase_name[STAT_PHASE_0] = "Init and sanity checks",
62 .stat_phase_name[STAT_PHASE_1] = "Map buffers",
63 .stat_phase_name[STAT_PHASE_2] = "Create sequence",
64 .stat_phase_name[STAT_PHASE_3] = "Send Request",
65 .stat_phase_name[STAT_PHASE_4] = "HW-Q push",
66 .stat_phase_name[STAT_PHASE_5] = "Sequence completion",
67 .stat_phase_name[STAT_PHASE_6] = "HW cycles",
68 },
69 { .op_type_name = "Setkey",
70 .stat_phase_name[STAT_PHASE_0] = "Init and sanity checks",
71 .stat_phase_name[STAT_PHASE_1] = "Copy key to ctx",
72 .stat_phase_name[STAT_PHASE_2] = "Create sequence",
73 .stat_phase_name[STAT_PHASE_3] = "Send Request",
74 .stat_phase_name[STAT_PHASE_4] = "HW-Q push",
75 .stat_phase_name[STAT_PHASE_5] = "Sequence completion",
76 .stat_phase_name[STAT_PHASE_6] = "HW cycles",
77 },
78 {
79 .op_type_name = "Generic",
80 .stat_phase_name[STAT_PHASE_0] = "Interrupt",
81 .stat_phase_name[STAT_PHASE_1] = "ISR-to-Tasklet",
82 .stat_phase_name[STAT_PHASE_2] = "Tasklet start-to-end",
83 .stat_phase_name[STAT_PHASE_3] = "Tasklet:user_cb()",
84 .stat_phase_name[STAT_PHASE_4] = "Tasklet:dx_X_complete() - w/o X_complete()",
85 .stat_phase_name[STAT_PHASE_5] = "",
86 .stat_phase_name[STAT_PHASE_6] = "HW cycles",
87 }
88};
89
90/*
91 * Structure used to create a directory
92 * and its attributes in sysfs.
93 */
94struct sys_dir {
95 struct kobject *sys_dir_kobj;
96 struct attribute_group sys_dir_attr_group;
97 struct attribute **sys_dir_attr_list;
98 uint32_t num_of_attrs;
99 struct ssi_drvdata *drvdata; /* Associated driver context */
100};
101
102/* top level directory structures */
103struct sys_dir sys_top_dir;
104
105static DEFINE_SPINLOCK(stat_lock);
106
107/* List of DBs */
108static struct stat_item stat_host_db[MAX_STAT_OP_TYPES][MAX_STAT_PHASES];
109static struct stat_item stat_cc_db[MAX_STAT_OP_TYPES][MAX_STAT_PHASES];
110
111
112static void init_db(struct stat_item item[MAX_STAT_OP_TYPES][MAX_STAT_PHASES])
113{
114 unsigned int i, j;
115
116 /* Clear db */
117 for (i=0; i<MAX_STAT_OP_TYPES; i++) {
118 for (j=0; j<MAX_STAT_PHASES; j++) {
119 item[i][j].min = 0xFFFFFFFF;
120 item[i][j].max = 0;
121 item[i][j].sum = 0;
122 item[i][j].count = 0;
123 }
124 }
125}
126
127static void update_db(struct stat_item *item, unsigned int result)
128{
129 item->count++;
130 item->sum += result;
131 if (result < item->min)
132 item->min = result;
133 if (result > item->max )
134 item->max = result;
135}
136
137static void display_db(struct stat_item item[MAX_STAT_OP_TYPES][MAX_STAT_PHASES])
138{
139 unsigned int i, j;
140 uint64_t avg;
141
142 for (i=STAT_OP_TYPE_ENCODE; i<MAX_STAT_OP_TYPES; i++) {
143 for (j=0; j<MAX_STAT_PHASES; j++) {
144 if (item[i][j].count > 0) {
145 avg = (uint64_t)item[i][j].sum;
146 do_div(avg, item[i][j].count);
147 SSI_LOG_ERR("%s, %s: min=%d avg=%d max=%d sum=%lld count=%d\n",
148 stat_name_db[i].op_type_name, stat_name_db[i].stat_phase_name[j],
149 item[i][j].min, (int)avg, item[i][j].max, (long long)item[i][j].sum, item[i][j].count);
150 }
151 }
152 }
153}
154
155
156/**************************************
157 * Attributes show functions section *
158 **************************************/
159
160static ssize_t ssi_sys_stats_host_db_clear(struct kobject *kobj,
161 struct kobj_attribute *attr, const char *buf, size_t count)
162{
163 init_db(stat_host_db);
164 return count;
165}
166
167static ssize_t ssi_sys_stats_cc_db_clear(struct kobject *kobj,
168 struct kobj_attribute *attr, const char *buf, size_t count)
169{
170 init_db(stat_cc_db);
171 return count;
172}
173
174static ssize_t ssi_sys_stat_host_db_show(struct kobject *kobj,
175 struct kobj_attribute *attr, char *buf)
176{
177 int i, j ;
178 char line[512];
179 uint32_t min_cyc, max_cyc;
180 uint64_t avg;
181 ssize_t buf_len, tmp_len=0;
182
183 buf_len = scnprintf(buf,PAGE_SIZE,
184 "phase\t\t\t\t\t\t\tmin[cy]\tavg[cy]\tmax[cy]\t#samples\n");
185 if ( buf_len <0 )/* scnprintf shouldn't return negative value according to its implementation*/
186 return buf_len;
187 for (i=STAT_OP_TYPE_ENCODE; i<MAX_STAT_OP_TYPES; i++) {
188 for (j=0; j<MAX_STAT_PHASES-1; j++) {
189 if (stat_host_db[i][j].count > 0) {
190 avg = (uint64_t)stat_host_db[i][j].sum;
191 do_div(avg, stat_host_db[i][j].count);
192 min_cyc = stat_host_db[i][j].min;
193 max_cyc = stat_host_db[i][j].max;
194 } else {
195 avg = min_cyc = max_cyc = 0;
196 }
197 tmp_len = scnprintf(line,512,
198 "%s::%s\t\t\t\t\t%6u\t%6u\t%6u\t%7u\n",
199 stat_name_db[i].op_type_name,
200 stat_name_db[i].stat_phase_name[j],
201 min_cyc, (unsigned int)avg, max_cyc,
202 stat_host_db[i][j].count);
203 if ( tmp_len <0 )/* scnprintf shouldn't return negative value according to its implementation*/
204 return buf_len;
205 if ( buf_len + tmp_len >= PAGE_SIZE)
206 return buf_len;
207 buf_len += tmp_len;
208 strncat(buf, line,512);
209 }
210 }
211 return buf_len;
212}
213
214static ssize_t ssi_sys_stat_cc_db_show(struct kobject *kobj,
215 struct kobj_attribute *attr, char *buf)
216{
217 int i;
218 char line[256];
219 uint32_t min_cyc, max_cyc;
220 uint64_t avg;
221 ssize_t buf_len,tmp_len=0;
222
223 buf_len = scnprintf(buf,PAGE_SIZE,
224 "phase\tmin[cy]\tavg[cy]\tmax[cy]\t#samples\n");
225 if ( buf_len <0 )/* scnprintf shouldn't return negative value according to its implementation*/
226 return buf_len;
227 for (i=STAT_OP_TYPE_ENCODE; i<MAX_STAT_OP_TYPES; i++) {
228 if (stat_cc_db[i][STAT_PHASE_6].count > 0) {
229 avg = (uint64_t)stat_cc_db[i][STAT_PHASE_6].sum;
230 do_div(avg, stat_cc_db[i][STAT_PHASE_6].count);
231 min_cyc = stat_cc_db[i][STAT_PHASE_6].min;
232 max_cyc = stat_cc_db[i][STAT_PHASE_6].max;
233 } else {
234 avg = min_cyc = max_cyc = 0;
235 }
236 tmp_len = scnprintf(line,256,
237 "%s\t%6u\t%6u\t%6u\t%7u\n",
238 stat_name_db[i].op_type_name,
239 min_cyc,
240 (unsigned int)avg,
241 max_cyc,
242 stat_cc_db[i][STAT_PHASE_6].count);
243
244 if ( tmp_len < 0 )/* scnprintf shouldn't return negative value according to its implementation*/
245 return buf_len;
246
247 if ( buf_len + tmp_len >= PAGE_SIZE)
248 return buf_len;
249 buf_len += tmp_len;
250 strncat(buf, line,256);
251 }
252 return buf_len;
253}
254
255void update_host_stat(unsigned int op_type, unsigned int phase, cycles_t result)
256{
257 unsigned long flags;
258
259 spin_lock_irqsave(&stat_lock, flags);
260 update_db(&(stat_host_db[op_type][phase]), (unsigned int)result);
261 spin_unlock_irqrestore(&stat_lock, flags);
262}
263
264void update_cc_stat(
265 unsigned int op_type,
266 unsigned int phase,
267 unsigned int elapsed_cycles)
268{
269 update_db(&(stat_cc_db[op_type][phase]), elapsed_cycles);
270}
271
272void display_all_stat_db(void)
273{
274 SSI_LOG_ERR("\n======= CYCLE COUNT STATS =======\n");
275 display_db(stat_host_db);
276 SSI_LOG_ERR("\n======= CC HW CYCLE COUNT STATS =======\n");
277 display_db(stat_cc_db);
278}
279#endif /*CC_CYCLE_COUNT*/
280
281
282
283static ssize_t ssi_sys_regdump_show(struct kobject *kobj,
284 struct kobj_attribute *attr, char *buf)
285{
286 struct ssi_drvdata *drvdata = sys_get_drvdata();
287 uint32_t register_value;
288 void __iomem* cc_base = drvdata->cc_base;
289 int offset = 0;
290
291 register_value = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_SIGNATURE));
292 offset += scnprintf(buf + offset, PAGE_SIZE - offset, "%s \t(0x%lX)\t 0x%08X \n", "HOST_SIGNATURE ", DX_HOST_SIGNATURE_REG_OFFSET, register_value);
293 register_value = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IRR));
294 offset += scnprintf(buf + offset, PAGE_SIZE - offset, "%s \t(0x%lX)\t 0x%08X \n", "HOST_IRR ", DX_HOST_IRR_REG_OFFSET, register_value);
295 register_value = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_POWER_DOWN_EN));
296 offset += scnprintf(buf + offset, PAGE_SIZE - offset, "%s \t(0x%lX)\t 0x%08X \n", "HOST_POWER_DOWN_EN ", DX_HOST_POWER_DOWN_EN_REG_OFFSET, register_value);
297 register_value = CC_HAL_READ_REGISTER(CC_REG_OFFSET(CRY_KERNEL, AXIM_MON_ERR));
298 offset += scnprintf(buf + offset, PAGE_SIZE - offset, "%s \t(0x%lX)\t 0x%08X \n", "AXIM_MON_ERR ", DX_AXIM_MON_ERR_REG_OFFSET, register_value);
299 register_value = CC_HAL_READ_REGISTER(CC_REG_OFFSET(CRY_KERNEL, DSCRPTR_QUEUE_CONTENT));
300 offset += scnprintf(buf + offset, PAGE_SIZE - offset, "%s \t(0x%lX)\t 0x%08X \n", "DSCRPTR_QUEUE_CONTENT", DX_DSCRPTR_QUEUE_CONTENT_REG_OFFSET, register_value);
301 return offset;
302}
303
304static ssize_t ssi_sys_help_show(struct kobject *kobj,
305 struct kobj_attribute *attr, char *buf)
306{
307 char* help_str[]={
308 "cat reg_dump ", "Print several of CC register values",
309 #if defined CC_CYCLE_COUNT
310 "cat stats_host ", "Print host statistics",
311 "echo <number> > stats_host", "Clear host statistics database",
312 "cat stats_cc ", "Print CC statistics",
313 "echo <number> > stats_cc ", "Clear CC statistics database",
314 #endif
315 };
316 int i=0, offset = 0;
317
318 offset += scnprintf(buf + offset, PAGE_SIZE - offset, "Usage:\n");
9cbd7dca 319 for ( i = 0; i < ARRAY_SIZE(help_str); i+=2) {
abefd674
GBY
320 offset += scnprintf(buf + offset, PAGE_SIZE - offset, "%s\t\t%s\n", help_str[i], help_str[i+1]);
321 }
322 return offset;
323}
324
325/********************************************************
326 * SYSFS objects *
327 ********************************************************/
328/*
329 * Structure used to create a directory
330 * and its attributes in sysfs.
331 */
332struct sys_dir {
333 struct kobject *sys_dir_kobj;
334 struct attribute_group sys_dir_attr_group;
335 struct attribute **sys_dir_attr_list;
336 uint32_t num_of_attrs;
337 struct ssi_drvdata *drvdata; /* Associated driver context */
338};
339
340/* top level directory structures */
341static struct sys_dir sys_top_dir;
342
343/* TOP LEVEL ATTRIBUTES */
344static struct kobj_attribute ssi_sys_top_level_attrs[] = {
345 __ATTR(dump_regs, 0444, ssi_sys_regdump_show, NULL),
346 __ATTR(help, 0444, ssi_sys_help_show, NULL),
347#if defined CC_CYCLE_COUNT
348 __ATTR(stats_host, 0664, ssi_sys_stat_host_db_show, ssi_sys_stats_host_db_clear),
349 __ATTR(stats_cc, 0664, ssi_sys_stat_cc_db_show, ssi_sys_stats_cc_db_clear),
350#endif
351
352};
353
354static struct ssi_drvdata *sys_get_drvdata(void)
355{
356 /* TODO: supporting multiple SeP devices would require avoiding
357 * global "top_dir" and finding associated "top_dir" by traversing
358 * up the tree to the kobject which matches one of the top_dir's */
359 return sys_top_dir.drvdata;
360}
361
362static int sys_init_dir(struct sys_dir *sys_dir, struct ssi_drvdata *drvdata,
363 struct kobject *parent_dir_kobj, const char *dir_name,
364 struct kobj_attribute *attrs, uint32_t num_of_attrs)
365{
366 int i;
367
368 memset(sys_dir, 0, sizeof(struct sys_dir));
369
370 sys_dir->drvdata = drvdata;
371
372 /* initialize directory kobject */
373 sys_dir->sys_dir_kobj =
374 kobject_create_and_add(dir_name, parent_dir_kobj);
375
376 if (!(sys_dir->sys_dir_kobj))
377 return -ENOMEM;
378 /* allocate memory for directory's attributes list */
379 sys_dir->sys_dir_attr_list =
380 kzalloc(sizeof(struct attribute *) * (num_of_attrs + 1),
381 GFP_KERNEL);
382
383 if (!(sys_dir->sys_dir_attr_list)) {
384 kobject_put(sys_dir->sys_dir_kobj);
385 return -ENOMEM;
386 }
387
388 sys_dir->num_of_attrs = num_of_attrs;
389
390 /* initialize attributes list */
391 for (i = 0; i < num_of_attrs; ++i)
392 sys_dir->sys_dir_attr_list[i] = &(attrs[i].attr);
393
394 /* last list entry should be NULL */
395 sys_dir->sys_dir_attr_list[num_of_attrs] = NULL;
396
397 sys_dir->sys_dir_attr_group.attrs = sys_dir->sys_dir_attr_list;
398
399 return sysfs_create_group(sys_dir->sys_dir_kobj,
400 &(sys_dir->sys_dir_attr_group));
401}
402
403static void sys_free_dir(struct sys_dir *sys_dir)
404{
405 if (!sys_dir)
406 return;
407
408 kfree(sys_dir->sys_dir_attr_list);
409
410 if (sys_dir->sys_dir_kobj != NULL)
411 kobject_put(sys_dir->sys_dir_kobj);
412}
413
414int ssi_sysfs_init(struct kobject *sys_dev_obj, struct ssi_drvdata *drvdata)
415{
416 int retval;
417
418#if defined CC_CYCLE_COUNT
419 /* Init. statistics */
420 init_db(stat_host_db);
421 init_db(stat_cc_db);
422#endif
423
424 SSI_LOG_ERR("setup sysfs under %s\n", sys_dev_obj->name);
425
426 /* Initialize top directory */
427 retval = sys_init_dir(&sys_top_dir, drvdata, sys_dev_obj,
428 "cc_info", ssi_sys_top_level_attrs,
9cbd7dca 429 ARRAY_SIZE(ssi_sys_top_level_attrs));
abefd674
GBY
430 return retval;
431}
432
433void ssi_sysfs_fini(void)
434{
435 sys_free_dir(&sys_top_dir);
436}
437
438#endif /*ENABLE_CC_SYSFS*/
439