diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/fw.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/fw.c | 160 |
1 files changed, 143 insertions, 17 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index ca38e9817374..bc5eac4960e1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -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,97 @@ 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); + } + + 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 *fmt, ...) +{ + unsigned int delay = msecs_to_jiffies(le32_to_cpu(trigger->stop_delay)); + u16 occurrences = le16_to_cpu(trigger->occurrences); + int ret, len = 0; + char buf[64]; + + if (!occurrences) + return 0; + + if (fmt) { + va_list ap; + + buf[sizeof(buf) - 1] = '\0'; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + /* check for truncation */ + if (WARN_ON_ONCE(buf[sizeof(buf) - 1])) + buf[sizeof(buf) - 1] = '\0'; + + len = strlen(buf) + 1; } - schedule_work(&mvm->fw_error_dump_wk); + ret = iwl_mvm_fw_dbg_collect(mvm, le32_to_cpu(trigger->id), buf, + len, delay); + if (ret) + return ret; + + trigger->occurrences = cpu_to_le16(occurrences - 1); + return 0; } -int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, enum iwl_fw_dbg_conf conf_id) +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, u8 conf_id) { u8 *ptr; int ret; @@ -474,6 +579,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 +696,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 +756,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) |