|
@@ -73,6 +73,7 @@
|
|
#include "iwl-csr.h"
|
|
#include "iwl-csr.h"
|
|
#include "iwl-prph.h"
|
|
#include "iwl-prph.h"
|
|
#include "iwl-agn-hw.h"
|
|
#include "iwl-agn-hw.h"
|
|
|
|
+#include "iwl-fw-error-dump.h"
|
|
#include "internal.h"
|
|
#include "internal.h"
|
|
|
|
|
|
static u32 iwl_trans_pcie_read_shr(struct iwl_trans *trans, u32 reg)
|
|
static u32 iwl_trans_pcie_read_shr(struct iwl_trans *trans, u32 reg)
|
|
@@ -1669,6 +1670,61 @@ err:
|
|
IWL_ERR(trans, "failed to create the trans debugfs entry\n");
|
|
IWL_ERR(trans, "failed to create the trans debugfs entry\n");
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+static u32 iwl_trans_pcie_get_cmdlen(struct iwl_tfd *tfd)
|
|
|
|
+{
|
|
|
|
+ u32 cmdlen = 0;
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < IWL_NUM_OF_TBS; i++)
|
|
|
|
+ cmdlen += iwl_pcie_tfd_tb_get_len(tfd, i);
|
|
|
|
+
|
|
|
|
+ return cmdlen;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static u32 iwl_trans_pcie_dump_data(struct iwl_trans *trans,
|
|
|
|
+ void *buf, u32 buflen)
|
|
|
|
+{
|
|
|
|
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
|
|
|
+ struct iwl_fw_error_dump_data *data;
|
|
|
|
+ struct iwl_txq *cmdq = &trans_pcie->txq[trans_pcie->cmd_queue];
|
|
|
|
+ struct iwl_fw_error_dump_txcmd *txcmd;
|
|
|
|
+ u32 len;
|
|
|
|
+ int i, ptr;
|
|
|
|
+
|
|
|
|
+ if (!buf)
|
|
|
|
+ return sizeof(*data) +
|
|
|
|
+ cmdq->q.n_window * (sizeof(*txcmd) +
|
|
|
|
+ TFD_MAX_PAYLOAD_SIZE);
|
|
|
|
+
|
|
|
|
+ len = 0;
|
|
|
|
+ data = buf;
|
|
|
|
+ data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_TXCMD);
|
|
|
|
+ txcmd = (void *)data->data;
|
|
|
|
+ spin_lock_bh(&cmdq->lock);
|
|
|
|
+ ptr = cmdq->q.write_ptr;
|
|
|
|
+ for (i = 0; i < cmdq->q.n_window; i++) {
|
|
|
|
+ u8 idx = get_cmd_index(&cmdq->q, ptr);
|
|
|
|
+ u32 caplen, cmdlen;
|
|
|
|
+
|
|
|
|
+ cmdlen = iwl_trans_pcie_get_cmdlen(&cmdq->tfds[ptr]);
|
|
|
|
+ caplen = min_t(u32, TFD_MAX_PAYLOAD_SIZE, cmdlen);
|
|
|
|
+
|
|
|
|
+ if (cmdlen) {
|
|
|
|
+ len += sizeof(*txcmd) + caplen;
|
|
|
|
+ txcmd->cmdlen = cpu_to_le32(cmdlen);
|
|
|
|
+ txcmd->caplen = cpu_to_le32(caplen);
|
|
|
|
+ memcpy(txcmd->data, cmdq->entries[idx].cmd, caplen);
|
|
|
|
+ txcmd = (void *)((u8 *)txcmd->data + caplen);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ptr = iwl_queue_dec_wrap(ptr);
|
|
|
|
+ }
|
|
|
|
+ spin_unlock_bh(&cmdq->lock);
|
|
|
|
+
|
|
|
|
+ data->len = cpu_to_le32(len);
|
|
|
|
+ return sizeof(*data) + len;
|
|
|
|
+}
|
|
#else
|
|
#else
|
|
static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
|
|
static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
|
|
struct dentry *dir)
|
|
struct dentry *dir)
|
|
@@ -1711,6 +1767,10 @@ static const struct iwl_trans_ops trans_ops_pcie = {
|
|
.grab_nic_access = iwl_trans_pcie_grab_nic_access,
|
|
.grab_nic_access = iwl_trans_pcie_grab_nic_access,
|
|
.release_nic_access = iwl_trans_pcie_release_nic_access,
|
|
.release_nic_access = iwl_trans_pcie_release_nic_access,
|
|
.set_bits_mask = iwl_trans_pcie_set_bits_mask,
|
|
.set_bits_mask = iwl_trans_pcie_set_bits_mask,
|
|
|
|
+
|
|
|
|
+#ifdef CONFIG_IWLWIFI_DEBUGFS
|
|
|
|
+ .dump_data = iwl_trans_pcie_dump_data,
|
|
|
|
+#endif
|
|
};
|
|
};
|
|
|
|
|
|
struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
|
|
struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
|