iwlwifi: pcie: support more monitor types dumping
authorLiad Kaufman <liad.kaufman@intel.com>
Mon, 17 Nov 2014 09:44:03 +0000 (11:44 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Tue, 2 Dec 2014 14:51:56 +0000 (16:51 +0200)
Until this patch, dumping the monitor data could be done only
for PCIe external (DRAM) mode in 7000 HW family. This patch
allows to pull the monitor data also on other families, and
also to pull the monitor data if an internal buffer is used.

Signed-off-by: Liad Kaufman <liad.kaufman@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
drivers/net/wireless/iwlwifi/pcie/trans.c

index 71d466c35671f88ff4dda8d583a12ad5abf548a7..5d79a1f44b8e43a723b9de98ca780a9ea5bc5812 100644 (file)
@@ -2065,6 +2065,7 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
        struct iwl_fw_error_dump_txcmd *txcmd;
        struct iwl_trans_dump_data *dump_data;
        u32 len;
+       u32 monitor_len;
        int i, ptr;
 
        /* transport dump header */
@@ -2091,9 +2092,30 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
        len += sizeof(*data) + (FH_MEM_UPPER_BOUND - FH_MEM_LOWER_BOUND);
 
        /* 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) +
-                       trans_pcie->fw_mon_size;
+                      trans_pcie->fw_mon_size;
+               monitor_len = trans_pcie->fw_mon_size;
+       } else if (trans->dbg_dest_tlv) {
+               u32 base, end;
+
+               base = le32_to_cpu(trans->dbg_dest_tlv->base_reg);
+               end = le32_to_cpu(trans->dbg_dest_tlv->end_reg);
+
+               base = iwl_read_prph(trans, base) <<
+                      trans->dbg_dest_tlv->base_shift;
+               end = iwl_read_prph(trans, end) <<
+                     trans->dbg_dest_tlv->end_shift;
+
+               /* Make "end" point to the actual end */
+               if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
+                       end += (1 << trans->dbg_dest_tlv->end_shift);
+               monitor_len = end - base;
+               len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) +
+                      monitor_len;
+       } else {
+               monitor_len = 0;
+       }
 
        dump_data = vzalloc(len);
        if (!dump_data)
@@ -2133,34 +2155,68 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
        len += iwl_trans_pcie_fh_regs_dump(trans, &data);
        /* 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->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);
-               data->len = cpu_to_le32(trans_pcie->fw_mon_size +
-                                       sizeof(*fw_mon_data));
                fw_mon_data = (void *)data->data;
                fw_mon_data->fw_mon_wr_ptr =
-                       cpu_to_le32(iwl_read_prph(trans, MON_BUFF_WRPTR));
+                       cpu_to_le32(iwl_read_prph(trans, write_ptr));
                fw_mon_data->fw_mon_cycle_cnt =
-                       cpu_to_le32(iwl_read_prph(trans, MON_BUFF_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, MON_BUFF_BASE_ADDR));
-
-               /*
-                * 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);
-
-               len += sizeof(*data) + sizeof(*fw_mon_data) +
-                       trans_pcie->fw_mon_size;
+                       cpu_to_le32(iwl_read_prph(trans, base));
+
+               len += sizeof(*data) + sizeof(*fw_mon_data);
+               if (trans_pcie->fw_mon_page) {
+                       data->len = cpu_to_le32(trans_pcie->fw_mon_size +
+                                               sizeof(*fw_mon_data));
+
+                       /*
+                        * 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);
+
+                       len += trans_pcie->fw_mon_size;
+               } else {
+                       /* If we are here then the buffer is internal */
+
+                       /*
+                        * 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));
+                       data->len = cpu_to_le32(sizeof(*fw_mon_data) +
+                                               monitor_len);
+                       len += monitor_len;
+               }
        }
 
        dump_data->len = len;