summaryrefslogblamecommitdiffstats
path: root/drivers/staging/rtlwifi/debug.c
blob: 8999feda29b4b4ddfbd308a142d55f7ab6b1dc36 (plain) (tree)
1
2
3
4
5
                                   



                                                                               


















                                                                               
                                                                       

















                                                                     
                                                                       


























                                                                           
                         
                                 


                                                                         






                                                            
                                                           
 
                                           










                                                                         
                                  



                                                              
                                                           














                                                                        



                                                                 




















                                                             
                                                           















                                                                              



                                                                 




















                                                            
                                                           




















                                                                             



                                                                 






                                                                  
                                                           










































                                                                                      



                                                                 







                                                            
                                                           










                                                                             

                                                        






                                                                    
                                                                   
                                                         




                           
                      
                               







                                                                      
                                   
                                                         
 
                      
                             


















                                                         






                                                                    
 







                                                                   
 



































































                                                                       

 



                                                             




                                                                    







                                                                   
 
                                                             
                             

                                          






                                                                
                                                                   






















                                                                         
                                                           









                                                                      

                    
                                      
                                                                                


                                                      
                   




                                                                       
                                            



                 


                                                           


                     
                                                          




                                        
                                          




                                                                            


                                                                            




                                                                            
                                                                        
                                                                            
                                                                     








                                                             
                                                                            




















































                                                                              

                                       
























                                                             
// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
 *
 * Copyright(c) 2009-2012  Realtek Corporation.
 *
 * Contact Information:
 * wlanfae <wlanfae@realtek.com>
 * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
 * Hsinchu 300, Taiwan.
 *
 * Larry Finger <Larry.Finger@lwfinger.net>
 *****************************************************************************/

#include "wifi.h"
#include "cam.h"

#include <linux/moduleparam.h>
#include <linux/vmalloc.h>

#ifdef CONFIG_RTLWIFI_DEBUG_ST
void _rtl_dbg_trace(struct rtl_priv *rtlpriv, u64 comp, int level,
		    const char *fmt, ...)
{
	if (unlikely((comp & rtlpriv->cfg->mod_params->debug_mask) &&
		     level <= rtlpriv->cfg->mod_params->debug_level)) {
		struct va_format vaf;
		va_list args;

		va_start(args, fmt);

		vaf.fmt = fmt;
		vaf.va = &args;

		pr_info(":<%lx> %pV", in_interrupt(), &vaf);

		va_end(args);
	}
}

void _rtl_dbg_print(struct rtl_priv *rtlpriv, u64 comp, int level,
		    const char *fmt, ...)
{
	if (unlikely((comp & rtlpriv->cfg->mod_params->debug_mask) &&
		     level <= rtlpriv->cfg->mod_params->debug_level)) {
		struct va_format vaf;
		va_list args;

		va_start(args, fmt);

		vaf.fmt = fmt;
		vaf.va = &args;

		pr_info("%pV", &vaf);

		va_end(args);
	}
}

void _rtl_dbg_print_data(struct rtl_priv *rtlpriv, u64 comp, int level,
			 const char *titlestring,
			 const void *hexdata, int hexdatalen)
{
	if (unlikely(((comp) & rtlpriv->cfg->mod_params->debug_mask) &&
		     ((level) <= rtlpriv->cfg->mod_params->debug_level))) {
		pr_info("In process \"%s\" (pid %i): %s\n",
			current->comm, current->pid, titlestring);
		print_hex_dump_bytes("", DUMP_PREFIX_NONE,
				     hexdata, hexdatalen);
	}
}

struct rtl_debugfs_priv {
	struct rtl_priv *rtlpriv;
	int (*cb_read)(struct seq_file *m, void *v);
	ssize_t (*cb_write)(struct file *filp, const char __user *buffer,
			    size_t count, loff_t *loff);
	u32 cb_data;
};

static struct dentry *debugfs_topdir;

static int rtl_debug_get_common(struct seq_file *m, void *v)
{
	struct rtl_debugfs_priv *debugfs_priv = m->private;

	return debugfs_priv->cb_read(m, v);
}

