iwlwifi: pcie: dump RBs when FW error occurs
Add support for dumping all the RBs in the RX queue when FW error occurs. This will assist debugging. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
This commit is contained in:
parent
192de2b406
commit
bd7fc617af
2 changed files with 74 additions and 2 deletions
|
@ -84,6 +84,8 @@
|
||||||
* @IWL_FW_ERROR_DUMP_MEM: chunk of memory
|
* @IWL_FW_ERROR_DUMP_MEM: chunk of memory
|
||||||
* @IWL_FW_ERROR_DUMP_ERROR_INFO: description of what triggered this dump.
|
* @IWL_FW_ERROR_DUMP_ERROR_INFO: description of what triggered this dump.
|
||||||
* Structured as &struct iwl_fw_error_dump_trigger_desc.
|
* Structured as &struct iwl_fw_error_dump_trigger_desc.
|
||||||
|
* @IWL_FW_ERROR_DUMP_RB: the content of an RB structured as
|
||||||
|
* &struct iwl_fw_error_dump_rb
|
||||||
*/
|
*/
|
||||||
enum iwl_fw_error_dump_type {
|
enum iwl_fw_error_dump_type {
|
||||||
/* 0 is deprecated */
|
/* 0 is deprecated */
|
||||||
|
@ -97,6 +99,7 @@ enum iwl_fw_error_dump_type {
|
||||||
IWL_FW_ERROR_DUMP_FH_REGS = 8,
|
IWL_FW_ERROR_DUMP_FH_REGS = 8,
|
||||||
IWL_FW_ERROR_DUMP_MEM = 9,
|
IWL_FW_ERROR_DUMP_MEM = 9,
|
||||||
IWL_FW_ERROR_DUMP_ERROR_INFO = 10,
|
IWL_FW_ERROR_DUMP_ERROR_INFO = 10,
|
||||||
|
IWL_FW_ERROR_DUMP_RB = 11,
|
||||||
|
|
||||||
IWL_FW_ERROR_DUMP_MAX,
|
IWL_FW_ERROR_DUMP_MAX,
|
||||||
};
|
};
|
||||||
|
@ -222,6 +225,20 @@ struct iwl_fw_error_dump_mem {
|
||||||
u8 data[];
|
u8 data[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct iwl_fw_error_dump_rb - content of an Receive Buffer
|
||||||
|
* @index: the index of the Receive Buffer in the Rx queue
|
||||||
|
* @rxq: the RB's Rx queue
|
||||||
|
* @reserved:
|
||||||
|
* @data: the content of the Receive Buffer
|
||||||
|
*/
|
||||||
|
struct iwl_fw_error_dump_rb {
|
||||||
|
__le32 index;
|
||||||
|
__le32 rxq;
|
||||||
|
__le32 reserved;
|
||||||
|
u8 data[];
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* iwl_fw_error_next_data - advance fw error dump data pointer
|
* iwl_fw_error_next_data - advance fw error dump data pointer
|
||||||
* @data: previous data block
|
* @data: previous data block
|
||||||
|
|
|
@ -2275,6 +2275,47 @@ static u32 iwl_trans_pcie_dump_prph(struct iwl_trans *trans,
|
||||||
return prph_len;
|
return prph_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 iwl_trans_pcie_dump_rbs(struct iwl_trans *trans,
|
||||||
|
struct iwl_fw_error_dump_data **data,
|
||||||
|
int allocated_rb_nums)
|
||||||
|
{
|
||||||
|
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||||
|
int max_len = PAGE_SIZE << trans_pcie->rx_page_order;
|
||||||
|
struct iwl_rxq *rxq = &trans_pcie->rxq;
|
||||||
|
u32 i, r, j, rb_len = 0;
|
||||||
|
|
||||||
|
spin_lock(&rxq->lock);
|
||||||
|
|
||||||
|
r = le16_to_cpu(ACCESS_ONCE(rxq->rb_stts->closed_rb_num)) & 0x0FFF;
|
||||||
|
|
||||||
|
for (i = rxq->read, j = 0;
|
||||||
|
i != r && j < allocated_rb_nums;
|
||||||
|
i = (i + 1) & RX_QUEUE_MASK, j++) {
|
||||||
|
struct iwl_rx_mem_buffer *rxb = rxq->queue[i];
|
||||||
|
struct iwl_fw_error_dump_rb *rb;
|
||||||
|
|
||||||
|
dma_unmap_page(trans->dev, rxb->page_dma, max_len,
|
||||||
|
DMA_FROM_DEVICE);
|
||||||
|
|
||||||
|
rb_len += sizeof(**data) + sizeof(*rb) + max_len;
|
||||||
|
|
||||||
|
(*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RB);
|
||||||
|
(*data)->len = cpu_to_le32(sizeof(*rb) + max_len);
|
||||||
|
rb = (void *)(*data)->data;
|
||||||
|
rb->index = cpu_to_le32(i);
|
||||||
|
memcpy(rb->data, page_address(rxb->page), max_len);
|
||||||
|
/* remap the page for the free benefit */
|
||||||
|
rxb->page_dma = dma_map_page(trans->dev, rxb->page, 0,
|
||||||
|
max_len,
|
||||||
|
DMA_FROM_DEVICE);
|
||||||
|
|
||||||
|
*data = iwl_fw_error_next_data(*data);
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_unlock(&rxq->lock);
|
||||||
|
|
||||||
|
return rb_len;
|
||||||
|
}
|
||||||
#define IWL_CSR_TO_DUMP (0x250)
|
#define IWL_CSR_TO_DUMP (0x250)
|
||||||
|
|
||||||
static u32 iwl_trans_pcie_dump_csr(struct iwl_trans *trans,
|
static u32 iwl_trans_pcie_dump_csr(struct iwl_trans *trans,
|
||||||
|
@ -2352,9 +2393,10 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
|
||||||
struct iwl_txq *cmdq = &trans_pcie->txq[trans_pcie->cmd_queue];
|
struct iwl_txq *cmdq = &trans_pcie->txq[trans_pcie->cmd_queue];
|
||||||
struct iwl_fw_error_dump_txcmd *txcmd;
|
struct iwl_fw_error_dump_txcmd *txcmd;
|
||||||
struct iwl_trans_dump_data *dump_data;
|
struct iwl_trans_dump_data *dump_data;
|
||||||
u32 len;
|
u32 len, num_rbs;
|
||||||
u32 monitor_len;
|
u32 monitor_len;
|
||||||
int i, ptr;
|
int i, ptr;
|
||||||
|
bool dump_rbs = test_bit(STATUS_FW_ERROR, &trans->status);
|
||||||
|
|
||||||
/* transport dump header */
|
/* transport dump header */
|
||||||
len = sizeof(*dump_data);
|
len = sizeof(*dump_data);
|
||||||
|
@ -2379,6 +2421,17 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
|
||||||
/* FH registers */
|
/* FH registers */
|
||||||
len += sizeof(*data) + (FH_MEM_UPPER_BOUND - FH_MEM_LOWER_BOUND);
|
len += sizeof(*data) + (FH_MEM_UPPER_BOUND - FH_MEM_LOWER_BOUND);
|
||||||
|
|
||||||
|
if (dump_rbs) {
|
||||||
|
/* RBs */
|
||||||
|
num_rbs = le16_to_cpu(ACCESS_ONCE(
|
||||||
|
trans_pcie->rxq.rb_stts->closed_rb_num))
|
||||||
|
& 0x0FFF;
|
||||||
|
num_rbs = (num_rbs - trans_pcie->rxq.read) & RX_QUEUE_MASK;
|
||||||
|
len += num_rbs * (sizeof(*data) +
|
||||||
|
sizeof(struct iwl_fw_error_dump_rb) +
|
||||||
|
(PAGE_SIZE << trans_pcie->rx_page_order));
|
||||||
|
}
|
||||||
|
|
||||||
/* FW monitor */
|
/* FW monitor */
|
||||||
if (trans_pcie->fw_mon_page) {
|
if (trans_pcie->fw_mon_page) {
|
||||||
len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) +
|
len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) +
|
||||||
|
@ -2442,8 +2495,10 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
|
||||||
len += iwl_trans_pcie_dump_prph(trans, &data);
|
len += iwl_trans_pcie_dump_prph(trans, &data);
|
||||||
len += iwl_trans_pcie_dump_csr(trans, &data);
|
len += iwl_trans_pcie_dump_csr(trans, &data);
|
||||||
len += iwl_trans_pcie_fh_regs_dump(trans, &data);
|
len += iwl_trans_pcie_fh_regs_dump(trans, &data);
|
||||||
/* data is already pointing to the next section */
|
if (dump_rbs)
|
||||||
|
len += iwl_trans_pcie_dump_rbs(trans, &data, num_rbs);
|
||||||
|
|
||||||
|
/* data is already pointing to the next section */
|
||||||
if ((trans_pcie->fw_mon_page &&
|
if ((trans_pcie->fw_mon_page &&
|
||||||
trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) ||
|
trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) ||
|
||||||
trans->dbg_dest_tlv) {
|
trans->dbg_dest_tlv) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue