forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
514 lines
13 KiB
514 lines
13 KiB
// SPDX-License-Identifier: GPL-2.0 |
|
/* Copyright(c) 2009-2012 Realtek Corporation.*/ |
|
|
|
#include "wifi.h" |
|
#include "cam.h" |
|
|
|
#include <linux/moduleparam.h> |
|
#include <linux/vmalloc.h> |
|
|
|
#ifdef CONFIG_RTLWIFI_DEBUG |
|
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); |
|
} |
|
} |
|
EXPORT_SYMBOL_GPL(_rtl_dbg_print); |
|
|
|
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); |
|
} |
|
} |
|
EXPORT_SYMBOL_GPL(_rtl_dbg_print_data); |
|
|
|
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) { |
|
rtl_dbg(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, |
|
}; |
|
|
|
#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) |
|
|
|
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; |
|
|
|
snprintf(rtlpriv->dbg.debugfs_name, 18, "%pMF", rtlefuse->dev_addr); |
|
|
|
rtlpriv->dbg.debugfs_dir = |
|
debugfs_create_dir(rtlpriv->dbg.debugfs_name, debugfs_topdir); |
|
|
|
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); |
|
} |
|
EXPORT_SYMBOL_GPL(rtl_debug_add_one); |
|
|
|
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; |
|
} |
|
EXPORT_SYMBOL_GPL(rtl_debug_remove_one); |
|
|
|
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
|
|
|