static int dl_debug_open_common(struct inode *inode, struct file *file)
{
	return single_open(file, rtl_debug_get_common, inode->i_private);
}

static const struct file_operations file_ops_common = {
	.open = dl_debug_open_common,
	.read = seq_read,
	.llseek = seq_lseek,
	.release = single_release,
};

static int rtl_debug_get_mac_page(struct seq_file *m, void *v)
{
	struct rtl_debugfs_priv *debugfs_priv = m->private;
	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;
	u32 page = debugfs_priv->cb_data;
	int i, n;
	int max = 0xff;

	for (n = 0; n <= max; ) {
		seq_printf(m, "\n%8.8x  ", n + page);
		for (i = 0; i < 4 && n <= max; i++, n += 4)
			seq_printf(m, "%8.8x    ",
				   rtl_read_dword(rtlpriv, (page | n)));
	}
	seq_puts(m, "\n");
	return 0;
}

#define RTL_DEBUG_IMPL_MAC_SERIES(page, addr)			\
static struct rtl_debugfs_priv rtl_debug_priv_mac_ ##page = {	\
	.cb_read = rtl_debug_get_mac_page,			\
	.cb_data = addr,					\
}

RTL_DEBUG_IMPL_MAC_SERIES(0, 0x0000);
RTL_DEBUG_IMPL_MAC_SERIES(1, 0x0100);
RTL_DEBUG_IMPL_MAC_SERIES(2, 0x0200);
RTL_DEBUG_IMPL_MAC_SERIES(3, 0x0300);
RTL_DEBUG_IMPL_MAC_SERIES(4, 0x0400);
RTL_DEBUG_IMPL_MAC_SERIES(5, 0x0500);
RTL_DEBUG_IMPL_MAC_SERIES(6, 0x0600);
RTL_DEBUG_IMPL_MAC_SERIES(7, 0x0700);
RTL_DEBUG_IMPL_MAC_SERIES(10, 0x1000);
RTL_DEBUG_IMPL_MAC_SERIES(11, 0x1100);
RTL_DEBUG_IMPL_MAC_SERIES(12, 0x1200);
RTL_DEBUG_IMPL_MAC_SERIES(13, 0x1300);
RTL_DEBUG_IMPL_MAC_SERIES(14, 0x1400);
RTL_DEBUG_IMPL_MAC_SERIES(15, 0x1500);
RTL_DEBUG_IMPL_MAC_SERIES(16, 0x1600);
RTL_DEBUG_IMPL_MAC_SERIES(17, 0x1700);

static int rtl_debug_get_bb_page(struct seq_file *m, void *v)
{
	struct rtl_debugfs_priv *debugfs_priv = m->private;
	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;
	struct ieee80211_hw *hw = rtlpriv->hw;
	u32 page = debugfs_priv->cb_data;
	int i, n;
	int max = 0xff;

	for (n = 0; n <= max; ) {
		seq_printf(m, "\n%8.8x  ", n + page);
		for (i = 0; i < 4 && n <= max; i++, n += 4)
			seq_printf(m, "%8.8x    ",
				   rtl_get_bbreg(hw, (page | n), 0xffffffff));
	}
	seq_puts(m, "\n");
	return 0;
}

#define RTL_DEBUG_IMPL_BB_SERIES(page, addr)			\
static struct rtl_debugfs_priv rtl_debug_priv_bb_ ##page = {	\
	.cb_read = rtl_debug_get_bb_page,			\
	.cb_data = addr,					\
}

