Skip to content

Commit

Permalink
iwmc3200wifi: Add a last_fw_err debugfs entry
Browse files Browse the repository at this point in the history
In order to check what was the last fw error we got accross resets, we add
this debugfs entry. It displays the complete ASSERT information.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Samuel Ortiz authored and John W. Linville committed Sep 1, 2009
1 parent d210176 commit 04e715c
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 4 deletions.
2 changes: 2 additions & 0 deletions drivers/net/wireless/iwmc3200wifi/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ struct iwm_debugfs {
struct dentry *txq_dentry;
struct dentry *tx_credit_dentry;
struct dentry *rx_ticket_dentry;

struct dentry *fw_err_dentry;
};

#ifdef CONFIG_IWM_DEBUG
Expand Down
105 changes: 101 additions & 4 deletions drivers/net/wireless/iwmc3200wifi/debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_iwm_dbg_modules,
iwm_debugfs_u32_read, iwm_debugfs_dbg_modules_write,
"%llu\n");

static int iwm_txrx_open(struct inode *inode, struct file *filp)
static int iwm_generic_open(struct inode *inode, struct file *filp)
{
filp->private_data = inode->i_private;
return 0;
Expand Down Expand Up @@ -289,25 +289,111 @@ static ssize_t iwm_debugfs_rx_ticket_read(struct file *filp,
return ret;
}

static ssize_t iwm_debugfs_fw_err_read(struct file *filp,
char __user *buffer,
size_t count, loff_t *ppos)
{

struct iwm_priv *iwm = filp->private_data;
char buf[512];
int buf_len = 512;
size_t len = 0;

if (*ppos != 0)
return 0;
if (count < sizeof(buf))
return -ENOSPC;

if (!iwm->last_fw_err)
return -ENOMEM;

if (iwm->last_fw_err->line_num == 0)
goto out;

len += snprintf(buf + len, buf_len - len, "%cMAC FW ERROR:\n",
(le32_to_cpu(iwm->last_fw_err->category) == UMAC_SYS_ERR_CAT_LMAC)
? 'L' : 'U');
len += snprintf(buf + len, buf_len - len,
"\tCategory: %d\n",
le32_to_cpu(iwm->last_fw_err->category));

len += snprintf(buf + len, buf_len - len,
"\tStatus: 0x%x\n",
le32_to_cpu(iwm->last_fw_err->status));

len += snprintf(buf + len, buf_len - len,
"\tPC: 0x%x\n",
le32_to_cpu(iwm->last_fw_err->pc));

len += snprintf(buf + len, buf_len - len,
"\tblink1: %d\n",
le32_to_cpu(iwm->last_fw_err->blink1));

len += snprintf(buf + len, buf_len - len,
"\tblink2: %d\n",
le32_to_cpu(iwm->last_fw_err->blink2));

len += snprintf(buf + len, buf_len - len,
"\tilink1: %d\n",
le32_to_cpu(iwm->last_fw_err->ilink1));

len += snprintf(buf + len, buf_len - len,
"\tilink2: %d\n",
le32_to_cpu(iwm->last_fw_err->ilink2));

len += snprintf(buf + len, buf_len - len,
"\tData1: 0x%x\n",
le32_to_cpu(iwm->last_fw_err->data1));

len += snprintf(buf + len, buf_len - len,
"\tData2: 0x%x\n",
le32_to_cpu(iwm->last_fw_err->data2));

len += snprintf(buf + len, buf_len - len,
"\tLine number: %d\n",
le32_to_cpu(iwm->last_fw_err->line_num));

len += snprintf(buf + len, buf_len - len,
"\tUMAC status: 0x%x\n",
le32_to_cpu(iwm->last_fw_err->umac_status));

len += snprintf(buf + len, buf_len - len,
"\tLMAC status: 0x%x\n",
le32_to_cpu(iwm->last_fw_err->lmac_status));

len += snprintf(buf + len, buf_len - len,
"\tSDIO status: 0x%x\n",
le32_to_cpu(iwm->last_fw_err->sdio_status));

out:

return simple_read_from_buffer(buffer, len, ppos, buf, buf_len);
}

static const struct file_operations iwm_debugfs_txq_fops = {
.owner = THIS_MODULE,
.open = iwm_txrx_open,
.open = iwm_generic_open,
.read = iwm_debugfs_txq_read,
};

static const struct file_operations iwm_debugfs_tx_credit_fops = {
.owner = THIS_MODULE,
.open = iwm_txrx_open,
.open = iwm_generic_open,
.read = iwm_debugfs_tx_credit_read,
};

static const struct file_operations iwm_debugfs_rx_ticket_fops = {
.owner = THIS_MODULE,
.open = iwm_txrx_open,
.open = iwm_generic_open,
.read = iwm_debugfs_rx_ticket_read,
};

static const struct file_operations iwm_debugfs_fw_err_fops = {
.owner = THIS_MODULE,
.open = iwm_generic_open,
.read = iwm_debugfs_fw_err_read,
};

int iwm_debugfs_init(struct iwm_priv *iwm)
{
int i, result;
Expand Down Expand Up @@ -423,6 +509,16 @@ int iwm_debugfs_init(struct iwm_priv *iwm)
goto error;
}

iwm->dbg.fw_err_dentry = debugfs_create_file("last_fw_err", 0200,
iwm->dbg.dbgdir, iwm,
&iwm_debugfs_fw_err_fops);
result = PTR_ERR(iwm->dbg.fw_err_dentry);
if (IS_ERR(iwm->dbg.fw_err_dentry) && (result != -ENODEV)) {
IWM_ERR(iwm, "Couldn't create last FW err: %d\n", result);
goto error;
}


return 0;

error:
Expand All @@ -441,6 +537,7 @@ void iwm_debugfs_exit(struct iwm_priv *iwm)
debugfs_remove(iwm->dbg.txq_dentry);
debugfs_remove(iwm->dbg.tx_credit_dentry);
debugfs_remove(iwm->dbg.rx_ticket_dentry);
debugfs_remove(iwm->dbg.fw_err_dentry);
if (iwm->bus_ops->debugfs_exit)
iwm->bus_ops->debugfs_exit(iwm);

Expand Down
2 changes: 2 additions & 0 deletions drivers/net/wireless/iwmc3200wifi/iwm.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,8 @@ struct iwm_priv {
u8 *resp_ie;
int resp_ie_len;

struct iwm_fw_error_hdr *last_fw_err;

char private[0] __attribute__((__aligned__(NETDEV_ALIGN)));
};

Expand Down
6 changes: 6 additions & 0 deletions drivers/net/wireless/iwmc3200wifi/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,11 @@ int iwm_priv_init(struct iwm_priv *iwm)
iwm->watchdog.data = (unsigned long)iwm;
mutex_init(&iwm->mutex);

iwm->last_fw_err = kzalloc(sizeof(struct iwm_fw_error_hdr),
GFP_KERNEL);
if (iwm->last_fw_err == NULL)
return -ENOMEM;

return 0;
}

Expand All @@ -271,6 +276,7 @@ void iwm_priv_deinit(struct iwm_priv *iwm)
destroy_workqueue(iwm->txq[i].wq);

destroy_workqueue(iwm->rx_wq);
kfree(iwm->last_fw_err);
}

/*
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/wireless/iwmc3200wifi/rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf,
error = (struct iwm_umac_notif_error *)buf;
fw_err = &error->err;

memcpy(iwm->last_fw_err, fw_err, sizeof(struct iwm_fw_error_hdr));

IWM_ERR(iwm, "%cMAC FW ERROR:\n",
(le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U');
IWM_ERR(iwm, "\tCategory: %d\n", le32_to_cpu(fw_err->category));
Expand Down

0 comments on commit 04e715c

Please sign in to comment.