Merge branch 'iwlwifi-fixes' into iwlwifi-next
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / iwlwifi / mvm / fw.c
index ca38e9817374cc6f4a462048c2d59a5244e33b1c..6cf7d9837ca54e938500302cd013a8a4a396be5d 100644 (file)
@@ -112,25 +112,27 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
        struct iwl_mvm *mvm =
                container_of(notif_wait, struct iwl_mvm, notif_wait);
        struct iwl_mvm_alive_data *alive_data = data;
-       struct mvm_alive_resp *palive;
+       struct mvm_alive_resp_ver1 *palive1;
        struct mvm_alive_resp_ver2 *palive2;
+       struct mvm_alive_resp *palive;
 
-       if (iwl_rx_packet_payload_len(pkt) == sizeof(*palive)) {
-               palive = (void *)pkt->data;
+       if (iwl_rx_packet_payload_len(pkt) == sizeof(*palive1)) {
+               palive1 = (void *)pkt->data;
 
                mvm->support_umac_log = false;
                mvm->error_event_table =
-                       le32_to_cpu(palive->error_event_table_ptr);
-               mvm->log_event_table = le32_to_cpu(palive->log_event_table_ptr);
-               alive_data->scd_base_addr = le32_to_cpu(palive->scd_base_ptr);
+                       le32_to_cpu(palive1->error_event_table_ptr);
+               mvm->log_event_table =
+                       le32_to_cpu(palive1->log_event_table_ptr);
+               alive_data->scd_base_addr = le32_to_cpu(palive1->scd_base_ptr);
 
-               alive_data->valid = le16_to_cpu(palive->status) ==
+               alive_data->valid = le16_to_cpu(palive1->status) ==
                                    IWL_ALIVE_STATUS_OK;
                IWL_DEBUG_FW(mvm,
                             "Alive VER1 ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n",
-                            le16_to_cpu(palive->status), palive->ver_type,
-                            palive->ver_subtype, palive->flags);
-       } else {
+                            le16_to_cpu(palive1->status), palive1->ver_type,
+                            palive1->ver_subtype, palive1->flags);
+       } else if (iwl_rx_packet_payload_len(pkt) == sizeof(*palive2)) {
                palive2 = (void *)pkt->data;
 
                mvm->error_event_table =
@@ -156,6 +158,33 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
                IWL_DEBUG_FW(mvm,
                             "UMAC version: Major - 0x%x, Minor - 0x%x\n",
                             palive2->umac_major, palive2->umac_minor);
+       } else if (iwl_rx_packet_payload_len(pkt) == sizeof(*palive)) {
+               palive = (void *)pkt->data;
+
+               mvm->error_event_table =
+                       le32_to_cpu(palive->error_event_table_ptr);
+               mvm->log_event_table =
+                       le32_to_cpu(palive->log_event_table_ptr);
+               alive_data->scd_base_addr = le32_to_cpu(palive->scd_base_ptr);
+               mvm->umac_error_event_table =
+                       le32_to_cpu(palive->error_info_addr);
+               mvm->sf_space.addr = le32_to_cpu(palive->st_fwrd_addr);
+               mvm->sf_space.size = le32_to_cpu(palive->st_fwrd_size);
+
+               alive_data->valid = le16_to_cpu(palive->status) ==
+                                   IWL_ALIVE_STATUS_OK;
+               if (mvm->umac_error_event_table)
+                       mvm->support_umac_log = true;
+
+               IWL_DEBUG_FW(mvm,
+                            "Alive VER3 ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n",
+                            le16_to_cpu(palive->status), palive->ver_type,
+                            palive->ver_subtype, palive->flags);
+
+               IWL_DEBUG_FW(mvm,
+                            "UMAC version: Major - 0x%x, Minor - 0x%x\n",
+                            le32_to_cpu(palive->umac_major),
+                            le32_to_cpu(palive->umac_minor));
        }
 
        return true;
@@ -188,8 +217,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
        struct iwl_sf_region st_fwrd_space;
 
        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))
+           iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_START_FROM_ALIVE))
                fw = iwl_get_ucode_image(mvm, IWL_UCODE_REGULAR_USNIFFER);
        else
                fw = iwl_get_ucode_image(mvm, ucode_type);
