|
@@ -1543,6 +1543,9 @@ struct iwlagn_firmware_pieces {
|
|
|
size_t inst_size, data_size, init_size, init_data_size, boot_size;
|
|
|
|
|
|
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,
|
|
@@ -1720,6 +1723,42 @@ static int iwlagn_load_firmware(struct iwl_priv *priv,
|
|
|
capa->max_probe_length =
|
|
|
le32_to_cpup((__le32 *)tlv_data);
|
|
|
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:
|
|
|
break;
|
|
|
}
|
|
@@ -1912,6 +1951,26 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
|
|
|
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 ... */
|
|
|
|
|
|
/* 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 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);
|
|
|
- else
|
|
|
+ if (!base)
|
|
|
+ base = priv->_agn.init_errlog_ptr;
|
|
|
+ } else {
|
|
|
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)) {
|
|
|
IWL_ERR(priv,
|
|
@@ -2100,10 +2164,16 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
|
|
|
|
|
|
if (num_events == 0)
|
|
|
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);
|
|
|
- else
|
|
|
+ if (!base)
|
|
|
+ base = priv->_agn.init_evtlog_ptr;
|
|
|
+ } else {
|
|
|
base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
|
|
|
+ if (!base)
|
|
|
+ base = priv->_agn.inst_evtlog_ptr;
|
|
|
+ }
|
|
|
|
|
|
if (mode == 0)
|
|
|
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 next_entry; /* index of next entry to be written by uCode */
|
|
|
u32 size; /* # entries that we'll print */
|
|
|
+ u32 logsize;
|
|
|
int pos = 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);
|
|
|
- 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);
|
|
|
+ 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)) {
|
|
|
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)));
|
|
|
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",
|
|
|
- capacity, priv->cfg->max_event_log_size);
|
|
|
- capacity = priv->cfg->max_event_log_size;
|
|
|
+ capacity, logsize);
|
|
|
+ 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",
|
|
|
- next_entry, priv->cfg->max_event_log_size);
|
|
|
- next_entry = priv->cfg->max_event_log_size;
|
|
|
+ next_entry, logsize);
|
|
|
+ next_entry = logsize;
|
|
|
}
|
|
|
|
|
|
size = num_wraps ? capacity : next_entry;
|