1 /*
2  * Support for atomisp driver sysfs interface
3  *
4  * Copyright (c) 2014 Intel Corporation. All Rights Reserved.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License version
8  * 2 as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  *
16  */
17 
18 #include <linux/device.h>
19 #include <linux/err.h>
20 #include <linux/kernel.h>
21 
22 #include "atomisp_compat.h"
23 #include "atomisp_internal.h"
24 #include "atomisp_ioctl.h"
25 #include "atomisp_drvfs.h"
26 #include "hmm/hmm.h"
27 #include "ia_css_debug.h"
28 
29 /*
30  * _iunit_debug:
31  * dbglvl: iunit css driver trace level
32  * dbgopt: iunit debug option:
33  *        bit 0: binary list
34  *        bit 1: running binary
35  *        bit 2: memory statistic
36 */
37 struct _iunit_debug {
38 	struct device_driver	*drv;
39 	struct atomisp_device	*isp;
40 	unsigned int		dbglvl;
41 	unsigned int		dbgfun;
42 	unsigned int		dbgopt;
43 };
44 
45 #define OPTION_BIN_LIST			BIT(0)
46 #define OPTION_BIN_RUN			BIT(1)
47 #define OPTION_MEM_STAT			BIT(2)
48 #define OPTION_VALID			(OPTION_BIN_LIST \
49 					| OPTION_BIN_RUN \
50 					| OPTION_MEM_STAT)
51 
52 static struct _iunit_debug iunit_debug = {
53 	.dbglvl = 0,
54 	.dbgopt = OPTION_BIN_LIST,
55 };
56 
57 static inline int iunit_dump_dbgopt(struct atomisp_device *isp,
58 				    unsigned int opt)
59 {
60 	int ret = 0;
61 
62 	if (opt & OPTION_VALID) {
63 		if (opt & OPTION_BIN_LIST) {
64 			ret = atomisp_css_dump_blob_infor();
65 			if (ret) {
66 				dev_err(atomisp_dev, "%s dump blob infor err[ret:%d]\n",
67 					__func__, ret);
68 				goto opt_err;
69 			}
70 		}
71 
72 		if (opt & OPTION_BIN_RUN) {
73 			if (atomisp_streaming_count(isp)) {
74 				atomisp_css_dump_sp_raw_copy_linecount(true);
75 				atomisp_css_debug_dump_isp_binary();
76 			} else {
77 				ret = -EPERM;
78 				dev_err(atomisp_dev, "%s dump running bin err[ret:%d]\n",
79 					__func__, ret);
80 				goto opt_err;
81 			}
82 		}
83 
84 		if (opt & OPTION_MEM_STAT)
85 			hmm_show_mem_stat(__func__, __LINE__);
86 	} else {
87 		ret = -EINVAL;
88 		dev_err(atomisp_dev, "%s dump nothing[ret=%d]\n", __func__,
89 			ret);
90 	}
91 
92 opt_err:
93 	return ret;
94 }
95 
96 static ssize_t iunit_dbglvl_show(struct device_driver *drv, char *buf)
97 {
98 	iunit_debug.dbglvl = dbg_level;
99 	return sprintf(buf, "dtrace level:%u\n", iunit_debug.dbglvl);
100 }
101 
102 static ssize_t iunit_dbglvl_store(struct device_driver *drv, const char *buf,
103 				  size_t size)
104 {
105 	if (kstrtouint(buf, 10, &iunit_debug.dbglvl)
106 	    || iunit_debug.dbglvl < 1
107 	    || iunit_debug.dbglvl > 9) {
108 		return -ERANGE;
109 	}
110 	ia_css_debug_set_dtrace_level(iunit_debug.dbglvl);
111 
112 	return size;
113 }
114 
115 static ssize_t iunit_dbgfun_show(struct device_driver *drv, char *buf)
116 {
117 	iunit_debug.dbgfun = atomisp_get_css_dbgfunc();
118 	return sprintf(buf, "dbgfun opt:%u\n", iunit_debug.dbgfun);
119 }
120 
121 static ssize_t iunit_dbgfun_store(struct device_driver *drv, const char *buf,
122 				  size_t size)
123 {
124 	unsigned int opt;
125 	int ret;
126 
127 	ret = kstrtouint(buf, 10, &opt);
128 	if (ret)
129 		return ret;
130 
131 	ret = atomisp_set_css_dbgfunc(iunit_debug.isp, opt);
132 	if (ret)
133 		return ret;
134 
135 	iunit_debug.dbgfun = opt;
136 
137 	return size;
138 }
139 
140 static ssize_t iunit_dbgopt_show(struct device_driver *drv, char *buf)
141 {
142 	return sprintf(buf, "option:0x%x\n", iunit_debug.dbgopt);
143 }
144 
145 static ssize_t iunit_dbgopt_store(struct device_driver *drv, const char *buf,
146 				  size_t size)
147 {
148 	unsigned int opt;
149 	int ret;
150 
151 	ret = kstrtouint(buf, 10, &opt);
152 	if (ret)
153 		return ret;
154 
155 	iunit_debug.dbgopt = opt;
156 	ret = iunit_dump_dbgopt(iunit_debug.isp, iunit_debug.dbgopt);
157 	if (ret)
158 		return ret;
159 
160 	return size;
161 }
162 
163 static const struct driver_attribute iunit_drvfs_attrs[] = {
164 	__ATTR(dbglvl, 0644, iunit_dbglvl_show, iunit_dbglvl_store),
165 	__ATTR(dbgfun, 0644, iunit_dbgfun_show, iunit_dbgfun_store),
166 	__ATTR(dbgopt, 0644, iunit_dbgopt_show, iunit_dbgopt_store),
167 };
168 
169 static int iunit_drvfs_create_files(struct device_driver *drv)
170 {
171 	int i, ret = 0;
172 
173 	for (i = 0; i < ARRAY_SIZE(iunit_drvfs_attrs); i++)
174 		ret |= driver_create_file(drv, &iunit_drvfs_attrs[i]);
175 
176 	return ret;
177 }
178 
179 static void iunit_drvfs_remove_files(struct device_driver *drv)
180 {
181 	int i;
182 
183 	for (i = 0; i < ARRAY_SIZE(iunit_drvfs_attrs); i++)
184 		driver_remove_file(drv, &iunit_drvfs_attrs[i]);
185 }
186 
187 int atomisp_drvfs_init(struct device_driver *drv, struct atomisp_device *isp)
188 {
189 	int ret;
190 
191 	iunit_debug.isp = isp;
192 	iunit_debug.drv = drv;
193 
194 	ret = iunit_drvfs_create_files(iunit_debug.drv);
195 	if (ret) {
196 		dev_err(atomisp_dev, "drvfs_create_files error: %d\n", ret);
197 		iunit_drvfs_remove_files(iunit_debug.drv);
198 	}
199 
200 	return ret;
201 }
202 
203 void atomisp_drvfs_exit(void)
204 {
205 	iunit_drvfs_remove_files(iunit_debug.drv);
206 }
207