@@ -451,20 +479,80 @@ exit:
        iwl_free_resp(&cmd);
 }
 
-void iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm)
+int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm,
+                               struct iwl_mvm_dump_desc *desc,
+                               unsigned int delay)
 {
+       if (test_and_set_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status))
+               return -EBUSY;
+
+       if (WARN_ON(mvm->fw_dump_desc))
+               iwl_mvm_free_fw_dump_desc(mvm);
+
+       IWL_WARN(mvm, "Collecting data: trigger %d fired.\n",
+                le32_to_cpu(desc->trig_desc.type));
+
+       mvm->fw_dump_desc = desc;
+
        /* 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);
+               /* wait before we collect the data till the DBGC stop */
+               udelay(100);
        }
 
-       schedule_work(&mvm->fw_error_dump_wk);
+       queue_delayed_work(system_wq, &mvm->fw_dump_wk, delay);
+
+       return 0;
+}
+
+int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig,
+                          const char *str, size_t len, unsigned int delay)
+{
+       struct iwl_mvm_dump_desc *desc;
+
+       desc = kzalloc(sizeof(*desc) + len, GFP_ATOMIC);
+       if (!desc)
+               return -ENOMEM;
+
+       desc->len = len;
+       desc->trig_desc.type = cpu_to_le32(trig);
+       memcpy(desc->trig_desc.data, str, len);
+
+       return iwl_mvm_fw_dbg_collect_desc(mvm, desc, delay);
+}
+
+int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm,
+                               struct iwl_fw_dbg_trigger_tlv *trigger,
+                               const char *str, size_t len)
+{
+       unsigned int delay = msecs_to_jiffies(le32_to_cpu(trigger->stop_delay));
+       u16 occurrences = le16_to_cpu(trigger->occurrences);
+       int ret;
+
+       if (!occurrences)
+               return 0;
+
+       ret = iwl_mvm_fw_dbg_collect(mvm, le32_to_cpu(trigger->id), str,
+                                    len, delay);
+       if (ret)
+               return ret;
+
+       trigger->occurrences = cpu_to_le16(occurrences - 1);
+       return 0;
+}
+
+static inline void iwl_mvm_restart_early_start(struct iwl_mvm *mvm)
+{
+       if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000)
+               iwl_clear_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100);
+       else
+               iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 1);
 }
 
-int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, enum iwl_fw_dbg_conf conf_id)
+int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, u8 conf_id)
 {
        u8 *ptr;
        int ret;
@@ -474,6 +562,14 @@ int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, enum iwl_fw_dbg_conf conf_id)
                      "Invalid configuration %d\n", conf_id))
                return -EINVAL;
 
+       /* EARLY START - firmware's configuration is hard coded */
+       if ((!mvm->fw->dbg_conf_tlv[conf_id] ||
+            !mvm->fw->dbg_conf_tlv[conf_id]->num_of_hcmds) &&
+           conf_id == FW_DBG_START_FROM_ALIVE) {
+               iwl_mvm_restart_early_start(mvm);
+               return 0;
+       }
+
        if (!mvm->fw->dbg_conf_tlv[conf_id])
                return -EINVAL;
 
@@ -583,7 +679,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
                IWL_ERR(mvm, "Failed to initialize Smart Fifo\n");
 
        mvm->fw_dbg_conf = FW_DBG_INVALID;
-       iwl_mvm_start_fw_dbg_conf(mvm, FW_DBG_CUSTOM);
+       /* if we have a destination, assume EARLY START */
+       if (mvm->fw->dbg_dest_tlv)
+               mvm->fw_dbg_conf = FW_DBG_START_FROM_ALIVE;
+       iwl_mvm_start_fw_dbg_conf(mvm, FW_DBG_START_FROM_ALIVE);
 
        ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm));
        if (ret)
@@ -640,6 +739,16 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
        if (ret)
                goto error;
 
+       /*
+        * RTNL is not taken during Ct-kill, but we don't need to scan/Tx
+        * anyway, so don't init MCC.
+        */
+       if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) {
+               ret = iwl_mvm_init_mcc(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)