blob: 41d2849749ac636ecdb36e634308f67741751fe6 [file] [log] [blame]
/** @file moal_debug.c
*
* @brief This file contains functions for debug proc file.
*
* Copyright (C) 2008-2009, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this File in
* accordance with the terms and conditions of the License, a copy of which
* is available by writing to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
* this warranty disclaimer.
*
*/
/********************************************************
Change log:
11/03/2008: initial version
********************************************************/
#include "moal_main.h"
/********************************************************
Local Variables
********************************************************/
#ifdef CONFIG_PROC_FS
/** MLAN debug info */
static mlan_debug_info info;
/** Get info item size */
#define item_size(n) (sizeof(info.n))
/** Get info item address */
#define item_addr(n) ((t_u32) &(info.n))
/** Get moal_private member size */
#define item_priv_size(n) (sizeof ((moal_private *)0)->n)
/** Get moal_private member address */
#define item_priv_addr(n) ((t_u32) &((moal_private *)0)->n)
/** Get moal_handle member size */
#define item_handle_size(n) (sizeof ((moal_handle *)0)->n)
/** Get moal_handle member address */
#define item_handle_addr(n) ((t_u32) &((moal_handle *)0)->n)
/** Debug data */
struct debug_data
{
/** Name */
char name[32];
/** Size */
t_u32 size;
/** Address */
t_u32 addr;
};
/** Private debug data */
struct debug_data_priv
{
/** moal_private handle */
moal_private *priv;
/** Debug items */
struct debug_data *items;
/** numbre of item */
int num_of_items;
};
static struct debug_data items[] = {
{"int_counter", item_size(int_counter), item_addr(int_counter)},
{"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]),
item_addr(packets_out[WMM_AC_VO])},
{"wmm_ac_vi", item_size(packets_out[WMM_AC_VI]),
item_addr(packets_out[WMM_AC_VI])},
{"wmm_ac_be", item_size(packets_out[WMM_AC_BE]),
item_addr(packets_out[WMM_AC_BE])},
{"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]),
item_addr(packets_out[WMM_AC_BK])},
{"max_tx_buf_size", item_size(max_tx_buf_size), item_addr(max_tx_buf_size)},
{"tx_buf_size", item_size(tx_buf_size), item_addr(tx_buf_size)},
{"ps_mode", item_size(ps_mode), item_addr(ps_mode)},
{"ps_state", item_size(ps_state), item_addr(ps_state)},
{"is_deep_sleep", item_size(is_deep_sleep), item_addr(is_deep_sleep)},
{"wakeup_dev_req", item_size(pm_wakeup_card_req),
item_addr(pm_wakeup_card_req)},
{"wakeup_tries", item_size(pm_wakeup_fw_try), item_addr(pm_wakeup_fw_try)},
{"hs_configured", item_size(is_hs_configured), item_addr(is_hs_configured)},
{"hs_activated", item_size(hs_activated), item_addr(hs_activated)},
{"num_tx_timeout", item_size(num_tx_timeout), item_addr(num_tx_timeout)},
{"num_cmd_timeout", item_size(num_cmd_timeout), item_addr(num_cmd_timeout)},
{"timeout_cmd_id", item_size(timeout_cmd_id), item_addr(timeout_cmd_id)},
{"timeout_cmd_act", item_size(timeout_cmd_act), item_addr(timeout_cmd_act)},
{"last_cmd_id", item_size(last_cmd_id), item_addr(last_cmd_id)},
{"last_cmd_act", item_size(last_cmd_act), item_addr(last_cmd_act)},
{"last_cmd_index", item_size(last_cmd_index), item_addr(last_cmd_index)},
{"last_cmd_resp_id", item_size(last_cmd_resp_id),
item_addr(last_cmd_resp_id)},
{"last_cmd_resp_index", item_size(last_cmd_resp_index),
item_addr(last_cmd_resp_index)},
{"last_event", item_size(last_event), item_addr(last_event)},
{"last_event_index", item_size(last_event_index),
item_addr(last_event_index)},
{"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure),
item_addr(num_cmd_host_to_card_failure)},
{"num_cmd_sleep_cfm_fail",
item_size(num_cmd_sleep_cfm_host_to_card_failure),
item_addr(num_cmd_sleep_cfm_host_to_card_failure)},
{"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure),
item_addr(num_tx_host_to_card_failure)},
{"num_evt_deauth", item_size(num_event_deauth),
item_addr(num_event_deauth)},
{"num_evt_disassoc", item_size(num_event_disassoc),
item_addr(num_event_disassoc)},
{"num_evt_link_lost", item_size(num_event_link_lost),
item_addr(num_event_link_lost)},
{"num_cmd_deauth", item_size(num_cmd_deauth), item_addr(num_cmd_deauth)},
{"num_cmd_assoc_ok", item_size(num_cmd_assoc_success),
item_addr(num_cmd_assoc_success)},
{"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure),
item_addr(num_cmd_assoc_failure)},
{"cmd_sent", item_size(cmd_sent), item_addr(cmd_sent)},
{"data_sent", item_size(data_sent), item_addr(data_sent)},
{"mp_rd_bitmap", item_size(mp_rd_bitmap), item_addr(mp_rd_bitmap)},
{"curr_rd_port", item_size(curr_rd_port), item_addr(curr_rd_port)},
{"mp_wr_bitmap", item_size(mp_wr_bitmap), item_addr(mp_wr_bitmap)},
{"curr_wr_port", item_size(curr_wr_port), item_addr(curr_wr_port)},
{"cmd_resp_received", item_size(cmd_resp_received),
item_addr(cmd_resp_received)},
{"event_received", item_size(event_received), item_addr(event_received)},
{"ioctl_pending", item_handle_size(ioctl_pending),
item_handle_addr(ioctl_pending)},
{"tx_pending", item_handle_size(tx_pending), item_handle_addr(tx_pending)},
{"rx_pending", item_handle_size(rx_pending), item_handle_addr(rx_pending)},
{"malloc_count", item_handle_size(malloc_count),
item_handle_addr(malloc_count)},
{"lock_count", item_handle_size(lock_count), item_handle_addr(lock_count)},
};
/** Private debug data */
static struct debug_data_priv items_priv;
/********************************************************
Global Variables
********************************************************/
/********************************************************
Local Functions
********************************************************/
/**
* @brief Proc read function
*
* @param page Pointer to buffer
* @param s Read data starting position
* @param off Offset
* @param cnt Counter
* @param eof End of file flag
* @param data Output data
*
* @return Number of output data
*/
static int
woal_debug_read(char *page, char **s, off_t off, int cnt, int *eof, void *data)
{
int val = 0;
int i;
char *p = page;
struct debug_data *d = ((struct debug_data_priv *) data)->items;
moal_private *priv = ((struct debug_data_priv *) data)->priv;
if (MODULE_GET == 0)
return MLAN_STATUS_FAILURE;
/* Get debug information */
if (woal_get_debug_info(priv, MOAL_PROC_WAIT, &info)) {
*eof = 1;
goto exit;
}
for (i = 0; i < ((struct debug_data_priv *) data)->num_of_items; i++) {
if (d[i].size == 1)
val = *((t_u8 *) d[i].addr);
else if (d[i].size == 2)
val = *((t_u16 *) d[i].addr);
else if (d[i].size == 4)
val = *((t_u32 *) d[i].addr);
else {
int j;
p += sprintf(p, "%s=", d[i].name);
for (j = 0; j < d[i].size; j += 2) {
val = *(t_u16 *) (d[i].addr + j);
p += sprintf(p, "0x%x ", val);
}
p += sprintf(p, "\n");
continue;
}
if (strstr(d[i].name, "id"))
p += sprintf(p, "%s=0x%x\n", d[i].name, val);
else
p += sprintf(p, "%s=%d\n", d[i].name, val);
}
if (info.tx_tbl_num) {
p += sprintf(p, "Tx BA stream table:\n");
for (i = 0; i < info.tx_tbl_num; i++) {
p += sprintf(p, "tid = %d, ra = %02x:%02x:%02x:%02x:%02x:%02x\n",
(int) info.tx_tbl[i].tid, info.tx_tbl[i].ra[0],
info.tx_tbl[i].ra[1], info.tx_tbl[i].ra[2],
info.tx_tbl[i].ra[3], info.tx_tbl[i].ra[4],
info.tx_tbl[i].ra[5]);
}
}
if (info.rx_tbl_num) {
p += sprintf(p, "Rx reorder table:\n");
for (i = 0; i < info.rx_tbl_num; i++) {
int j;
p += sprintf(p,
"tid = %d, ta = %02x:%02x:%02x:%02x:%02x:%02x, start_win = %d, "
"win_size = %d, buffer: ", (int) info.rx_tbl[i].tid,
info.rx_tbl[i].ta[0], info.rx_tbl[i].ta[1],
info.rx_tbl[i].ta[2], info.rx_tbl[i].ta[3],
info.rx_tbl[i].ta[4], info.rx_tbl[i].ta[5],
(int) info.rx_tbl[i].start_win,
(int) info.rx_tbl[i].win_size);
for (j = 0; j < info.rx_tbl[i].win_size; j++) {
if (info.rx_tbl[i].buffer[j] == MTRUE)
p += sprintf(p, "1 ");
else
p += sprintf(p, "0 ");
}
p += sprintf(p, "\n");
}
}
exit:
MODULE_PUT;
return p - page;
}
/**
* @brief Proc write function
*
* @param f File pointer
* @param buf Pointer to data buffer
* @param cnt Data number to write
* @param data Data to write
*
* @return Number of data
*/
static int
woal_debug_write(struct file *f, const char *buf, unsigned long cnt, void *data)
{
int r, i;
char *pdata;
char *p;
char *p0;
char *p1;
char *p2;
struct debug_data *d = ((struct debug_data_priv *) data)->items;
moal_private *priv = ((struct debug_data_priv *) data)->priv;
if (MODULE_GET == 0)
return MLAN_STATUS_FAILURE;
pdata = (char *) kmalloc(cnt, GFP_ATOMIC);
if (pdata == NULL) {
MODULE_PUT;
return 0;
}
if (copy_from_user(pdata, buf, cnt)) {
PRINTM(MERROR, "Copy from user failed\n");
kfree(pdata);
MODULE_PUT;
return 0;
}
p0 = pdata;
for (i = 0; i < ((struct debug_data_priv *) data)->num_of_items; i++) {
do {
p = strstr(p0, d[i].name);
if (p == NULL)
break;
p1 = strchr(p, '\n');
if (p1 == NULL)
break;
p0 = p1++;
p2 = strchr(p, '=');
if (!p2)
break;
p2++;
r = woal_string_to_number(p2);
if (d[i].size == 1)
*((t_u8 *) d[i].addr) = (t_u8) r;
else if (d[i].size == 2)
*((t_u16 *) d[i].addr) = (t_u16) r;
else if (d[i].size == 4)
*((t_u32 *) d[i].addr) = (t_u32) r;
break;
} while (MTRUE);
}
kfree(pdata);
/* Set debug information */
if (woal_set_debug_info(priv, MOAL_IOCTL_WAIT, &info)) {
MODULE_PUT;
return 0;
}
MODULE_PUT;
return cnt;
}
/********************************************************
Global Functions
********************************************************/
/**
* @brief Create debug proc file
*
* @param priv A pointer to a moal_private structure
*
* @return None
*/
void
woal_debug_entry(moal_private * priv)
{
struct proc_dir_entry *r;
ENTER();
if (priv->proc_entry == NULL)
return;
if (woal_get_debug_info(priv, MOAL_PROC_WAIT, &info)) {
LEAVE();
return;
}
/* Setup MOAL debug info */
if (priv->bss_type == MLAN_BSS_TYPE_STA) {
items_priv.priv = priv;
items_priv.items = items;
items_priv.num_of_items = sizeof(items) / sizeof(items[0]);
items[items_priv.num_of_items - 1].addr += (t_u32) (priv->phandle);
items[items_priv.num_of_items - 2].addr += (t_u32) (priv->phandle);
items[items_priv.num_of_items - 3].addr += (t_u32) (priv->phandle);
items[items_priv.num_of_items - 4].addr += (t_u32) (priv->phandle);
items[items_priv.num_of_items - 5].addr += (t_u32) (priv->phandle);
}
/* Create proc entry */
r = create_proc_entry("debug", 0644, priv->proc_entry);
if (r == NULL) {
LEAVE();
return;
}
/* Populate proc entry handlers */
if (priv->bss_type == MLAN_BSS_TYPE_STA)
r->data = &items_priv;
r->read_proc = woal_debug_read;
r->write_proc = woal_debug_write;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
r->owner = THIS_MODULE;
#endif
LEAVE();
}
/**
* @brief Remove proc file
*
* @param priv A pointer to a moal_private structure
*
* @return None
*/
void
woal_debug_remove(moal_private * priv)
{
ENTER();
if (priv->bss_type == MLAN_BSS_TYPE_STA) {
/* Reset MOAL debug info */
items[items_priv.num_of_items - 1].addr -= (t_u32) (priv->phandle);
items[items_priv.num_of_items - 2].addr -= (t_u32) (priv->phandle);
items[items_priv.num_of_items - 3].addr -= (t_u32) (priv->phandle);
items[items_priv.num_of_items - 4].addr -= (t_u32) (priv->phandle);
items[items_priv.num_of_items - 5].addr -= (t_u32) (priv->phandle);
}
/* Remove proc entry */
remove_proc_entry("debug", priv->proc_entry);
LEAVE();
}
#endif