Commit 04e715cd authored by Samuel Ortiz's avatar Samuel Ortiz Committed by John W. Linville

iwmc3200wifi: Add a last_fw_err debugfs entry

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: default avatarSamuel Ortiz <sameo@linux.intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent d210176e
......@@ -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
......
......@@ -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;
......@@ -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;
......@@ -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:
......@@ -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);
......
......@@ -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)));
};
......
......@@ -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;
}
......@@ -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);
}
/*
......
......@@ -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));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment