xref: /linux/drivers/net/wireless/realtek/rtlwifi/debug.c (revision 610247f46feb23beda99d0bb44aa8f51a8dc27e1)
1f1d2b4d3SLarry Finger /******************************************************************************
2f1d2b4d3SLarry Finger  *
3f1d2b4d3SLarry Finger  * Copyright(c) 2009-2012  Realtek Corporation.
4f1d2b4d3SLarry Finger  *
5f1d2b4d3SLarry Finger  * This program is free software; you can redistribute it and/or modify it
6f1d2b4d3SLarry Finger  * under the terms of version 2 of the GNU General Public License as
7f1d2b4d3SLarry Finger  * published by the Free Software Foundation.
8f1d2b4d3SLarry Finger  *
9f1d2b4d3SLarry Finger  * This program is distributed in the hope that it will be useful, but WITHOUT
10f1d2b4d3SLarry Finger  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11f1d2b4d3SLarry Finger  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12f1d2b4d3SLarry Finger  * more details.
13f1d2b4d3SLarry Finger  *
14f1d2b4d3SLarry Finger  * The full GNU General Public License is included in this distribution in the
15f1d2b4d3SLarry Finger  * file called LICENSE.
16f1d2b4d3SLarry Finger  *
17f1d2b4d3SLarry Finger  * Contact Information:
18f1d2b4d3SLarry Finger  * wlanfae <wlanfae@realtek.com>
19f1d2b4d3SLarry Finger  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
20f1d2b4d3SLarry Finger  * Hsinchu 300, Taiwan.
21f1d2b4d3SLarry Finger  *
22f1d2b4d3SLarry Finger  * Larry Finger <Larry.Finger@lwfinger.net>
23f1d2b4d3SLarry Finger  *****************************************************************************/
24f1d2b4d3SLarry Finger 
25f1d2b4d3SLarry Finger #include "wifi.h"
26*610247f4SPing-Ke Shih #include "cam.h"
27f1d2b4d3SLarry Finger 
28f1d2b4d3SLarry Finger #include <linux/moduleparam.h>
29*610247f4SPing-Ke Shih #include <linux/vmalloc.h>
30f1d2b4d3SLarry Finger 
319ce22191SJoe Perches #ifdef CONFIG_RTLWIFI_DEBUG
3279b64ed7SPing-Ke Shih void _rtl_dbg_trace(struct rtl_priv *rtlpriv, u64 comp, int level,
33102e295eSLarry Finger 		    const char *fmt, ...)
349ce22191SJoe Perches {
35c34df318SLarry Finger 	if (unlikely((comp & rtlpriv->cfg->mod_params->debug_mask) &&
36d63589cbSFrank A. Cancio Bello 		     level <= rtlpriv->cfg->mod_params->debug_level)) {
379ce22191SJoe Perches 		struct va_format vaf;
389ce22191SJoe Perches 		va_list args;
399ce22191SJoe Perches 
409ce22191SJoe Perches 		va_start(args, fmt);
419ce22191SJoe Perches 
429ce22191SJoe Perches 		vaf.fmt = fmt;
439ce22191SJoe Perches 		vaf.va = &args;
449ce22191SJoe Perches 
45c34df318SLarry Finger 		pr_info(":<%lx> %pV", in_interrupt(), &vaf);
469ce22191SJoe Perches 
479ce22191SJoe Perches 		va_end(args);
489ce22191SJoe Perches 	}
499ce22191SJoe Perches }
509ce22191SJoe Perches EXPORT_SYMBOL_GPL(_rtl_dbg_trace);
51102e295eSLarry Finger 
52102e295eSLarry Finger void _rtl_dbg_print(struct rtl_priv *rtlpriv, u64 comp, int level,
53102e295eSLarry Finger 		    const char *fmt, ...)
54102e295eSLarry Finger {
55c34df318SLarry Finger 	if (unlikely((comp & rtlpriv->cfg->mod_params->debug_mask) &&
56d63589cbSFrank A. Cancio Bello 		     level <= rtlpriv->cfg->mod_params->debug_level)) {
57102e295eSLarry Finger 		struct va_format vaf;
58102e295eSLarry Finger 		va_list args;
59102e295eSLarry Finger 
60102e295eSLarry Finger 		va_start(args, fmt);
61102e295eSLarry Finger 
62102e295eSLarry Finger 		vaf.fmt = fmt;
63102e295eSLarry Finger 		vaf.va = &args;
64102e295eSLarry Finger 
65c34df318SLarry Finger 		pr_info("%pV", &vaf);
66102e295eSLarry Finger 
67102e295eSLarry Finger 		va_end(args);
68102e295eSLarry Finger 	}
69102e295eSLarry Finger }
70102e295eSLarry Finger EXPORT_SYMBOL_GPL(_rtl_dbg_print);
71102e295eSLarry Finger 
72102e295eSLarry Finger void _rtl_dbg_print_data(struct rtl_priv *rtlpriv, u64 comp, int level,
73102e295eSLarry Finger 			 const char *titlestring,
74102e295eSLarry Finger 			 const void *hexdata, int hexdatalen)
75102e295eSLarry Finger {
76c34df318SLarry Finger 	if (unlikely(((comp) & rtlpriv->cfg->mod_params->debug_mask) &&
77c34df318SLarry Finger 		     ((level) <= rtlpriv->cfg->mod_params->debug_level))) {
78c34df318SLarry Finger 		pr_info("In process \"%s\" (pid %i): %s\n",
79102e295eSLarry Finger 			current->comm, current->pid, titlestring);
80102e295eSLarry Finger 		print_hex_dump_bytes("", DUMP_PREFIX_NONE,
81102e295eSLarry Finger 				     hexdata, hexdatalen);
82102e295eSLarry Finger 	}
83102e295eSLarry Finger }
84102e295eSLarry Finger EXPORT_SYMBOL_GPL(_rtl_dbg_print_data);
85102e295eSLarry Finger 
86*610247f4SPing-Ke Shih struct rtl_debugfs_priv {
87*610247f4SPing-Ke Shih 	struct rtl_priv *rtlpriv;
88*610247f4SPing-Ke Shih 	int (*cb_read)(struct seq_file *m, void *v);
89*610247f4SPing-Ke Shih 	ssize_t (*cb_write)(struct file *filp, const char __user *buffer,
90*610247f4SPing-Ke Shih 			    size_t count, loff_t *loff);
91*610247f4SPing-Ke Shih 	u32 cb_data;
92*610247f4SPing-Ke Shih };
93*610247f4SPing-Ke Shih 
94*610247f4SPing-Ke Shih static struct dentry *debugfs_topdir;
95*610247f4SPing-Ke Shih 
96*610247f4SPing-Ke Shih static int rtl_debug_get_common(struct seq_file *m, void *v)
97*610247f4SPing-Ke Shih {
98*610247f4SPing-Ke Shih 	struct rtl_debugfs_priv *debugfs_priv = m->private;
99*610247f4SPing-Ke Shih 
100*610247f4SPing-Ke Shih 	return debugfs_priv->cb_read(m, v);
101*610247f4SPing-Ke Shih }
102*610247f4SPing-Ke Shih 
103*610247f4SPing-Ke Shih static int dl_debug_open_common(struct inode *inode, struct file *file)
104*610247f4SPing-Ke Shih {
105*610247f4SPing-Ke Shih 	return single_open(file, rtl_debug_get_common, inode->i_private);
106*610247f4SPing-Ke Shih }
107*610247f4SPing-Ke Shih 
108*610247f4SPing-Ke Shih static const struct file_operations file_ops_common = {
109*610247f4SPing-Ke Shih 	.open = dl_debug_open_common,
110*610247f4SPing-Ke Shih 	.read = seq_read,
111*610247f4SPing-Ke Shih 	.llseek = seq_lseek,
112*610247f4SPing-Ke Shih 	.release = seq_release,
113*610247f4SPing-Ke Shih };
114*610247f4SPing-Ke Shih 
115*610247f4SPing-Ke Shih static int rtl_debug_get_mac_page(struct seq_file *m, void *v)
116*610247f4SPing-Ke Shih {
117*610247f4SPing-Ke Shih 	struct rtl_debugfs_priv *debugfs_priv = m->private;
118*610247f4SPing-Ke Shih 	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;
119*610247f4SPing-Ke Shih 	u32 page = debugfs_priv->cb_data;
120*610247f4SPing-Ke Shih 	int i, n;
121*610247f4SPing-Ke Shih 	int max = 0xff;
122*610247f4SPing-Ke Shih 
123*610247f4SPing-Ke Shih 	for (n = 0; n <= max; ) {
124*610247f4SPing-Ke Shih 		seq_printf(m, "\n%8.8x  ", n + page);
125*610247f4SPing-Ke Shih 		for (i = 0; i < 4 && n <= max; i++, n += 4)
126*610247f4SPing-Ke Shih 			seq_printf(m, "%8.8x    ",
127*610247f4SPing-Ke Shih 				   rtl_read_dword(rtlpriv, (page | n)));
128*610247f4SPing-Ke Shih 	}
129*610247f4SPing-Ke Shih 	seq_puts(m, "\n");
130*610247f4SPing-Ke Shih 	return 0;
131*610247f4SPing-Ke Shih }
132*610247f4SPing-Ke Shih 
133*610247f4SPing-Ke Shih #define RTL_DEBUG_IMPL_MAC_SERIES(page, addr)			\
134*610247f4SPing-Ke Shih static struct rtl_debugfs_priv rtl_debug_priv_mac_ ##page = {	\
135*610247f4SPing-Ke Shih 	.cb_read = rtl_debug_get_mac_page,			\
136*610247f4SPing-Ke Shih 	.cb_data = addr,					\
137*610247f4SPing-Ke Shih }
138*610247f4SPing-Ke Shih 
139*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(0, 0x0000);
140*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(1, 0x0100);
141*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(2, 0x0200);
142*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(3, 0x0300);
143*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(4, 0x0400);
144*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(5, 0x0500);
145*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(6, 0x0600);
146*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(7, 0x0700);
147*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(10, 0x1000);
148*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(11, 0x1100);
149*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(12, 0x1200);
150*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(13, 0x1300);
151*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(14, 0x1400);
152*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(15, 0x1500);
153*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(16, 0x1600);
154*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_MAC_SERIES(17, 0x1700);
155*610247f4SPing-Ke Shih 
156*610247f4SPing-Ke Shih static int rtl_debug_get_bb_page(struct seq_file *m, void *v)
157*610247f4SPing-Ke Shih {
158*610247f4SPing-Ke Shih 	struct rtl_debugfs_priv *debugfs_priv = m->private;
159*610247f4SPing-Ke Shih 	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;
160*610247f4SPing-Ke Shih 	struct ieee80211_hw *hw = rtlpriv->hw;
161*610247f4SPing-Ke Shih 	u32 page = debugfs_priv->cb_data;
162*610247f4SPing-Ke Shih 	int i, n;
163*610247f4SPing-Ke Shih 	int max = 0xff;
164*610247f4SPing-Ke Shih 
165*610247f4SPing-Ke Shih 	for (n = 0; n <= max; ) {
166*610247f4SPing-Ke Shih 		seq_printf(m, "\n%8.8x  ", n + page);
167*610247f4SPing-Ke Shih 		for (i = 0; i < 4 && n <= max; i++, n += 4)
168*610247f4SPing-Ke Shih 			seq_printf(m, "%8.8x    ",
169*610247f4SPing-Ke Shih 				   rtl_get_bbreg(hw, (page | n), 0xffffffff));
170*610247f4SPing-Ke Shih 	}
171*610247f4SPing-Ke Shih 	seq_puts(m, "\n");
172*610247f4SPing-Ke Shih 	return 0;
173*610247f4SPing-Ke Shih }
174*610247f4SPing-Ke Shih 
175*610247f4SPing-Ke Shih #define RTL_DEBUG_IMPL_BB_SERIES(page, addr)			\
176*610247f4SPing-Ke Shih static struct rtl_debugfs_priv rtl_debug_priv_bb_ ##page = {	\
177*610247f4SPing-Ke Shih 	.cb_read = rtl_debug_get_bb_page,			\
178*610247f4SPing-Ke Shih 	.cb_data = addr,					\
179*610247f4SPing-Ke Shih }
180*610247f4SPing-Ke Shih 
181*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(8, 0x0800);
182*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(9, 0x0900);
183*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(a, 0x0a00);
184*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(b, 0x0b00);
185*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(c, 0x0c00);
186*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(d, 0x0d00);
187*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(e, 0x0e00);
188*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(f, 0x0f00);
189*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(18, 0x1800);
190*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(19, 0x1900);
191*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(1a, 0x1a00);
192*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(1b, 0x1b00);
193*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(1c, 0x1c00);
194*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(1d, 0x1d00);
195*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(1e, 0x1e00);
196*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_BB_SERIES(1f, 0x1f00);
197*610247f4SPing-Ke Shih 
198*610247f4SPing-Ke Shih static int rtl_debug_get_reg_rf(struct seq_file *m, void *v)
199*610247f4SPing-Ke Shih {
200*610247f4SPing-Ke Shih 	struct rtl_debugfs_priv *debugfs_priv = m->private;
201*610247f4SPing-Ke Shih 	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;
202*610247f4SPing-Ke Shih 	struct ieee80211_hw *hw = rtlpriv->hw;
203*610247f4SPing-Ke Shih 	enum radio_path rfpath = debugfs_priv->cb_data;
204*610247f4SPing-Ke Shih 	int i, n;
205*610247f4SPing-Ke Shih 	int max = 0x40;
206*610247f4SPing-Ke Shih 
207*610247f4SPing-Ke Shih 	if (IS_HARDWARE_TYPE_8822B(rtlpriv))
208*610247f4SPing-Ke Shih 		max = 0xff;
209*610247f4SPing-Ke Shih 
210*610247f4SPing-Ke Shih 	seq_printf(m, "\nPATH(%d)", rfpath);
211*610247f4SPing-Ke Shih 
212*610247f4SPing-Ke Shih 	for (n = 0; n <= max; ) {
213*610247f4SPing-Ke Shih 		seq_printf(m, "\n%8.8x  ", n);
214*610247f4SPing-Ke Shih 		for (i = 0; i < 4 && n <= max; n += 1, i++)
215*610247f4SPing-Ke Shih 			seq_printf(m, "%8.8x    ",
216*610247f4SPing-Ke Shih 				   rtl_get_rfreg(hw, rfpath, n, 0xffffffff));
217*610247f4SPing-Ke Shih 	}
218*610247f4SPing-Ke Shih 	seq_puts(m, "\n");
219*610247f4SPing-Ke Shih 	return 0;
220*610247f4SPing-Ke Shih }
221*610247f4SPing-Ke Shih 
222*610247f4SPing-Ke Shih #define RTL_DEBUG_IMPL_RF_SERIES(page, addr)			\
223*610247f4SPing-Ke Shih static struct rtl_debugfs_priv rtl_debug_priv_rf_ ##page = {	\
224*610247f4SPing-Ke Shih 	.cb_read = rtl_debug_get_reg_rf,			\
225*610247f4SPing-Ke Shih 	.cb_data = addr,					\
226*610247f4SPing-Ke Shih }
227*610247f4SPing-Ke Shih 
228*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_RF_SERIES(a, RF90_PATH_A);
229*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_RF_SERIES(b, RF90_PATH_B);
230*610247f4SPing-Ke Shih 
231*610247f4SPing-Ke Shih static int rtl_debug_get_cam_register(struct seq_file *m, void *v)
232*610247f4SPing-Ke Shih {
233*610247f4SPing-Ke Shih 	struct rtl_debugfs_priv *debugfs_priv = m->private;
234*610247f4SPing-Ke Shih 	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;
235*610247f4SPing-Ke Shih 	int start = debugfs_priv->cb_data;
236*610247f4SPing-Ke Shih 	u32 target_cmd = 0;
237*610247f4SPing-Ke Shih 	u32 target_val = 0;
238*610247f4SPing-Ke Shih 	u8 entry_i = 0;
239*610247f4SPing-Ke Shih 	u32 ulstatus;
240*610247f4SPing-Ke Shih 	int i = 100, j = 0;
241*610247f4SPing-Ke Shih 	int end = (start + 11 > TOTAL_CAM_ENTRY ? TOTAL_CAM_ENTRY : start + 11);
242*610247f4SPing-Ke Shih 
243*610247f4SPing-Ke Shih 	/* This dump the current register page */
244*610247f4SPing-Ke Shih 	seq_printf(m,
245*610247f4SPing-Ke Shih 		   "\n#################### SECURITY CAM (%d-%d) ##################\n",
246*610247f4SPing-Ke Shih 		   start, end - 1);
247*610247f4SPing-Ke Shih 
248*610247f4SPing-Ke Shih 	for (j = start; j < end; j++) {
249*610247f4SPing-Ke Shih 		seq_printf(m, "\nD:  %2x > ", j);
250*610247f4SPing-Ke Shih 		for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {
251*610247f4SPing-Ke Shih 			/* polling bit, and No Write enable, and address  */
252*610247f4SPing-Ke Shih 			target_cmd = entry_i + CAM_CONTENT_COUNT * j;
253*610247f4SPing-Ke Shih 			target_cmd = target_cmd | BIT(31);
254*610247f4SPing-Ke Shih 
255*610247f4SPing-Ke Shih 			/* Check polling bit is clear */
256*610247f4SPing-Ke Shih 			while ((i--) >= 0) {
257*610247f4SPing-Ke Shih 				ulstatus =
258*610247f4SPing-Ke Shih 				    rtl_read_dword(rtlpriv,
259*610247f4SPing-Ke Shih 						   rtlpriv->cfg->maps[RWCAM]);
260*610247f4SPing-Ke Shih 				if (ulstatus & BIT(31))
261*610247f4SPing-Ke Shih 					continue;
262*610247f4SPing-Ke Shih 				else
263*610247f4SPing-Ke Shih 					break;
264*610247f4SPing-Ke Shih 			}
265*610247f4SPing-Ke Shih 
266*610247f4SPing-Ke Shih 			rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
267*610247f4SPing-Ke Shih 					target_cmd);
268*610247f4SPing-Ke Shih 			target_val = rtl_read_dword(rtlpriv,
269*610247f4SPing-Ke Shih 						    rtlpriv->cfg->maps[RCAMO]);
270*610247f4SPing-Ke Shih 			seq_printf(m, "%8.8x ", target_val);
271*610247f4SPing-Ke Shih 		}
272*610247f4SPing-Ke Shih 	}
273*610247f4SPing-Ke Shih 	seq_puts(m, "\n");
274*610247f4SPing-Ke Shih 	return 0;
275*610247f4SPing-Ke Shih }
276*610247f4SPing-Ke Shih 
277*610247f4SPing-Ke Shih #define RTL_DEBUG_IMPL_CAM_SERIES(page, addr)			\
278*610247f4SPing-Ke Shih static struct rtl_debugfs_priv rtl_debug_priv_cam_ ##page = {	\
279*610247f4SPing-Ke Shih 	.cb_read = rtl_debug_get_cam_register,			\
280*610247f4SPing-Ke Shih 	.cb_data = addr,					\
281*610247f4SPing-Ke Shih }
282*610247f4SPing-Ke Shih 
283*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_CAM_SERIES(1, 0);
284*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_CAM_SERIES(2, 11);
285*610247f4SPing-Ke Shih RTL_DEBUG_IMPL_CAM_SERIES(3, 22);
286*610247f4SPing-Ke Shih 
287*610247f4SPing-Ke Shih static int rtl_debug_get_btcoex(struct seq_file *m, void *v)
288*610247f4SPing-Ke Shih {
289*610247f4SPing-Ke Shih 	struct rtl_debugfs_priv *debugfs_priv = m->private;
290*610247f4SPing-Ke Shih 	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;
291*610247f4SPing-Ke Shih 
292*610247f4SPing-Ke Shih 	if (rtlpriv->cfg->ops->get_btc_status())
293*610247f4SPing-Ke Shih 		rtlpriv->btcoexist.btc_ops->btc_display_bt_coex_info(rtlpriv,
294*610247f4SPing-Ke Shih 								     m);
295*610247f4SPing-Ke Shih 
296*610247f4SPing-Ke Shih 	seq_puts(m, "\n");
297*610247f4SPing-Ke Shih 
298*610247f4SPing-Ke Shih 	return 0;
299*610247f4SPing-Ke Shih }
300*610247f4SPing-Ke Shih 
301*610247f4SPing-Ke Shih static struct rtl_debugfs_priv rtl_debug_priv_btcoex = {
302*610247f4SPing-Ke Shih 	.cb_read = rtl_debug_get_btcoex,
303*610247f4SPing-Ke Shih 	.cb_data = 0,
304*610247f4SPing-Ke Shih };
305*610247f4SPing-Ke Shih 
306*610247f4SPing-Ke Shih static ssize_t rtl_debugfs_set_write_reg(struct file *filp,
307*610247f4SPing-Ke Shih 					 const char __user *buffer,
308*610247f4SPing-Ke Shih 					 size_t count, loff_t *loff)
309*610247f4SPing-Ke Shih {
310*610247f4SPing-Ke Shih 	struct rtl_debugfs_priv *debugfs_priv = filp->private_data;
311*610247f4SPing-Ke Shih 	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;
312*610247f4SPing-Ke Shih 	char tmp[32 + 1];
313*610247f4SPing-Ke Shih 	int tmp_len;
314*610247f4SPing-Ke Shih 	u32 addr, val, len;
315*610247f4SPing-Ke Shih 	int num;
316*610247f4SPing-Ke Shih 
317*610247f4SPing-Ke Shih 	if (count < 3)
318*610247f4SPing-Ke Shih 		return -EFAULT;
319*610247f4SPing-Ke Shih 
320*610247f4SPing-Ke Shih 	tmp_len = (count > sizeof(tmp) - 1 ? sizeof(tmp) - 1 : count);
321*610247f4SPing-Ke Shih 
322*610247f4SPing-Ke Shih 	if (!buffer || copy_from_user(tmp, buffer, tmp_len))
323*610247f4SPing-Ke Shih 		return count;
324*610247f4SPing-Ke Shih 
325*610247f4SPing-Ke Shih 	tmp[tmp_len] = '\0';
326*610247f4SPing-Ke Shih 
327*610247f4SPing-Ke Shih 	/* write BB/MAC register */
328*610247f4SPing-Ke Shih 	num = sscanf(tmp, "%x %x %x", &addr, &val, &len);
329*610247f4SPing-Ke Shih 
330*610247f4SPing-Ke Shih 	if (num !=  3)
331*610247f4SPing-Ke Shih 		return count;
332*610247f4SPing-Ke Shih 
333*610247f4SPing-Ke Shih 	switch (len) {
334*610247f4SPing-Ke Shih 	case 1:
335*610247f4SPing-Ke Shih 		rtl_write_byte(rtlpriv, addr, (u8)val);
336*610247f4SPing-Ke Shih 		break;
337*610247f4SPing-Ke Shih 	case 2:
338*610247f4SPing-Ke Shih 		rtl_write_word(rtlpriv, addr, (u16)val);
339*610247f4SPing-Ke Shih 		break;
340*610247f4SPing-Ke Shih 	case 4:
341*610247f4SPing-Ke Shih 		rtl_write_dword(rtlpriv, addr, val);
342*610247f4SPing-Ke Shih 		break;
343*610247f4SPing-Ke Shih 	default:
344*610247f4SPing-Ke Shih 		/*printk("error write length=%d", len);*/
345*610247f4SPing-Ke Shih 		break;
346*610247f4SPing-Ke Shih 	}
347*610247f4SPing-Ke Shih 
348*610247f4SPing-Ke Shih 	return count;
349*610247f4SPing-Ke Shih }
350*610247f4SPing-Ke Shih 
351*610247f4SPing-Ke Shih static struct rtl_debugfs_priv rtl_debug_priv_write_reg = {
352*610247f4SPing-Ke Shih 	.cb_write = rtl_debugfs_set_write_reg,
353*610247f4SPing-Ke Shih };
354*610247f4SPing-Ke Shih 
355*610247f4SPing-Ke Shih static ssize_t rtl_debugfs_set_write_h2c(struct file *filp,
356*610247f4SPing-Ke Shih 					 const char __user *buffer,
357*610247f4SPing-Ke Shih 					 size_t count, loff_t *loff)
358*610247f4SPing-Ke Shih {
359*610247f4SPing-Ke Shih 	struct rtl_debugfs_priv *debugfs_priv = filp->private_data;
360*610247f4SPing-Ke Shih 	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;
361*610247f4SPing-Ke Shih 	struct ieee80211_hw *hw = rtlpriv->hw;
362*610247f4SPing-Ke Shih 	char tmp[32 + 1];
363*610247f4SPing-Ke Shih 	int tmp_len;
364*610247f4SPing-Ke Shih 	u8 h2c_len, h2c_data_packed[8];
365*610247f4SPing-Ke Shih 	int h2c_data[8];	/* idx 0: cmd */
366*610247f4SPing-Ke Shih 	int i;
367*610247f4SPing-Ke Shih 
368*610247f4SPing-Ke Shih 	if (count < 3)
369*610247f4SPing-Ke Shih 		return -EFAULT;
370*610247f4SPing-Ke Shih 
371*610247f4SPing-Ke Shih 	tmp_len = (count > sizeof(tmp) - 1 ? sizeof(tmp) - 1 : count);
372*610247f4SPing-Ke Shih 
373*610247f4SPing-Ke Shih 	if (!buffer || copy_from_user(tmp, buffer, tmp_len))
374*610247f4SPing-Ke Shih 		return count;
375*610247f4SPing-Ke Shih 
376*610247f4SPing-Ke Shih 	tmp[tmp_len] = '\0';
377*610247f4SPing-Ke Shih 
378*610247f4SPing-Ke Shih 	h2c_len = sscanf(tmp, "%X %X %X %X %X %X %X %X",
379*610247f4SPing-Ke Shih 			 &h2c_data[0], &h2c_data[1],
380*610247f4SPing-Ke Shih 			 &h2c_data[2], &h2c_data[3],
381*610247f4SPing-Ke Shih 			 &h2c_data[4], &h2c_data[5],
382*610247f4SPing-Ke Shih 			 &h2c_data[6], &h2c_data[7]);
383*610247f4SPing-Ke Shih 
384*610247f4SPing-Ke Shih 	if (h2c_len <= 0)
385*610247f4SPing-Ke Shih 		return count;
386*610247f4SPing-Ke Shih 
387*610247f4SPing-Ke Shih 	for (i = 0; i < h2c_len; i++)
388*610247f4SPing-Ke Shih 		h2c_data_packed[i] = (u8)h2c_data[i];
389*610247f4SPing-Ke Shih 
390*610247f4SPing-Ke Shih 	rtlpriv->cfg->ops->fill_h2c_cmd(hw, h2c_data_packed[0],
391*610247f4SPing-Ke Shih 					h2c_len - 1,
392*610247f4SPing-Ke Shih 					&h2c_data_packed[1]);
393*610247f4SPing-Ke Shih 
394*610247f4SPing-Ke Shih 	return count;
395*610247f4SPing-Ke Shih }
396*610247f4SPing-Ke Shih 
397*610247f4SPing-Ke Shih static struct rtl_debugfs_priv rtl_debug_priv_write_h2c = {
398*610247f4SPing-Ke Shih 	.cb_write = rtl_debugfs_set_write_h2c,
399*610247f4SPing-Ke Shih };
400*610247f4SPing-Ke Shih 
401*610247f4SPing-Ke Shih static ssize_t rtl_debugfs_set_write_rfreg(struct file *filp,
402*610247f4SPing-Ke Shih 					   const char __user *buffer,
403*610247f4SPing-Ke Shih 					    size_t count, loff_t *loff)
404*610247f4SPing-Ke Shih {
405*610247f4SPing-Ke Shih 	struct rtl_debugfs_priv *debugfs_priv = filp->private_data;
406*610247f4SPing-Ke Shih 	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;
407*610247f4SPing-Ke Shih 	struct ieee80211_hw *hw = rtlpriv->hw;
408*610247f4SPing-Ke Shih 	char tmp[32 + 1];
409*610247f4SPing-Ke Shih 	int tmp_len;
410*610247f4SPing-Ke Shih 	int num;
411*610247f4SPing-Ke Shih 	int path;
412*610247f4SPing-Ke Shih 	u32 addr, bitmask, data;
413*610247f4SPing-Ke Shih 
414*610247f4SPing-Ke Shih 	if (count < 3)
415*610247f4SPing-Ke Shih 		return -EFAULT;
416*610247f4SPing-Ke Shih 
417*610247f4SPing-Ke Shih 	tmp_len = (count > sizeof(tmp) - 1 ? sizeof(tmp) - 1 : count);
418*610247f4SPing-Ke Shih 
419*610247f4SPing-Ke Shih 	if (!buffer || copy_from_user(tmp, buffer, tmp_len))
420*610247f4SPing-Ke Shih 		return count;
421*610247f4SPing-Ke Shih 
422*610247f4SPing-Ke Shih 	tmp[tmp_len] = '\0';
423*610247f4SPing-Ke Shih 
424*610247f4SPing-Ke Shih 	num = sscanf(tmp, "%X %X %X %X",
425*610247f4SPing-Ke Shih 		     &path, &addr, &bitmask, &data);
426*610247f4SPing-Ke Shih 
427*610247f4SPing-Ke Shih 	if (num != 4) {
428*610247f4SPing-Ke Shih 		RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG,
429*610247f4SPing-Ke Shih 			 "Format is <path> <addr> <mask> <data>\n");
430*610247f4SPing-Ke Shih 		return count;
431*610247f4SPing-Ke Shih 	}
432*610247f4SPing-Ke Shih 
433*610247f4SPing-Ke Shih 	rtl_set_rfreg(hw, path, addr, bitmask, data);
434*610247f4SPing-Ke Shih 
435*610247f4SPing-Ke Shih 	return count;
436*610247f4SPing-Ke Shih }
437*610247f4SPing-Ke Shih 
438*610247f4SPing-Ke Shih static struct rtl_debugfs_priv rtl_debug_priv_write_rfreg = {
439*610247f4SPing-Ke Shih 	.cb_write = rtl_debugfs_set_write_rfreg,
440*610247f4SPing-Ke Shih };
441*610247f4SPing-Ke Shih 
442*610247f4SPing-Ke Shih static int rtl_debugfs_close(struct inode *inode, struct file *filp)
443*610247f4SPing-Ke Shih {
444*610247f4SPing-Ke Shih 	return 0;
445*610247f4SPing-Ke Shih }
446*610247f4SPing-Ke Shih 
447*610247f4SPing-Ke Shih static ssize_t rtl_debugfs_common_write(struct file *filp,
448*610247f4SPing-Ke Shih 					const char __user *buffer,
449*610247f4SPing-Ke Shih 					size_t count, loff_t *loff)
450*610247f4SPing-Ke Shih {
451*610247f4SPing-Ke Shih 	struct rtl_debugfs_priv *debugfs_priv = filp->private_data;
452*610247f4SPing-Ke Shih 
453*610247f4SPing-Ke Shih 	return debugfs_priv->cb_write(filp, buffer, count, loff);
454*610247f4SPing-Ke Shih }
455*610247f4SPing-Ke Shih 
456*610247f4SPing-Ke Shih static const struct file_operations file_ops_common_write = {
457*610247f4SPing-Ke Shih 	.owner = THIS_MODULE,
458*610247f4SPing-Ke Shih 	.write = rtl_debugfs_common_write,
459*610247f4SPing-Ke Shih 	.open = simple_open,
460*610247f4SPing-Ke Shih 	.release = rtl_debugfs_close,
461*610247f4SPing-Ke Shih };
462*610247f4SPing-Ke Shih 
463*610247f4SPing-Ke Shih #define RTL_DEBUGFS_ADD_CORE(name, mode, fopname)			   \
464*610247f4SPing-Ke Shih 	do {								   \
465*610247f4SPing-Ke Shih 		rtl_debug_priv_ ##name.rtlpriv = rtlpriv;		   \
466*610247f4SPing-Ke Shih 		if (!debugfs_create_file(#name, mode,			   \
467*610247f4SPing-Ke Shih 					 parent, &rtl_debug_priv_ ##name,  \
468*610247f4SPing-Ke Shih 					 &file_ops_ ##fopname))		   \
469*610247f4SPing-Ke Shih 			pr_err("Unable to initialize debugfs:%s/%s\n",	   \
470*610247f4SPing-Ke Shih 			       rtlpriv->dbg.debugfs_name,		   \
471*610247f4SPing-Ke Shih 			       #name);					   \
472*610247f4SPing-Ke Shih 	} while (0)
473*610247f4SPing-Ke Shih 
474*610247f4SPing-Ke Shih #define RTL_DEBUGFS_ADD(name)						   \
475*610247f4SPing-Ke Shih 		RTL_DEBUGFS_ADD_CORE(name, S_IFREG | 0444, common)
476*610247f4SPing-Ke Shih #define RTL_DEBUGFS_ADD_W(name)						   \
477*610247f4SPing-Ke Shih 		RTL_DEBUGFS_ADD_CORE(name, S_IFREG | 0222, common_write)
478*610247f4SPing-Ke Shih 
479*610247f4SPing-Ke Shih void rtl_debug_add_one(struct ieee80211_hw *hw)
480*610247f4SPing-Ke Shih {
481*610247f4SPing-Ke Shih 	struct rtl_priv *rtlpriv = rtl_priv(hw);
482*610247f4SPing-Ke Shih 	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
483*610247f4SPing-Ke Shih 	struct dentry *parent;
484*610247f4SPing-Ke Shih 
485*610247f4SPing-Ke Shih 	snprintf(rtlpriv->dbg.debugfs_name, 18, "%pMF", rtlefuse->dev_addr);
486*610247f4SPing-Ke Shih 
487*610247f4SPing-Ke Shih 	rtlpriv->dbg.debugfs_dir =
488*610247f4SPing-Ke Shih 		debugfs_create_dir(rtlpriv->dbg.debugfs_name, debugfs_topdir);
489*610247f4SPing-Ke Shih 	if (!rtlpriv->dbg.debugfs_dir) {
490*610247f4SPing-Ke Shih 		pr_err("Unable to init debugfs:/%s/%s\n", rtlpriv->cfg->name,
491*610247f4SPing-Ke Shih 		       rtlpriv->dbg.debugfs_name);
492*610247f4SPing-Ke Shih 		return;
493*610247f4SPing-Ke Shih 	}
494*610247f4SPing-Ke Shih 
495*610247f4SPing-Ke Shih 	parent = rtlpriv->dbg.debugfs_dir;
496*610247f4SPing-Ke Shih 
497*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_0);
498*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_1);
499*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_2);
500*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_3);
501*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_4);
502*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_5);
503*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_6);
504*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_7);
505*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_8);
506*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_9);
507*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_a);
508*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_b);
509*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_c);
510*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_d);
511*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_e);
512*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_f);
513*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_10);
514*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_11);
515*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_12);
516*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_13);
517*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_14);
518*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_15);
519*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_16);
520*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(mac_17);
521*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_18);
522*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_19);
523*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_1a);
524*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_1b);
525*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_1c);
526*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_1d);
527*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_1e);
528*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(bb_1f);
529*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(rf_a);
530*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(rf_b);
531*610247f4SPing-Ke Shih 
532*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(cam_1);
533*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(cam_2);
534*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(cam_3);
535*610247f4SPing-Ke Shih 
536*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD(btcoex);
537*610247f4SPing-Ke Shih 
538*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD_W(write_reg);
539*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD_W(write_h2c);
540*610247f4SPing-Ke Shih 	RTL_DEBUGFS_ADD_W(write_rfreg);
541*610247f4SPing-Ke Shih }
542*610247f4SPing-Ke Shih EXPORT_SYMBOL_GPL(rtl_debug_add_one);
543*610247f4SPing-Ke Shih 
544*610247f4SPing-Ke Shih void rtl_debug_remove_one(struct ieee80211_hw *hw)
545*610247f4SPing-Ke Shih {
546*610247f4SPing-Ke Shih 	struct rtl_priv *rtlpriv = rtl_priv(hw);
547*610247f4SPing-Ke Shih 
548*610247f4SPing-Ke Shih 	debugfs_remove_recursive(rtlpriv->dbg.debugfs_dir);
549*610247f4SPing-Ke Shih 	rtlpriv->dbg.debugfs_dir = NULL;
550*610247f4SPing-Ke Shih }
551*610247f4SPing-Ke Shih EXPORT_SYMBOL_GPL(rtl_debug_remove_one);
552*610247f4SPing-Ke Shih 
553*610247f4SPing-Ke Shih void rtl_debugfs_add_topdir(void)
554*610247f4SPing-Ke Shih {
555*610247f4SPing-Ke Shih 	debugfs_topdir = debugfs_create_dir("rtlwifi", NULL);
556*610247f4SPing-Ke Shih }
557*610247f4SPing-Ke Shih 
558*610247f4SPing-Ke Shih void rtl_debugfs_remove_topdir(void)
559*610247f4SPing-Ke Shih {
560*610247f4SPing-Ke Shih 	debugfs_remove_recursive(debugfs_topdir);
561*610247f4SPing-Ke Shih }
562*610247f4SPing-Ke Shih 
5639ce22191SJoe Perches #endif
564