RTL_DEBUG_IMPL_BB_SERIES(8, 0x0800);
RTL_DEBUG_IMPL_BB_SERIES(9, 0x0900);
RTL_DEBUG_IMPL_BB_SERIES(a, 0x0a00);
RTL_DEBUG_IMPL_BB_SERIES(b, 0x0b00);
RTL_DEBUG_IMPL_BB_SERIES(c, 0x0c00);
RTL_DEBUG_IMPL_BB_SERIES(d, 0x0d00);
RTL_DEBUG_IMPL_BB_SERIES(e, 0x0e00);
RTL_DEBUG_IMPL_BB_SERIES(f, 0x0f00);
RTL_DEBUG_IMPL_BB_SERIES(18, 0x1800);
RTL_DEBUG_IMPL_BB_SERIES(19, 0x1900);
RTL_DEBUG_IMPL_BB_SERIES(1a, 0x1a00);
RTL_DEBUG_IMPL_BB_SERIES(1b, 0x1b00);
RTL_DEBUG_IMPL_BB_SERIES(1c, 0x1c00);
RTL_DEBUG_IMPL_BB_SERIES(1d, 0x1d00);
RTL_DEBUG_IMPL_BB_SERIES(1e, 0x1e00);
RTL_DEBUG_IMPL_BB_SERIES(1f, 0x1f00);

static int rtl_debug_get_reg_rf(struct seq_file *m, void *v)
{
	struct rtl_debugfs_priv *debugfs_priv = m->private;
	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;
	struct ieee80211_hw *hw = rtlpriv->hw;
	enum radio_path rfpath = debugfs_priv->cb_data;
	int i, n;
	int max = 0x40;

	if (IS_HARDWARE_TYPE_8822B(rtlpriv))
		max = 0xff;

	seq_printf(m, "\nPATH(%d)", rfpath);

	for (n = 0; n <= max; ) {
		seq_printf(m, "\n%8.8x  ", n);
		for (i = 0; i < 4 && n <= max; n += 1, i++)
			seq_printf(m, "%8.8x    ",
				   rtl_get_rfreg(hw, rfpath, n, 0xffffffff));
	}
	seq_puts(m, "\n");
	return 0;
}

#define RTL_DEBUG_IMPL_RF_SERIES(page, addr)			\
static struct rtl_debugfs_priv rtl_debug_priv_rf_ ##page = {	\
	.cb_read = rtl_debug_get_reg_rf,			\
	.cb_data = addr,					\
}

RTL_DEBUG_IMPL_RF_SERIES(a, RF90_PATH_A);
RTL_DEBUG_IMPL_RF_SERIES(b, RF90_PATH_B);

static int rtl_debug_get_cam_register(struct seq_file *m, void *v)
{
	struct rtl_debugfs_priv *debugfs_priv = m->private;
	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;
	int start = debugfs_priv->cb_data;
	u32 target_cmd = 0;
	u32 target_val = 0;
	u8 entry_i = 0;
	u32 ulstatus;
	int i = 100, j = 0;
	int end = (start + 11 > TOTAL_CAM_ENTRY ? TOTAL_CAM_ENTRY : start + 11);

	/* This dump the current register page */
	seq_printf(m,
		   "\n#################### SECURITY CAM (%d-%d) ##################\n",
		   start, end - 1);

	for (j = start; j < end; j++) {
		seq_printf(m, "\nD:  %2x > ", j);
		for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {
			/* polling bit, and No Write enable, and address  */
			target_cmd = entry_i + CAM_CONTENT_COUNT * j;
			target_cmd = target_cmd | BIT(31);

			/* Check polling bit is clear */
			while ((i--) >= 0) {
				ulstatus = rtl_read_dword(
						rtlpriv,
						rtlpriv->cfg->maps[RWCAM]);
				if (ulstatus & BIT(31))
					continue;
				else
					break;
			}

			rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
					target_cmd);
			target_val = rtl_read_dword(rtlpriv,
						    rtlpriv->cfg->maps[RCAMO]);
			seq_printf(m, "%8.8x ", target_val);
		}
	}
	seq_puts(m, "\n");
	return 0;
}

#define RTL_DEBUG_IMPL_CAM_SERIES(page, addr)			\
static struct rtl_debugfs_priv rtl_debug_priv_cam_ ##page = {	\
	.cb_read = rtl_debug_get_cam_register,			\
	.cb_data = addr,					\
}

RTL_DEBUG_IMPL_CAM_SERIES(1, 0);
RTL_DEBUG_IMPL_CAM_SERIES(2, 11);
RTL_DEBUG_IMPL_CAM_SERIES(3, 22);

