iwlwifi: pcie: config regs according to fw tlv
authorLiad Kaufman <liad.kaufman@intel.com>
Mon, 17 Nov 2014 09:41:07 +0000 (11:41 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Tue, 2 Dec 2014 14:51:55 +0000 (16:51 +0200)
Sometimes there is a need to configure some registers for
setting some FW properties, such as the FW monitor mode
(internal/external). This patch supports setting this for
PCIe mode.

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/iwl-trans.h
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/pcie/trans.c

index 0289803fa3817e2db9df88973a5a5799bd9072ee..028408a6ecba44cdcfa9aca8fd160156e9f8ddb0 100644 (file)
@@ -574,6 +574,9 @@ enum iwl_trans_state {
  * @rx_mpdu_cmd_hdr_size: used for tracing, amount of data before the
  *     start of the 802.11 header in the @rx_mpdu_cmd
  * @dflt_pwr_limit: default power limit fetched from the platform (ACPI)
+ * @dbg_dest_tlv: points to the destination TLV for debug
+ * @dbg_conf_tlv: array of pointers to configuration TLVs for debug
+ * @dbg_dest_reg_num: num of reg_ops in %dbg_dest_tlv
  */
 struct iwl_trans {
        const struct iwl_trans_ops *ops;
@@ -605,6 +608,10 @@ struct iwl_trans {
 
        u64 dflt_pwr_limit;
 
+       const struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv;
+       const struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_MAX];
+       u8 dbg_dest_reg_num;
+
        /* pointer to trans specific struct */
        /*Ensure that this pointer will always be aligned to sizeof pointer */
        char trans_specific[0] __aligned(sizeof(void *));
index daad985332692c382f52f71ffe238afd6ff9fb5b..97dfba50c6820b3432244551c2d235b3b2941fa7 100644 (file)
@@ -496,6 +496,10 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
 
        trans->rx_mpdu_cmd = REPLY_RX_MPDU_CMD;
        trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_res_start);
+       trans->dbg_dest_tlv = mvm->fw->dbg_dest_tlv;
+       trans->dbg_dest_reg_num = mvm->fw->dbg_dest_reg_num;
+       memcpy(trans->dbg_conf_tlv, mvm->fw->dbg_conf_tlv,
+              sizeof(trans->dbg_conf_tlv));
 
        /* set up notification wait support */
        iwl_notification_wait_init(&mvm->notif_wait);
index ced3354230619d651d1001e5e1650861a2145132..71d466c35671f88ff4dda8d583a12ad5abf548a7 100644 (file)
@@ -756,6 +756,64 @@ static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans,
        return 0;
 }
 
+static void iwl_pcie_apply_destination(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       const struct iwl_fw_dbg_dest_tlv *dest = trans->dbg_dest_tlv;
+       int i;
+
+       if (dest->version)
+               IWL_ERR(trans,
+                       "DBG DEST version is %d - expect issues\n",
+                       dest->version);
+
+       IWL_INFO(trans, "Applying debug destination %s\n",
+                get_fw_dbg_mode_string(dest->monitor_mode));
+
+       if (dest->monitor_mode == EXTERNAL_MODE)
+               iwl_pcie_alloc_fw_monitor(trans);
+       else
+               IWL_WARN(trans, "PCI should have external buffer debug\n");
+
+       for (i = 0; i < trans->dbg_dest_reg_num; i++) {
+               u32 addr = le32_to_cpu(dest->reg_ops[i].addr);
+               u32 val = le32_to_cpu(dest->reg_ops[i].val);
+
+               switch (dest->reg_ops[i].op) {
+               case CSR_ASSIGN:
+                       iwl_write32(trans, addr, val);
+                       break;
+               case CSR_SETBIT:
+                       iwl_set_bit(trans, addr, BIT(val));
+                       break;
+               case CSR_CLEARBIT:
+                       iwl_clear_bit(trans, addr, BIT(val));
+                       break;
+               case PRPH_ASSIGN:
+                       iwl_write_prph(trans, addr, val);
+                       break;
+               case PRPH_SETBIT:
+                       iwl_set_bits_prph(trans, addr, BIT(val));
+                       break;
+               case PRPH_CLEARBIT:
+                       iwl_clear_bits_prph(trans, addr, BIT(val));
+                       break;
+               default:
+                       IWL_ERR(trans, "FW debug - unknown OP %d\n",
+                               dest->reg_ops[i].op);
+                       break;
+               }
+       }
+
+       if (dest->monitor_mode == EXTERNAL_MODE && trans_pcie->fw_mon_size) {
+               iwl_write_prph(trans, le32_to_cpu(dest->base_reg),
+                              trans_pcie->fw_mon_phys >> dest->base_shift);
+               iwl_write_prph(trans, le32_to_cpu(dest->end_reg),
+                              (trans_pcie->fw_mon_phys +
+                               trans_pcie->fw_mon_size) >> dest->end_shift);
+       }
+}
+
 static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
                                const struct fw_img *image)
 {
@@ -796,6 +854,8 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
                                       (trans_pcie->fw_mon_phys +
                                        trans_pcie->fw_mon_size) >> 4);
                }
+       } else if (trans->dbg_dest_tlv) {
+               iwl_pcie_apply_destination(trans);
        }
 
        /* release CPU reset */