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