Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+15 −12
Original line number Diff line number Diff line
@@ -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);
+51 −39
Original line number Diff line number Diff line
@@ -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;
+15 −3
Original line number Diff line number Diff line
@@ -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;
}

+10 −0
Original line number Diff line number Diff line
@@ -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