193b167c1SMordechay Goodstein /******************************************************************************
293b167c1SMordechay Goodstein  *
393b167c1SMordechay Goodstein  * This file is provided under a dual BSD/GPLv2 license.  When using or
493b167c1SMordechay Goodstein  * redistributing this file, you may do so under either license.
593b167c1SMordechay Goodstein  *
693b167c1SMordechay Goodstein  * GPL LICENSE SUMMARY
793b167c1SMordechay Goodstein  *
893b167c1SMordechay Goodstein  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
993b167c1SMordechay Goodstein  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
1093b167c1SMordechay Goodstein  * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
1193b167c1SMordechay Goodstein  *
1293b167c1SMordechay Goodstein  * This program is free software; you can redistribute it and/or modify
1393b167c1SMordechay Goodstein  * it under the terms of version 2 of the GNU General Public License as
1493b167c1SMordechay Goodstein  * published by the Free Software Foundation.
1593b167c1SMordechay Goodstein  *
1693b167c1SMordechay Goodstein  * This program is distributed in the hope that it will be useful, but
1793b167c1SMordechay Goodstein  * WITHOUT ANY WARRANTY; without even the implied warranty of
1893b167c1SMordechay Goodstein  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1993b167c1SMordechay Goodstein  * General Public License for more details.
2093b167c1SMordechay Goodstein  *
2193b167c1SMordechay Goodstein  * You should have received a copy of the GNU General Public License
2293b167c1SMordechay Goodstein  * along with this program.
2393b167c1SMordechay Goodstein  *
2493b167c1SMordechay Goodstein  * The full GNU General Public License is included in this distribution
2593b167c1SMordechay Goodstein  * in the file called COPYING.
2693b167c1SMordechay Goodstein  *
2793b167c1SMordechay Goodstein  * Contact Information:
2893b167c1SMordechay Goodstein  *  Intel Linux Wireless <linuxwifi@intel.com>
2993b167c1SMordechay Goodstein  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
3093b167c1SMordechay Goodstein  *
3193b167c1SMordechay Goodstein  * BSD LICENSE
3293b167c1SMordechay Goodstein  *
3393b167c1SMordechay Goodstein  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
3493b167c1SMordechay Goodstein  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
3593b167c1SMordechay Goodstein  * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
3693b167c1SMordechay Goodstein  * All rights reserved.
3793b167c1SMordechay Goodstein  *
3893b167c1SMordechay Goodstein  * Redistribution and use in source and binary forms, with or without
3993b167c1SMordechay Goodstein  * modification, are permitted provided that the following conditions
4093b167c1SMordechay Goodstein  * are met:
4193b167c1SMordechay Goodstein  *
4293b167c1SMordechay Goodstein  *  * Redistributions of source code must retain the above copyright
4393b167c1SMordechay Goodstein  *    notice, this list of conditions and the following disclaimer.
4493b167c1SMordechay Goodstein  *  * Redistributions in binary form must reproduce the above copyright
4593b167c1SMordechay Goodstein  *    notice, this list of conditions and the following disclaimer in
4693b167c1SMordechay Goodstein  *    the documentation and/or other materials provided with the
4793b167c1SMordechay Goodstein  *    distribution.
4893b167c1SMordechay Goodstein  *  * Neither the name Intel Corporation nor the names of its
4993b167c1SMordechay Goodstein  *    contributors may be used to endorse or promote products derived
5093b167c1SMordechay Goodstein  *    from this software without specific prior written permission.
5193b167c1SMordechay Goodstein  *
5293b167c1SMordechay Goodstein  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
5393b167c1SMordechay Goodstein  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5493b167c1SMordechay Goodstein  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
5593b167c1SMordechay Goodstein  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
5693b167c1SMordechay Goodstein  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
5793b167c1SMordechay Goodstein  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
5893b167c1SMordechay Goodstein  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
5993b167c1SMordechay Goodstein  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
6093b167c1SMordechay Goodstein  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
6193b167c1SMordechay Goodstein  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
6293b167c1SMordechay Goodstein  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
6393b167c1SMordechay Goodstein  *
6493b167c1SMordechay Goodstein  *****************************************************************************/
6593b167c1SMordechay Goodstein #include "api/commands.h"
6693b167c1SMordechay Goodstein #include "debugfs.h"
67422b5dd4SHaim Dreyfuss #include "dbg.h"
6893b167c1SMordechay Goodstein 
6993b167c1SMordechay Goodstein #define FWRT_DEBUGFS_READ_FILE_OPS(name)				\
7093b167c1SMordechay Goodstein static ssize_t iwl_dbgfs_##name##_read(struct iwl_fw_runtime *fwrt,	\
7193b167c1SMordechay Goodstein 				       char *buf, size_t count,		\
7293b167c1SMordechay Goodstein 				       loff_t *ppos);			\
7393b167c1SMordechay Goodstein static const struct file_operations iwl_dbgfs_##name##_ops = {		\
7493b167c1SMordechay Goodstein 	.read = iwl_dbgfs_##name##_read,				\
7593b167c1SMordechay Goodstein 	.open = simple_open,						\
7693b167c1SMordechay Goodstein 	.llseek = generic_file_llseek,					\
7793b167c1SMordechay Goodstein }
7893b167c1SMordechay Goodstein 
7993b167c1SMordechay Goodstein #define FWRT_DEBUGFS_WRITE_WRAPPER(name, buflen)			\
8093b167c1SMordechay Goodstein static ssize_t iwl_dbgfs_##name##_write(struct iwl_fw_runtime *fwrt,	\
8193b167c1SMordechay Goodstein 					char *buf, size_t count,	\
8293b167c1SMordechay Goodstein 					loff_t *ppos);			\
8393b167c1SMordechay Goodstein static ssize_t _iwl_dbgfs_##name##_write(struct file *file,		\
8493b167c1SMordechay Goodstein 					 const char __user *user_buf,	\
8593b167c1SMordechay Goodstein 					 size_t count, loff_t *ppos)	\
8693b167c1SMordechay Goodstein {									\
8793b167c1SMordechay Goodstein 	struct iwl_fw_runtime *fwrt = file->private_data;		\
8893b167c1SMordechay Goodstein 	char buf[buflen] = {};						\
8993b167c1SMordechay Goodstein 	size_t buf_size = min(count, sizeof(buf) -  1);			\
9093b167c1SMordechay Goodstein 									\
9193b167c1SMordechay Goodstein 	if (copy_from_user(buf, user_buf, buf_size))			\
9293b167c1SMordechay Goodstein 		return -EFAULT;						\
9393b167c1SMordechay Goodstein 									\
9493b167c1SMordechay Goodstein 	return iwl_dbgfs_##name##_write(fwrt, buf, buf_size, ppos);	\
9593b167c1SMordechay Goodstein }
9693b167c1SMordechay Goodstein 
9793b167c1SMordechay Goodstein #define FWRT_DEBUGFS_READ_WRITE_FILE_OPS(name, buflen)			\
9893b167c1SMordechay Goodstein FWRT_DEBUGFS_WRITE_WRAPPER(name, buflen)				\
9993b167c1SMordechay Goodstein static const struct file_operations iwl_dbgfs_##name##_ops = {		\
10093b167c1SMordechay Goodstein 	.write = _iwl_dbgfs_##name##_write,				\
10193b167c1SMordechay Goodstein 	.read = iwl_dbgfs_##name##_read,				\
10293b167c1SMordechay Goodstein 	.open = simple_open,						\
10393b167c1SMordechay Goodstein 	.llseek = generic_file_llseek,					\
10493b167c1SMordechay Goodstein }
10593b167c1SMordechay Goodstein 
10693b167c1SMordechay Goodstein #define FWRT_DEBUGFS_WRITE_FILE_OPS(name, buflen)			\
10793b167c1SMordechay Goodstein FWRT_DEBUGFS_WRITE_WRAPPER(name, buflen)				\
10893b167c1SMordechay Goodstein static const struct file_operations iwl_dbgfs_##name##_ops = {		\
10993b167c1SMordechay Goodstein 	.write = _iwl_dbgfs_##name##_write,				\
11093b167c1SMordechay Goodstein 	.open = simple_open,						\
11193b167c1SMordechay Goodstein 	.llseek = generic_file_llseek,					\
11293b167c1SMordechay Goodstein }
11393b167c1SMordechay Goodstein 
11493b167c1SMordechay Goodstein #define FWRT_DEBUGFS_ADD_FILE_ALIAS(alias, name, parent, mode) do {	\
11593b167c1SMordechay Goodstein 		if (!debugfs_create_file(alias, mode, parent, fwrt,	\
11693b167c1SMordechay Goodstein 					 &iwl_dbgfs_##name##_ops))	\
11793b167c1SMordechay Goodstein 			goto err;					\
11893b167c1SMordechay Goodstein 	} while (0)
11993b167c1SMordechay Goodstein #define FWRT_DEBUGFS_ADD_FILE(name, parent, mode) \
12093b167c1SMordechay Goodstein 	FWRT_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode)
12193b167c1SMordechay Goodstein 
12293b167c1SMordechay Goodstein static int iwl_fw_send_timestamp_marker_cmd(struct iwl_fw_runtime *fwrt)
12393b167c1SMordechay Goodstein {
12493b167c1SMordechay Goodstein 	struct iwl_mvm_marker marker = {
12593b167c1SMordechay Goodstein 		.dw_len = sizeof(struct iwl_mvm_marker) / 4,
12693b167c1SMordechay Goodstein 		.marker_id = MARKER_ID_SYNC_CLOCK,
12793b167c1SMordechay Goodstein 
12893b167c1SMordechay Goodstein 		/* the real timestamp is taken from the ftrace clock
12993b167c1SMordechay Goodstein 		 * this is for finding the match between fw and kernel logs
13093b167c1SMordechay Goodstein 		 */
13193b167c1SMordechay Goodstein 		.timestamp = cpu_to_le64(fwrt->timestamp.seq++),
13293b167c1SMordechay Goodstein 	};
13393b167c1SMordechay Goodstein 
13493b167c1SMordechay Goodstein 	struct iwl_host_cmd hcmd = {
13593b167c1SMordechay Goodstein 		.id = MARKER_CMD,
13693b167c1SMordechay Goodstein 		.flags = CMD_ASYNC,
13793b167c1SMordechay Goodstein 		.data[0] = &marker,
13893b167c1SMordechay Goodstein 		.len[0] = sizeof(marker),
13993b167c1SMordechay Goodstein 	};
14093b167c1SMordechay Goodstein 
14193b167c1SMordechay Goodstein 	return iwl_trans_send_cmd(fwrt->trans, &hcmd);
14293b167c1SMordechay Goodstein }
14393b167c1SMordechay Goodstein 
14493b167c1SMordechay Goodstein static void iwl_fw_timestamp_marker_wk(struct work_struct *work)
14593b167c1SMordechay Goodstein {
14693b167c1SMordechay Goodstein 	int ret;
14793b167c1SMordechay Goodstein 	struct iwl_fw_runtime *fwrt =
14893b167c1SMordechay Goodstein 		container_of(work, struct iwl_fw_runtime, timestamp.wk.work);
14993b167c1SMordechay Goodstein 	unsigned long delay = fwrt->timestamp.delay;
15093b167c1SMordechay Goodstein 
15193b167c1SMordechay Goodstein 	ret = iwl_fw_send_timestamp_marker_cmd(fwrt);
15293b167c1SMordechay Goodstein 	if (!ret && delay)
15393b167c1SMordechay Goodstein 		schedule_delayed_work(&fwrt->timestamp.wk,
15493b167c1SMordechay Goodstein 				      round_jiffies_relative(delay));
15593b167c1SMordechay Goodstein 	else
15693b167c1SMordechay Goodstein 		IWL_INFO(fwrt,
15793b167c1SMordechay Goodstein 			 "stopping timestamp_marker, ret: %d, delay: %u\n",
15893b167c1SMordechay Goodstein 			 ret, jiffies_to_msecs(delay) / 1000);
15993b167c1SMordechay Goodstein }
16093b167c1SMordechay Goodstein 
161759931c7SMordechay Goodstein void iwl_fw_trigger_timestamp(struct iwl_fw_runtime *fwrt, u32 delay)
162759931c7SMordechay Goodstein {
163759931c7SMordechay Goodstein 	IWL_INFO(fwrt,
164759931c7SMordechay Goodstein 		 "starting timestamp_marker trigger with delay: %us\n",
165759931c7SMordechay Goodstein 		 delay);
166759931c7SMordechay Goodstein 
167759931c7SMordechay Goodstein 	iwl_fw_cancel_timestamp(fwrt);
168759931c7SMordechay Goodstein 
169759931c7SMordechay Goodstein 	fwrt->timestamp.delay = msecs_to_jiffies(delay * 1000);
170759931c7SMordechay Goodstein 
171759931c7SMordechay Goodstein 	schedule_delayed_work(&fwrt->timestamp.wk,
172759931c7SMordechay Goodstein 			      round_jiffies_relative(fwrt->timestamp.delay));
173759931c7SMordechay Goodstein }
174759931c7SMordechay Goodstein 
17593b167c1SMordechay Goodstein static ssize_t iwl_dbgfs_timestamp_marker_write(struct iwl_fw_runtime *fwrt,
17693b167c1SMordechay Goodstein 						char *buf, size_t count,
17793b167c1SMordechay Goodstein 						loff_t *ppos)
17893b167c1SMordechay Goodstein {
17993b167c1SMordechay Goodstein 	int ret;
18093b167c1SMordechay Goodstein 	u32 delay;
18193b167c1SMordechay Goodstein 
18293b167c1SMordechay Goodstein 	ret = kstrtou32(buf, 10, &delay);
18393b167c1SMordechay Goodstein 	if (ret < 0)
18493b167c1SMordechay Goodstein 		return ret;
18593b167c1SMordechay Goodstein 
186759931c7SMordechay Goodstein 	iwl_fw_trigger_timestamp(fwrt, delay);
18793b167c1SMordechay Goodstein 
18893b167c1SMordechay Goodstein 	return count;
18993b167c1SMordechay Goodstein }
19093b167c1SMordechay Goodstein 
19193b167c1SMordechay Goodstein FWRT_DEBUGFS_WRITE_FILE_OPS(timestamp_marker, 10);
19293b167c1SMordechay Goodstein 
19393b167c1SMordechay Goodstein int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt,
19493b167c1SMordechay Goodstein 			    struct dentry *dbgfs_dir)
19593b167c1SMordechay Goodstein {
19693b167c1SMordechay Goodstein 	INIT_DELAYED_WORK(&fwrt->timestamp.wk, iwl_fw_timestamp_marker_wk);
1972ef00c53SJoe Perches 	FWRT_DEBUGFS_ADD_FILE(timestamp_marker, dbgfs_dir, 0200);
19893b167c1SMordechay Goodstein 	return 0;
19993b167c1SMordechay Goodstein err:
20093b167c1SMordechay Goodstein 	IWL_ERR(fwrt, "Can't create the fwrt debugfs directory\n");
20193b167c1SMordechay Goodstein 	return -ENOMEM;
20293b167c1SMordechay Goodstein }
203