|
|
@@ -2385,8 +2385,87 @@ iwl_trans_pci_dump_marbh_monitor(struct iwl_trans *trans,
|
|
|
return monitor_len;
|
|
|
}
|
|
|
|
|
|
-static
|
|
|
-struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
|
|
|
+static u32
|
|
|
+iwl_trans_pcie_dump_monitor(struct iwl_trans *trans,
|
|
|
+ struct iwl_fw_error_dump_data **data,
|
|
|
+ u32 monitor_len)
|
|
|
+{
|
|
|
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
|
|
+ u32 len = 0;
|
|
|
+
|
|
|
+ if ((trans_pcie->fw_mon_page &&
|
|
|
+ trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) ||
|
|
|
+ trans->dbg_dest_tlv) {
|
|
|
+ struct iwl_fw_error_dump_fw_mon *fw_mon_data;
|
|
|
+ u32 base, write_ptr, wrap_cnt;
|
|
|
+
|
|
|
+ /* If there was a dest TLV - use the values from there */
|
|
|
+ if (trans->dbg_dest_tlv) {
|
|
|
+ write_ptr =
|
|
|
+ le32_to_cpu(trans->dbg_dest_tlv->write_ptr_reg);
|
|
|
+ wrap_cnt = le32_to_cpu(trans->dbg_dest_tlv->wrap_count);
|
|
|
+ base = le32_to_cpu(trans->dbg_dest_tlv->base_reg);
|
|
|
+ } else {
|
|
|
+ base = MON_BUFF_BASE_ADDR;
|
|
|
+ write_ptr = MON_BUFF_WRPTR;
|
|
|
+ wrap_cnt = MON_BUFF_CYCLE_CNT;
|
|
|
+ }
|
|
|
+
|
|
|
+ (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR);
|
|
|
+ fw_mon_data = (void *)(*data)->data;
|
|
|
+ fw_mon_data->fw_mon_wr_ptr =
|
|
|
+ cpu_to_le32(iwl_read_prph(trans, write_ptr));
|
|
|
+ fw_mon_data->fw_mon_cycle_cnt =
|
|
|
+ cpu_to_le32(iwl_read_prph(trans, wrap_cnt));
|
|
|
+ fw_mon_data->fw_mon_base_ptr =
|
|
|
+ cpu_to_le32(iwl_read_prph(trans, base));
|
|
|
+
|
|
|
+ len += sizeof(**data) + sizeof(*fw_mon_data);
|
|
|
+ if (trans_pcie->fw_mon_page) {
|
|
|
+ /*
|
|
|
+ * The firmware is now asserted, it won't write anything
|
|
|
+ * to the buffer. CPU can take ownership to fetch the
|
|
|
+ * data. The buffer will be handed back to the device
|
|
|
+ * before the firmware will be restarted.
|
|
|
+ */
|
|
|
+ dma_sync_single_for_cpu(trans->dev,
|
|
|
+ trans_pcie->fw_mon_phys,
|
|
|
+ trans_pcie->fw_mon_size,
|
|
|
+ DMA_FROM_DEVICE);
|
|
|
+ memcpy(fw_mon_data->data,
|
|
|
+ page_address(trans_pcie->fw_mon_page),
|
|
|
+ trans_pcie->fw_mon_size);
|
|
|
+
|
|
|
+ monitor_len = trans_pcie->fw_mon_size;
|
|
|
+ } else if (trans->dbg_dest_tlv->monitor_mode == SMEM_MODE) {
|
|
|
+ /*
|
|
|
+ * Update pointers to reflect actual values after
|
|
|
+ * shifting
|
|
|
+ */
|
|
|
+ base = iwl_read_prph(trans, base) <<
|
|
|
+ trans->dbg_dest_tlv->base_shift;
|
|
|
+ iwl_trans_read_mem(trans, base, fw_mon_data->data,
|
|
|
+ monitor_len / sizeof(u32));
|
|
|
+ } else if (trans->dbg_dest_tlv->monitor_mode == MARBH_MODE) {
|
|
|
+ monitor_len =
|
|
|
+ iwl_trans_pci_dump_marbh_monitor(trans,
|
|
|
+ fw_mon_data,
|
|
|
+ monitor_len);
|
|
|
+ } else {
|
|
|
+ /* Didn't match anything - output no monitor data */
|
|
|
+ monitor_len = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ len += monitor_len;
|
|
|
+ (*data)->len = cpu_to_le32(monitor_len + sizeof(*fw_mon_data));
|
|
|
+ }
|
|
|
+
|
|
|
+ return len;
|
|
|
+}
|
|
|
+
|
|
|
+static struct iwl_trans_dump_data
|
|
|
+*iwl_trans_pcie_dump_data(struct iwl_trans *trans,
|
|
|
+ struct iwl_fw_dbg_trigger_tlv *trigger)
|
|
|
{
|
|
|
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
|
|
struct iwl_fw_error_dump_data *data;
|
|
|
@@ -2405,33 +2484,6 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
|
|
|
len += sizeof(*data) +
|
|
|
cmdq->q.n_window * (sizeof(*txcmd) + TFD_MAX_PAYLOAD_SIZE);
|
|
|
|
|
|
- /* CSR registers */
|
|
|
- len += sizeof(*data) + IWL_CSR_TO_DUMP;
|
|
|
-
|
|
|
- /* PRPH registers */
|
|
|
- for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr); i++) {
|
|
|
- /* The range includes both boundaries */
|
|
|
- int num_bytes_in_chunk = iwl_prph_dump_addr[i].end -
|
|
|
- iwl_prph_dump_addr[i].start + 4;
|
|
|
-
|
|
|
- len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_prph) +
|
|
|
- num_bytes_in_chunk;
|
|
|
- }
|
|
|
-
|
|
|
- /* FH registers */
|
|
|
- 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 */
|
|
|
if (trans_pcie->fw_mon_page) {
|
|
|
len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) +
|
|
|
@@ -2459,6 +2511,45 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
|
|
|
monitor_len = 0;
|
|
|
}
|
|
|
|
|
|
+ if (trigger && (trigger->mode & IWL_FW_DBG_TRIGGER_MONITOR_ONLY)) {
|
|
|
+ dump_data = vzalloc(len);
|
|
|
+ if (!dump_data)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ data = (void *)dump_data->data;
|
|
|
+ len = iwl_trans_pcie_dump_monitor(trans, &data, monitor_len);
|
|
|
+ dump_data->len = len;
|
|
|
+
|
|
|
+ return dump_data;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* CSR registers */
|
|
|
+ len += sizeof(*data) + IWL_CSR_TO_DUMP;
|
|
|
+
|
|
|
+ /* PRPH registers */
|
|
|
+ for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr); i++) {
|
|
|
+ /* The range includes both boundaries */
|
|
|
+ int num_bytes_in_chunk = iwl_prph_dump_addr[i].end -
|
|
|
+ iwl_prph_dump_addr[i].start + 4;
|
|
|
+
|
|
|
+ len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_prph) +
|
|
|
+ num_bytes_in_chunk;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* FH registers */
|
|
|
+ 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));
|
|
|
+ }
|
|
|
+
|
|
|
dump_data = vzalloc(len);
|
|
|
if (!dump_data)
|
|
|
return NULL;
|
|
|
@@ -2498,73 +2589,7 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
|
|
|
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 &&
|
|
|
- trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) ||
|
|
|
- trans->dbg_dest_tlv) {
|
|
|
- struct iwl_fw_error_dump_fw_mon *fw_mon_data;
|
|
|
- u32 base, write_ptr, wrap_cnt;
|
|
|
-
|
|
|
- /* If there was a dest TLV - use the values from there */
|
|
|
- if (trans->dbg_dest_tlv) {
|
|
|
- write_ptr =
|
|
|
- le32_to_cpu(trans->dbg_dest_tlv->write_ptr_reg);
|
|
|
- wrap_cnt = le32_to_cpu(trans->dbg_dest_tlv->wrap_count);
|
|
|
- base = le32_to_cpu(trans->dbg_dest_tlv->base_reg);
|
|
|
- } else {
|
|
|
- base = MON_BUFF_BASE_ADDR;
|
|
|
- write_ptr = MON_BUFF_WRPTR;
|
|
|
- wrap_cnt = MON_BUFF_CYCLE_CNT;
|
|
|
- }
|
|
|
-
|
|
|
- data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR);
|
|
|
- fw_mon_data = (void *)data->data;
|
|
|
- fw_mon_data->fw_mon_wr_ptr =
|
|
|
- cpu_to_le32(iwl_read_prph(trans, write_ptr));
|
|
|
- fw_mon_data->fw_mon_cycle_cnt =
|
|
|
- cpu_to_le32(iwl_read_prph(trans, wrap_cnt));
|
|
|
- fw_mon_data->fw_mon_base_ptr =
|
|
|
- cpu_to_le32(iwl_read_prph(trans, base));
|
|
|
-
|
|
|
- len += sizeof(*data) + sizeof(*fw_mon_data);
|
|
|
- if (trans_pcie->fw_mon_page) {
|
|
|
- /*
|
|
|
- * The firmware is now asserted, it won't write anything
|
|
|
- * to the buffer. CPU can take ownership to fetch the
|
|
|
- * data. The buffer will be handed back to the device
|
|
|
- * before the firmware will be restarted.
|
|
|
- */
|
|
|
- dma_sync_single_for_cpu(trans->dev,
|
|
|
- trans_pcie->fw_mon_phys,
|
|
|
- trans_pcie->fw_mon_size,
|
|
|
- DMA_FROM_DEVICE);
|
|
|
- memcpy(fw_mon_data->data,
|
|
|
- page_address(trans_pcie->fw_mon_page),
|
|
|
- trans_pcie->fw_mon_size);
|
|
|
-
|
|
|
- monitor_len = trans_pcie->fw_mon_size;
|
|
|
- } else if (trans->dbg_dest_tlv->monitor_mode == SMEM_MODE) {
|
|
|
- /*
|
|
|
- * Update pointers to reflect actual values after
|
|
|
- * shifting
|
|
|
- */
|
|
|
- base = iwl_read_prph(trans, base) <<
|
|
|
- trans->dbg_dest_tlv->base_shift;
|
|
|
- iwl_trans_read_mem(trans, base, fw_mon_data->data,
|
|
|
- monitor_len / sizeof(u32));
|
|
|
- } else if (trans->dbg_dest_tlv->monitor_mode == MARBH_MODE) {
|
|
|
- monitor_len =
|
|
|
- iwl_trans_pci_dump_marbh_monitor(trans,
|
|
|
- fw_mon_data,
|
|
|
- monitor_len);
|
|
|
- } else {
|
|
|
- /* Didn't match anything - output no monitor data */
|
|
|
- monitor_len = 0;
|
|
|
- }
|
|
|
-
|
|
|
- len += monitor_len;
|
|
|
- data->len = cpu_to_le32(monitor_len + sizeof(*fw_mon_data));
|
|
|
- }
|
|
|
+ len += iwl_trans_pcie_dump_monitor(trans, &data, monitor_len);
|
|
|
|
|
|
dump_data->len = len;
|
|
|
|