static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); u8 radio_cfg_type, radio_cfg_step, radio_cfg_dash; u32 reg_val = 0; radio_cfg_type = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_TYPE) >> FW_PHY_CFG_RADIO_TYPE_POS; radio_cfg_step = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_STEP) >> FW_PHY_CFG_RADIO_STEP_POS; radio_cfg_dash = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_DASH) >> FW_PHY_CFG_RADIO_DASH_POS; /* SKU control */ reg_val |= CSR_HW_REV_STEP(mvm->trans->hw_rev) << CSR_HW_IF_CONFIG_REG_POS_MAC_STEP; reg_val |= CSR_HW_REV_DASH(mvm->trans->hw_rev) << CSR_HW_IF_CONFIG_REG_POS_MAC_DASH; /* radio configuration */ reg_val |= radio_cfg_type << CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE; reg_val |= radio_cfg_step << CSR_HW_IF_CONFIG_REG_POS_PHY_STEP; reg_val |= radio_cfg_dash << CSR_HW_IF_CONFIG_REG_POS_PHY_DASH; WARN_ON((radio_cfg_type << CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE) & ~CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE); /* * TODO: Bits 7-8 of CSR in 8000 HW family set the ADC sampling, and * shouldn't be set to any non-zero value. The same is supposed to be * true of the other HW, but unsetting them (such as the 7260) causes * automatic tests to fail on seemingly unrelated errors. Need to * further investigate this, but for now we'll separate cases. */ if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI; iwl_trans_set_bits_mask(mvm->trans, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH | CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP | CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE | CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP | CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH | CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | CSR_HW_IF_CONFIG_REG_BIT_MAC_SI, reg_val); IWL_DEBUG_INFO(mvm, "Radio type=0x%x-0x%x-0x%x\n", radio_cfg_type, radio_cfg_step, radio_cfg_dash); /* * W/A : NIC is stuck in a reset state after Early PCIe power off * (PCIe power is lost before PERST# is asserted), causing ME FW * to lose ownership and not being able to obtain it back. */ if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) iwl_set_bits_mask_prph(mvm->trans, APMG_PS_CTRL_REG, APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); }
static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); u8 radio_cfg_type, radio_cfg_step, radio_cfg_dash; u32 reg_val = 0; radio_cfg_type = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_TYPE) >> FW_PHY_CFG_RADIO_TYPE_POS; radio_cfg_step = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_STEP) >> FW_PHY_CFG_RADIO_STEP_POS; radio_cfg_dash = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_DASH) >> FW_PHY_CFG_RADIO_DASH_POS; /* SKU control */ reg_val |= CSR_HW_REV_STEP(mvm->trans->hw_rev) << CSR_HW_IF_CONFIG_REG_POS_MAC_STEP; reg_val |= CSR_HW_REV_DASH(mvm->trans->hw_rev) << CSR_HW_IF_CONFIG_REG_POS_MAC_DASH; /* radio configuration */ reg_val |= radio_cfg_type << CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE; reg_val |= radio_cfg_step << CSR_HW_IF_CONFIG_REG_POS_PHY_STEP; reg_val |= radio_cfg_dash << CSR_HW_IF_CONFIG_REG_POS_PHY_DASH; WARN_ON((radio_cfg_type << CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE) & ~CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE); /* silicon bits */ reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI; iwl_trans_set_bits_mask(mvm->trans, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH | CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP | CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE | CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP | CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH | CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | CSR_HW_IF_CONFIG_REG_BIT_MAC_SI, reg_val); IWL_DEBUG_INFO(mvm, "Radio type=0x%x-0x%x-0x%x\n", radio_cfg_type, radio_cfg_step, radio_cfg_dash); /* * W/A : NIC is stuck in a reset state after Early PCIe power off * (PCIe power is lost before PERST# is asserted), causing ME FW * to lose ownership and not being able to obtain it back. */ if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) iwl_set_bits_mask_prph(mvm->trans, APMG_PS_CTRL_REG, APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); }
static int iwl_tm_gnl_get_sil_step(struct iwl_trans *trans, struct iwl_tm_data *data_out) { struct iwl_sil_step *resp; data_out->data = kmalloc(sizeof(struct iwl_sil_step), GFP_KERNEL); if (!data_out->data) return -ENOMEM; data_out->len = sizeof(struct iwl_sil_step); resp = (struct iwl_sil_step *)data_out->data; resp->silicon_step = CSR_HW_REV_STEP(trans->hw_rev); return 0; }
static struct iwl_op_mode * iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, const struct iwl_fw *fw, struct dentry *dbgfs_dir) { struct ieee80211_hw *hw; struct iwl_op_mode *op_mode; struct iwl_mvm *mvm; struct iwl_trans_config trans_cfg = {}; static const u8 no_reclaim_cmds[] = { TX_CMD, }; int err, scan_size; u32 min_backoff; /* * We use IWL_MVM_STATION_COUNT to check the validity of the station * index all over the driver - check that its value corresponds to the * array size. */ BUILD_BUG_ON(ARRAY_SIZE(mvm->fw_id_to_mac_id) != IWL_MVM_STATION_COUNT); /******************************** * 1. Allocating and configuring HW data ********************************/ hw = ieee80211_alloc_hw(sizeof(struct iwl_op_mode) + sizeof(struct iwl_mvm), &iwl_mvm_hw_ops); if (!hw) return NULL; if (cfg->max_rx_agg_size) hw->max_rx_aggregation_subframes = cfg->max_rx_agg_size; if (cfg->max_tx_agg_size) hw->max_tx_aggregation_subframes = cfg->max_tx_agg_size; op_mode = hw->priv; op_mode->ops = &iwl_mvm_ops; mvm = IWL_OP_MODE_GET_MVM(op_mode); mvm->dev = trans->dev; mvm->trans = trans; mvm->cfg = cfg; mvm->fw = fw; mvm->hw = hw; mvm->restart_fw = iwlwifi_mod_params.restart_fw ? -1 : 0; mvm->aux_queue = 15; mvm->first_agg_queue = 16; mvm->last_agg_queue = mvm->cfg->base_params->num_of_queues - 1; if (mvm->cfg->base_params->num_of_queues == 16) { mvm->aux_queue = 11; mvm->first_agg_queue = 12; } mvm->sf_state = SF_UNINIT; mvm->low_latency_agg_frame_limit = 6; mvm->cur_ucode = IWL_UCODE_INIT; mutex_init(&mvm->mutex); mutex_init(&mvm->d0i3_suspend_mutex); spin_lock_init(&mvm->async_handlers_lock); INIT_LIST_HEAD(&mvm->time_event_list); INIT_LIST_HEAD(&mvm->aux_roc_te_list); INIT_LIST_HEAD(&mvm->async_handlers_list); spin_lock_init(&mvm->time_event_lock); INIT_WORK(&mvm->async_handlers_wk, iwl_mvm_async_handlers_wk); INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk); INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk); INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work); INIT_DELAYED_WORK(&mvm->fw_dump_wk, iwl_mvm_fw_error_dump_wk); INIT_DELAYED_WORK(&mvm->tdls_cs.dwork, iwl_mvm_tdls_ch_switch_work); spin_lock_init(&mvm->d0i3_tx_lock); spin_lock_init(&mvm->refs_lock); skb_queue_head_init(&mvm->d0i3_tx); init_waitqueue_head(&mvm->d0i3_exit_waitq); SET_IEEE80211_DEV(mvm->hw, mvm->trans->dev); /* * Populate the state variables that the transport layer needs * to know about. */ trans_cfg.op_mode = op_mode; trans_cfg.no_reclaim_cmds = no_reclaim_cmds; trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K; if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DW_BC_TABLE) trans_cfg.bc_table_dword = true; trans_cfg.command_names = iwl_mvm_cmd_strings; trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE; trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD; trans_cfg.scd_set_active = true; trans_cfg.sdio_adma_addr = fw->sdio_adma_addr; /* Set a short watchdog for the command queue */ trans_cfg.cmd_q_wdg_timeout = iwl_mvm_get_wd_timeout(mvm, NULL, false, true); snprintf(mvm->hw->wiphy->fw_version, sizeof(mvm->hw->wiphy->fw_version), "%s", fw->fw_version); /* Configure transport layer */ iwl_trans_configure(mvm->trans, &trans_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)); trans->dbg_trigger_tlv = mvm->fw->dbg_trigger_tlv; /* set up notification wait support */ iwl_notification_wait_init(&mvm->notif_wait); /* Init phy db */ mvm->phy_db = iwl_phy_db_init(trans); if (!mvm->phy_db) { IWL_ERR(mvm, "Cannot init phy_db\n"); goto out_free; } IWL_INFO(mvm, "Detected %s, REV=0x%X\n", mvm->cfg->name, mvm->trans->hw_rev); min_backoff = calc_min_backoff(trans, cfg); iwl_mvm_tt_initialize(mvm, min_backoff); /* set the nvm_file_name according to priority */ if (iwlwifi_mod_params.nvm_file) { mvm->nvm_file_name = iwlwifi_mod_params.nvm_file; } else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) { if (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_B_STEP) mvm->nvm_file_name = mvm->cfg->default_nvm_file_B_step; else mvm->nvm_file_name = mvm->cfg->default_nvm_file_C_step; } if (WARN(cfg->no_power_up_nic_in_init && !mvm->nvm_file_name, "not allowing power-up and not having nvm_file\n")) goto out_free; /* * Even if nvm exists in the nvm_file driver should read again the nvm * from the nic because there might be entries that exist in the OTP * and not in the file. * for nics with no_power_up_nic_in_init: rely completley on nvm_file */ if (cfg->no_power_up_nic_in_init && mvm->nvm_file_name) { err = iwl_nvm_init(mvm, false); if (err) goto out_free; } else { err = iwl_trans_start_hw(mvm->trans); if (err) goto out_free; mutex_lock(&mvm->mutex); err = iwl_run_init_mvm_ucode(mvm, true); if (!err || !iwlmvm_mod_params.init_dbg) iwl_trans_stop_device(trans); mutex_unlock(&mvm->mutex); /* returns 0 if successful, 1 if success but in rfkill */ if (err < 0 && !iwlmvm_mod_params.init_dbg) { IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err); goto out_free; } } scan_size = iwl_mvm_scan_size(mvm); mvm->scan_cmd = kmalloc(scan_size, GFP_KERNEL); if (!mvm->scan_cmd) goto out_free; /* Set EBS as successful as long as not stated otherwise by the FW. */ mvm->last_ebs_successful = true; err = iwl_mvm_mac_setup_register(mvm); if (err) goto out_free; err = iwl_mvm_dbgfs_register(mvm, dbgfs_dir); if (err) goto out_unregister; memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx)); /* rpm starts with a taken ref. only set the appropriate bit here. */ mvm->refs[IWL_MVM_REF_UCODE_DOWN] = 1; return op_mode; out_unregister: ieee80211_unregister_hw(mvm->hw); iwl_mvm_leds_exit(mvm); out_free: iwl_phy_db_free(mvm->phy_db); kfree(mvm->scan_cmd); if (!cfg->no_power_up_nic_in_init || !mvm->nvm_file_name) iwl_trans_op_mode_leave(trans); ieee80211_free_hw(mvm->hw); return NULL; }
void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) { struct iwl_fw_error_dump_file *dump_file; struct iwl_fw_error_dump_data *dump_data; struct iwl_fw_error_dump_info *dump_info; struct iwl_fw_error_dump_mem *dump_mem; struct iwl_fw_error_dump_trigger_desc *dump_trig; struct iwl_mvm_dump_ptrs *fw_error_dump; u32 sram_len, sram_ofs; struct iwl_fw_dbg_mem_seg_tlv * const *fw_dbg_mem = mvm->fw->dbg_mem_tlv; u32 file_len, fifo_data_len = 0, prph_len = 0, radio_len = 0; u32 smem_len = mvm->fw->dbg_dynamic_mem ? 0 : mvm->cfg->smem_len; u32 sram2_len = mvm->fw->dbg_dynamic_mem ? 0 : mvm->cfg->dccm2_len; bool monitor_dump_only = false; int i; if (!IWL_MVM_COLLECT_FW_ERR_DUMP && !mvm->trans->dbg_dest_tlv) return; lockdep_assert_held(&mvm->mutex); /* there's no point in fw dump if the bus is dead */ if (test_bit(STATUS_TRANS_DEAD, &mvm->trans->status)) { IWL_ERR(mvm, "Skip fw error dump since bus is dead\n"); goto out; } if (mvm->fw_dump_trig && mvm->fw_dump_trig->mode & IWL_FW_DBG_TRIGGER_MONITOR_ONLY) monitor_dump_only = true; fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL); if (!fw_error_dump) goto out; /* SRAM - include stack CCM if driver knows the values for it */ if (!mvm->cfg->dccm_offset || !mvm->cfg->dccm_len) { const struct fw_img *img; img = &mvm->fw->img[mvm->cur_ucode]; sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; } else { sram_ofs = mvm->cfg->dccm_offset; sram_len = mvm->cfg->dccm_len; } /* reading RXF/TXF sizes */ if (test_bit(STATUS_FW_ERROR, &mvm->trans->status)) { struct iwl_mvm_shared_mem_cfg *mem_cfg = &mvm->shared_mem_cfg; fifo_data_len = 0; /* Count RXF size */ for (i = 0; i < ARRAY_SIZE(mem_cfg->rxfifo_size); i++) { if (!mem_cfg->rxfifo_size[i]) continue; /* Add header info */ fifo_data_len += mem_cfg->rxfifo_size[i] + sizeof(*dump_data) + sizeof(struct iwl_fw_error_dump_fifo); } for (i = 0; i < ARRAY_SIZE(mem_cfg->txfifo_size); i++) { if (!mem_cfg->txfifo_size[i]) continue; /* Add header info */ fifo_data_len += mem_cfg->txfifo_size[i] + sizeof(*dump_data) + sizeof(struct iwl_fw_error_dump_fifo); } if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) { for (i = 0; i < ARRAY_SIZE(mem_cfg->internal_txfifo_size); i++) { if (!mem_cfg->internal_txfifo_size[i]) continue; /* Add header info */ fifo_data_len += mem_cfg->internal_txfifo_size[i] + sizeof(*dump_data) + sizeof(struct iwl_fw_error_dump_fifo); } } /* Make room for PRPH registers */ for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr); i++) { /* The range includes both boundaries */ int num_bytes_in_chunk = iwl_prph_dump_addr[i].end - iwl_prph_dump_addr[i].start + 4; prph_len += sizeof(*dump_data) + sizeof(struct iwl_fw_error_dump_prph) + num_bytes_in_chunk; } if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) radio_len = sizeof(*dump_data) + RADIO_REG_MAX_READ; } file_len = sizeof(*dump_file) + sizeof(*dump_data) * 2 + fifo_data_len + prph_len + radio_len + sizeof(*dump_info); /* Make room for the SMEM, if it exists */ if (smem_len) file_len += sizeof(*dump_data) + sizeof(*dump_mem) + smem_len; /* Make room for the secondary SRAM, if it exists */ if (sram2_len) file_len += sizeof(*dump_data) + sizeof(*dump_mem) + sram2_len; /* Make room for MEM segments */ for (i = 0; i < ARRAY_SIZE(mvm->fw->dbg_mem_tlv); i++) { if (fw_dbg_mem[i]) file_len += sizeof(*dump_data) + sizeof(*dump_mem) + le32_to_cpu(fw_dbg_mem[i]->len); } /* Make room for fw's virtual image pages, if it exists */ if (mvm->fw->img[mvm->cur_ucode].paging_mem_size && mvm->fw_paging_db[0].fw_paging_block) file_len += mvm->num_of_paging_blk * (sizeof(*dump_data) + sizeof(struct iwl_fw_error_dump_paging) + PAGING_BLOCK_SIZE); /* If we only want a monitor dump, reset the file length */ if (monitor_dump_only) { file_len = sizeof(*dump_file) + sizeof(*dump_data) + sizeof(*dump_info); } /* * In 8000 HW family B-step include the ICCM (which resides separately) */ if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000 && CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_B_STEP) file_len += sizeof(*dump_data) + sizeof(*dump_mem) + IWL8260_ICCM_LEN; if (mvm->fw_dump_desc) file_len += sizeof(*dump_data) + sizeof(*dump_trig) + mvm->fw_dump_desc->len; if (!mvm->fw->dbg_dynamic_mem) file_len += sram_len + sizeof(*dump_mem); dump_file = vzalloc(file_len); if (!dump_file) { kfree(fw_error_dump); goto out; } fw_error_dump->op_mode_ptr = dump_file; dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER); dump_data = (void *)dump_file->data; dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO); dump_data->len = cpu_to_le32(sizeof(*dump_info)); dump_info = (void *)dump_data->data; dump_info->device_family = mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000 ? cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_7) : cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_8); dump_info->hw_step = cpu_to_le32(CSR_HW_REV_STEP(mvm->trans->hw_rev)); memcpy(dump_info->fw_human_readable, mvm->fw->human_readable, sizeof(dump_info->fw_human_readable)); strncpy(dump_info->dev_human_readable, mvm->cfg->name, sizeof(dump_info->dev_human_readable)); strncpy(dump_info->bus_human_readable, mvm->dev->bus->name, sizeof(dump_info->bus_human_readable)); dump_data = iwl_fw_error_next_data(dump_data); /* We only dump the FIFOs if the FW is in error state */ if (test_bit(STATUS_FW_ERROR, &mvm->trans->status)) { iwl_mvm_dump_fifos(mvm, &dump_data); if (radio_len) iwl_mvm_read_radio_reg(mvm, &dump_data); } if (mvm->fw_dump_desc) { dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_ERROR_INFO); dump_data->len = cpu_to_le32(sizeof(*dump_trig) + mvm->fw_dump_desc->len); dump_trig = (void *)dump_data->data; memcpy(dump_trig, &mvm->fw_dump_desc->trig_desc, sizeof(*dump_trig) + mvm->fw_dump_desc->len); dump_data = iwl_fw_error_next_data(dump_data); } /* In case we only want monitor dump, skip to dump trasport data */ if (monitor_dump_only) goto dump_trans_data; if (!mvm->fw->dbg_dynamic_mem) { dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); dump_data->len = cpu_to_le32(sram_len + sizeof(*dump_mem)); dump_mem = (void *)dump_data->data; dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM); dump_mem->offset = cpu_to_le32(sram_ofs); iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_mem->data, sram_len); dump_data = iwl_fw_error_next_data(dump_data); } for (i = 0; i < ARRAY_SIZE(mvm->fw->dbg_mem_tlv); i++) { if (fw_dbg_mem[i]) { u32 len = le32_to_cpu(fw_dbg_mem[i]->len); u32 ofs = le32_to_cpu(fw_dbg_mem[i]->ofs); dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); dump_data->len = cpu_to_le32(len + sizeof(*dump_mem)); dump_mem = (void *)dump_data->data; dump_mem->type = fw_dbg_mem[i]->data_type; dump_mem->offset = cpu_to_le32(ofs); iwl_trans_read_mem_bytes(mvm->trans, ofs, dump_mem->data, len); dump_data = iwl_fw_error_next_data(dump_data); } } if (smem_len) { dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); dump_data->len = cpu_to_le32(smem_len + sizeof(*dump_mem)); dump_mem = (void *)dump_data->data; dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SMEM); dump_mem->offset = cpu_to_le32(mvm->cfg->smem_offset); iwl_trans_read_mem_bytes(mvm->trans, mvm->cfg->smem_offset, dump_mem->data, smem_len); dump_data = iwl_fw_error_next_data(dump_data); } if (sram2_len) { dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); dump_data->len = cpu_to_le32(sram2_len + sizeof(*dump_mem)); dump_mem = (void *)dump_data->data; dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM); dump_mem->offset = cpu_to_le32(mvm->cfg->dccm2_offset); iwl_trans_read_mem_bytes(mvm->trans, mvm->cfg->dccm2_offset, dump_mem->data, sram2_len); dump_data = iwl_fw_error_next_data(dump_data); } if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000 && CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_B_STEP) { dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); dump_data->len = cpu_to_le32(IWL8260_ICCM_LEN + sizeof(*dump_mem)); dump_mem = (void *)dump_data->data; dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM); dump_mem->offset = cpu_to_le32(IWL8260_ICCM_OFFSET); iwl_trans_read_mem_bytes(mvm->trans, IWL8260_ICCM_OFFSET, dump_mem->data, IWL8260_ICCM_LEN); dump_data = iwl_fw_error_next_data(dump_data); } /* Dump fw's virtual image */ if (mvm->fw->img[mvm->cur_ucode].paging_mem_size && mvm->fw_paging_db[0].fw_paging_block) { for (i = 1; i < mvm->num_of_paging_blk + 1; i++) { struct iwl_fw_error_dump_paging *paging; struct page *pages = mvm->fw_paging_db[i].fw_paging_block; dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PAGING); dump_data->len = cpu_to_le32(sizeof(*paging) + PAGING_BLOCK_SIZE); paging = (void *)dump_data->data; paging->index = cpu_to_le32(i); memcpy(paging->data, page_address(pages), PAGING_BLOCK_SIZE); dump_data = iwl_fw_error_next_data(dump_data); } } if (prph_len) iwl_dump_prph(mvm->trans, &dump_data); dump_trans_data: fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans, mvm->fw_dump_trig); fw_error_dump->op_mode_len = file_len; if (fw_error_dump->trans_ptr) file_len += fw_error_dump->trans_ptr->len; dump_file->file_len = cpu_to_le32(file_len); dev_coredumpm(mvm->trans->dev, THIS_MODULE, fw_error_dump, 0, GFP_KERNEL, iwl_mvm_read_coredump, iwl_mvm_free_coredump); out: iwl_mvm_free_fw_dump_desc(mvm); mvm->fw_dump_trig = NULL; clear_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status); }
int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic) { int ret, section; u32 size_read = 0; u8 *nvm_buffer, *temp; const char *nvm_file_B = mvm->cfg->default_nvm_file_B_step; const char *nvm_file_C = mvm->cfg->default_nvm_file_C_step; if (WARN_ON_ONCE(mvm->cfg->nvm_hw_section_num >= NVM_MAX_NUM_SECTIONS)) return -EINVAL; /* load NVM values from nic */ if (read_nvm_from_nic) { /* Read From FW NVM */ IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n"); nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size, GFP_KERNEL); if (!nvm_buffer) return -ENOMEM; for (section = 0; section < NVM_MAX_NUM_SECTIONS; section++) { /* we override the constness for initial read */ ret = iwl_nvm_read_section(mvm, section, nvm_buffer, size_read); if (ret < 0) continue; size_read += ret; temp = kmemdup(nvm_buffer, ret, GFP_KERNEL); if (!temp) { ret = -ENOMEM; break; } iwl_mvm_nvm_fixups(mvm, section, temp, ret); mvm->nvm_sections[section].data = temp; mvm->nvm_sections[section].length = ret; #ifdef CONFIG_IWLWIFI_DEBUGFS switch (section) { case NVM_SECTION_TYPE_SW: mvm->nvm_sw_blob.data = temp; mvm->nvm_sw_blob.size = ret; break; case NVM_SECTION_TYPE_CALIBRATION: mvm->nvm_calib_blob.data = temp; mvm->nvm_calib_blob.size = ret; break; case NVM_SECTION_TYPE_PRODUCTION: mvm->nvm_prod_blob.data = temp; mvm->nvm_prod_blob.size = ret; break; case NVM_SECTION_TYPE_PHY_SKU: mvm->nvm_phy_sku_blob.data = temp; mvm->nvm_phy_sku_blob.size = ret; break; default: if (section == mvm->cfg->nvm_hw_section_num) { mvm->nvm_hw_blob.data = temp; mvm->nvm_hw_blob.size = ret; break; } } #endif } if (!size_read) IWL_ERR(mvm, "OTP is blank\n"); kfree(nvm_buffer); } /* Only if PNVM selected in the mod param - load external NVM */ if (mvm->nvm_file_name) { /* read External NVM file from the mod param */ ret = iwl_mvm_read_external_nvm(mvm); if (ret) { /* choose the nvm_file name according to the * HW step */ if (CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_B_STEP) mvm->nvm_file_name = nvm_file_B; else mvm->nvm_file_name = nvm_file_C; if ((ret == -EFAULT || ret == -ENOENT) && mvm->nvm_file_name) { /* in case nvm file was failed try again */ ret = iwl_mvm_read_external_nvm(mvm); if (ret) return ret; } else { return ret; } } } /* parse the relevant nvm sections */ mvm->nvm_data = iwl_parse_nvm_sections(mvm); if (!mvm->nvm_data) return -ENODATA; IWL_DEBUG_EEPROM(mvm->trans->dev, "nvm version = %x\n", mvm->nvm_data->nvm_version); return 0; }
/* * Reads external NVM from a file into mvm->nvm_sections * * HOW TO CREATE THE NVM FILE FORMAT: * ------------------------------ * 1. create hex file, format: * 3800 -> header * 0000 -> header * 5a40 -> data * * rev - 6 bit (word1) * len - 10 bit (word1) * id - 4 bit (word2) * rsv - 12 bit (word2) * * 2. flip 8bits with 8 bits per line to get the right NVM file format * * 3. create binary file from the hex file * * 4. save as "iNVM_xxx.bin" under /lib/firmware */ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) { int ret, section_size; u16 section_id; const struct firmware *fw_entry; const struct { __le16 word1; __le16 word2; u8 data[]; } *file_sec; const u8 *eof; u8 *temp; int max_section_size; const __le32 *dword_buff; #define NVM_WORD1_LEN(x) (8 * (x & 0x03FF)) #define NVM_WORD2_ID(x) (x >> 12) #define NVM_WORD2_LEN_FAMILY_8000(x) (2 * ((x & 0xFF) << 8 | x >> 8)) #define NVM_WORD1_ID_FAMILY_8000(x) (x >> 4) #define NVM_HEADER_0 (0x2A504C54) #define NVM_HEADER_1 (0x4E564D2A) #define NVM_HEADER_SIZE (4 * sizeof(u32)) IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n"); /* Maximal size depends on HW family and step */ if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) max_section_size = IWL_MAX_NVM_SECTION_SIZE; else max_section_size = IWL_MAX_NVM_8000_SECTION_SIZE; /* * Obtain NVM image via request_firmware. Since we already used * request_firmware_nowait() for the firmware binary load and only * get here after that we assume the NVM request can be satisfied * synchronously. */ ret = request_firmware(&fw_entry, mvm->nvm_file_name, mvm->trans->dev); if (ret) { IWL_ERR(mvm, "ERROR: %s isn't available %d\n", mvm->nvm_file_name, ret); return ret; } IWL_INFO(mvm, "Loaded NVM file %s (%zu bytes)\n", mvm->nvm_file_name, fw_entry->size); if (fw_entry->size > MAX_NVM_FILE_LEN) { IWL_ERR(mvm, "NVM file too large\n"); ret = -EINVAL; goto out; } eof = fw_entry->data + fw_entry->size; dword_buff = (__le32 *)fw_entry->data; /* some NVM file will contain a header. * The header is identified by 2 dwords header as follow: * dword[0] = 0x2A504C54 * dword[1] = 0x4E564D2A * * This header must be skipped when providing the NVM data to the FW. */ if (fw_entry->size > NVM_HEADER_SIZE && dword_buff[0] == cpu_to_le32(NVM_HEADER_0) && dword_buff[1] == cpu_to_le32(NVM_HEADER_1)) { file_sec = (void *)(fw_entry->data + NVM_HEADER_SIZE); IWL_INFO(mvm, "NVM Version %08X\n", le32_to_cpu(dword_buff[2])); IWL_INFO(mvm, "NVM Manufacturing date %08X\n", le32_to_cpu(dword_buff[3])); /* nvm file validation, dword_buff[2] holds the file version */ if ((CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_C_STEP && le32_to_cpu(dword_buff[2]) < 0xE4A) || (CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_B_STEP && le32_to_cpu(dword_buff[2]) >= 0xE4A)) { ret = -EFAULT; goto out; } } else { file_sec = (void *)fw_entry->data; } while (true) { if (file_sec->data > eof) { IWL_ERR(mvm, "ERROR - NVM file too short for section header\n"); ret = -EINVAL; break; } /* check for EOF marker */ if (!file_sec->word1 && !file_sec->word2) { ret = 0; break; } if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { section_size = 2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1)); section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2)); } else { section_size = 2 * NVM_WORD2_LEN_FAMILY_8000( le16_to_cpu(file_sec->word2)); section_id = NVM_WORD1_ID_FAMILY_8000( le16_to_cpu(file_sec->word1)); } if (section_size > max_section_size) { IWL_ERR(mvm, "ERROR - section too large (%d)\n", section_size); ret = -EINVAL; break; } if (!section_size) { IWL_ERR(mvm, "ERROR - section empty\n"); ret = -EINVAL; break; } if (file_sec->data + section_size > eof) { IWL_ERR(mvm, "ERROR - NVM file too short for section (%d bytes)\n", section_size); ret = -EINVAL; break; } if (WARN(section_id >= NVM_MAX_NUM_SECTIONS, "Invalid NVM section ID %d\n", section_id)) { ret = -EINVAL; break; } temp = kmemdup(file_sec->data, section_size, GFP_KERNEL); if (!temp) { ret = -ENOMEM; break; } iwl_mvm_nvm_fixups(mvm, section_id, temp, section_size); kfree(mvm->nvm_sections[section_id].data); mvm->nvm_sections[section_id].data = temp; mvm->nvm_sections[section_id].length = section_size; /* advance to the next section */ file_sec = (void *)(file_sec->data + section_size); } out: release_firmware(fw_entry); return ret; }
static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); u8 radio_cfg_type, radio_cfg_step, radio_cfg_dash; u32 reg_val = 0; /* * We can't upload the correct value to the INIT image * as we don't have nvm_data by that time. * * TODO: Figure out what we should do here */ if (mvm->nvm_data) { radio_cfg_type = mvm->nvm_data->radio_cfg_type; radio_cfg_step = mvm->nvm_data->radio_cfg_step; radio_cfg_dash = mvm->nvm_data->radio_cfg_dash; } else { radio_cfg_type = 0; radio_cfg_step = 0; radio_cfg_dash = 0; } /* SKU control */ reg_val |= CSR_HW_REV_STEP(mvm->trans->hw_rev) << CSR_HW_IF_CONFIG_REG_POS_MAC_STEP; reg_val |= CSR_HW_REV_DASH(mvm->trans->hw_rev) << CSR_HW_IF_CONFIG_REG_POS_MAC_DASH; /* radio configuration */ reg_val |= radio_cfg_type << CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE; reg_val |= radio_cfg_step << CSR_HW_IF_CONFIG_REG_POS_PHY_STEP; reg_val |= radio_cfg_dash << CSR_HW_IF_CONFIG_REG_POS_PHY_DASH; WARN_ON((radio_cfg_type << CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE) & ~CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE); /* silicon bits */ reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI; reg_val |= CSR_HW_IF_CONFIG_REG_BIT_MAC_SI; iwl_trans_set_bits_mask(mvm->trans, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH | CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP | CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE | CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP | CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH | CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | CSR_HW_IF_CONFIG_REG_BIT_MAC_SI, reg_val); IWL_DEBUG_INFO(mvm, "Radio type=0x%x-0x%x-0x%x\n", radio_cfg_type, radio_cfg_step, radio_cfg_dash); /* * W/A : NIC is stuck in a reset state after Early PCIe power off * (PCIe power is lost before PERST# is asserted), causing ME FW * to lose ownership and not being able to obtain it back. */ iwl_set_bits_mask_prph(mvm->trans, APMG_PS_CTRL_REG, APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); }