iwlagn: simplify error table reading
authorJohannes Berg <johannes.berg@intel.com>
Wed, 13 Apr 2011 10:14:43 +0000 (03:14 -0700)
committerWey-Yi Guy <wey-yi.w.guy@intel.com>
Fri, 22 Apr 2011 17:02:19 +0000 (10:02 -0700)
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: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-commands.h
drivers/net/wireless/iwlwifi/iwl-io.c
drivers/net/wireless/iwlwifi/iwl-io.h

index cdeb09eee7396cfb87447ed517d6d1840c3afb21..f8559cc974f8f4e8ee9e0f437d5f84f9faba74d2 100644 (file)
@@ -1878,6 +1878,7 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
        u32 desc, time, count, base, data1;
        u32 blink1, blink2, ilink1, ilink2;
        u32 pc, hcmd;
+       struct iwl_error_event_table table;
 
        base = priv->device_pointers.error_event_table;
        if (priv->ucode_type == UCODE_INIT) {
@@ -1895,7 +1896,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
                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) {
                IWL_ERR(priv, "Start IWL Error Log Dump:\n");
@@ -1903,18 +1906,18 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
                        priv->status, count);
        }
 
-       desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
+       desc = table.error_id;
        priv->isr_stats.err_code = desc;
-       pc = iwl_read_targ_mem(priv, base + 2 * sizeof(u32));
-       blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
-       blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
-       ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32));
-       ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32));
-       data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32));
-       data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32));
-       line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
-       time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
-       hcmd = iwl_read_targ_mem(priv, base + 22 * sizeof(u32));
+       pc = table.pc;
+       blink1 = table.blink1;
+       blink2 = table.blink2;
+       ilink1 = table.ilink1;
+       ilink2 = table.ilink2;
+       data1 = table.data1;
+       data2 = table.data2;
+       line = table.line;
+       time = table.tsf_low;
+       hcmd = table.hcmd;
 
        trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line,
                                      blink1, blink2, ilink1, ilink2);
index 0edba8a6419b315d7cd5f3ecff04bddc3bc9cd23..7aea7b34f36c0206c67a626ce2d544402f9bd76d 100644 (file)
@@ -422,49 +422,61 @@ struct iwl_tx_ant_config_cmd {
  *
  * 2)  error_event_table_ptr indicates base of the error log.  This contains
  *     information about any uCode error that occurs.  For agn, the format
- *     of the error log is:
- *
- *     __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;
+ *     of the error log is defined by struct iwl_error_event_table.
  *
  * The Linux driver can print both logs to the system log when a uCode error
  * 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 {
        u8 ucode_minor;
        u8 ucode_major;
index 51337416e4ca76b8e630b1337afaa26b2b203e21..993b3df1b72b6d7c3b17a19100de250696f213ba 100644 (file)
@@ -242,20 +242,32 @@ void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask)
        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;
-       u32 value;
+       int offs;
+       u32 *vals = buf;
 
        spin_lock_irqsave(&priv->reg_lock, flags);
        iwl_grab_nic_access(priv);
 
        iwl_write32(priv, HBUS_TARG_MEM_RADDR, addr);
        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);
        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;
 }
 
index ab632baf49d51d9347f963558dc22bb8ef4d1800..262e0262496d670fac4087cb6f7f422869092d4a 100644 (file)
@@ -76,6 +76,16 @@ void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg,
                            u32 bits, 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);
 void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val);
 #endif