iwlagn: use firmware event/error log information

In order to debug problems before the ALIVE
notification is received, new firmware files
contain the event/error log information in
the file. Use that information.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
This commit is contained in:
Johannes Berg 2010-05-05 23:24:54 -07:00 committed by Reinette Chatre
parent 9c5ac091b2
commit b2e640d485
2 changed files with 99 additions and 12 deletions

View File

@ -1543,6 +1543,9 @@ struct iwlagn_firmware_pieces {
size_t inst_size, data_size, init_size, init_data_size, boot_size; size_t inst_size, data_size, init_size, init_data_size, boot_size;
u32 build; u32 build;
u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
}; };
static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, static int iwlagn_load_legacy_firmware(struct iwl_priv *priv,
@ -1720,6 +1723,42 @@ static int iwlagn_load_firmware(struct iwl_priv *priv,
capa->max_probe_length = capa->max_probe_length =
le32_to_cpup((__le32 *)tlv_data); le32_to_cpup((__le32 *)tlv_data);
break; break;
case IWL_UCODE_TLV_INIT_EVTLOG_PTR:
if (tlv_len != 4)
return -EINVAL;
pieces->init_evtlog_ptr =
le32_to_cpup((__le32 *)tlv_data);
break;
case IWL_UCODE_TLV_INIT_EVTLOG_SIZE:
if (tlv_len != 4)
return -EINVAL;
pieces->init_evtlog_size =
le32_to_cpup((__le32 *)tlv_data);
break;
case IWL_UCODE_TLV_INIT_ERRLOG_PTR:
if (tlv_len != 4)
return -EINVAL;
pieces->init_errlog_ptr =
le32_to_cpup((__le32 *)tlv_data);
break;
case IWL_UCODE_TLV_RUNT_EVTLOG_PTR:
if (tlv_len != 4)
return -EINVAL;
pieces->inst_evtlog_ptr =
le32_to_cpup((__le32 *)tlv_data);
break;
case IWL_UCODE_TLV_RUNT_EVTLOG_SIZE:
if (tlv_len != 4)
return -EINVAL;
pieces->inst_evtlog_size =
le32_to_cpup((__le32 *)tlv_data);
break;
case IWL_UCODE_TLV_RUNT_ERRLOG_PTR:
if (tlv_len != 4)
return -EINVAL;
pieces->inst_errlog_ptr =
le32_to_cpup((__le32 *)tlv_data);
break;
default: default:
break; break;
} }
@ -1912,6 +1951,26 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
goto err_pci_alloc; goto err_pci_alloc;
} }
/* Now that we can no longer fail, copy information */
/*
* The (size - 16) / 12 formula is based on the information recorded
* for each event, which is of mode 1 (including timestamp) for all
* new microcodes that include this information.
*/
priv->_agn.init_evtlog_ptr = pieces.init_evtlog_ptr;
if (pieces.init_evtlog_size)
priv->_agn.init_evtlog_size = (pieces.init_evtlog_size - 16)/12;
else
priv->_agn.init_evtlog_size = priv->cfg->max_event_log_size;
priv->_agn.init_errlog_ptr = pieces.init_errlog_ptr;
priv->_agn.inst_evtlog_ptr = pieces.inst_evtlog_ptr;
if (pieces.inst_evtlog_size)
priv->_agn.inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12;
else
priv->_agn.inst_evtlog_size = priv->cfg->max_event_log_size;
priv->_agn.inst_errlog_ptr = pieces.inst_errlog_ptr;
/* Copy images into buffers for card's bus-master reads ... */ /* Copy images into buffers for card's bus-master reads ... */
/* Runtime instructions (first block of data in file) */ /* Runtime instructions (first block of data in file) */
@ -2037,10 +2096,15 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
u32 blink1, blink2, ilink1, ilink2; u32 blink1, blink2, ilink1, ilink2;
u32 pc, hcmd; u32 pc, hcmd;
if (priv->ucode_type == UCODE_INIT) if (priv->ucode_type == UCODE_INIT) {
base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
else if (!base)
base = priv->_agn.init_errlog_ptr;
} else {
base = le32_to_cpu(priv->card_alive.error_event_table_ptr); base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
if (!base)
base = priv->_agn.inst_errlog_ptr;
}
if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
IWL_ERR(priv, IWL_ERR(priv,
@ -2100,10 +2164,16 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
if (num_events == 0) if (num_events == 0)
return pos; return pos;
if (priv->ucode_type == UCODE_INIT)
if (priv->ucode_type == UCODE_INIT) {
base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
else if (!base)
base = priv->_agn.init_evtlog_ptr;
} else {
base = le32_to_cpu(priv->card_alive.log_event_table_ptr); base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
if (!base)
base = priv->_agn.inst_evtlog_ptr;
}
if (mode == 0) if (mode == 0)
event_size = 2 * sizeof(u32); event_size = 2 * sizeof(u32);
@ -2205,13 +2275,21 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
u32 num_wraps; /* # times uCode wrapped to top of log */ u32 num_wraps; /* # times uCode wrapped to top of log */
u32 next_entry; /* index of next entry to be written by uCode */ u32 next_entry; /* index of next entry to be written by uCode */
u32 size; /* # entries that we'll print */ u32 size; /* # entries that we'll print */
u32 logsize;
int pos = 0; int pos = 0;
size_t bufsz = 0; size_t bufsz = 0;
if (priv->ucode_type == UCODE_INIT) if (priv->ucode_type == UCODE_INIT) {
base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr); base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
else logsize = priv->_agn.init_evtlog_size;
if (!base)
base = priv->_agn.init_evtlog_ptr;
} else {
base = le32_to_cpu(priv->card_alive.log_event_table_ptr); base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
logsize = priv->_agn.inst_evtlog_size;
if (!base)
base = priv->_agn.inst_evtlog_ptr;
}
if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
IWL_ERR(priv, IWL_ERR(priv,
@ -2226,16 +2304,16 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
if (capacity > priv->cfg->max_event_log_size) { if (capacity > logsize) {
IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n", IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n",
capacity, priv->cfg->max_event_log_size); capacity, logsize);
capacity = priv->cfg->max_event_log_size; capacity = logsize;
} }
if (next_entry > priv->cfg->max_event_log_size) { if (next_entry > logsize) {
IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n", IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n",
next_entry, priv->cfg->max_event_log_size); next_entry, logsize);
next_entry = priv->cfg->max_event_log_size; next_entry = logsize;
} }
size = num_wraps ? capacity : next_entry; size = num_wraps ? capacity : next_entry;

