int iwl_pcie_init_fw_sec(struct iwl_trans *trans, const struct fw_img *fw, struct iwl_context_info_dram *ctxt_dram) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_self_init_dram *dram = &trans_pcie->init_dram; int i, ret, lmac_cnt, umac_cnt, paging_cnt; if (WARN(dram->paging, "paging shouldn't already be initialized (%d pages)\n", dram->paging_cnt)) iwl_pcie_ctxt_info_free_paging(trans); lmac_cnt = iwl_pcie_get_num_sections(fw, 0); /* add 1 due to separator */ umac_cnt = iwl_pcie_get_num_sections(fw, lmac_cnt + 1); /* add 2 due to separators */ paging_cnt = iwl_pcie_get_num_sections(fw, lmac_cnt + umac_cnt + 2); dram->fw = kcalloc(umac_cnt + lmac_cnt, sizeof(*dram->fw), GFP_KERNEL); if (!dram->fw) return -ENOMEM; dram->paging = kcalloc(paging_cnt, sizeof(*dram->paging), GFP_KERNEL); if (!dram->paging) return -ENOMEM; /* initialize lmac sections */ for (i = 0; i < lmac_cnt; i++) { ret = iwl_pcie_ctxt_info_alloc_dma(trans, &fw->sec[i], &dram->fw[dram->fw_cnt]); if (ret) return ret; ctxt_dram->lmac_img[i] = cpu_to_le64(dram->fw[dram->fw_cnt].physical); dram->fw_cnt++; } /* initialize umac sections */ for (i = 0; i < umac_cnt; i++) { /* access FW with +1 to make up for lmac separator */ ret = iwl_pcie_ctxt_info_alloc_dma(trans, &fw->sec[dram->fw_cnt + 1], &dram->fw[dram->fw_cnt]); if (ret) return ret; ctxt_dram->umac_img[i] = cpu_to_le64(dram->fw[dram->fw_cnt].physical); dram->fw_cnt++; } /* * Initialize paging. * Paging memory isn't stored in dram->fw as the umac and lmac - it is * stored separately. * This is since the timing of its release is different - * while fw memory can be released on alive, the paging memory can be * freed only when the device goes down. * Given that, the logic here in accessing the fw image is a bit * different - fw_cnt isn't changing so loop counter is added to it. */ for (i = 0; i < paging_cnt; i++) { /* access FW with +2 to make up for lmac & umac separators */ int fw_idx = dram->fw_cnt + i + 2; ret = iwl_pcie_ctxt_info_alloc_dma(trans, &fw->sec[fw_idx], &dram->paging[i]); if (ret) return ret; ctxt_dram->virtual_img[i] = cpu_to_le64(dram->paging[i].physical); dram->paging_cnt++; } return 0; }
void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); lockdep_assert_held(&trans_pcie->mutex); if (trans_pcie->is_down) return; trans_pcie->is_down = true; /* Stop dbgc before stopping device */ _iwl_fw_dbg_stop_recording(trans, NULL); /* tell the device to stop sending interrupts */ iwl_disable_interrupts(trans); /* device going down, Stop using ICT table */ iwl_pcie_disable_ict(trans); /* * If a HW restart happens during firmware loading, * then the firmware loading might call this function * and later it might be called again due to the * restart. So don't process again if the device is * already dead. */ if (test_and_clear_bit(STATUS_DEVICE_ENABLED, &trans->status)) { IWL_DEBUG_INFO(trans, "DEVICE_ENABLED bit was set and is now cleared\n"); iwl_pcie_gen2_tx_stop(trans); iwl_pcie_rx_stop(trans); } iwl_pcie_ctxt_info_free_paging(trans); if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_22560) iwl_pcie_ctxt_info_gen3_free(trans); else iwl_pcie_ctxt_info_free(trans); /* Make sure (redundant) we've released our request to stay awake */ iwl_clear_bit(trans, CSR_GP_CNTRL, BIT(trans->cfg->csr->flag_mac_access_req)); /* Stop the device, and put it in low power state */ iwl_pcie_gen2_apm_stop(trans, false); iwl_trans_sw_reset(trans); /* * Upon stop, the IVAR table gets erased, so msi-x won't * work. This causes a bug in RF-KILL flows, since the interrupt * that enables radio won't fire on the correct irq, and the * driver won't be able to handle the interrupt. * Configure the IVAR table again after reset. */ iwl_pcie_conf_msix_hw(trans_pcie); /* * Upon stop, the APM issues an interrupt if HW RF kill is set. * This is a bug in certain verions of the hardware. * Certain devices also keep sending HW RF kill interrupt all * the time, unless the interrupt is ACKed even if the interrupt * should be masked. Re-ACK all the interrupts here. */ iwl_disable_interrupts(trans); /* clear all status bits */ clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); clear_bit(STATUS_INT_ENABLED, &trans->status); clear_bit(STATUS_TPOWER_PMI, &trans->status); /* * Even if we stop the HW, we still want the RF kill * interrupt */ iwl_enable_rfkill_int(trans); /* re-take ownership to prevent other users from stealing the device */ iwl_pcie_prepare_card_hw(trans); }