Commit 696bdee3 authored by Wey-Yi Guy's avatar Wey-Yi Guy Committed by John W. Linville

iwlwifi: dump "Control and Status Register" when detect uCode HW/SW error

When uCode HW/SW error detected, dumping important CSR (Control and Status
Registers) values.
Also add "csr" debugfs file to dump the current values of CSR defined in
CSR table to syslog.
Signed-off-by: default avatarWey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: default avatarReinette Chatre <reinette.chatre@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 3a41bbd5
...@@ -105,6 +105,7 @@ static struct iwl_lib_ops iwl1000_lib = { ...@@ -105,6 +105,7 @@ static struct iwl_lib_ops iwl1000_lib = {
.load_ucode = iwl5000_load_ucode, .load_ucode = iwl5000_load_ucode,
.dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_event_log = iwl_dump_nic_event_log,
.dump_nic_error_log = iwl_dump_nic_error_log, .dump_nic_error_log = iwl_dump_nic_error_log,
.dump_csr = iwl_dump_csr,
.init_alive_start = iwl5000_init_alive_start, .init_alive_start = iwl5000_init_alive_start,
.alive_notify = iwl5000_alive_notify, .alive_notify = iwl5000_alive_notify,
.send_tx_power = iwl5000_send_tx_power, .send_tx_power = iwl5000_send_tx_power,
......
...@@ -1465,6 +1465,7 @@ struct iwl_lib_ops iwl5000_lib = { ...@@ -1465,6 +1465,7 @@ struct iwl_lib_ops iwl5000_lib = {
.is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr, .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
.dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_event_log = iwl_dump_nic_event_log,
.dump_nic_error_log = iwl_dump_nic_error_log, .dump_nic_error_log = iwl_dump_nic_error_log,
.dump_csr = iwl_dump_csr,
.load_ucode = iwl5000_load_ucode, .load_ucode = iwl5000_load_ucode,
.init_alive_start = iwl5000_init_alive_start, .init_alive_start = iwl5000_init_alive_start,
.alive_notify = iwl5000_alive_notify, .alive_notify = iwl5000_alive_notify,
...@@ -1517,6 +1518,7 @@ static struct iwl_lib_ops iwl5150_lib = { ...@@ -1517,6 +1518,7 @@ static struct iwl_lib_ops iwl5150_lib = {
.is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr, .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
.dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_event_log = iwl_dump_nic_event_log,
.dump_nic_error_log = iwl_dump_nic_error_log, .dump_nic_error_log = iwl_dump_nic_error_log,
.dump_csr = iwl_dump_csr,
.load_ucode = iwl5000_load_ucode, .load_ucode = iwl5000_load_ucode,
.init_alive_start = iwl5000_init_alive_start, .init_alive_start = iwl5000_init_alive_start,
.alive_notify = iwl5000_alive_notify, .alive_notify = iwl5000_alive_notify,
......
...@@ -215,6 +215,7 @@ static struct iwl_lib_ops iwl6000_lib = { ...@@ -215,6 +215,7 @@ static struct iwl_lib_ops iwl6000_lib = {
.load_ucode = iwl5000_load_ucode, .load_ucode = iwl5000_load_ucode,
.dump_nic_event_log = iwl_dump_nic_event_log, .dump_nic_event_log = iwl_dump_nic_event_log,
.dump_nic_error_log = iwl_dump_nic_error_log, .dump_nic_error_log = iwl_dump_nic_error_log,
.dump_csr = iwl_dump_csr,
.init_alive_start = iwl5000_init_alive_start, .init_alive_start = iwl5000_init_alive_start,
.alive_notify = iwl5000_alive_notify, .alive_notify = iwl5000_alive_notify,
.send_tx_power = iwl5000_send_tx_power, .send_tx_power = iwl5000_send_tx_power,
......
...@@ -1363,6 +1363,8 @@ void iwl_irq_handle_error(struct iwl_priv *priv) ...@@ -1363,6 +1363,8 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
clear_bit(STATUS_HCMD_ACTIVE, &priv->status); clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
priv->cfg->ops->lib->dump_nic_error_log(priv); priv->cfg->ops->lib->dump_nic_error_log(priv);
if (priv->cfg->ops->lib->dump_csr)
priv->cfg->ops->lib->dump_csr(priv);
priv->cfg->ops->lib->dump_nic_event_log(priv, false); priv->cfg->ops->lib->dump_nic_event_log(priv, false);
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS)
...@@ -3191,6 +3193,77 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len) ...@@ -3191,6 +3193,77 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len)
EXPORT_SYMBOL(iwl_update_stats); EXPORT_SYMBOL(iwl_update_stats);
#endif #endif
const static char *get_csr_string(int cmd)
{
switch (cmd) {
IWL_CMD(CSR_HW_IF_CONFIG_REG);
IWL_CMD(CSR_INT_COALESCING);
IWL_CMD(CSR_INT);
IWL_CMD(CSR_INT_MASK);
IWL_CMD(CSR_FH_INT_STATUS);
IWL_CMD(CSR_GPIO_IN);
IWL_CMD(CSR_RESET);
IWL_CMD(CSR_GP_CNTRL);
IWL_CMD(CSR_HW_REV);
IWL_CMD(CSR_EEPROM_REG);
IWL_CMD(CSR_EEPROM_GP);
IWL_CMD(CSR_OTP_GP_REG);
IWL_CMD(CSR_GIO_REG);
IWL_CMD(CSR_GP_UCODE_REG);
IWL_CMD(CSR_GP_DRIVER_REG);
IWL_CMD(CSR_UCODE_DRV_GP1);
IWL_CMD(CSR_UCODE_DRV_GP2);
IWL_CMD(CSR_LED_REG);
IWL_CMD(CSR_DRAM_INT_TBL_REG);
IWL_CMD(CSR_GIO_CHICKEN_BITS);
IWL_CMD(CSR_ANA_PLL_CFG);
IWL_CMD(CSR_HW_REV_WA_REG);
IWL_CMD(CSR_DBG_HPET_MEM_REG);
default:
return "UNKNOWN";
}
}
void iwl_dump_csr(struct iwl_priv *priv)
{
int i;
u32 csr_tbl[] = {
CSR_HW_IF_CONFIG_REG,
CSR_INT_COALESCING,
CSR_INT,
CSR_INT_MASK,
CSR_FH_INT_STATUS,
CSR_GPIO_IN,
CSR_RESET,
CSR_GP_CNTRL,
CSR_HW_REV,
CSR_EEPROM_REG,
CSR_EEPROM_GP,
CSR_OTP_GP_REG,
CSR_GIO_REG,
CSR_GP_UCODE_REG,
CSR_GP_DRIVER_REG,
CSR_UCODE_DRV_GP1,
CSR_UCODE_DRV_GP2,
CSR_LED_REG,
CSR_DRAM_INT_TBL_REG,
CSR_GIO_CHICKEN_BITS,
CSR_ANA_PLL_CFG,
CSR_HW_REV_WA_REG,
CSR_DBG_HPET_MEM_REG
};
IWL_ERR(priv, "CSR values:\n");
IWL_ERR(priv, "(2nd byte of CSR_INT_COALESCING is "
"CSR_INT_PERIODIC_REG)\n");
for (i = 0; i < ARRAY_SIZE(csr_tbl); i++) {
IWL_ERR(priv, " %25s: 0X%08x\n",
get_csr_string(csr_tbl[i]),
iwl_read32(priv, csr_tbl[i]));
}
}
EXPORT_SYMBOL(iwl_dump_csr);
#ifdef CONFIG_PM #ifdef CONFIG_PM
int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
......
...@@ -171,6 +171,7 @@ struct iwl_lib_ops { ...@@ -171,6 +171,7 @@ struct iwl_lib_ops {
int (*load_ucode)(struct iwl_priv *priv); int (*load_ucode)(struct iwl_priv *priv);
void (*dump_nic_event_log)(struct iwl_priv *priv, bool full_log); void (*dump_nic_event_log)(struct iwl_priv *priv, bool full_log);
void (*dump_nic_error_log)(struct iwl_priv *priv); void (*dump_nic_error_log)(struct iwl_priv *priv);
void (*dump_csr)(struct iwl_priv *priv);
int (*set_channel_switch)(struct iwl_priv *priv, u16 channel); int (*set_channel_switch)(struct iwl_priv *priv, u16 channel);
/* power management */ /* power management */
struct iwl_apm_ops apm_ops; struct iwl_apm_ops apm_ops;
...@@ -582,6 +583,7 @@ int iwl_pci_resume(struct pci_dev *pdev); ...@@ -582,6 +583,7 @@ int iwl_pci_resume(struct pci_dev *pdev);
******************************************************/ ******************************************************/
void iwl_dump_nic_error_log(struct iwl_priv *priv); void iwl_dump_nic_error_log(struct iwl_priv *priv);
void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log); void iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log);
void iwl_dump_csr(struct iwl_priv *priv);
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
void iwl_print_rx_config_cmd(struct iwl_priv *priv); void iwl_print_rx_config_cmd(struct iwl_priv *priv);
#else #else
......
...@@ -109,6 +109,7 @@ struct iwl_debugfs { ...@@ -109,6 +109,7 @@ struct iwl_debugfs {
struct dentry *file_power_save_status; struct dentry *file_power_save_status;
struct dentry *file_clear_ucode_statistics; struct dentry *file_clear_ucode_statistics;
struct dentry *file_clear_traffic_statistics; struct dentry *file_clear_traffic_statistics;
struct dentry *file_csr;
} dbgfs_debug_files; } dbgfs_debug_files;
u32 sram_offset; u32 sram_offset;
u32 sram_len; u32 sram_len;
......
...@@ -1845,6 +1845,28 @@ static ssize_t iwl_dbgfs_clear_ucode_statistics_write(struct file *file, ...@@ -1845,6 +1845,28 @@ static ssize_t iwl_dbgfs_clear_ucode_statistics_write(struct file *file,
return count; return count;
} }
static ssize_t iwl_dbgfs_csr_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct iwl_priv *priv = file->private_data;
char buf[8];
int buf_size;
int csr;
memset(buf, 0, sizeof(buf));
buf_size = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT;
if (sscanf(buf, "%d", &csr) != 1)
return -EFAULT;
if (priv->cfg->ops->lib->dump_csr)
priv->cfg->ops->lib->dump_csr(priv);
return count;
}
DEBUGFS_READ_FILE_OPS(rx_statistics); DEBUGFS_READ_FILE_OPS(rx_statistics);
DEBUGFS_READ_FILE_OPS(tx_statistics); DEBUGFS_READ_FILE_OPS(tx_statistics);
DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
...@@ -1859,6 +1881,7 @@ DEBUGFS_READ_FILE_OPS(tx_power); ...@@ -1859,6 +1881,7 @@ DEBUGFS_READ_FILE_OPS(tx_power);
DEBUGFS_READ_FILE_OPS(power_save_status); DEBUGFS_READ_FILE_OPS(power_save_status);
DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics); DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics);
DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics); DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics);
DEBUGFS_WRITE_FILE_OPS(csr);
/* /*
* Create the debugfs files and directories * Create the debugfs files and directories
...@@ -1909,6 +1932,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) ...@@ -1909,6 +1932,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(power_save_status, debug, S_IRUSR); DEBUGFS_ADD_FILE(power_save_status, debug, S_IRUSR);
DEBUGFS_ADD_FILE(clear_ucode_statistics, debug, S_IWUSR); DEBUGFS_ADD_FILE(clear_ucode_statistics, debug, S_IWUSR);
DEBUGFS_ADD_FILE(clear_traffic_statistics, debug, S_IWUSR); DEBUGFS_ADD_FILE(clear_traffic_statistics, debug, S_IWUSR);
DEBUGFS_ADD_FILE(csr, debug, S_IWUSR);
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
DEBUGFS_ADD_FILE(ucode_rx_stats, debug, S_IRUSR); DEBUGFS_ADD_FILE(ucode_rx_stats, debug, S_IRUSR);
DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR); DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR);
...@@ -1966,6 +1990,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) ...@@ -1966,6 +1990,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
file_clear_ucode_statistics); file_clear_ucode_statistics);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
file_clear_traffic_statistics); file_clear_traffic_statistics);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_csr);
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
file_ucode_rx_stats); file_ucode_rx_stats);
......
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