iwlwifi: yoyo: add the ability to dump phy periphery
authorMordechay Goodstein <mordechay.goodstein@intel.com>
Wed, 9 Dec 2020 21:16:06 +0000 (23:16 +0200)
committerLuca Coelho <luciano.coelho@intel.com>
Wed, 9 Dec 2020 22:11:16 +0000 (00:11 +0200)
This enables analyzing phy/HW bugs.

Signed-off-by: Mordechay Goodstein <mordechay.goodstein@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Link: https://lore.kernel.org/r/iwlwifi.20201209231351.53bce4f8353d.Ia6944582bd2c748387aaef96755d8919c5d25dc1@changeid
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
drivers/net/wireless/intel/iwlwifi/fw/dbg.c
drivers/net/wireless/intel/iwlwifi/iwl-prph.h

index ab4a8b9..579c192 100644 (file)
@@ -1066,9 +1066,10 @@ struct iwl_dump_ini_region_data {
        struct iwl_fwrt_dump_data *dump_data;
 };
 
-static int iwl_dump_ini_prph_iter(struct iwl_fw_runtime *fwrt,
-                                 struct iwl_dump_ini_region_data *reg_data,
-                                 void *range_ptr, int idx)
+static int
+iwl_dump_ini_prph_mac_iter(struct iwl_fw_runtime *fwrt,
+                          struct iwl_dump_ini_region_data *reg_data,
+                          void *range_ptr, int idx)
 {
        struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
        struct iwl_fw_ini_error_dump_range *range = range_ptr;
@@ -1090,6 +1091,58 @@ static int iwl_dump_ini_prph_iter(struct iwl_fw_runtime *fwrt,
        return sizeof(*range) + le32_to_cpu(range->range_data_size);
 }
 
+static int
+iwl_dump_ini_prph_phy_iter(struct iwl_fw_runtime *fwrt,
+                          struct iwl_dump_ini_region_data *reg_data,
+                          void *range_ptr, int idx)
+{
+       struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data;
+       struct iwl_fw_ini_error_dump_range *range = range_ptr;
+       __le32 *val = range->data;
+       u32 indirect_wr_addr = WMAL_INDRCT_RD_CMD1;
+       u32 indirect_rd_addr = WMAL_MRSPF_1;
+       u32 prph_val;
+       u32 addr = le32_to_cpu(reg->addrs[idx]);
+       u32 dphy_state;
+       u32 dphy_addr;
+       unsigned long flags;
+       int i;
+
+       range->internal_base_addr = cpu_to_le32(addr);
+       range->range_data_size = reg->dev_addr.size;
+
+       if (fwrt->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
+               indirect_wr_addr = WMAL_INDRCT_CMD1;
+
+       indirect_wr_addr += le32_to_cpu(reg->dev_addr.offset);
+       indirect_rd_addr += le32_to_cpu(reg->dev_addr.offset);
+
+       if (!iwl_trans_grab_nic_access(fwrt->trans, &flags))
+               return -EBUSY;
+
+       dphy_addr = (reg->dev_addr.offset) ? WFPM_LMAC2_PS_CTL_RW :
+                                            WFPM_LMAC1_PS_CTL_RW;
+       dphy_state = iwl_read_umac_prph_no_grab(fwrt->trans, dphy_addr);
+
+       for (i = 0; i < le32_to_cpu(reg->dev_addr.size); i += 4) {
+               if (dphy_state == HBUS_TIMEOUT ||
+                   (dphy_state & WFPM_PS_CTL_RW_PHYRF_PD_FSM_CURSTATE_MSK) !=
+                   WFPM_PHYRF_STATE_ON) {
+                       *val++ = cpu_to_le32(WFPM_DPHY_OFF);
+                       continue;
+               }
+
+               iwl_write_prph_no_grab(fwrt->trans, indirect_wr_addr,
+                                      WMAL_INDRCT_CMD(addr + i));
+               prph_val = iwl_read_prph_no_grab(fwrt->trans,
+                                                indirect_rd_addr);
+               *val++ = cpu_to_le32(prph_val);
+       }
+
+       iwl_trans_release_nic_access(fwrt->trans, &flags);
+       return sizeof(*range) + le32_to_cpu(range->range_data_size);
+}
+
 static int iwl_dump_ini_csr_iter(struct iwl_fw_runtime *fwrt,
                                 struct iwl_dump_ini_region_data *reg_data,
                                 void *range_ptr, int idx)
@@ -2152,9 +2205,14 @@ static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = {
                .get_num_of_ranges = iwl_dump_ini_mem_ranges,
                .get_size = iwl_dump_ini_mem_get_size,
                .fill_mem_hdr = iwl_dump_ini_mem_fill_header,
-               .fill_range = iwl_dump_ini_prph_iter,
+               .fill_range = iwl_dump_ini_prph_mac_iter,
+       },
+       [IWL_FW_INI_REGION_PERIPHERY_PHY] = {
+               .get_num_of_ranges = iwl_dump_ini_mem_ranges,
+               .get_size = iwl_dump_ini_mem_get_size,
+               .fill_mem_hdr = iwl_dump_ini_mem_fill_header,
+               .fill_range = iwl_dump_ini_prph_phy_iter,
        },
-       [IWL_FW_INI_REGION_PERIPHERY_PHY] = {},
        [IWL_FW_INI_REGION_PERIPHERY_AUX] = {},
        [IWL_FW_INI_REGION_PAGING] = {
                .fill_mem_hdr = iwl_dump_ini_mem_fill_header,
@@ -2188,6 +2246,7 @@ static u32 iwl_dump_ini_trigger(struct iwl_fw_runtime *fwrt,
                                struct list_head *list)
 {
        struct iwl_fw_ini_trigger_tlv *trigger = dump_data->trig;
+       enum iwl_fw_ini_time_point tp_id = le32_to_cpu(trigger->time_point);
        struct iwl_dump_ini_region_data reg_data = {
                .dump_data = dump_data,
        };
@@ -2218,6 +2277,14 @@ static u32 iwl_dump_ini_trigger(struct iwl_fw_runtime *fwrt,
                if (reg_type >= ARRAY_SIZE(iwl_dump_ini_region_ops))
                        continue;
 
+               if (reg_type == IWL_FW_INI_REGION_PERIPHERY_PHY &&
+                   tp_id != IWL_FW_INI_TIME_POINT_FW_ASSERT) {
+                       IWL_WARN(fwrt,
+                                "WRT: trying to collect phy prph at time point: %d, skipping\n",
+                                tp_id);
+                       continue;
+               }
+
                size += iwl_dump_ini_mem(fwrt, list, &reg_data,
                                         &iwl_dump_ini_region_ops[reg_type]);
        }
index fa3f157..4417fef 100644 (file)
@@ -473,4 +473,22 @@ enum {
 
 #define IWL_D3_SLEEP_STATUS_SUSPEND    0xD3
 #define IWL_D3_SLEEP_STATUS_RESUME     0xD0
+
+#define WMAL_INDRCT_RD_CMD1_OPMOD_POS 28
+#define WMAL_INDRCT_RD_CMD1_BYTE_ADDRESS_MSK 0xFFFFF
+#define WMAL_CMD_READ_BURST_ACCESS 2
+#define WMAL_MRSPF_1 0xADFC20
+#define WMAL_INDRCT_RD_CMD1 0xADFD44
+#define WMAL_INDRCT_CMD1 0xADFC14
+#define WMAL_INDRCT_CMD(addr) \
+       ((WMAL_CMD_READ_BURST_ACCESS << WMAL_INDRCT_RD_CMD1_OPMOD_POS) | \
+        ((addr) & WMAL_INDRCT_RD_CMD1_BYTE_ADDRESS_MSK))
+
+#define WFPM_LMAC1_PS_CTL_RW 0xA03380
+#define WFPM_LMAC2_PS_CTL_RW 0xA033C0
+#define WFPM_PS_CTL_RW_PHYRF_PD_FSM_CURSTATE_MSK 0x0000000F
+#define WFPM_PHYRF_STATE_ON 5
+#define HBUS_TIMEOUT 0xA5A5A5A1
+#define WFPM_DPHY_OFF 0xDF10FF
+
 #endif                         /* __iwl_prph_h__ */