18e99ea8dSJohannes Berg // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 28e99ea8dSJohannes Berg /* 38e99ea8dSJohannes Berg * Copyright (C) 2017 Intel Deutschland GmbH 48e99ea8dSJohannes Berg * Copyright (C) 2018-2020 Intel Corporation 58e99ea8dSJohannes Berg */ 6eda50cdeSSara Sharon #include "iwl-trans.h" 70232d2cdSSara Sharon #include "iwl-prph.h" 8eda50cdeSSara Sharon #include "iwl-context-info.h" 92ee82402SGolan Ben Ami #include "iwl-context-info-gen3.h" 10eda50cdeSSara Sharon #include "internal.h" 11ae17404eSShahar S Matityahu #include "fw/dbg.h" 12eda50cdeSSara Sharon 13eda50cdeSSara Sharon /* 14eda50cdeSSara Sharon * Start up NIC's basic functionality after it has been reset 15eda50cdeSSara Sharon * (e.g. after platform boot, or shutdown via iwl_pcie_apm_stop()) 16eda50cdeSSara Sharon * NOTE: This does not load uCode nor start the embedded processor 17eda50cdeSSara Sharon */ 18b6fe2757SGolan Ben Ami int iwl_pcie_gen2_apm_init(struct iwl_trans *trans) 19eda50cdeSSara Sharon { 20eda50cdeSSara Sharon int ret = 0; 21eda50cdeSSara Sharon 22eda50cdeSSara Sharon IWL_DEBUG_INFO(trans, "Init card's basic functions\n"); 23eda50cdeSSara Sharon 24eda50cdeSSara Sharon /* 25eda50cdeSSara Sharon * Use "set_bit" below rather than "write", to preserve any hardware 26eda50cdeSSara Sharon * bits already set by default after reset. 27eda50cdeSSara Sharon */ 28eda50cdeSSara Sharon 29eda50cdeSSara Sharon /* 30eda50cdeSSara Sharon * Disable L0s without affecting L1; 31eda50cdeSSara Sharon * don't wait for ICH L0s (ICH bug W/A) 32eda50cdeSSara Sharon */ 33eda50cdeSSara Sharon iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS, 34eda50cdeSSara Sharon CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); 35eda50cdeSSara Sharon 36eda50cdeSSara Sharon /* Set FH wait threshold to maximum (HW error during stress W/A) */ 37eda50cdeSSara Sharon iwl_set_bit(trans, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL); 38eda50cdeSSara Sharon 39eda50cdeSSara Sharon /* 40eda50cdeSSara Sharon * Enable HAP INTA (interrupt from management bus) to 41eda50cdeSSara Sharon * wake device's PCI Express link L1a -> L0s 42eda50cdeSSara Sharon */ 43eda50cdeSSara Sharon iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, 44eda50cdeSSara Sharon CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); 45eda50cdeSSara Sharon 46eda50cdeSSara Sharon iwl_pcie_apm_config(trans); 47eda50cdeSSara Sharon 487d34a7d7SLuca Coelho ret = iwl_finish_nic_init(trans, trans->trans_cfg); 49c96b5eecSJohannes Berg if (ret) 50eda50cdeSSara Sharon return ret; 51eda50cdeSSara Sharon 52eda50cdeSSara Sharon set_bit(STATUS_DEVICE_ENABLED, &trans->status); 53eda50cdeSSara Sharon 54eda50cdeSSara Sharon return 0; 55eda50cdeSSara Sharon } 56eda50cdeSSara Sharon 5777c09bc8SSara Sharon static void iwl_pcie_gen2_apm_stop(struct iwl_trans *trans, bool op_mode_leave) 5877c09bc8SSara Sharon { 5977c09bc8SSara Sharon IWL_DEBUG_INFO(trans, "Stop card, put in low power state\n"); 6077c09bc8SSara Sharon 6177c09bc8SSara Sharon if (op_mode_leave) { 6277c09bc8SSara Sharon if (!test_bit(STATUS_DEVICE_ENABLED, &trans->status)) 6377c09bc8SSara Sharon iwl_pcie_gen2_apm_init(trans); 6477c09bc8SSara Sharon 6577c09bc8SSara Sharon /* inform ME that we are leaving */ 6677c09bc8SSara Sharon iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, 6777c09bc8SSara Sharon CSR_RESET_LINK_PWR_MGMT_DISABLED); 6877c09bc8SSara Sharon iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, 6977c09bc8SSara Sharon CSR_HW_IF_CONFIG_REG_PREPARE | 7077c09bc8SSara Sharon CSR_HW_IF_CONFIG_REG_ENABLE_PME); 7177c09bc8SSara Sharon mdelay(1); 7277c09bc8SSara Sharon iwl_clear_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, 7377c09bc8SSara Sharon CSR_RESET_LINK_PWR_MGMT_DISABLED); 7477c09bc8SSara Sharon mdelay(5); 7577c09bc8SSara Sharon } 7677c09bc8SSara Sharon 7777c09bc8SSara Sharon clear_bit(STATUS_DEVICE_ENABLED, &trans->status); 7877c09bc8SSara Sharon 7977c09bc8SSara Sharon /* Stop device's DMA activity */ 8077c09bc8SSara Sharon iwl_pcie_apm_stop_master(trans); 8177c09bc8SSara Sharon 82870c2a11SGolan Ben Ami iwl_trans_sw_reset(trans); 8377c09bc8SSara Sharon 8477c09bc8SSara Sharon /* 8577c09bc8SSara Sharon * Clear "initialization complete" bit to move adapter from 8677c09bc8SSara Sharon * D0A* (powered-up Active) --> D0U* (Uninitialized) state. 8777c09bc8SSara Sharon */ 886dece0e9SLuca Coelho iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); 8977c09bc8SSara Sharon } 9077c09bc8SSara Sharon 91*906d4eb8SJohannes Berg static void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans) 92*906d4eb8SJohannes Berg { 93*906d4eb8SJohannes Berg struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 94*906d4eb8SJohannes Berg int ret; 95*906d4eb8SJohannes Berg 96*906d4eb8SJohannes Berg trans_pcie->fw_reset_done = false; 97*906d4eb8SJohannes Berg 98*906d4eb8SJohannes Berg if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) 99*906d4eb8SJohannes Berg iwl_write_umac_prph(trans, UREG_NIC_SET_NMI_DRIVER, 100*906d4eb8SJohannes Berg UREG_NIC_SET_NMI_DRIVER_RESET_HANDSHAKE); 101*906d4eb8SJohannes Berg else 102*906d4eb8SJohannes Berg iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, 103*906d4eb8SJohannes Berg UREG_DOORBELL_TO_ISR6_RESET_HANDSHAKE); 104*906d4eb8SJohannes Berg 105*906d4eb8SJohannes Berg /* wait 200ms */ 106*906d4eb8SJohannes Berg ret = wait_event_timeout(trans_pcie->fw_reset_waitq, 107*906d4eb8SJohannes Berg trans_pcie->fw_reset_done, HZ / 5); 108*906d4eb8SJohannes Berg if (!ret) 109*906d4eb8SJohannes Berg IWL_ERR(trans, 110*906d4eb8SJohannes Berg "firmware didn't ACK the reset - continue anyway\n"); 111*906d4eb8SJohannes Berg } 112*906d4eb8SJohannes Berg 113bab3cb92SEmmanuel Grumbach void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) 11477c09bc8SSara Sharon { 11577c09bc8SSara Sharon struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 11677c09bc8SSara Sharon 11777c09bc8SSara Sharon lockdep_assert_held(&trans_pcie->mutex); 11877c09bc8SSara Sharon 11977c09bc8SSara Sharon if (trans_pcie->is_down) 12077c09bc8SSara Sharon return; 12177c09bc8SSara Sharon 122*906d4eb8SJohannes Berg if (trans_pcie->fw_reset_handshake && 123*906d4eb8SJohannes Berg trans->state >= IWL_TRANS_FW_STARTED) 124*906d4eb8SJohannes Berg iwl_trans_pcie_fw_reset_handshake(trans); 125*906d4eb8SJohannes Berg 12677c09bc8SSara Sharon trans_pcie->is_down = true; 12777c09bc8SSara Sharon 12877c09bc8SSara Sharon /* tell the device to stop sending interrupts */ 12977c09bc8SSara Sharon iwl_disable_interrupts(trans); 13077c09bc8SSara Sharon 13177c09bc8SSara Sharon /* device going down, Stop using ICT table */ 13277c09bc8SSara Sharon iwl_pcie_disable_ict(trans); 13377c09bc8SSara Sharon 13477c09bc8SSara Sharon /* 13577c09bc8SSara Sharon * If a HW restart happens during firmware loading, 13677c09bc8SSara Sharon * then the firmware loading might call this function 13777c09bc8SSara Sharon * and later it might be called again due to the 13877c09bc8SSara Sharon * restart. So don't process again if the device is 13977c09bc8SSara Sharon * already dead. 14077c09bc8SSara Sharon */ 14177c09bc8SSara Sharon if (test_and_clear_bit(STATUS_DEVICE_ENABLED, &trans->status)) { 14277c09bc8SSara Sharon IWL_DEBUG_INFO(trans, 14377c09bc8SSara Sharon "DEVICE_ENABLED bit was set and is now cleared\n"); 1440cd1ad2dSMordechay Goodstein iwl_txq_gen2_tx_stop(trans); 14577c09bc8SSara Sharon iwl_pcie_rx_stop(trans); 14677c09bc8SSara Sharon } 14777c09bc8SSara Sharon 14877c09bc8SSara Sharon iwl_pcie_ctxt_info_free_paging(trans); 1493681021fSJohannes Berg if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) 1502ee82402SGolan Ben Ami iwl_pcie_ctxt_info_gen3_free(trans); 1512ee82402SGolan Ben Ami else 15277c09bc8SSara Sharon iwl_pcie_ctxt_info_free(trans); 15377c09bc8SSara Sharon 15477c09bc8SSara Sharon /* Make sure (redundant) we've released our request to stay awake */ 15577c09bc8SSara Sharon iwl_clear_bit(trans, CSR_GP_CNTRL, 1566dece0e9SLuca Coelho CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); 15777c09bc8SSara Sharon 15877c09bc8SSara Sharon /* Stop the device, and put it in low power state */ 15977c09bc8SSara Sharon iwl_pcie_gen2_apm_stop(trans, false); 16077c09bc8SSara Sharon 161870c2a11SGolan Ben Ami iwl_trans_sw_reset(trans); 16277c09bc8SSara Sharon 16377c09bc8SSara Sharon /* 16477c09bc8SSara Sharon * Upon stop, the IVAR table gets erased, so msi-x won't 16577c09bc8SSara Sharon * work. This causes a bug in RF-KILL flows, since the interrupt 16677c09bc8SSara Sharon * that enables radio won't fire on the correct irq, and the 16777c09bc8SSara Sharon * driver won't be able to handle the interrupt. 16877c09bc8SSara Sharon * Configure the IVAR table again after reset. 16977c09bc8SSara Sharon */ 17077c09bc8SSara Sharon iwl_pcie_conf_msix_hw(trans_pcie); 17177c09bc8SSara Sharon 17277c09bc8SSara Sharon /* 17377c09bc8SSara Sharon * Upon stop, the APM issues an interrupt if HW RF kill is set. 17477c09bc8SSara Sharon * This is a bug in certain verions of the hardware. 17577c09bc8SSara Sharon * Certain devices also keep sending HW RF kill interrupt all 17677c09bc8SSara Sharon * the time, unless the interrupt is ACKed even if the interrupt 17777c09bc8SSara Sharon * should be masked. Re-ACK all the interrupts here. 17877c09bc8SSara Sharon */ 17977c09bc8SSara Sharon iwl_disable_interrupts(trans); 18077c09bc8SSara Sharon 18177c09bc8SSara Sharon /* clear all status bits */ 18277c09bc8SSara Sharon clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); 18377c09bc8SSara Sharon clear_bit(STATUS_INT_ENABLED, &trans->status); 18477c09bc8SSara Sharon clear_bit(STATUS_TPOWER_PMI, &trans->status); 18577c09bc8SSara Sharon 18677c09bc8SSara Sharon /* 18777c09bc8SSara Sharon * Even if we stop the HW, we still want the RF kill 18877c09bc8SSara Sharon * interrupt 18977c09bc8SSara Sharon */ 19077c09bc8SSara Sharon iwl_enable_rfkill_int(trans); 19177c09bc8SSara Sharon 19277c09bc8SSara Sharon /* re-take ownership to prevent other users from stealing the device */ 19377c09bc8SSara Sharon iwl_pcie_prepare_card_hw(trans); 19477c09bc8SSara Sharon } 19577c09bc8SSara Sharon 196bab3cb92SEmmanuel Grumbach void iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) 19777c09bc8SSara Sharon { 19877c09bc8SSara Sharon struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 199326477e4SJohannes Berg bool was_in_rfkill; 20077c09bc8SSara Sharon 20177c09bc8SSara Sharon mutex_lock(&trans_pcie->mutex); 202326477e4SJohannes Berg trans_pcie->opmode_down = true; 203326477e4SJohannes Berg was_in_rfkill = test_bit(STATUS_RFKILL_OPMODE, &trans->status); 204bab3cb92SEmmanuel Grumbach _iwl_trans_pcie_gen2_stop_device(trans); 205326477e4SJohannes Berg iwl_trans_pcie_handle_stop_rfkill(trans, was_in_rfkill); 20677c09bc8SSara Sharon mutex_unlock(&trans_pcie->mutex); 20777c09bc8SSara Sharon } 20877c09bc8SSara Sharon 209eda50cdeSSara Sharon static int iwl_pcie_gen2_nic_init(struct iwl_trans *trans) 210eda50cdeSSara Sharon { 211eda50cdeSSara Sharon struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 212718a8b23SShaul Triebitz int queue_size = max_t(u32, IWL_CMD_QUEUE_SIZE, 213718a8b23SShaul Triebitz trans->cfg->min_txq_size); 214eda50cdeSSara Sharon 215eda50cdeSSara Sharon /* TODO: most of the logic can be removed in A0 - but not in Z0 */ 216eda50cdeSSara Sharon spin_lock(&trans_pcie->irq_lock); 217eda50cdeSSara Sharon iwl_pcie_gen2_apm_init(trans); 218eda50cdeSSara Sharon spin_unlock(&trans_pcie->irq_lock); 219eda50cdeSSara Sharon 220eda50cdeSSara Sharon iwl_op_mode_nic_config(trans->op_mode); 221eda50cdeSSara Sharon 222eda50cdeSSara Sharon /* Allocate the RX queue, or reset if it is already allocated */ 223eda50cdeSSara Sharon if (iwl_pcie_gen2_rx_init(trans)) 224eda50cdeSSara Sharon return -ENOMEM; 225eda50cdeSSara Sharon 226eda50cdeSSara Sharon /* Allocate or reset and init all Tx and Command queues */ 2270cd1ad2dSMordechay Goodstein if (iwl_txq_gen2_init(trans, trans->txqs.cmd.q_id, queue_size)) 228eda50cdeSSara Sharon return -ENOMEM; 229eda50cdeSSara Sharon 230eda50cdeSSara Sharon /* enable shadow regs in HW */ 231eda50cdeSSara Sharon iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL, 0x800FFFFF); 232eda50cdeSSara Sharon IWL_DEBUG_INFO(trans, "Enabling shadow registers in device\n"); 233eda50cdeSSara Sharon 234eda50cdeSSara Sharon return 0; 235eda50cdeSSara Sharon } 236eda50cdeSSara Sharon 237eda50cdeSSara Sharon void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr) 238eda50cdeSSara Sharon { 239eda50cdeSSara Sharon struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 240eda50cdeSSara Sharon 241eda50cdeSSara Sharon iwl_pcie_reset_ict(trans); 242eda50cdeSSara Sharon 243eda50cdeSSara Sharon /* make sure all queue are not stopped/used */ 2444f4822b7SMordechay Goodstein memset(trans->txqs.queue_stopped, 0, 2454f4822b7SMordechay Goodstein sizeof(trans->txqs.queue_stopped)); 2464f4822b7SMordechay Goodstein memset(trans->txqs.queue_used, 0, sizeof(trans->txqs.queue_used)); 247eda50cdeSSara Sharon 248eda50cdeSSara Sharon /* now that we got alive we can free the fw image & the context info. 249eda50cdeSSara Sharon * paging memory cannot be freed included since FW will still use it 250eda50cdeSSara Sharon */ 251eda50cdeSSara Sharon iwl_pcie_ctxt_info_free(trans); 252ed3e4c6dSEmmanuel Grumbach 253ed3e4c6dSEmmanuel Grumbach /* 254ed3e4c6dSEmmanuel Grumbach * Re-enable all the interrupts, including the RF-Kill one, now that 255ed3e4c6dSEmmanuel Grumbach * the firmware is alive. 256ed3e4c6dSEmmanuel Grumbach */ 257ed3e4c6dSEmmanuel Grumbach iwl_enable_interrupts(trans); 258ed3e4c6dSEmmanuel Grumbach mutex_lock(&trans_pcie->mutex); 259ed3e4c6dSEmmanuel Grumbach iwl_pcie_check_hw_rf_kill(trans); 260ed3e4c6dSEmmanuel Grumbach mutex_unlock(&trans_pcie->mutex); 261eda50cdeSSara Sharon } 262eda50cdeSSara Sharon 263eda50cdeSSara Sharon int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, 264eda50cdeSSara Sharon const struct fw_img *fw, bool run_in_rfkill) 265eda50cdeSSara Sharon { 266eda50cdeSSara Sharon struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 267eda50cdeSSara Sharon bool hw_rfkill; 268eda50cdeSSara Sharon int ret; 269eda50cdeSSara Sharon 270eda50cdeSSara Sharon /* This may fail if AMT took ownership of the device */ 271eda50cdeSSara Sharon if (iwl_pcie_prepare_card_hw(trans)) { 272eda50cdeSSara Sharon IWL_WARN(trans, "Exit HW not ready\n"); 273eda50cdeSSara Sharon ret = -EIO; 274eda50cdeSSara Sharon goto out; 275eda50cdeSSara Sharon } 276eda50cdeSSara Sharon 277eda50cdeSSara Sharon iwl_enable_rfkill_int(trans); 278eda50cdeSSara Sharon 279eda50cdeSSara Sharon iwl_write32(trans, CSR_INT, 0xFFFFFFFF); 280eda50cdeSSara Sharon 281eda50cdeSSara Sharon /* 282eda50cdeSSara Sharon * We enabled the RF-Kill interrupt and the handler may very 283eda50cdeSSara Sharon * well be running. Disable the interrupts to make sure no other 284eda50cdeSSara Sharon * interrupt can be fired. 285eda50cdeSSara Sharon */ 286eda50cdeSSara Sharon iwl_disable_interrupts(trans); 287eda50cdeSSara Sharon 288eda50cdeSSara Sharon /* Make sure it finished running */ 289eda50cdeSSara Sharon iwl_pcie_synchronize_irqs(trans); 290eda50cdeSSara Sharon 291eda50cdeSSara Sharon mutex_lock(&trans_pcie->mutex); 292eda50cdeSSara Sharon 293eda50cdeSSara Sharon /* If platform's RF_KILL switch is NOT set to KILL */ 2949ad8fd0bSJohannes Berg hw_rfkill = iwl_pcie_check_hw_rf_kill(trans); 295eda50cdeSSara Sharon if (hw_rfkill && !run_in_rfkill) { 296eda50cdeSSara Sharon ret = -ERFKILL; 297eda50cdeSSara Sharon goto out; 298eda50cdeSSara Sharon } 299eda50cdeSSara Sharon 300eda50cdeSSara Sharon /* Someone called stop_device, don't try to start_fw */ 301eda50cdeSSara Sharon if (trans_pcie->is_down) { 302eda50cdeSSara Sharon IWL_WARN(trans, 303eda50cdeSSara Sharon "Can't start_fw since the HW hasn't been started\n"); 304eda50cdeSSara Sharon ret = -EIO; 305eda50cdeSSara Sharon goto out; 306eda50cdeSSara Sharon } 307eda50cdeSSara Sharon 308eda50cdeSSara Sharon /* make sure rfkill handshake bits are cleared */ 309eda50cdeSSara Sharon iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); 310eda50cdeSSara Sharon iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, 311eda50cdeSSara Sharon CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); 312eda50cdeSSara Sharon 313eda50cdeSSara Sharon /* clear (again), then enable host interrupts */ 314eda50cdeSSara Sharon iwl_write32(trans, CSR_INT, 0xFFFFFFFF); 315eda50cdeSSara Sharon 316eda50cdeSSara Sharon ret = iwl_pcie_gen2_nic_init(trans); 317eda50cdeSSara Sharon if (ret) { 318eda50cdeSSara Sharon IWL_ERR(trans, "Unable to init nic\n"); 319eda50cdeSSara Sharon goto out; 320eda50cdeSSara Sharon } 321eda50cdeSSara Sharon 3223681021fSJohannes Berg if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) 3232ee82402SGolan Ben Ami ret = iwl_pcie_ctxt_info_gen3_init(trans, fw); 3242ee82402SGolan Ben Ami else 32597b00d87SJohannes Berg ret = iwl_pcie_ctxt_info_init(trans, fw); 32697b00d87SJohannes Berg if (ret) 32797b00d87SJohannes Berg goto out; 328eda50cdeSSara Sharon 329eda50cdeSSara Sharon /* re-check RF-Kill state since we may have missed the interrupt */ 3309ad8fd0bSJohannes Berg hw_rfkill = iwl_pcie_check_hw_rf_kill(trans); 331eda50cdeSSara Sharon if (hw_rfkill && !run_in_rfkill) 332eda50cdeSSara Sharon ret = -ERFKILL; 333eda50cdeSSara Sharon 334eda50cdeSSara Sharon out: 335eda50cdeSSara Sharon mutex_unlock(&trans_pcie->mutex); 336eda50cdeSSara Sharon return ret; 337eda50cdeSSara Sharon } 338