Commit e46f6538 authored by Johannes Berg's avatar Johannes Berg Committed by Wey-Yi Guy

iwlagn: simplify error table reading

The current code to read the error table header
just hardcodes all the offsets, which is a bit
hard to understand. We can read in the entire
header (as much as we need) into a structure,
and then take the data from there, which makes
it easier to understand. To read a bigger blob
we also don't need to grab NIC access for each
word read, making the code more efficient.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarWey-Yi Guy <wey-yi.w.guy@intel.com>
parent 73b48099
...@@ -1878,6 +1878,7 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) ...@@ -1878,6 +1878,7 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
u32 desc, time, count, base, data1; u32 desc, time, count, base, data1;
u32 blink1, blink2, ilink1, ilink2; u32 blink1, blink2, ilink1, ilink2;
u32 pc, hcmd; u32 pc, hcmd;
struct iwl_error_event_table table;
base = priv->device_pointers.error_event_table; base = priv->device_pointers.error_event_table;
if (priv->ucode_type == UCODE_INIT) { if (priv->ucode_type == UCODE_INIT) {
...@@ -1895,7 +1896,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) ...@@ -1895,7 +1896,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
return; return;
} }
count = iwl_read_targ_mem(priv, base); iwl_read_targ_mem_words(priv, base, &table, sizeof(table));
count = table.valid;
if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
IWL_ERR(priv, "Start IWL Error Log Dump:\n"); IWL_ERR(priv, "Start IWL Error Log Dump:\n");
...@@ -1903,18 +1906,18 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) ...@@ -1903,18 +1906,18 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
priv->status, count); priv->status, count);
} }
desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32)); desc = table.error_id;
priv->isr_stats.err_code = desc; priv->isr_stats.err_code = desc;
pc = iwl_read_targ_mem(priv, base + 2 * sizeof(u32)); pc = table.pc;
blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32)); blink1 = table.blink1;
blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32)); blink2 = table.blink2;
ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32)); ilink1 = table.ilink1;
ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32)); ilink2 = table.ilink2;
data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32)); data1 = table.data1;
data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32)); data2 = table.data2;
line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32)); line = table.line;
time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32)); time = table.tsf_low;
hcmd = iwl_read_targ_mem(priv, base + 22 * sizeof(u32)); hcmd = table.hcmd;
trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line, trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line,
blink1, blink2, ilink1, ilink2); blink1, blink2, ilink1, ilink2);
......
...@@ -422,49 +422,61 @@ struct iwl_tx_ant_config_cmd { ...@@ -422,49 +422,61 @@ struct iwl_tx_ant_config_cmd {
* *
* 2) error_event_table_ptr indicates base of the error log. This contains * 2) error_event_table_ptr indicates base of the error log. This contains
* information about any uCode error that occurs. For agn, the format * information about any uCode error that occurs. For agn, the format
* of the error log is: * of the error log is defined by struct iwl_error_event_table.
*
* __le32 valid; (nonzero) valid, (0) log is empty
* __le32 error_id; type of error
* __le32 pc; program counter
* __le32 blink1; branch link
* __le32 blink2; branch link
* __le32 ilink1; interrupt link
* __le32 ilink2; interrupt link
* __le32 data1; error-specific data
* __le32 data2; error-specific data
* __le32 line; source code line of error
* __le32 bcon_time; beacon timer
* __le32 tsf_low; network timestamp function timer
* __le32 tsf_hi; network timestamp function timer
* __le32 gp1; GP1 timer register
* __le32 gp2; GP2 timer register
* __le32 gp3; GP3 timer register
* __le32 ucode_ver; uCode version
* __le32 hw_ver; HW Silicon version
* __le32 brd_ver; HW board version
* __le32 log_pc; log program counter
* __le32 frame_ptr; frame pointer
* __le32 stack_ptr; stack pointer
* __le32 hcmd; last host command
* __le32 isr0; isr status register LMPM_NIC_ISR0: rxtx_flag
* __le32 isr1; isr status register LMPM_NIC_ISR1: host_flag
* __le32 isr2; isr status register LMPM_NIC_ISR2: enc_flag
* __le32 isr3; isr status register LMPM_NIC_ISR3: time_flag
* __le32 isr4; isr status register LMPM_NIC_ISR4: wico interrupt
* __le32 isr_pref; isr status register LMPM_NIC_PREF_STAT
* __le32 wait_event; wait event() caller address
* __le32 l2p_control; L2pControlField
* __le32 l2p_duration; L2pDurationField
* __le32 l2p_mhvalid; L2pMhValidBits
* __le32 l2p_addr_match; L2pAddrMatchStat
* __le32 lmpm_pmg_sel; indicate which clocks are turned on (LMPM_PMG_SEL)
* __le32 u_timestamp; indicate when the date and time of the compilation
* __le32 reserved;
* *
* The Linux driver can print both logs to the system log when a uCode error * The Linux driver can print both logs to the system log when a uCode error
* occurs. * occurs.
*/ */
/*
* Note: This structure is read from the device with IO accesses,
* and the reading already does the endian conversion. As it is
* read with u32-sized accesses, any members with a different size
* need to be ordered correctly though!
*/
struct iwl_error_event_table {
u32 valid; /* (nonzero) valid, (0) log is empty */
u32 error_id; /* type of error */
u32 pc; /* program counter */
u32 blink1; /* branch link */
u32 blink2; /* branch link */
u32 ilink1; /* interrupt link */
u32 ilink2; /* interrupt link */
u32 data1; /* error-specific data */
u32 data2; /* error-specific data */
u32 line; /* source code line of error */
u32 bcon_time; /* beacon timer */
u32 tsf_low; /* network timestamp function timer */
u32 tsf_hi; /* network timestamp function timer */
u32 gp1; /* GP1 timer register */
u32 gp2; /* GP2 timer register */
u32 gp3; /* GP3 timer register */
u32 ucode_ver; /* uCode version */
u32 hw_ver; /* HW Silicon version */
u32 brd_ver; /* HW board version */
u32 log_pc; /* log program counter */
u32 frame_ptr; /* frame pointer */
u32 stack_ptr; /* stack pointer */
u32 hcmd; /* last host command header */
#if 0
/* no need to read the remainder, we don't use the values */
u32 isr0; /* isr status register LMPM_NIC_ISR0: rxtx_flag */
u32 isr1; /* isr status register LMPM_NIC_ISR1: host_flag */
u32 isr2; /* isr status register LMPM_NIC_ISR2: enc_flag */
u32 isr3; /* isr status register LMPM_NIC_ISR3: time_flag */
u32 isr4; /* isr status register LMPM_NIC_ISR4: wico interrupt */
u32 isr_pref; /* isr status register LMPM_NIC_PREF_STAT */
u32 wait_event; /* wait event() caller address */
u32 l2p_control; /* L2pControlField */
u32 l2p_duration; /* L2pDurationField */
u32 l2p_mhvalid; /* L2pMhValidBits */
u32 l2p_addr_match; /* L2pAddrMatchStat */
u32 lmpm_pmg_sel; /* indicate which clocks are turned on (LMPM_PMG_SEL) */
u32 u_timestamp; /* indicate when the date and time of the compilation */
u32 flow_handler; /* FH read/write pointers, RX credit */
#endif
} __packed;
struct iwl_alive_resp { struct iwl_alive_resp {
u8 ucode_minor; u8 ucode_minor;
u8 ucode_major; u8 ucode_major;
......
...@@ -242,20 +242,32 @@ void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) ...@@ -242,20 +242,32 @@ void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask)
spin_unlock_irqrestore(&priv->reg_lock, flags); spin_unlock_irqrestore(&priv->reg_lock, flags);
} }
u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) void _iwl_read_targ_mem_words(struct iwl_priv *priv, u32 addr,
void *buf, int words)
{ {
unsigned long flags; unsigned long flags;
u32 value; int offs;
u32 *vals = buf;
spin_lock_irqsave(&priv->reg_lock, flags); spin_lock_irqsave(&priv->reg_lock, flags);
iwl_grab_nic_access(priv); iwl_grab_nic_access(priv);
iwl_write32(priv, HBUS_TARG_MEM_RADDR, addr); iwl_write32(priv, HBUS_TARG_MEM_RADDR, addr);
rmb(); rmb();
value = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
for (offs = 0; offs < words; offs++)
vals[offs] = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
iwl_release_nic_access(priv); iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->reg_lock, flags); spin_unlock_irqrestore(&priv->reg_lock, flags);
}
u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr)
{
u32 value;
_iwl_read_targ_mem_words(priv, addr, &value, 1);
return value; return value;
} }
......
...@@ -76,6 +76,16 @@ void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, ...@@ -76,6 +76,16 @@ void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg,
u32 bits, u32 mask); u32 bits, u32 mask);
void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask); void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask);
void _iwl_read_targ_mem_words(struct iwl_priv *priv, u32 addr,
void *buf, int words);
#define iwl_read_targ_mem_words(priv, addr, buf, bufsize) \
do { \
BUILD_BUG_ON((bufsize) % sizeof(u32)); \
_iwl_read_targ_mem_words(priv, addr, buf, \
(bufsize) / sizeof(u32));\
} while (0)
u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr); u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr);
void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val); void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val);
#endif #endif
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