static int rtl_debug_get_btcoex(struct seq_file *m, void *v)
{
	struct rtl_debugfs_priv *debugfs_priv = m->private;
	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;

	if (rtlpriv->cfg->ops->get_btc_status())
		rtlpriv->btcoexist.btc_ops->btc_display_bt_coex_info(rtlpriv,
								     m);

	seq_puts(m, "\n");

	return 0;
}

static struct rtl_debugfs_priv rtl_debug_priv_btcoex = {
	.cb_read = rtl_debug_get_btcoex,
	.cb_data = 0,
};

static ssize_t rtl_debugfs_set_write_reg(struct file *filp,
					 const char __user *buffer,
					 size_t count, loff_t *loff)
{
	struct rtl_debugfs_priv *debugfs_priv = filp->private_data;
	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;
	char tmp[32 + 1];
	int tmp_len;
	u32 addr, val, len;
	int num;

	if (count < 3)
		return -EFAULT;

	tmp_len = (count > sizeof(tmp) - 1 ? sizeof(tmp) - 1 : count);

	if (!buffer || copy_from_user(tmp, buffer, tmp_len))
		return count;

	tmp[tmp_len] = '\0';

	/* write BB/MAC register */
	num = sscanf(tmp, "%x %x %x", &addr, &val, &len);

	if (num !=  3)
		return count;

	switch (len) {
	case 1:
		rtl_write_byte(rtlpriv, addr, (u8)val);
		break;
	case 2:
		rtl_write_word(rtlpriv, addr, (u16)val);
		break;
	case 4:
		rtl_write_dword(rtlpriv, addr, val);
		break;
	default:
		/*printk("error write length=%d", len);*/
		break;
	}

	return count;
}

static struct rtl_debugfs_priv rtl_debug_priv_write_reg = {
	.cb_write = rtl_debugfs_set_write_reg,
};

static ssize_t rtl_debugfs_set_write_h2c(struct file *filp,
					 const char __user *buffer,
					 size_t count, loff_t *loff)
{
	struct rtl_debugfs_priv *debugfs_priv = filp->private_data;
	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;
	struct ieee80211_hw *hw = rtlpriv->hw;
	char tmp[32 + 1];
	int tmp_len;
	u8 h2c_len, h2c_data_packed[8];
	int h2c_data[8];	/* idx 0: cmd */
	int i;

	if (count < 3)
		return -EFAULT;

	tmp_len = (count > sizeof(tmp) - 1 ? sizeof(tmp) - 1 : count);

	if (!buffer || copy_from_user(tmp, buffer, tmp_len))
		return count;

	tmp[tmp_len] = '\0';

	h2c_len = sscanf(tmp, "%X %X %X %X %X %X %X %X",
			 &h2c_data[0], &h2c_data[1],
			 &h2c_data[2], &h2c_data[3],
			 &h2c_data[4], &h2c_data[5],
			 &h2c_data[6], &h2c_data[7]);

	if (h2c_len <= 0)
		return count;

	for (i = 0; i < h2c_len; i++)
		h2c_data_packed[i] = (u8)h2c_data[i];

	rtlpriv->cfg->ops->fill_h2c_cmd(hw, h2c_data_packed[0],
					h2c_len - 1,
					&h2c_data_packed[1]);

	return count;
}

static struct rtl_debugfs_priv rtl_debug_priv_write_h2c = {
	.cb_write = rtl_debugfs_set_write_h2c,
};

static ssize_t rtl_debugfs_set_write_rfreg(struct file *filp,
					   const char __user *buffer,
					    size_t count, loff_t *loff)
{
	struct rtl_debugfs_priv *debugfs_priv = filp->private_data;
	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;
	struct ieee80211_hw *hw = rtlpriv->hw;
	char tmp[32 + 1];
	int tmp_len;
	int num;
	int path;
	u32 addr, bitmask, data;

	if (count < 3)
		return -EFAULT;

	tmp_len = (count > sizeof(tmp) - 1 ? sizeof(tmp) - 1 : count);

	if (!buffer || copy_from_user(tmp, buffer, tmp_len))
		return count;

	tmp[tmp_len] = '\0';

	num = sscanf(tmp, "%X %X %X %X",
		     &path, &addr, &bitmask, &data);

	if (num != 4) {
		RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG,
			 "Format is <path> <addr> <mask> <data>\n");
		return count;
	}

	rtl_set_rfreg(hw, path, addr, bitmask, data);

	return count;
}

static struct rtl_debugfs_priv rtl_debug_priv_write_rfreg = {
	.cb_write = rtl_debugfs_set_write_rfreg,
};

static int rtl_debugfs_close(struct inode *inode, struct file *filp)
{
	return 0;
}

static ssize_t rtl_debugfs_common_write(struct file *filp,
					const char __user *buffer,
					size_t count, loff_t *loff)
{
	struct rtl_debugfs_priv *debugfs_priv = filp->private_data;

	return debugfs_priv->cb_write(filp, buffer, count, loff);
}

static const struct file_operations file_ops_common_write = {
	.owner = THIS_MODULE,
	.write = rtl_debugfs_common_write,
	.open = simple_open,
	.release = rtl_debugfs_close,
};

static ssize_t rtl_debugfs_phydm_cmd(struct file *filp,
				     const char __user *buffer,
				     size_t count, loff_t *loff)
{
	struct rtl_debugfs_priv *debugfs_priv = filp->private_data;
	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;

	char tmp[64];

	if (!rtlpriv->dbg.msg_buf)
		return -ENOMEM;

	if (!rtlpriv->phydm.ops)
		return -EFAULT;

	if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
		tmp[count] = '\0';

		rtlpriv->phydm.ops->phydm_debug_cmd(rtlpriv, tmp, count,
						    rtlpriv->dbg.msg_buf,
						    80 * 25);
	}

	return count;
}

static int rtl_debug_get_phydm_cmd(struct seq_file *m, void *v)
{
	struct rtl_debugfs_priv *debugfs_priv = m->private;
	struct rtl_priv *rtlpriv = debugfs_priv->rtlpriv;

	if (rtlpriv->dbg.msg_buf)
		seq_puts(m, rtlpriv->dbg.msg_buf);

	return 0;
}

static int rtl_debugfs_open_rw(struct inode *inode, struct file *filp)
{
	int ret = 0;

	if (filp->f_mode & FMODE_READ)
		ret = single_open(filp, rtl_debug_get_common, inode->i_private);
	else
		filp->private_data = inode->i_private;

	return ret;
}

static int rtl_debugfs_close_rw(struct inode *inode, struct file *filp)
{
	if (filp->f_mode == FMODE_READ)
		single_release(inode, filp);

	return 0;
}

static struct rtl_debugfs_priv rtl_debug_priv_phydm_cmd = {
	.cb_read = rtl_debug_get_phydm_cmd,
	.cb_write = rtl_debugfs_phydm_cmd,
	.cb_data = 0,
};

static const struct file_operations file_ops_common_rw = {
	.owner = THIS_MODULE,
	.open = rtl_debugfs_open_rw,
	.release = rtl_debugfs_close_rw,
	.read = seq_read,
	.llseek = seq_lseek,
	.write = rtl_debugfs_common_write,
};

