#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"
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 =
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;
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);
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 =
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;
return ret;
}
-static int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm,
- enum iwl_fw_dbg_conf conf_id)
+static void iwl_mvm_get_shared_mem_conf(struct iwl_mvm *mvm)
+{
+ struct iwl_host_cmd cmd = {
+ .id = SHARED_MEM_CFG,
+ .flags = CMD_WANT_SKB,
+ .data = { NULL, },
+ .len = { 0, },
+ };
+ struct iwl_rx_packet *pkt;
+ struct iwl_shared_mem_cfg *mem_cfg;
+ u32 i;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (WARN_ON(iwl_mvm_send_cmd(mvm, &cmd)))
+ return;
+
+ pkt = cmd.resp_pkt;
+ if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERR(mvm, "Bad return from SHARED_MEM_CFG (0x%08X)\n",
+ pkt->hdr.flags);
+ goto exit;
+ }
+
+ mem_cfg = (void *)pkt->data;
+
+ mvm->shared_mem_cfg.shared_mem_addr =
+ le32_to_cpu(mem_cfg->shared_mem_addr);
+ mvm->shared_mem_cfg.shared_mem_size =
+ le32_to_cpu(mem_cfg->shared_mem_size);
+ mvm->shared_mem_cfg.sample_buff_addr =
+ le32_to_cpu(mem_cfg->sample_buff_addr);
+ mvm->shared_mem_cfg.sample_buff_size =
+ le32_to_cpu(mem_cfg->sample_buff_size);
+ mvm->shared_mem_cfg.txfifo_addr = le32_to_cpu(mem_cfg->txfifo_addr);
+ for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.txfifo_size); i++)
+ mvm->shared_mem_cfg.txfifo_size[i] =
+ le32_to_cpu(mem_cfg->txfifo_size[i]);
+ for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.rxfifo_size); i++)
+ mvm->shared_mem_cfg.rxfifo_size[i] =
+ le32_to_cpu(mem_cfg->rxfifo_size[i]);
+ mvm->shared_mem_cfg.page_buff_addr =
+ le32_to_cpu(mem_cfg->page_buff_addr);
+ mvm->shared_mem_cfg.page_buff_size =
+ le32_to_cpu(mem_cfg->page_buff_size);
+ IWL_DEBUG_INFO(mvm, "SHARED MEM CFG: got memory offsets/sizes\n");
+
+exit:
+ iwl_free_resp(&cmd);
+}
+
+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);
+ /* 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 *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, u8 conf_id)
{
u8 *ptr;
int ret;
"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;
return ret;
}
+static int iwl_mvm_config_ltr_v1(struct iwl_mvm *mvm)
+{
+ struct iwl_ltr_config_cmd_v1 cmd_v1 = {
+ .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE),
+ };
+
+ if (!mvm->trans->ltr_enabled)
+ return 0;
+
+ return iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0,
+ sizeof(cmd_v1), &cmd_v1);
+}
+
+static int iwl_mvm_config_ltr(struct iwl_mvm *mvm)
+{
+ struct iwl_ltr_config_cmd cmd = {
+ .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE),
+ };
+
+ if (!mvm->trans->ltr_enabled)
+ return 0;
+
+ if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_HDC_PHASE_0))
+ return iwl_mvm_config_ltr_v1(mvm);
+
+ return iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0,
+ sizeof(cmd), &cmd);
+}
+
int iwl_mvm_up(struct iwl_mvm *mvm)
{
int ret, i;
goto error;
}
+ if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 10)
+ iwl_mvm_get_shared_mem_conf(mvm);
+
ret = iwl_mvm_sf_update(mvm, NULL, false);
if (ret)
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, mvm->fw->valid_tx_ant);
+ ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm));
if (ret)
goto error;
/* Initialize tx backoffs to the minimal possible */
iwl_mvm_tt_tx_backoff(mvm, 0);
- if (mvm->trans->ltr_enabled) {
- struct iwl_ltr_config_cmd cmd = {
- .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE),
- };
-
- WARN_ON(iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0,
- sizeof(cmd), &cmd));
- }
+ WARN_ON(iwl_mvm_config_ltr(mvm));
ret = iwl_mvm_power_update_device(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)
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;