xref: /linux/drivers/net/wireless/realtek/rtlwifi/debug.c (revision 5dbe1f8eb8c5ac69394400a5b86fd81775e96c43)
1d27a76faSLarry Finger // SPDX-License-Identifier: GPL-2.0
2d27a76faSLarry Finger /* Copyright(c) 2009-2012  Realtek Corporation.*/
3f1d2b4d3SLarry Finger 
4f1d2b4d3SLarry Finger #include "wifi.h"
5610247f4SPing-Ke Shih #include "cam.h"
6f1d2b4d3SLarry Finger 
7f1d2b4d3SLarry Finger #include <linux/moduleparam.h>
8610247f4SPing-Ke Shih #include <linux/vmalloc.h>
9f1d2b4d3SLarry Finger 
109ce22191SJoe Perches #ifdef CONFIG_RTLWIFI_DEBUG
11102e295eSLarry Finger void _rtl_dbg_print(struct rtl_priv *rtlpriv, u64 comp, int level,
12102e295eSLarry Finger 		    const char *fmt, ...)
13102e295eSLarry Finger {
14c34df318SLarry Finger 	if (unlikely((comp & rtlpriv->cfg->mod_params->debug_mask) &&
15d63589cbSFrank A. Cancio Bello 		     level <= rtlpriv->cfg->mod_params->debug_level)) {
16102e295eSLarry Finger 		struct va_format vaf;
17102e295eSLarry Finger 		va_list args;
18102e295eSLarry Finger 
19102e295eSLarry Finger 		va_start(args, fmt);
20102e295eSLarry Finger 
21102e295eSLarry Finger 		vaf.fmt = fmt;
22102e295eSLarry Finger 		vaf.va = &args;
23102e295eSLarry Finger 
24c34df318SLarry Finger 		pr_info("%pV", &vaf);
25102e295eSLarry Finger 
26102e295eSLarry Finger 		va_end(args);
27102e295eSLarry Finger 	}
28102e295eSLarry Finger }
29102e295eSLarry Finger EXPORT_SYMBOL_GPL(_rtl_dbg_print);
30102e295eSLarry Finger 
31102e295eSLarry Finger void _rtl_dbg_print_data(struct rtl_priv *rtlpriv, u64 comp, int level,
32102e295eSLarry Finger 			 const char *titlestring,
33102e295eSLarry Finger 			 const void *hexdata, int hexdatalen)
34102e295eSLarry Finger {
35c34df318SLarry Finger 	if (unlikely(((comp) & rtlpriv->cfg->mod_params->debug_mask) &&
36c34df318SLarry Finger 		     ((level) <= rtlpriv->cfg->mod_params->debug_level))) {
37c34df318SLarry Finger 		pr_info("In process \"%s\" (pid %i): %s\n",
38102e295eSLarry Finger 			current->comm, current->pid, titlestring);
39102e295eSLarry Finger 		print_hex_dump_bytes("", DUMP_PREFIX_NONE,
40102e295eSLarry Finger 				     hexdata, hexdatalen);
41102e295eSLarry Finger 	}
42102e295eSLarry Finger }
43102e295eSLarry Finger EXPORT_SYMBOL_GPL(_rtl_dbg_print_data);
44102e295eSLarry Finger 
45610247f4SPing-Ke Shih struct rtl_debugfs_priv {
46610247f4SPing-Ke Shih 	struct rtl_priv *rtlpriv;
47610247f4SPing-Ke Shih 	int (*cb_read)(struct seq_file *m, void *v);
48610247f4SPing-Ke Shih 	ssize_t (*cb_write)(struct file *filp, const char __user *buffer,
49610247f4SPing-Ke Shih 			    size_t count, loff_t *loff);
50610247f4SPing-Ke Shih 	u32 cb_data;
51610247f4SPing-Ke Shih };
52610247f4SPing-Ke Shih 
53610247f4SPing-Ke Shih static struct dentry *debugfs_topdir;
54610247f4SPing-Ke Shih 
55610247f4SPing-Ke Shih static int rtl_debug_get_common(struct seq_file *m, void *v)
56610247f4SPing-Ke Shih {
57610247f4SPing-Ke Shih 	struct rtl_debugfs_priv *debugfs_priv = m->private;
58610247f4SPing-Ke Shih 
59610247f4SPing-Ke Shih 	return debugfs_priv->cb_read(m, v);
60610247f4SPing-Ke Shih }
61610247f4SPing-Ke Shih 
62610247f4SPing-Ke Shih static int dl_debug_open_common(struct inode *inode, struct file *file)
63610247f4SPing-Ke Shih {
64610247f4SPing-Ke Shih 	return single_open(file, rtl_debug_get_common, inode->i_private);
65610247f4SPing-Ke Shih }
66610247f4SPing-Ke Shih 
67610247f4SPing-Ke Shih static const struct file_operations file_ops_common = {
68610247f4SPing-Ke Shih 	.open = dl_debug_open_common,
69610247f4SPing-Ke Shih 	.read = seq_read,
70610247f4SPing-Ke Shih 	.llseek = seq_lseek,
714c3e4879SWei Yongjun 	.release = single_release,
72610247f4SPing-Ke Shih };
73610247f4SPing-Ke Shih 
74610247f4SPing-Ke Shih static int rtl_debug_get_mac_page(struct seq_file *m, void *v)
75610247f4SPing-Ke Shih {
76610247f4SPing-Ke Shih 	struct rtl_debugfs_priv *debugfs_priv = m->private;
77610247f4SPing-Ke Shih 	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;
78610247f4SPing-Ke Shih 	u32 page = debugfs_priv->cb_data;
79610247f4SPing-Ke Shih 	int i, n;
80610247f4SPing-Ke Shih 	int max = 0xff;
81610247f4SPing-Ke Shih 
82610247f4SPing-Ke Shih 	for (n = 0; n <= max; ) {
83610247f4SPing-Ke Shih 		seq_printf(m, "\n%8.8x  ", n + page);
84610247f4SPing-Ke Shih 		for (i = 0; i < 4 && n <= max; i++, n += 4)
85610247f4SPing-Ke Shih 			seq_printf(m, "%8.8x    ",
86610247f4SPing-Ke Shih 				   rtl_read_dword(rtlpriv, (page | n)));
87610247f4SPing-Ke Shih 	}
88610247f4SPing-Ke Shih 	seq_puts(m, "\n");
89610247f4SPing-Ke Shih 	return 0;
90610247f4SPing-Ke Shih }
91610247f4SPing-Ke Shih 
92610247f4SPing-Ke Shih #define RTL_DEBUG_IMPL_MAC_SERIES(page, addr)			\
93610247f4SPing-Ke Shih static struct rtl_debugfs_priv rtl_debug_priv_mac_ ##page = {	\
94610247f4SPing-Ke Shih 	.cb_read = rtl_debug_get_mac_page,			\
95610247f4SPing-Ke Shih 	.cb_data = addr,					\
96610247f4SPing-Ke Shih }
97610247f4SPing-Ke Shih 
98610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(0, 0x0000);
99610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(1, 0x0100);
100610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(2, 0x0200);
101610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(3, 0x0300);
102610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(4, 0x0400);
103610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(5, 0x0500);
104610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(6, 0x0600);
105610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(7, 0x0700);
106610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(10, 0x1000);
107610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(11, 0x1100);
108610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(12, 0x1200);
109610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(13, 0x1300);
110610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(14, 0x1400);
111610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(15, 0x1500);
112610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(16, 0x1600);
113610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(17, 0x1700);
114610247f4SPing-Ke Shih 
115610247f4SPing-Ke Shih static int rtl_debug_get_bb_page(struct seq_file *m, void *v)
116610247f4SPing-Ke Shih {
117610247f4SPing-Ke Shih 	struct rtl_debugfs_priv *debugfs_priv = m->private;
118610247f4SPing-Ke Shih 	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;
119610247f4SPing-Ke Shih 	struct ieee80211_hw *hw = rtlpriv->hw;
120610247f4SPing-Ke Shih 	u32 page = debugfs_priv->cb_data;
121610247f4SPing-Ke Shih 	int i, n;
122610247f4SPing-Ke Shih 	int max = 0xff;
123610247f4SPing-Ke Shih 
124610247f4SPing-Ke Shih 	for (n = 0; n <= max; ) {
125610247f4SPing-Ke Shih 		seq_printf(m, "\n%8.8x  ", n + page);
126610247f4SPing-Ke Shih 		for (i = 0; i < 4 && n <= max; i++, n += 4)
127610247f4SPing-Ke Shih 			seq_printf(m, "%8.8x    ",
128610247f4SPing-Ke Shih 				   rtl_get_bbreg(hw, (page | n), 0xffffffff));
129610247f4SPing-Ke Shih 	}
130610247f4SPing-Ke Shih 	seq_puts(m, "\n");
131610247f4SPing-Ke Shih 	return 0;
132610247f4SPing-Ke Shih }
133610247f4SPing-Ke Shih 
134610247f4SPing-Ke Shih #define RTL_DEBUG_IMPL_BB_SERIES(page, addr)			\
135610247f4SPing-Ke Shih static struct rtl_debugfs_priv rtl_debug_priv_bb_ ##page = {	\
136610247f4SPing-Ke Shih 	.cb_read = rtl_debug_get_bb_page,			\
137610247f4SPing-Ke Shih 	.cb_data = addr,					\
138610247f4SPing-Ke Shih }
139610247f4SPing-Ke Shih 
140610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(8, 0x0800);
141610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(9, 0x0900);
142610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(a, 0x0a00);
143610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(b, 0x0b00);
144610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(c, 0x0c00);
145610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(d, 0x0d00);
146610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(e, 0x0e00);
147610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(f, 0x0f00);
148610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(18, 0x1800);
149610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(19, 0x1900);
150610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(1a, 0x1a00);
151610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(1b, 0x1b00);
152610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(1c, 0x1c00);
153610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(1d, 0x1d00);
154610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(1e, 0x1e00);
155610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(1f, 0x1f00);
156610247f4SPing-Ke Shih 
157610247f4SPing-Ke Shih static int rtl_debug_get_reg_rf(struct seq_file *m, void *v)
158610247f4SPing-Ke Shih {
159610247f4SPing-Ke Shih 	struct rtl_debugfs_priv *debugfs_priv = m->private;
160610247f4SPing-Ke Shih 	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;
161610247f4SPing-Ke Shih 	struct ieee80211_hw *hw = rtlpriv->hw;
162610247f4SPing-Ke Shih 	enum radio_path rfpath = debugfs_priv->cb_data;
163610247f4SPing-Ke Shih 	int i, n;
164610247f4SPing-Ke Shih 	int max = 0x40;
165610247f4SPing-Ke Shih 
166610247f4SPing-Ke Shih 	if (IS_HARDWARE_TYPE_8822B(rtlpriv))
167610247f4SPing-Ke Shih 		max = 0xff;
168610247f4SPing-Ke Shih 
169610247f4SPing-Ke Shih 	seq_printf(m, "\nPATH(%d)", rfpath);
170610247f4SPing-Ke Shih 
171610247f4SPing-Ke Shih 	for (n = 0; n <= max; ) {
172610247f4SPing-Ke Shih 		seq_printf(m, "\n%8.8x  ", n);
173610247f4SPing-Ke Shih 		for (i = 0; i < 4 && n <= max; n += 1, i++)
174610247f4SPing-Ke Shih 			seq_printf(m, "%8.8x    ",
175610247f4SPing-Ke Shih 				   rtl_get_rfreg(hw, rfpath, n, 0xffffffff));
176610247f4SPing-Ke Shih 	}
177610247f4SPing-Ke Shih 	seq_puts(m, "\n");
178610247f4SPing-Ke Shih 	return 0;
179610247f4SPing-Ke Shih }
180610247f4SPing-Ke Shih 
181610247f4SPing-Ke Shih #define RTL_DEBUG_IMPL_RF_SERIES(page, addr)			\
182610247f4SPing-Ke Shih static struct rtl_debugfs_priv rtl_debug_priv_rf_ ##page = {	\
183610247f4SPing-Ke Shih 	.cb_read = rtl_debug_get_reg_rf,			\
184610247f4SPing-Ke Shih 	.cb_data = addr,					\
185610247f4SPing-Ke Shih }
186610247f4SPing-Ke Shih 
187610247f4SPing-Ke Shih RTL_DEBUG_IMPL_RF_SERIES(a, RF90_PATH_A);
188610247f4SPing-Ke Shih RTL_DEBUG_IMPL_RF_SERIES(b, RF90_PATH_B);
189610247f4SPing-Ke Shih 
190610247f4SPing-Ke Shih static int rtl_debug_get_cam_register(struct seq_file *m, void *v)
191610247f4SPing-Ke Shih {
192610247f4SPing-Ke Shih 	struct rtl_debugfs_priv *debugfs_priv = m->private;
193610247f4SPing-Ke Shih 	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;
194610247f4SPing-Ke Shih 	int start = debugfs_priv->cb_data;
195610247f4SPing-Ke Shih 	u32 target_cmd = 0;
196610247f4SPing-Ke Shih 	u32 target_val = 0;
197610247f4SPing-Ke Shih 	u8 entry_i = 0;
198610247f4SPing-Ke Shih 	u32 ulstatus;
199610247f4SPing-Ke Shih 	int i = 100, j = 0;
200610247f4SPing-Ke Shih 	int end = (start + 11 > TOTAL_CAM_ENTRY ? TOTAL_CAM_ENTRY : start + 11);
201610247f4SPing-Ke Shih 
202610247f4SPing-Ke Shih 	/* This dump the current register page */
203610247f4SPing-Ke Shih 	seq_printf(m,
204610247f4SPing-Ke Shih 		   "\n#################### SECURITY CAM (%d-%d) ##################\n",
205610247f4SPing-Ke Shih 		   start, end - 1);
206610247f4SPing-Ke Shih 
207610247f4SPing-Ke Shih 	for (j = start; j < end; j++) {
208610247f4SPing-Ke Shih 		seq_printf(m, "\nD:  %2x > ", j);
209610247f4SPing-Ke Shih 		for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {
210610247f4SPing-Ke Shih 			/* polling bit, and No Write enable, and address  */
211610247f4SPing-Ke Shih 			target_cmd = entry_i + CAM_CONTENT_COUNT * j;
212610247f4SPing-Ke Shih 			target_cmd = target_cmd | BIT(31);
213610247f4SPing-Ke Shih 
214610247f4SPing-Ke Shih 			/* Check polling bit is clear */
215610247f4SPing-Ke Shih 			while ((i--) >= 0) {
216610247f4SPing-Ke Shih 				ulstatus =
217610247f4SPing-Ke Shih 				    rtl_read_dword(rtlpriv,
218610247f4SPing-Ke Shih 						   rtlpriv->cfg->maps[RWCAM]);
219610247f4SPing-Ke Shih 				if (ulstatus & BIT(31))
220610247f4SPing-Ke Shih 					continue;
221610247f4SPing-Ke Shih 				else
222610247f4SPing-Ke Shih 					break;
223610247f4SPing-Ke Shih 			}
224610247f4SPing-Ke Shih 
225610247f4SPing-Ke Shih 			rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
226610247f4SPing-Ke Shih 					target_cmd);
227610247f4SPing-Ke Shih 			target_val = rtl_read_dword(rtlpriv,
228610247f4SPing-Ke Shih 						    rtlpriv->cfg->maps[RCAMO]);
229610247f4SPing-Ke Shih 			seq_printf(m, "%8.8x ", target_val);
230610247f4SPing-Ke Shih 		}
231610247f4SPing-Ke Shih 	}
232610247f4SPing-Ke Shih 	seq_puts(m, "\n");
233610247f4SPing-Ke Shih 	return 0;
234610247f4SPing-Ke Shih }
235610247f4SPing-Ke Shih 
236610247f4SPing-Ke Shih #define RTL_DEBUG_IMPL_CAM_SERIES(page, addr)			\
237610247f4SPing-Ke Shih static struct rtl_debugfs_priv rtl_debug_priv_cam_ ##page = {	\
238610247f4SPing-Ke Shih 	.cb_read = rtl_debug_get_cam_register,			\
239610247f4SPing-Ke Shih 	.cb_data = addr,					\
240610247f4SPing-Ke Shih }
241610247f4SPing-Ke Shih 
242610247f4SPing-Ke Shih RTL_DEBUG_IMPL_CAM_SERIES(1, 0);
243610247f4SPing-Ke Shih RTL_DEBUG_IMPL_CAM_SERIES(2, 11);
244610247f4SPing-Ke Shih RTL_DEBUG_IMPL_CAM_SERIES(3, 22);
245610247f4SPing-Ke Shih 
246610247f4SPing-Ke Shih static int rtl_debug_get_btcoex(struct seq_file *m, void *v)
247610247f4SPing-Ke Shih {
248610247f4SPing-Ke Shih 	struct rtl_debugfs_priv *debugfs_priv = m->private;
249610247f4SPing-Ke Shih 	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;
250610247f4SPing-Ke Shih 
251610247f4SPing-Ke Shih 	if (rtlpriv->cfg->ops->get_btc_status())
252610247f4SPing-Ke Shih 		rtlpriv->btcoexist.btc_ops->btc_display_bt_coex_info(rtlpriv,
253610247f4SPing-Ke Shih 								     m);
254610247f4SPing-Ke Shih 
255610247f4SPing-Ke Shih 	seq_puts(m, "\n");
256610247f4SPing-Ke Shih 
257610247f4SPing-Ke Shih 	return 0;
258610247f4SPing-Ke Shih }
259610247f4SPing-Ke Shih 
260610247f4SPing-Ke Shih static struct rtl_debugfs_priv rtl_debug_priv_btcoex = {
261610247f4SPing-Ke Shih 	.cb_read = rtl_debug_get_btcoex,
262610247f4SPing-Ke Shih 	.cb_data = 0,
263610247f4SPing-Ke Shih };
264610247f4SPing-Ke Shih 
265610247f4SPing-Ke Shih static ssize_t rtl_debugfs_set_write_reg(struct file *filp,
266610247f4SPing-Ke Shih 					 const char __user *buffer,
267610247f4SPing-Ke Shih 					 size_t count, loff_t *loff)
268610247f4SPing-Ke Shih {
269610247f4SPing-Ke Shih 	struct rtl_debugfs_priv *debugfs_priv = filp->private_data;
270610247f4SPing-Ke Shih 	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;
271610247f4SPing-Ke Shih 	char tmp[32 + 1];
272610247f4SPing-Ke Shih 	int tmp_len;
273610247f4SPing-Ke Shih 	u32 addr, val, len;
274610247f4SPing-Ke Shih 	int num;
275610247f4SPing-Ke Shih 
276610247f4SPing-Ke Shih 	if (count < 3)
277610247f4SPing-Ke Shih 		return -EFAULT;
278610247f4SPing-Ke Shih 
279610247f4SPing-Ke Shih 	tmp_len = (count > sizeof(tmp) - 1 ? sizeof(tmp) - 1 : count);
280610247f4SPing-Ke Shih 
281*5dbe1f8eSWei Chen 	if (copy_from_user(tmp, buffer, tmp_len))
282*5dbe1f8eSWei Chen 		return -EFAULT;
283610247f4SPing-Ke Shih 
284610247f4SPing-Ke Shih 	tmp[tmp_len] = '\0';
285610247f4SPing-Ke Shih 
286610247f4SPing-Ke Shih 	/* write BB/MAC register */
287610247f4SPing-Ke Shih 	num = sscanf(tmp, "%x %x %x", &addr, &val, &len);
288610247f4SPing-Ke Shih 
289610247f4SPing-Ke Shih 	if (num !=  3)
290*5dbe1f8eSWei Chen 		return -EINVAL;
291610247f4SPing-Ke Shih 
292610247f4SPing-Ke Shih 	switch (len) {
293610247f4SPing-Ke Shih 	case 1:
294610247f4SPing-Ke Shih 		rtl_write_byte(rtlpriv, addr, (u8)val);
295610247f4SPing-Ke Shih 		break;
296610247f4SPing-Ke Shih 	case 2:
297610247f4SPing-Ke Shih 		rtl_write_word(rtlpriv, addr, (u16)val);
298610247f4SPing-Ke Shih 		break;
299610247f4SPing-Ke Shih 	case 4:
300610247f4SPing-Ke Shih 		rtl_write_dword(rtlpriv, addr, val);
301610247f4SPing-Ke Shih 		break;
302610247f4SPing-Ke Shih 	default:
303610247f4SPing-Ke Shih 		/*printk("error write length=%d", len);*/
304610247f4SPing-Ke Shih 		break;
305610247f4SPing-Ke Shih 	}
306610247f4SPing-Ke Shih 
307610247f4SPing-Ke Shih 	return count;
308610247f4SPing-Ke Shih }
309610247f4SPing-Ke Shih 
310610247f4SPing-Ke Shih static struct rtl_debugfs_priv rtl_debug_priv_write_reg = {
311610247f4SPing-Ke Shih 	.cb_write = rtl_debugfs_set_write_reg,
312610247f4SPing-Ke Shih };
313610247f4SPing-Ke Shih 
314610247f4SPing-Ke Shih static ssize_t rtl_debugfs_set_write_h2c(struct file *filp,
315610247f4SPing-Ke Shih 					 const char __user *buffer,
316610247f4SPing-Ke Shih 					 size_t count, loff_t *loff)
317610247f4SPing-Ke Shih {
318610247f4SPing-Ke Shih 	struct rtl_debugfs_priv *debugfs_priv = filp->private_data;
319610247f4SPing-Ke Shih 	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;
320610247f4SPing-Ke Shih 	struct ieee80211_hw *hw = rtlpriv->hw;
321610247f4SPing-Ke Shih 	char tmp[32 + 1];
322610247f4SPing-Ke Shih 	int tmp_len;
323610247f4SPing-Ke Shih 	u8 h2c_len, h2c_data_packed[8];
324610247f4SPing-Ke Shih 	int h2c_data[8];	/* idx 0: cmd */
325610247f4SPing-Ke Shih 	int i;
326610247f4SPing-Ke Shih 
327610247f4SPing-Ke Shih 	if (count < 3)
328610247f4SPing-Ke Shih 		return -EFAULT;
329610247f4SPing-Ke Shih 
330610247f4SPing-Ke Shih 	tmp_len = (count > sizeof(tmp) - 1 ? sizeof(tmp) - 1 : count);
331610247f4SPing-Ke Shih 
332b88d2814SDan Carpenter 	if (copy_from_user(tmp, buffer, tmp_len))
333b88d2814SDan Carpenter 		return -EFAULT;
334610247f4SPing-Ke Shih 
335610247f4SPing-Ke Shih 	tmp[tmp_len] = '\0';
336610247f4SPing-Ke Shih 
337610247f4SPing-Ke Shih 	h2c_len = sscanf(tmp, "%X %X %X %X %X %X %X %X",
338610247f4SPing-Ke Shih 			 &h2c_data[0], &h2c_data[1],
339610247f4SPing-Ke Shih 			 &h2c_data[2], &h2c_data[3],
340610247f4SPing-Ke Shih 			 &h2c_data[4], &h2c_data[5],
341610247f4SPing-Ke Shih 			 &h2c_data[6], &h2c_data[7]);
342610247f4SPing-Ke Shih 
343b88d2814SDan Carpenter 	if (h2c_len == 0)
344b88d2814SDan Carpenter 		return -EINVAL;
345610247f4SPing-Ke Shih 
346610247f4SPing-Ke Shih 	for (i = 0; i < h2c_len; i++)
347610247f4SPing-Ke Shih 		h2c_data_packed[i] = (u8)h2c_data[i];
348610247f4SPing-Ke Shih 
349610247f4SPing-Ke Shih 	rtlpriv->cfg->ops->fill_h2c_cmd(hw, h2c_data_packed[0],
350610247f4SPing-Ke Shih 					h2c_len - 1,
351610247f4SPing-Ke Shih 					&h2c_data_packed[1]);
352610247f4SPing-Ke Shih 
353610247f4SPing-Ke Shih 	return count;
354610247f4SPing-Ke Shih }
355610247f4SPing-Ke Shih 
356610247f4SPing-Ke Shih static struct rtl_debugfs_priv rtl_debug_priv_write_h2c = {
357610247f4SPing-Ke Shih 	.cb_write = rtl_debugfs_set_write_h2c,
358610247f4SPing-Ke Shih };
359610247f4SPing-Ke Shih 
360610247f4SPing-Ke Shih static ssize_t rtl_debugfs_set_write_rfreg(struct file *filp,
361610247f4SPing-Ke Shih 					   const char __user *buffer,
362610247f4SPing-Ke Shih 					    size_t count, loff_t *loff)
363610247f4SPing-Ke Shih {
364610247f4SPing-Ke Shih 	struct rtl_debugfs_priv *debugfs_priv = filp->private_data;
365610247f4SPing-Ke Shih 	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;
366610247f4SPing-Ke Shih 	struct ieee80211_hw *hw = rtlpriv->hw;
367610247f4SPing-Ke Shih 	char tmp[32 + 1];
368610247f4SPing-Ke Shih 	int tmp_len;
369610247f4SPing-Ke Shih 	int num;
370610247f4SPing-Ke Shih 	int path;
371610247f4SPing-Ke Shih 	u32 addr, bitmask, data;
372610247f4SPing-Ke Shih 
373610247f4SPing-Ke Shih 	if (count < 3)
374610247f4SPing-Ke Shih 		return -EFAULT;
375610247f4SPing-Ke Shih 
376610247f4SPing-Ke Shih 	tmp_len = (count > sizeof(tmp) - 1 ? sizeof(tmp) - 1 : count);
377610247f4SPing-Ke Shih 
378905a9241SWei Chen 	if (copy_from_user(tmp, buffer, tmp_len))
379905a9241SWei Chen 		return -EFAULT;
380610247f4SPing-Ke Shih 
381610247f4SPing-Ke Shih 	tmp[tmp_len] = '\0';
382610247f4SPing-Ke Shih 
383610247f4SPing-Ke Shih 	num = sscanf(tmp, "%X %X %X %X",
384610247f4SPing-Ke Shih 		     &path, &addr, &bitmask, &data);
385610247f4SPing-Ke Shih 
386610247f4SPing-Ke Shih 	if (num != 4) {
387f108a420SLarry Finger 		rtl_dbg(rtlpriv, COMP_ERR, DBG_DMESG,
388610247f4SPing-Ke Shih 			"Format is <path> <addr> <mask> <data>\n");
389905a9241SWei Chen 		return -EINVAL;
390610247f4SPing-Ke Shih 	}
391610247f4SPing-Ke Shih 
392610247f4SPing-Ke Shih 	rtl_set_rfreg(hw, path, addr, bitmask, data);
393610247f4SPing-Ke Shih 
394610247f4SPing-Ke Shih 	return count;
395610247f4SPing-Ke Shih }
396610247f4SPing-Ke Shih 
397610247f4SPing-Ke Shih static struct rtl_debugfs_priv rtl_debug_priv_write_rfreg = {
398610247f4SPing-Ke Shih 	.cb_write = rtl_debugfs_set_write_rfreg,
399610247f4SPing-Ke Shih };
400610247f4SPing-Ke Shih 
401610247f4SPing-Ke Shih static int rtl_debugfs_close(struct inode *inode, struct file *filp)
402610247f4SPing-Ke Shih {
403610247f4SPing-Ke Shih 	return 0;
404610247f4SPing-Ke Shih }
405610247f4SPing-Ke Shih 
406610247f4SPing-Ke Shih static ssize_t rtl_debugfs_common_write(struct file *filp,
407610247f4SPing-Ke Shih 					const char __user *buffer,
408610247f4SPing-Ke Shih 					size_t count, loff_t *loff)
409610247f4SPing-Ke Shih {
410610247f4SPing-Ke Shih 	struct rtl_debugfs_priv *debugfs_priv = filp->private_data;
411610247f4SPing-Ke Shih 
412610247f4SPing-Ke Shih 	return debugfs_priv->cb_write(filp, buffer, count, loff);
413610247f4SPing-Ke Shih }
414610247f4SPing-Ke Shih 
415610247f4SPing-Ke Shih static const struct file_operations file_ops_common_write = {
416610247f4SPing-Ke Shih 	.owner = THIS_MODULE,
417610247f4SPing-Ke Shih 	.write = rtl_debugfs_common_write,
418610247f4SPing-Ke Shih 	.open = simple_open,
419610247f4SPing-Ke Shih 	.release = rtl_debugfs_close,
420610247f4SPing-Ke Shih };
421610247f4SPing-Ke Shih 
422610247f4SPing-Ke Shih #define RTL_DEBUGFS_ADD_CORE(name, mode, fopname)			   \
423610247f4SPing-Ke Shih 	do {								   \
424610247f4SPing-Ke Shih 		rtl_debug_priv_ ##name.rtlpriv = rtlpriv;		   \
4253059785bSGreg Kroah-Hartman 		debugfs_create_file(#name, mode, parent,		   \
4263059785bSGreg Kroah-Hartman 				    &rtl_debug_priv_ ##name,		   \
4273059785bSGreg Kroah-Hartman 				    &file_ops_ ##fopname);		   \
428610247f4SPing-Ke Shih 	} while (0)
429610247f4SPing-Ke Shih 
430610247f4SPing-Ke Shih #define RTL_DEBUGFS_ADD(name)						   \
431610247f4SPing-Ke Shih 		RTL_DEBUGFS_ADD_CORE(name, S_IFREG | 0444, common)
432610247f4SPing-Ke Shih #define RTL_DEBUGFS_ADD_W(name)						   \
433610247f4SPing-Ke Shih 		RTL_DEBUGFS_ADD_CORE(name, S_IFREG | 0222, common_write)
434610247f4SPing-Ke Shih 
435610247f4SPing-Ke Shih void rtl_debug_add_one(struct ieee80211_hw *hw)
436610247f4SPing-Ke Shih {
437610247f4SPing-Ke Shih 	struct rtl_priv *rtlpriv = rtl_priv(hw);
438610247f4SPing-Ke Shih 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
439610247f4SPing-Ke Shih 	struct dentry *parent;
440610247f4SPing-Ke Shih 
441610247f4SPing-Ke Shih 	snprintf(rtlpriv->dbg.debugfs_name, 18, "%pMF", rtlefuse->dev_addr);
442610247f4SPing-Ke Shih 
443610247f4SPing-Ke Shih 	rtlpriv->dbg.debugfs_dir =
444610247f4SPing-Ke Shih 		debugfs_create_dir(rtlpriv->dbg.debugfs_name, debugfs_topdir);
445610247f4SPing-Ke Shih 
446610247f4SPing-Ke Shih 	parent = rtlpriv->dbg.debugfs_dir;
447610247f4SPing-Ke Shih 
448610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_0);
449610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_1);
450610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_2);
451610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_3);
452610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_4);
453610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_5);
454610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_6);
455610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_7);
456610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_8);
457610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_9);
458610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_a);
459610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_b);
460610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_c);
461610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_d);
462610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_e);
463610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_f);
464610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_10);
465610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_11);
466610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_12);
467610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_13);
468610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_14);
469610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_15);
470610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_16);
471610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_17);
472610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_18);
473610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_19);
474610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_1a);
475610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_1b);
476610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_1c);
477610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_1d);
478610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_1e);
479610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_1f);
480610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(rf_a);
481610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(rf_b);
482610247f4SPing-Ke Shih 
483610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(cam_1);
484610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(cam_2);
485610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(cam_3);
486610247f4SPing-Ke Shih 
487610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(btcoex);
488610247f4SPing-Ke Shih 
489610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD_W(write_reg);
490610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD_W(write_h2c);
491610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD_W(write_rfreg);
492610247f4SPing-Ke Shih }
493610247f4SPing-Ke Shih EXPORT_SYMBOL_GPL(rtl_debug_add_one);
494610247f4SPing-Ke Shih 
495610247f4SPing-Ke Shih void rtl_debug_remove_one(struct ieee80211_hw *hw)
496610247f4SPing-Ke Shih {
497610247f4SPing-Ke Shih 	struct rtl_priv *rtlpriv = rtl_priv(hw);
498610247f4SPing-Ke Shih 
499610247f4SPing-Ke Shih 	debugfs_remove_recursive(rtlpriv->dbg.debugfs_dir);
500610247f4SPing-Ke Shih 	rtlpriv->dbg.debugfs_dir = NULL;
501610247f4SPing-Ke Shih }
502610247f4SPing-Ke Shih EXPORT_SYMBOL_GPL(rtl_debug_remove_one);
503610247f4SPing-Ke Shih 
504610247f4SPing-Ke Shih void rtl_debugfs_add_topdir(void)
505610247f4SPing-Ke Shih {
506610247f4SPing-Ke Shih 	debugfs_topdir = debugfs_create_dir("rtlwifi", NULL);
507610247f4SPing-Ke Shih }
508610247f4SPing-Ke Shih 
509610247f4SPing-Ke Shih void rtl_debugfs_remove_topdir(void)
510610247f4SPing-Ke Shih {
511610247f4SPing-Ke Shih 	debugfs_remove_recursive(debugfs_topdir);
512610247f4SPing-Ke Shih }
513610247f4SPing-Ke Shih 
5149ce22191SJoe Perches #endif
515