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