static void iwl_mvm_dump_rxf(struct iwl_mvm *mvm, struct iwl_fw_error_dump_data **dump_data, int size, u32 offset, int fifo_num) { struct iwl_fw_error_dump_fifo *fifo_hdr; u32 *fifo_data; u32 fifo_len; int i; fifo_hdr = (void *)(*dump_data)->data; fifo_data = (void *)fifo_hdr->data; fifo_len = size; /* No need to try to read the data if the length is 0 */ if (fifo_len == 0) return; /* Add a TLV for the RXF */ (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF); (*dump_data)->len = cpu_to_le32(fifo_len + sizeof(*fifo_hdr)); fifo_hdr->fifo_num = cpu_to_le32(fifo_num); fifo_hdr->available_bytes = cpu_to_le32(iwl_trans_read_prph(mvm->trans, RXF_RD_D_SPACE + offset)); fifo_hdr->wr_ptr = cpu_to_le32(iwl_trans_read_prph(mvm->trans, RXF_RD_WR_PTR + offset)); fifo_hdr->rd_ptr = cpu_to_le32(iwl_trans_read_prph(mvm->trans, RXF_RD_RD_PTR + offset)); fifo_hdr->fence_ptr = cpu_to_le32(iwl_trans_read_prph(mvm->trans, RXF_RD_FENCE_PTR + offset)); fifo_hdr->fence_mode = cpu_to_le32(iwl_trans_read_prph(mvm->trans, RXF_SET_FENCE_MODE + offset)); /* Lock fence */ iwl_trans_write_prph(mvm->trans, RXF_SET_FENCE_MODE + offset, 0x1); /* Set fence pointer to the same place like WR pointer */ iwl_trans_write_prph(mvm->trans, RXF_LD_WR2FENCE + offset, 0x1); /* Set fence offset */ iwl_trans_write_prph(mvm->trans, RXF_LD_FENCE_OFFSET_ADDR + offset, 0x0); /* Read FIFO */ fifo_len /= sizeof(u32); /* Size in DWORDS */ for (i = 0; i < fifo_len; i++) fifo_data[i] = iwl_trans_read_prph(mvm->trans, RXF_FIFO_RD_FENCE_INC + offset); *dump_data = iwl_fw_error_next_data(*dump_data); }
static void iwl_mvm_dump_txf(struct iwl_mvm *mvm, struct iwl_fw_error_dump_data **dump_data, int size, u32 offset, int fifo_num) { struct iwl_fw_error_dump_fifo *fifo_hdr; u32 *fifo_data; u32 fifo_len; int i; fifo_hdr = (void *)(*dump_data)->data; fifo_data = (void *)fifo_hdr->data; fifo_len = size; /* No need to try to read the data if the length is 0 */ if (fifo_len == 0) return; /* Add a TLV for the FIFO */ (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_TXF); (*dump_data)->len = cpu_to_le32(fifo_len + sizeof(*fifo_hdr)); fifo_hdr->fifo_num = cpu_to_le32(fifo_num); fifo_hdr->available_bytes = cpu_to_le32(iwl_trans_read_prph(mvm->trans, TXF_FIFO_ITEM_CNT + offset)); fifo_hdr->wr_ptr = cpu_to_le32(iwl_trans_read_prph(mvm->trans, TXF_WR_PTR + offset)); fifo_hdr->rd_ptr = cpu_to_le32(iwl_trans_read_prph(mvm->trans, TXF_RD_PTR + offset)); fifo_hdr->fence_ptr = cpu_to_le32(iwl_trans_read_prph(mvm->trans, TXF_FENCE_PTR + offset)); fifo_hdr->fence_mode = cpu_to_le32(iwl_trans_read_prph(mvm->trans, TXF_LOCK_FENCE + offset)); /* Set the TXF_READ_MODIFY_ADDR to TXF_WR_PTR */ iwl_trans_write_prph(mvm->trans, TXF_READ_MODIFY_ADDR + offset, TXF_WR_PTR + offset); /* Dummy-read to advance the read pointer to the head */ iwl_trans_read_prph(mvm->trans, TXF_READ_MODIFY_DATA + offset); /* Read FIFO */ fifo_len /= sizeof(u32); /* Size in DWORDS */ for (i = 0; i < fifo_len; i++) fifo_data[i] = iwl_trans_read_prph(mvm->trans, TXF_READ_MODIFY_DATA + offset); *dump_data = iwl_fw_error_next_data(*dump_data); }
int iwl_mvm_up(struct iwl_mvm *mvm) { int ret, i; struct ieee80211_channel *chan; struct cfg80211_chan_def chandef; lockdep_assert_held(&mvm->mutex); ret = iwl_trans_start_hw(mvm->trans); if (ret) return ret; /* * If we haven't completed the run of the init ucode during * module loading, load init ucode now * (for example, if we were in RFKILL) */ ret = iwl_run_init_mvm_ucode(mvm, false); if (ret && !iwlmvm_mod_params.init_dbg) { IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret); /* this can't happen */ if (WARN_ON(ret > 0)) ret = -ERFKILL; goto error; } if (!iwlmvm_mod_params.init_dbg) { /* * Stop and start the transport without entering low power * mode. This will save the state of other components on the * device that are triggered by the INIT firwmare (MFUART). */ _iwl_trans_stop_device(mvm->trans, false); ret = _iwl_trans_start_hw(mvm->trans, false); if (ret) goto error; } if (iwlmvm_mod_params.init_dbg) return 0; ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_REGULAR); if (ret) { IWL_ERR(mvm, "Failed to start RT ucode: %d\n", ret); goto error; } 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; /* 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) goto error; ret = iwl_send_bt_init_conf(mvm); if (ret) goto error; /* Send phy db control command and then phy db calibration*/ ret = iwl_send_phy_db_data(mvm->phy_db); if (ret) goto error; ret = iwl_send_phy_cfg_cmd(mvm); if (ret) goto error; /* init the fw <-> mac80211 STA mapping */ 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)); /* Add auxiliary station for scanning */ ret = iwl_mvm_add_aux_sta(mvm); if (ret) goto error; /* Add all the PHY contexts */ chan = &mvm->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->channels[0]; cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT); for (i = 0; i < NUM_PHY_CTX; i++) { /* * The channel used here isn't relevant as it's * going to be overwritten in the other flows. * For now use the first channel we have. */ ret = iwl_mvm_phy_ctxt_add(mvm, &mvm->phy_ctxts[i], &chandef, 1, 1); if (ret) goto error; } /* Initialize tx backoffs to the minimal possible */ iwl_mvm_tt_tx_backoff(mvm, 0); 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 (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { ret = iwl_mvm_config_scan(mvm); if (ret) goto error; } if (iwl_mvm_is_csum_supported(mvm) && mvm->cfg->features & NETIF_F_RXCSUM) iwl_trans_write_prph(mvm->trans, RX_EN_CSUM, 0x3); /* 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); IWL_DEBUG_INFO(mvm, "RT uCode started.\n"); return 0; error: iwl_trans_stop_device(mvm->trans); return ret; }
static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm, struct iwl_fw_error_dump_data **dump_data) { struct iwl_fw_error_dump_fifo *fifo_hdr; u32 *fifo_data; u32 fifo_len; unsigned long flags; int i, j; if (!iwl_trans_grab_nic_access(mvm->trans, &flags)) return; /* Pull RXF data from all RXFs */ for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.rxfifo_size); i++) { /* * Keep aside the additional offset that might be needed for * next RXF */ u32 offset_diff = RXF_DIFF_FROM_PREV * i; fifo_hdr = (void *)(*dump_data)->data; fifo_data = (void *)fifo_hdr->data; fifo_len = mvm->shared_mem_cfg.rxfifo_size[i]; /* No need to try to read the data if the length is 0 */ if (fifo_len == 0) continue; /* Add a TLV for the RXF */ (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF); (*dump_data)->len = cpu_to_le32(fifo_len + sizeof(*fifo_hdr)); fifo_hdr->fifo_num = cpu_to_le32(i); fifo_hdr->available_bytes = cpu_to_le32(iwl_trans_read_prph(mvm->trans, RXF_RD_D_SPACE + offset_diff)); fifo_hdr->wr_ptr = cpu_to_le32(iwl_trans_read_prph(mvm->trans, RXF_RD_WR_PTR + offset_diff)); fifo_hdr->rd_ptr = cpu_to_le32(iwl_trans_read_prph(mvm->trans, RXF_RD_RD_PTR + offset_diff)); fifo_hdr->fence_ptr = cpu_to_le32(iwl_trans_read_prph(mvm->trans, RXF_RD_FENCE_PTR + offset_diff)); fifo_hdr->fence_mode = cpu_to_le32(iwl_trans_read_prph(mvm->trans, RXF_SET_FENCE_MODE + offset_diff)); /* Lock fence */ iwl_trans_write_prph(mvm->trans, RXF_SET_FENCE_MODE + offset_diff, 0x1); /* Set fence pointer to the same place like WR pointer */ iwl_trans_write_prph(mvm->trans, RXF_LD_WR2FENCE + offset_diff, 0x1); /* Set fence offset */ iwl_trans_write_prph(mvm->trans, RXF_LD_FENCE_OFFSET_ADDR + offset_diff, 0x0); /* Read FIFO */ fifo_len /= sizeof(u32); /* Size in DWORDS */ for (j = 0; j < fifo_len; j++) fifo_data[j] = iwl_trans_read_prph(mvm->trans, RXF_FIFO_RD_FENCE_INC + offset_diff); *dump_data = iwl_fw_error_next_data(*dump_data); } /* Pull TXF data from all TXFs */ for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.txfifo_size); i++) { /* Mark the number of TXF we're pulling now */ iwl_trans_write_prph(mvm->trans, TXF_LARC_NUM, i); fifo_hdr = (void *)(*dump_data)->data; fifo_data = (void *)fifo_hdr->data; fifo_len = mvm->shared_mem_cfg.txfifo_size[i]; /* No need to try to read the data if the length is 0 */ if (fifo_len == 0) continue; /* Add a TLV for the FIFO */ (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_TXF); (*dump_data)->len = cpu_to_le32(fifo_len + sizeof(*fifo_hdr)); fifo_hdr->fifo_num = cpu_to_le32(i); fifo_hdr->available_bytes = cpu_to_le32(iwl_trans_read_prph(mvm->trans, TXF_FIFO_ITEM_CNT)); fifo_hdr->wr_ptr = cpu_to_le32(iwl_trans_read_prph(mvm->trans, TXF_WR_PTR)); fifo_hdr->rd_ptr = cpu_to_le32(iwl_trans_read_prph(mvm->trans, TXF_RD_PTR)); fifo_hdr->fence_ptr = cpu_to_le32(iwl_trans_read_prph(mvm->trans, TXF_FENCE_PTR)); fifo_hdr->fence_mode = cpu_to_le32(iwl_trans_read_prph(mvm->trans, TXF_LOCK_FENCE)); /* Set the TXF_READ_MODIFY_ADDR to TXF_WR_PTR */ iwl_trans_write_prph(mvm->trans, TXF_READ_MODIFY_ADDR, TXF_WR_PTR); /* Dummy-read to advance the read pointer to the head */ iwl_trans_read_prph(mvm->trans, TXF_READ_MODIFY_DATA); /* Read FIFO */ fifo_len /= sizeof(u32); /* Size in DWORDS */ for (j = 0; j < fifo_len; j++) fifo_data[j] = iwl_trans_read_prph(mvm->trans, TXF_READ_MODIFY_DATA); *dump_data = iwl_fw_error_next_data(*dump_data); } if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) { /* Pull UMAC internal TXF data from all TXFs */ for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.internal_txfifo_size); i++) { /* Mark the number of TXF we're pulling now */ iwl_trans_write_prph(mvm->trans, TXF_CPU2_NUM, i); fifo_hdr = (void *)(*dump_data)->data; fifo_data = (void *)fifo_hdr->data; fifo_len = mvm->shared_mem_cfg.internal_txfifo_size[i]; /* No need to try to read the data if the length is 0 */ if (fifo_len == 0) continue; /* Add a TLV for the internal FIFOs */ (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_INTERNAL_TXF); (*dump_data)->len = cpu_to_le32(fifo_len + sizeof(*fifo_hdr)); fifo_hdr->fifo_num = cpu_to_le32(i); fifo_hdr->available_bytes = cpu_to_le32(iwl_trans_read_prph(mvm->trans, TXF_CPU2_FIFO_ITEM_CNT)); fifo_hdr->wr_ptr = cpu_to_le32(iwl_trans_read_prph(mvm->trans, TXF_CPU2_WR_PTR)); fifo_hdr->rd_ptr = cpu_to_le32(iwl_trans_read_prph(mvm->trans, TXF_CPU2_RD_PTR)); fifo_hdr->fence_ptr = cpu_to_le32(iwl_trans_read_prph(mvm->trans, TXF_CPU2_FENCE_PTR)); fifo_hdr->fence_mode = cpu_to_le32(iwl_trans_read_prph(mvm->trans, TXF_CPU2_LOCK_FENCE)); /* Set TXF_CPU2_READ_MODIFY_ADDR to TXF_CPU2_WR_PTR */ iwl_trans_write_prph(mvm->trans, TXF_CPU2_READ_MODIFY_ADDR, TXF_CPU2_WR_PTR); /* Dummy-read to advance the read pointer to head */ iwl_trans_read_prph(mvm->trans, TXF_CPU2_READ_MODIFY_DATA); /* Read FIFO */ fifo_len /= sizeof(u32); /* Size in DWORDS */ for (j = 0; j < fifo_len; j++) fifo_data[j] = iwl_trans_read_prph(mvm->trans, TXF_CPU2_READ_MODIFY_DATA); *dump_data = iwl_fw_error_next_data(*dump_data); } } iwl_trans_release_nic_access(mvm->trans, &flags); }
static inline void __iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) { trace_iwlwifi_dev_iowrite_prph32(trans->dev, ofs, val); iwl_trans_write_prph(trans, ofs, val); }
static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm, struct iwl_fw_error_dump_data **dump_data) { struct iwl_fw_error_dump_fifo *fifo_hdr; struct iwl_mvm_shared_mem_cfg *cfg = &mvm->smem_cfg; u32 *fifo_data; u32 fifo_len; unsigned long flags; int i, j; if (!iwl_trans_grab_nic_access(mvm->trans, &flags)) return; /* Pull RXF1 */ iwl_mvm_dump_rxf(mvm, dump_data, cfg->lmac[0].rxfifo1_size, 0, 0); /* Pull RXF2 */ iwl_mvm_dump_rxf(mvm, dump_data, cfg->rxfifo2_size, RXF_DIFF_FROM_PREV, 1); /* Pull LMAC2 RXF1 */ if (mvm->smem_cfg.num_lmacs > 1) iwl_mvm_dump_rxf(mvm, dump_data, cfg->lmac[1].rxfifo1_size, LMAC2_PRPH_OFFSET, 2); /* Pull TXF data from LMAC1 */ for (i = 0; i < mvm->smem_cfg.num_txfifo_entries; i++) { /* Mark the number of TXF we're pulling now */ iwl_trans_write_prph(mvm->trans, TXF_LARC_NUM, i); iwl_mvm_dump_txf(mvm, dump_data, cfg->lmac[0].txfifo_size[i], 0, i); } /* Pull TXF data from LMAC2 */ if (mvm->smem_cfg.num_lmacs > 1) { for (i = 0; i < mvm->smem_cfg.num_txfifo_entries; i++) { /* Mark the number of TXF we're pulling now */ iwl_trans_write_prph(mvm->trans, TXF_LARC_NUM + LMAC2_PRPH_OFFSET, i); iwl_mvm_dump_txf(mvm, dump_data, cfg->lmac[1].txfifo_size[i], LMAC2_PRPH_OFFSET, i + cfg->num_txfifo_entries); } } if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) { /* Pull UMAC internal TXF data from all TXFs */ for (i = 0; i < ARRAY_SIZE(mvm->smem_cfg.internal_txfifo_size); i++) { fifo_hdr = (void *)(*dump_data)->data; fifo_data = (void *)fifo_hdr->data; fifo_len = mvm->smem_cfg.internal_txfifo_size[i]; /* No need to try to read the data if the length is 0 */ if (fifo_len == 0) continue; /* Add a TLV for the internal FIFOs */ (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_INTERNAL_TXF); (*dump_data)->len = cpu_to_le32(fifo_len + sizeof(*fifo_hdr)); fifo_hdr->fifo_num = cpu_to_le32(i); /* Mark the number of TXF we're pulling now */ iwl_trans_write_prph(mvm->trans, TXF_CPU2_NUM, i + mvm->smem_cfg.num_txfifo_entries); fifo_hdr->available_bytes = cpu_to_le32(iwl_trans_read_prph(mvm->trans, TXF_CPU2_FIFO_ITEM_CNT)); fifo_hdr->wr_ptr = cpu_to_le32(iwl_trans_read_prph(mvm->trans, TXF_CPU2_WR_PTR)); fifo_hdr->rd_ptr = cpu_to_le32(iwl_trans_read_prph(mvm->trans, TXF_CPU2_RD_PTR)); fifo_hdr->fence_ptr = cpu_to_le32(iwl_trans_read_prph(mvm->trans, TXF_CPU2_FENCE_PTR)); fifo_hdr->fence_mode = cpu_to_le32(iwl_trans_read_prph(mvm->trans, TXF_CPU2_LOCK_FENCE)); /* Set TXF_CPU2_READ_MODIFY_ADDR to TXF_CPU2_WR_PTR */ iwl_trans_write_prph(mvm->trans, TXF_CPU2_READ_MODIFY_ADDR, TXF_CPU2_WR_PTR); /* Dummy-read to advance the read pointer to head */ iwl_trans_read_prph(mvm->trans, TXF_CPU2_READ_MODIFY_DATA); /* Read FIFO */ fifo_len /= sizeof(u32); /* Size in DWORDS */ for (j = 0; j < fifo_len; j++) fifo_data[j] = iwl_trans_read_prph(mvm->trans, TXF_CPU2_READ_MODIFY_DATA); *dump_data = iwl_fw_error_next_data(*dump_data); } } iwl_trans_release_nic_access(mvm->trans, &flags); }
void iwl_write_prph_no_grab(struct iwl_trans *trans, u32 ofs, u32 val) { trace_iwlwifi_dev_iowrite_prph32(trans->dev, ofs, val); iwl_trans_write_prph(trans, ofs, val); }