Merge tag 'iwlwifi-next-for-kalle-2014-12-30' of https://git.kernel.org/pub/scm/linux...
[cascardo/linux.git] / drivers / net / wireless / iwlwifi / mvm / fw.c
index eb03943..534ee31 100644 (file)
@@ -70,6 +70,7 @@
 #include "iwl-debug.h"
 #include "iwl-csr.h" /* for iwl_mvm_rx_card_state_notif */
 #include "iwl-io.h" /* for iwl_mvm_rx_card_state_notif */
+#include "iwl-prph.h"
 #include "iwl-eeprom-parse.h"
 
 #include "mvm.h"
@@ -186,7 +187,12 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
        static const u8 alive_cmd[] = { MVM_ALIVE };
        struct iwl_sf_region st_fwrd_space;
 
-       fw = iwl_get_ucode_image(mvm, ucode_type);
+       if (ucode_type == IWL_UCODE_REGULAR &&
+           iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_CUSTOM) &&
+           iwl_fw_dbg_conf_enabled(mvm->fw, FW_DBG_CUSTOM))
+               fw = iwl_get_ucode_image(mvm, IWL_UCODE_REGULAR_USNIFFER);
+       else
+               fw = iwl_get_ucode_image(mvm, ucode_type);
        if (WARN_ON(!fw))
                return -EINVAL;
        mvm->cur_ucode = ucode_type;
@@ -227,6 +233,10 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
        st_fwrd_space.addr = mvm->sf_space.addr;
        st_fwrd_space.size = mvm->sf_space.size;
        ret = iwl_trans_update_sf(mvm->trans, &st_fwrd_space);
+       if (ret) {
+               IWL_ERR(mvm, "Failed to update SF size. ret %d\n", ret);
+               return ret;
+       }
 
        iwl_trans_fw_alive(mvm->trans, alive_data.scd_base_addr);
 
@@ -260,7 +270,7 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)
        enum iwl_ucode_type ucode_type = mvm->cur_ucode;
 
        /* Set parameters */
-       phy_cfg_cmd.phy_cfg = cpu_to_le32(mvm->fw->phy_config);
+       phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_get_phy_config(mvm));
        phy_cfg_cmd.calib_control.event_trigger =
                mvm->fw->default_calib[ucode_type].event_trigger;
        phy_cfg_cmd.calib_control.flow_trigger =
@@ -337,7 +347,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
        mvm->calibrating = true;
 
        /* Send TX valid antennas before triggering calibrations */
-       ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant);
+       ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm));
        if (ret)
                goto error;
 
@@ -390,6 +400,60 @@ out:
        return ret;
 }
 
+void iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm)
+{
+       lockdep_assert_held(&mvm->mutex);
+
+       /* stop recording */
+       if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+               iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100);
+       } else {
+               iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 0);
+               iwl_write_prph(mvm->trans, DBGC_OUT_CTRL, 0);
+       }
+
+       iwl_mvm_fw_error_dump(mvm);
+
+       /* start recording again */
+       WARN_ON_ONCE(mvm->fw->dbg_dest_tlv &&
+                    iwl_mvm_start_fw_dbg_conf(mvm, mvm->fw_dbg_conf));
+}
+
+int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, enum iwl_fw_dbg_conf conf_id)
+{
+       u8 *ptr;
+       int ret;
+       int i;
+
+       if (WARN_ONCE(conf_id >= ARRAY_SIZE(mvm->fw->dbg_conf_tlv),
+                     "Invalid configuration %d\n", conf_id))
+               return -EINVAL;
+
+       if (!mvm->fw->dbg_conf_tlv[conf_id])
+               return -EINVAL;
+
+       if (mvm->fw_dbg_conf != FW_DBG_INVALID)
+               IWL_WARN(mvm, "FW already configured (%d) - re-configuring\n",
+                        mvm->fw_dbg_conf);
+
+       /* Send all HCMDs for configuring the FW debug */
+       ptr = (void *)&mvm->fw->dbg_conf_tlv[conf_id]->hcmd;
+       for (i = 0; i < mvm->fw->dbg_conf_tlv[conf_id]->num_of_hcmds; i++) {
+               struct iwl_fw_dbg_conf_hcmd *cmd = (void *)ptr;
+
+               ret = iwl_mvm_send_cmd_pdu(mvm, cmd->id, 0,
+                                          le16_to_cpu(cmd->len), cmd->data);
+               if (ret)
+                       return ret;
+
+               ptr += sizeof(*cmd);
+               ptr += le16_to_cpu(cmd->len);
+       }
+
+       mvm->fw_dbg_conf = conf_id;
+       return ret;
+}
+
 int iwl_mvm_up(struct iwl_mvm *mvm)
 {
        int ret, i;
@@ -441,7 +505,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
        if (ret)
                IWL_ERR(mvm, "Failed to initialize Smart Fifo\n");
 
-       ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant);
+       mvm->fw_dbg_conf = FW_DBG_INVALID;
+       iwl_mvm_start_fw_dbg_conf(mvm, FW_DBG_CUSTOM);
+
+       ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm));
        if (ret)
                goto error;
 
@@ -462,6 +529,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
        for (i = 0; i < IWL_MVM_STATION_COUNT; i++)
                RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL);
 
+       mvm->tdls_cs.peer.sta_id = IWL_MVM_STATION_COUNT;
+
        /* reset quota debouncing buffer - 0xff will yield invalid data */
        memset(&mvm->last_quota_cmd, 0xff, sizeof(mvm->last_quota_cmd));
 
@@ -501,6 +570,12 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
        if (ret)
                goto error;
 
+       if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) {
+               ret = iwl_mvm_config_scan(mvm);
+               if (ret)
+                       goto error;
+       }
+
        /* allow FW/transport low power modes if not during restart */
        if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
                iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN);
@@ -528,7 +603,7 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm)
                goto error;
        }
 
-       ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant);
+       ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm));
        if (ret)
                goto error;
 
@@ -587,3 +662,19 @@ int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
                       le32_to_cpu(radio_version->radio_dash));
        return 0;
 }
+
+int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm,
+                           struct iwl_rx_cmd_buffer *rxb,
+                           struct iwl_device_cmd *cmd)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_mfuart_load_notif *mfuart_notif = (void *)pkt->data;
+
+       IWL_DEBUG_INFO(mvm,
+                      "MFUART: installed ver: 0x%08x, external ver: 0x%08x, status: 0x%08x, duration: 0x%08x\n",
+                      le32_to_cpu(mfuart_notif->installed_ver),
+                      le32_to_cpu(mfuart_notif->external_ver),
+                      le32_to_cpu(mfuart_notif->status),
+                      le32_to_cpu(mfuart_notif->duration));
+       return 0;
+}