View File

@ -583,6 +583,12 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_INIT_DATA = 4, IWL_UCODE_TLV_INIT_DATA = 4,
IWL_UCODE_TLV_BOOT = 5, IWL_UCODE_TLV_BOOT = 5,
IWL_UCODE_TLV_PROBE_MAX_LEN = 6, /* a u32 value */ IWL_UCODE_TLV_PROBE_MAX_LEN = 6, /* a u32 value */
IWL_UCODE_TLV_RUNT_EVTLOG_PTR = 8,
IWL_UCODE_TLV_RUNT_EVTLOG_SIZE = 9,
IWL_UCODE_TLV_RUNT_ERRLOG_PTR = 10,
IWL_UCODE_TLV_INIT_EVTLOG_PTR = 11,
IWL_UCODE_TLV_INIT_EVTLOG_SIZE = 12,
IWL_UCODE_TLV_INIT_ERRLOG_PTR = 13,
}; };
struct iwl_ucode_tlv { struct iwl_ucode_tlv {
@ -1317,6 +1323,9 @@ struct iwl_priv {
struct iwl_notif_statistics delta_statistics; struct iwl_notif_statistics delta_statistics;
struct iwl_notif_statistics max_delta; struct iwl_notif_statistics max_delta;
#endif #endif
u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
} _agn; } _agn;
#endif #endif
}; };