1 /******************************************************************************
2  *
3  * This file is provided under a dual BSD/GPLv2 license.  When using or
4  * redistributing this file, you may do so under either license.
5  *
6  * GPL LICENSE SUMMARY
7  *
8  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
9  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
10  * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
11  * Copyright (C) 2018 Intel Corporation
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of version 2 of the GNU General Public License as
15  * published by the Free Software Foundation.
16  *
17  * This program is distributed in the hope that it will be useful, but
18  * WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * General Public License for more details.
21  *
22  * The full GNU General Public License is included in this distribution
23  * in the file called COPYING.
24  *
25  * Contact Information:
26  *  Intel Linux Wireless <linuxwifi@intel.com>
27  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
28  *
29  * BSD LICENSE
30  *
31  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
32  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
33  * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
34  * Copyright (C) 2018 Intel Corporation
35  * All rights reserved.
36  *
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that the following conditions
39  * are met:
40  *
41  *  * Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  *  * Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in
45  *    the documentation and/or other materials provided with the
46  *    distribution.
47  *  * Neither the name Intel Corporation nor the names of its
48  *    contributors may be used to endorse or promote products derived
49  *    from this software without specific prior written permission.
50  *
51  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
52  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
53  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
54  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
55  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
56  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
57  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
58  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
59  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
61  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62  *
63  *****************************************************************************/
64 #include "api/commands.h"
65 #include "debugfs.h"
66 #include "dbg.h"
67 
68 #define FWRT_DEBUGFS_OPEN_WRAPPER(name, buflen, argtype)		\
69 struct dbgfs_##name##_data {						\
70 	argtype *arg;							\
71 	bool read_done;							\
72 	ssize_t rlen;							\
73 	char rbuf[buflen];						\
74 };									\
75 static int _iwl_dbgfs_##name##_open(struct inode *inode,		\
76 				    struct file *file)			\
77 {									\
78 	struct dbgfs_##name##_data *data;				\
79 									\
80 	data = kzalloc(sizeof(*data), GFP_KERNEL);			\
81 	if (!data)							\
82 		return -ENOMEM;						\
83 									\
84 	data->read_done = false;					\
85 	data->arg = inode->i_private;					\
86 	file->private_data = data;					\
87 									\
88 	return 0;							\
89 }
90 
91 #define FWRT_DEBUGFS_READ_WRAPPER(name)					\
92 static ssize_t _iwl_dbgfs_##name##_read(struct file *file,		\
93 					char __user *user_buf,		\
94 					size_t count, loff_t *ppos)	\
95 {									\
96 	struct dbgfs_##name##_data *data = file->private_data;		\
97 									\
98 	if (!data->read_done) {						\
99 		data->read_done = true;					\
100 		data->rlen = iwl_dbgfs_##name##_read(data->arg,		\
101 						     sizeof(data->rbuf),\
102 						     data->rbuf);	\
103 	}								\
104 									\
105 	if (data->rlen < 0)						\
106 		return data->rlen;					\
107 	return simple_read_from_buffer(user_buf, count, ppos,		\
108 				       data->rbuf, data->rlen);		\
109 }
110 
111 static int _iwl_dbgfs_release(struct inode *inode, struct file *file)
112 {
113 	kfree(file->private_data);
114 
115 	return 0;
116 }
117 
118 #define _FWRT_DEBUGFS_READ_FILE_OPS(name, buflen, argtype)		\
119 FWRT_DEBUGFS_OPEN_WRAPPER(name, buflen, argtype)			\
120 FWRT_DEBUGFS_READ_WRAPPER(name)						\
121 static const struct file_operations iwl_dbgfs_##name##_ops = {		\
122 	.read = _iwl_dbgfs_##name##_read,				\
123 	.open = _iwl_dbgfs_##name##_open,				\
124 	.llseek = generic_file_llseek,					\
125 	.release = _iwl_dbgfs_release,					\
126 }
127 
128 #define FWRT_DEBUGFS_WRITE_WRAPPER(name, buflen, argtype)		\
129 static ssize_t _iwl_dbgfs_##name##_write(struct file *file,		\
130 					 const char __user *user_buf,	\
131 					 size_t count, loff_t *ppos)	\
132 {									\
133 	argtype *arg =							\
134 		((struct dbgfs_##name##_data *)file->private_data)->arg;\
135 	char buf[buflen] = {};						\
136 	size_t buf_size = min(count, sizeof(buf) -  1);			\
137 									\
138 	if (copy_from_user(buf, user_buf, buf_size))			\
139 		return -EFAULT;						\
140 									\
141 	return iwl_dbgfs_##name##_write(arg, buf, buf_size);		\
142 }
143 
144 #define _FWRT_DEBUGFS_READ_WRITE_FILE_OPS(name, buflen, argtype)	\
145 FWRT_DEBUGFS_OPEN_WRAPPER(name, buflen, argtype)			\
146 FWRT_DEBUGFS_WRITE_WRAPPER(name, buflen, argtype)			\
147 FWRT_DEBUGFS_READ_WRAPPER(name)						\
148 static const struct file_operations iwl_dbgfs_##name##_ops = {		\
149 	.write = _iwl_dbgfs_##name##_write,				\
150 	.read = _iwl_dbgfs_##name##_read,				\
151 	.open = _iwl_dbgfs_##name##_open,				\
152 	.llseek = generic_file_llseek,					\
153 	.release = _iwl_dbgfs_release,					\
154 }
155 
156 #define _FWRT_DEBUGFS_WRITE_FILE_OPS(name, buflen, argtype)		\
157 FWRT_DEBUGFS_OPEN_WRAPPER(name, buflen, argtype)			\
158 FWRT_DEBUGFS_WRITE_WRAPPER(name, buflen, argtype)			\
159 static const struct file_operations iwl_dbgfs_##name##_ops = {		\
160 	.write = _iwl_dbgfs_##name##_write,				\
161 	.open = _iwl_dbgfs_##name##_open,				\
162 	.llseek = generic_file_llseek,					\
163 	.release = _iwl_dbgfs_release,					\
164 }
165 
166 #define FWRT_DEBUGFS_READ_FILE_OPS(name, bufsz)				\
167 	_FWRT_DEBUGFS_READ_FILE_OPS(name, bufsz, struct iwl_fw_runtime)
168 
169 #define FWRT_DEBUGFS_WRITE_FILE_OPS(name, bufsz)			\
170 	_FWRT_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct iwl_fw_runtime)
171 
172 #define FWRT_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz)			\
173 	_FWRT_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_fw_runtime)
174 
175 #define FWRT_DEBUGFS_ADD_FILE_ALIAS(alias, name, parent, mode) do {	\
176 	if (!debugfs_create_file(alias, mode, parent, fwrt,		\
177 				 &iwl_dbgfs_##name##_ops))		\
178 		goto err;						\
179 	} while (0)
180 #define FWRT_DEBUGFS_ADD_FILE(name, parent, mode) \
181 	FWRT_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode)
182 
183 static int iwl_fw_send_timestamp_marker_cmd(struct iwl_fw_runtime *fwrt)
184 {
185 	struct iwl_mvm_marker marker = {
186 		.dw_len = sizeof(struct iwl_mvm_marker) / 4,
187 		.marker_id = MARKER_ID_SYNC_CLOCK,
188 
189 		/* the real timestamp is taken from the ftrace clock
190 		 * this is for finding the match between fw and kernel logs
191 		 */
192 		.timestamp = cpu_to_le64(fwrt->timestamp.seq++),
193 	};
194 
195 	struct iwl_host_cmd hcmd = {
196 		.id = MARKER_CMD,
197 		.flags = CMD_ASYNC,
198 		.data[0] = &marker,
199 		.len[0] = sizeof(marker),
200 	};
201 
202 	return iwl_trans_send_cmd(fwrt->trans, &hcmd);
203 }
204 
205 static void iwl_fw_timestamp_marker_wk(struct work_struct *work)
206 {
207 	int ret;
208 	struct iwl_fw_runtime *fwrt =
209 		container_of(work, struct iwl_fw_runtime, timestamp.wk.work);
210 	unsigned long delay = fwrt->timestamp.delay;
211 
212 	ret = iwl_fw_send_timestamp_marker_cmd(fwrt);
213 	if (!ret && delay)
214 		schedule_delayed_work(&fwrt->timestamp.wk,
215 				      round_jiffies_relative(delay));
216 	else
217 		IWL_INFO(fwrt,
218 			 "stopping timestamp_marker, ret: %d, delay: %u\n",
219 			 ret, jiffies_to_msecs(delay) / 1000);
220 }
221 
222 void iwl_fw_trigger_timestamp(struct iwl_fw_runtime *fwrt, u32 delay)
223 {
224 	IWL_INFO(fwrt,
225 		 "starting timestamp_marker trigger with delay: %us\n",
226 		 delay);
227 
228 	iwl_fw_cancel_timestamp(fwrt);
229 
230 	fwrt->timestamp.delay = msecs_to_jiffies(delay * 1000);
231 
232 	schedule_delayed_work(&fwrt->timestamp.wk,
233 			      round_jiffies_relative(fwrt->timestamp.delay));
234 }
235 
236 static ssize_t iwl_dbgfs_timestamp_marker_write(struct iwl_fw_runtime *fwrt,
237 						char *buf, size_t count)
238 {
239 	int ret;
240 	u32 delay;
241 
242 	ret = kstrtou32(buf, 10, &delay);
243 	if (ret < 0)
244 		return ret;
245 
246 	iwl_fw_trigger_timestamp(fwrt, delay);
247 
248 	return count;
249 }
250 
251 static ssize_t iwl_dbgfs_timestamp_marker_read(struct iwl_fw_runtime *fwrt,
252 					       size_t size, char *buf)
253 {
254 	u32 delay_secs = jiffies_to_msecs(fwrt->timestamp.delay) / 1000;
255 
256 	return scnprintf(buf, size, "%d\n", delay_secs);
257 }
258 
259 FWRT_DEBUGFS_READ_WRITE_FILE_OPS(timestamp_marker, 16);
260 
261 struct hcmd_write_data {
262 	__be32 cmd_id;
263 	__be32 flags;
264 	__be16 length;
265 	u8 data[0];
266 } __packed;
267 
268 static ssize_t iwl_dbgfs_send_hcmd_write(struct iwl_fw_runtime *fwrt, char *buf,
269 					 size_t count)
270 {
271 	size_t header_size = (sizeof(u32) * 2 + sizeof(u16)) * 2;
272 	size_t data_size = (count - 1) / 2;
273 	int ret;
274 	struct hcmd_write_data *data;
275 	struct iwl_host_cmd hcmd = {
276 		.len = { 0, },
277 		.data = { NULL, },
278 	};
279 
280 	if (fwrt->ops && fwrt->ops->fw_running &&
281 	    !fwrt->ops->fw_running(fwrt->ops_ctx))
282 		return -EIO;
283 
284 	if (count < header_size + 1 || count > 1024 * 4)
285 		return -EINVAL;
286 
287 	data = kmalloc(data_size, GFP_KERNEL);
288 	if (!data)
289 		return -ENOMEM;
290 
291 	ret = hex2bin((u8 *)data, buf, data_size);
292 	if (ret)
293 		goto out;
294 
295 	hcmd.id = be32_to_cpu(data->cmd_id);
296 	hcmd.flags = be32_to_cpu(data->flags);
297 	hcmd.len[0] = be16_to_cpu(data->length);
298 	hcmd.data[0] = data->data;
299 
300 	if (count != header_size + hcmd.len[0] * 2 + 1) {
301 		IWL_ERR(fwrt,
302 			"host command data size does not match header length\n");
303 		ret = -EINVAL;
304 		goto out;
305 	}
306 
307 	if (fwrt->ops && fwrt->ops->send_hcmd)
308 		ret = fwrt->ops->send_hcmd(fwrt->ops_ctx, &hcmd);
309 	else
310 		ret = -EPERM;
311 
312 	if (ret < 0)
313 		goto out;
314 
315 	if (hcmd.flags & CMD_WANT_SKB)
316 		iwl_free_resp(&hcmd);
317 out:
318 	kfree(data);
319 	return ret ?: count;
320 }
321 
322 FWRT_DEBUGFS_WRITE_FILE_OPS(send_hcmd, 512);
323 
324 int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt,
325 			    struct dentry *dbgfs_dir)
326 {
327 	INIT_DELAYED_WORK(&fwrt->timestamp.wk, iwl_fw_timestamp_marker_wk);
328 	FWRT_DEBUGFS_ADD_FILE(timestamp_marker, dbgfs_dir, 0200);
329 	FWRT_DEBUGFS_ADD_FILE(send_hcmd, dbgfs_dir, 0200);
330 	return 0;
331 err:
332 	IWL_ERR(fwrt, "Can't create the fwrt debugfs directory\n");
333 	return -ENOMEM;
334 }
335