#define RTL_DEBUGFS_ADD_CORE(name, mode, fopname)			   \
	do {								   \
		rtl_debug_priv_ ##name.rtlpriv = rtlpriv;		   \
		debugfs_create_file(#name, mode, parent,		   \
				    &rtl_debug_priv_ ##name,		   \
				    &file_ops_ ##fopname);		   \
	} while (0)

#define RTL_DEBUGFS_ADD(name)						   \
		RTL_DEBUGFS_ADD_CORE(name, S_IFREG | 0444, common)
#define RTL_DEBUGFS_ADD_W(name)						   \
		RTL_DEBUGFS_ADD_CORE(name, S_IFREG | 0222, common_write)
#define RTL_DEBUGFS_ADD_RW(name)					   \
		RTL_DEBUGFS_ADD_CORE(name, S_IFREG | 0666, common_rw)

void rtl_debug_add_one(struct ieee80211_hw *hw)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
	struct dentry *parent;

	rtlpriv->dbg.msg_buf = vzalloc(80 * 25);

	snprintf(rtlpriv->dbg.debugfs_name, 18, "%pMF", rtlefuse->dev_addr);

	rtlpriv->dbg.debugfs_dir =
		debugfs_create_dir(rtlpriv->dbg.debugfs_name, debugfs_topdir);
	if (!rtlpriv->dbg.debugfs_dir) {
		pr_err("Unable to init debugfs:/%s/%s\n", rtlpriv->cfg->name,
		       rtlpriv->dbg.debugfs_name);
		return;
	}

	parent = rtlpriv->dbg.debugfs_dir;

	RTL_DEBUGFS_ADD(mac_0);
	RTL_DEBUGFS_ADD(mac_1);
	RTL_DEBUGFS_ADD(mac_2);
	RTL_DEBUGFS_ADD(mac_3);
	RTL_DEBUGFS_ADD(mac_4);
	RTL_DEBUGFS_ADD(mac_5);
	RTL_DEBUGFS_ADD(mac_6);
	RTL_DEBUGFS_ADD(mac_7);
	RTL_DEBUGFS_ADD(bb_8);
	RTL_DEBUGFS_ADD(bb_9);
	RTL_DEBUGFS_ADD(bb_a);
	RTL_DEBUGFS_ADD(bb_b);
	RTL_DEBUGFS_ADD(bb_c);
	RTL_DEBUGFS_ADD(bb_d);
	RTL_DEBUGFS_ADD(bb_e);
	RTL_DEBUGFS_ADD(bb_f);
	RTL_DEBUGFS_ADD(mac_10);
	RTL_DEBUGFS_ADD(mac_11);
	RTL_DEBUGFS_ADD(mac_12);
	RTL_DEBUGFS_ADD(mac_13);
	RTL_DEBUGFS_ADD(mac_14);
	RTL_DEBUGFS_ADD(mac_15);
	RTL_DEBUGFS_ADD(mac_16);
	RTL_DEBUGFS_ADD(mac_17);
	RTL_DEBUGFS_ADD(bb_18);
	RTL_DEBUGFS_ADD(bb_19);
	RTL_DEBUGFS_ADD(bb_1a);
	RTL_DEBUGFS_ADD(bb_1b);
	RTL_DEBUGFS_ADD(bb_1c);
	RTL_DEBUGFS_ADD(bb_1d);
	RTL_DEBUGFS_ADD(bb_1e);
	RTL_DEBUGFS_ADD(bb_1f);
	RTL_DEBUGFS_ADD(rf_a);
	RTL_DEBUGFS_ADD(rf_b);

	RTL_DEBUGFS_ADD(cam_1);
	RTL_DEBUGFS_ADD(cam_2);
	RTL_DEBUGFS_ADD(cam_3);

	RTL_DEBUGFS_ADD(btcoex);

	RTL_DEBUGFS_ADD_W(write_reg);
	RTL_DEBUGFS_ADD_W(write_h2c);
	RTL_DEBUGFS_ADD_W(write_rfreg);

	RTL_DEBUGFS_ADD_RW(phydm_cmd);
}

void rtl_debug_remove_one(struct ieee80211_hw *hw)
{
	struct rtl_priv *rtlpriv = rtl_priv(hw);

	debugfs_remove_recursive(rtlpriv->dbg.debugfs_dir);
	rtlpriv->dbg.debugfs_dir = NULL;

	vfree(rtlpriv->dbg.msg_buf);
}

void rtl_debugfs_add_topdir(void)
{
	debugfs_topdir = debugfs_create_dir("rtlwifi", NULL);
}

void rtl_debugfs_remove_topdir(void)
{
	debugfs_remove_recursive(debugfs_topdir);
}

#endif