18c2ecf20Sopenharmony_ci/******************************************************************************
28c2ecf20Sopenharmony_ci *
38c2ecf20Sopenharmony_ci * This file is provided under a dual BSD/GPLv2 license.  When using or
48c2ecf20Sopenharmony_ci * redistributing this file, you may do so under either license.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * GPL LICENSE SUMMARY
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Copyright(c) 2017 Intel Deutschland GmbH
98c2ecf20Sopenharmony_ci * Copyright(c) 2018 - 2020 Intel Corporation
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify
128c2ecf20Sopenharmony_ci * it under the terms of version 2 of the GNU General Public License as
138c2ecf20Sopenharmony_ci * published by the Free Software Foundation.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but
168c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of
178c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
188c2ecf20Sopenharmony_ci * General Public License for more details.
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci * BSD LICENSE
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci * Copyright(c) 2017 Intel Deutschland GmbH
238c2ecf20Sopenharmony_ci * Copyright(c) 2018 - 2020 Intel Corporation
248c2ecf20Sopenharmony_ci * All rights reserved.
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
278c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions
288c2ecf20Sopenharmony_ci * are met:
298c2ecf20Sopenharmony_ci *
308c2ecf20Sopenharmony_ci *  * Redistributions of source code must retain the above copyright
318c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer.
328c2ecf20Sopenharmony_ci *  * Redistributions in binary form must reproduce the above copyright
338c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer in
348c2ecf20Sopenharmony_ci *    the documentation and/or other materials provided with the
358c2ecf20Sopenharmony_ci *    distribution.
368c2ecf20Sopenharmony_ci *  * Neither the name Intel Corporation nor the names of its
378c2ecf20Sopenharmony_ci *    contributors may be used to endorse or promote products derived
388c2ecf20Sopenharmony_ci *    from this software without specific prior written permission.
398c2ecf20Sopenharmony_ci *
408c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
418c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
428c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
438c2ecf20Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
448c2ecf20Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
458c2ecf20Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
468c2ecf20Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
478c2ecf20Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
488c2ecf20Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
498c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
508c2ecf20Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
518c2ecf20Sopenharmony_ci *
528c2ecf20Sopenharmony_ci *****************************************************************************/
538c2ecf20Sopenharmony_ci#include "iwl-trans.h"
548c2ecf20Sopenharmony_ci#include "iwl-prph.h"
558c2ecf20Sopenharmony_ci#include "iwl-context-info.h"
568c2ecf20Sopenharmony_ci#include "iwl-context-info-gen3.h"
578c2ecf20Sopenharmony_ci#include "internal.h"
588c2ecf20Sopenharmony_ci#include "fw/dbg.h"
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci/*
618c2ecf20Sopenharmony_ci * Start up NIC's basic functionality after it has been reset
628c2ecf20Sopenharmony_ci * (e.g. after platform boot, or shutdown via iwl_pcie_apm_stop())
638c2ecf20Sopenharmony_ci * NOTE:  This does not load uCode nor start the embedded processor
648c2ecf20Sopenharmony_ci */
658c2ecf20Sopenharmony_ciint iwl_pcie_gen2_apm_init(struct iwl_trans *trans)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	int ret = 0;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	IWL_DEBUG_INFO(trans, "Init card's basic functions\n");
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	/*
728c2ecf20Sopenharmony_ci	 * Use "set_bit" below rather than "write", to preserve any hardware
738c2ecf20Sopenharmony_ci	 * bits already set by default after reset.
748c2ecf20Sopenharmony_ci	 */
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	/*
778c2ecf20Sopenharmony_ci	 * Disable L0s without affecting L1;
788c2ecf20Sopenharmony_ci	 * don't wait for ICH L0s (ICH bug W/A)
798c2ecf20Sopenharmony_ci	 */
808c2ecf20Sopenharmony_ci	iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS,
818c2ecf20Sopenharmony_ci		    CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	/* Set FH wait threshold to maximum (HW error during stress W/A) */
848c2ecf20Sopenharmony_ci	iwl_set_bit(trans, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	/*
878c2ecf20Sopenharmony_ci	 * Enable HAP INTA (interrupt from management bus) to
888c2ecf20Sopenharmony_ci	 * wake device's PCI Express link L1a -> L0s
898c2ecf20Sopenharmony_ci	 */
908c2ecf20Sopenharmony_ci	iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
918c2ecf20Sopenharmony_ci		    CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	iwl_pcie_apm_config(trans);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	ret = iwl_finish_nic_init(trans, trans->trans_cfg);
968c2ecf20Sopenharmony_ci	if (ret)
978c2ecf20Sopenharmony_ci		return ret;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	set_bit(STATUS_DEVICE_ENABLED, &trans->status);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	return 0;
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic void iwl_pcie_gen2_apm_stop(struct iwl_trans *trans, bool op_mode_leave)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	IWL_DEBUG_INFO(trans, "Stop card, put in low power state\n");
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	if (op_mode_leave) {
1098c2ecf20Sopenharmony_ci		if (!test_bit(STATUS_DEVICE_ENABLED, &trans->status))
1108c2ecf20Sopenharmony_ci			iwl_pcie_gen2_apm_init(trans);
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci		/* inform ME that we are leaving */
1138c2ecf20Sopenharmony_ci		iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
1148c2ecf20Sopenharmony_ci			    CSR_RESET_LINK_PWR_MGMT_DISABLED);
1158c2ecf20Sopenharmony_ci		iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
1168c2ecf20Sopenharmony_ci			    CSR_HW_IF_CONFIG_REG_PREPARE |
1178c2ecf20Sopenharmony_ci			    CSR_HW_IF_CONFIG_REG_ENABLE_PME);
1188c2ecf20Sopenharmony_ci		mdelay(1);
1198c2ecf20Sopenharmony_ci		iwl_clear_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
1208c2ecf20Sopenharmony_ci			      CSR_RESET_LINK_PWR_MGMT_DISABLED);
1218c2ecf20Sopenharmony_ci		mdelay(5);
1228c2ecf20Sopenharmony_ci	}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	clear_bit(STATUS_DEVICE_ENABLED, &trans->status);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	/* Stop device's DMA activity */
1278c2ecf20Sopenharmony_ci	iwl_pcie_apm_stop_master(trans);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	iwl_trans_sw_reset(trans);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	/*
1328c2ecf20Sopenharmony_ci	 * Clear "initialization complete" bit to move adapter from
1338c2ecf20Sopenharmony_ci	 * D0A* (powered-up Active) --> D0U* (Uninitialized) state.
1348c2ecf20Sopenharmony_ci	 */
1358c2ecf20Sopenharmony_ci	iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_civoid _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	lockdep_assert_held(&trans_pcie->mutex);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	if (trans_pcie->is_down)
1458c2ecf20Sopenharmony_ci		return;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	trans_pcie->is_down = true;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	/* tell the device to stop sending interrupts */
1508c2ecf20Sopenharmony_ci	iwl_disable_interrupts(trans);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	/* device going down, Stop using ICT table */
1538c2ecf20Sopenharmony_ci	iwl_pcie_disable_ict(trans);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	/*
1568c2ecf20Sopenharmony_ci	 * If a HW restart happens during firmware loading,
1578c2ecf20Sopenharmony_ci	 * then the firmware loading might call this function
1588c2ecf20Sopenharmony_ci	 * and later it might be called again due to the
1598c2ecf20Sopenharmony_ci	 * restart. So don't process again if the device is
1608c2ecf20Sopenharmony_ci	 * already dead.
1618c2ecf20Sopenharmony_ci	 */
1628c2ecf20Sopenharmony_ci	if (test_and_clear_bit(STATUS_DEVICE_ENABLED, &trans->status)) {
1638c2ecf20Sopenharmony_ci		IWL_DEBUG_INFO(trans,
1648c2ecf20Sopenharmony_ci			       "DEVICE_ENABLED bit was set and is now cleared\n");
1658c2ecf20Sopenharmony_ci		iwl_txq_gen2_tx_stop(trans);
1668c2ecf20Sopenharmony_ci		iwl_pcie_rx_stop(trans);
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	iwl_pcie_ctxt_info_free_paging(trans);
1708c2ecf20Sopenharmony_ci	if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)
1718c2ecf20Sopenharmony_ci		iwl_pcie_ctxt_info_gen3_free(trans);
1728c2ecf20Sopenharmony_ci	else
1738c2ecf20Sopenharmony_ci		iwl_pcie_ctxt_info_free(trans);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	/* Make sure (redundant) we've released our request to stay awake */
1768c2ecf20Sopenharmony_ci	iwl_clear_bit(trans, CSR_GP_CNTRL,
1778c2ecf20Sopenharmony_ci		      CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	/* Stop the device, and put it in low power state */
1808c2ecf20Sopenharmony_ci	iwl_pcie_gen2_apm_stop(trans, false);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	iwl_trans_sw_reset(trans);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	/*
1858c2ecf20Sopenharmony_ci	 * Upon stop, the IVAR table gets erased, so msi-x won't
1868c2ecf20Sopenharmony_ci	 * work. This causes a bug in RF-KILL flows, since the interrupt
1878c2ecf20Sopenharmony_ci	 * that enables radio won't fire on the correct irq, and the
1888c2ecf20Sopenharmony_ci	 * driver won't be able to handle the interrupt.
1898c2ecf20Sopenharmony_ci	 * Configure the IVAR table again after reset.
1908c2ecf20Sopenharmony_ci	 */
1918c2ecf20Sopenharmony_ci	iwl_pcie_conf_msix_hw(trans_pcie);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	/*
1948c2ecf20Sopenharmony_ci	 * Upon stop, the APM issues an interrupt if HW RF kill is set.
1958c2ecf20Sopenharmony_ci	 * This is a bug in certain verions of the hardware.
1968c2ecf20Sopenharmony_ci	 * Certain devices also keep sending HW RF kill interrupt all
1978c2ecf20Sopenharmony_ci	 * the time, unless the interrupt is ACKed even if the interrupt
1988c2ecf20Sopenharmony_ci	 * should be masked. Re-ACK all the interrupts here.
1998c2ecf20Sopenharmony_ci	 */
2008c2ecf20Sopenharmony_ci	iwl_disable_interrupts(trans);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	/* clear all status bits */
2038c2ecf20Sopenharmony_ci	clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
2048c2ecf20Sopenharmony_ci	clear_bit(STATUS_INT_ENABLED, &trans->status);
2058c2ecf20Sopenharmony_ci	clear_bit(STATUS_TPOWER_PMI, &trans->status);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	/*
2088c2ecf20Sopenharmony_ci	 * Even if we stop the HW, we still want the RF kill
2098c2ecf20Sopenharmony_ci	 * interrupt
2108c2ecf20Sopenharmony_ci	 */
2118c2ecf20Sopenharmony_ci	iwl_enable_rfkill_int(trans);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	/* re-take ownership to prevent other users from stealing the device */
2148c2ecf20Sopenharmony_ci	iwl_pcie_prepare_card_hw(trans);
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_civoid iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
2208c2ecf20Sopenharmony_ci	bool was_in_rfkill;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	mutex_lock(&trans_pcie->mutex);
2238c2ecf20Sopenharmony_ci	trans_pcie->opmode_down = true;
2248c2ecf20Sopenharmony_ci	was_in_rfkill = test_bit(STATUS_RFKILL_OPMODE, &trans->status);
2258c2ecf20Sopenharmony_ci	_iwl_trans_pcie_gen2_stop_device(trans);
2268c2ecf20Sopenharmony_ci	iwl_trans_pcie_handle_stop_rfkill(trans, was_in_rfkill);
2278c2ecf20Sopenharmony_ci	mutex_unlock(&trans_pcie->mutex);
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistatic int iwl_pcie_gen2_nic_init(struct iwl_trans *trans)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
2338c2ecf20Sopenharmony_ci	int queue_size = max_t(u32, IWL_CMD_QUEUE_SIZE,
2348c2ecf20Sopenharmony_ci			       trans->cfg->min_txq_size);
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	/* TODO: most of the logic can be removed in A0 - but not in Z0 */
2378c2ecf20Sopenharmony_ci	spin_lock(&trans_pcie->irq_lock);
2388c2ecf20Sopenharmony_ci	iwl_pcie_gen2_apm_init(trans);
2398c2ecf20Sopenharmony_ci	spin_unlock(&trans_pcie->irq_lock);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	iwl_op_mode_nic_config(trans->op_mode);
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	/* Allocate the RX queue, or reset if it is already allocated */
2448c2ecf20Sopenharmony_ci	if (iwl_pcie_gen2_rx_init(trans))
2458c2ecf20Sopenharmony_ci		return -ENOMEM;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	/* Allocate or reset and init all Tx and Command queues */
2488c2ecf20Sopenharmony_ci	if (iwl_txq_gen2_init(trans, trans->txqs.cmd.q_id, queue_size))
2498c2ecf20Sopenharmony_ci		return -ENOMEM;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	/* enable shadow regs in HW */
2528c2ecf20Sopenharmony_ci	iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL, 0x800FFFFF);
2538c2ecf20Sopenharmony_ci	IWL_DEBUG_INFO(trans, "Enabling shadow registers in device\n");
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	return 0;
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_civoid iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	iwl_pcie_reset_ict(trans);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	/* make sure all queue are not stopped/used */
2658c2ecf20Sopenharmony_ci	memset(trans->txqs.queue_stopped, 0,
2668c2ecf20Sopenharmony_ci	       sizeof(trans->txqs.queue_stopped));
2678c2ecf20Sopenharmony_ci	memset(trans->txqs.queue_used, 0, sizeof(trans->txqs.queue_used));
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	/* now that we got alive we can free the fw image & the context info.
2708c2ecf20Sopenharmony_ci	 * paging memory cannot be freed included since FW will still use it
2718c2ecf20Sopenharmony_ci	 */
2728c2ecf20Sopenharmony_ci	if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
2738c2ecf20Sopenharmony_ci		iwl_pcie_ctxt_info_free(trans);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	/*
2768c2ecf20Sopenharmony_ci	 * Re-enable all the interrupts, including the RF-Kill one, now that
2778c2ecf20Sopenharmony_ci	 * the firmware is alive.
2788c2ecf20Sopenharmony_ci	 */
2798c2ecf20Sopenharmony_ci	iwl_enable_interrupts(trans);
2808c2ecf20Sopenharmony_ci	mutex_lock(&trans_pcie->mutex);
2818c2ecf20Sopenharmony_ci	iwl_pcie_check_hw_rf_kill(trans);
2828c2ecf20Sopenharmony_ci	mutex_unlock(&trans_pcie->mutex);
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_cistatic void iwl_pcie_set_ltr(struct iwl_trans *trans)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci	u32 ltr_val = CSR_LTR_LONG_VAL_AD_NO_SNOOP_REQ |
2888c2ecf20Sopenharmony_ci		      u32_encode_bits(CSR_LTR_LONG_VAL_AD_SCALE_USEC,
2898c2ecf20Sopenharmony_ci				      CSR_LTR_LONG_VAL_AD_NO_SNOOP_SCALE) |
2908c2ecf20Sopenharmony_ci		      u32_encode_bits(250,
2918c2ecf20Sopenharmony_ci				      CSR_LTR_LONG_VAL_AD_NO_SNOOP_VAL) |
2928c2ecf20Sopenharmony_ci		      CSR_LTR_LONG_VAL_AD_SNOOP_REQ |
2938c2ecf20Sopenharmony_ci		      u32_encode_bits(CSR_LTR_LONG_VAL_AD_SCALE_USEC,
2948c2ecf20Sopenharmony_ci				      CSR_LTR_LONG_VAL_AD_SNOOP_SCALE) |
2958c2ecf20Sopenharmony_ci		      u32_encode_bits(250, CSR_LTR_LONG_VAL_AD_SNOOP_VAL);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	/*
2988c2ecf20Sopenharmony_ci	 * To workaround hardware latency issues during the boot process,
2998c2ecf20Sopenharmony_ci	 * initialize the LTR to ~250 usec (see ltr_val above).
3008c2ecf20Sopenharmony_ci	 * The firmware initializes this again later (to a smaller value).
3018c2ecf20Sopenharmony_ci	 */
3028c2ecf20Sopenharmony_ci	if ((trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_AX210 ||
3038c2ecf20Sopenharmony_ci	     trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_22000) &&
3048c2ecf20Sopenharmony_ci	    !trans->trans_cfg->integrated) {
3058c2ecf20Sopenharmony_ci		iwl_write32(trans, CSR_LTR_LONG_VAL_AD, ltr_val);
3068c2ecf20Sopenharmony_ci	} else if (trans->trans_cfg->integrated &&
3078c2ecf20Sopenharmony_ci		   trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_22000) {
3088c2ecf20Sopenharmony_ci		iwl_write_prph(trans, HPM_MAC_LTR_CSR, HPM_MAC_LRT_ENABLE_ALL);
3098c2ecf20Sopenharmony_ci		iwl_write_prph(trans, HPM_UMAC_LTR, ltr_val);
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ciint iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans,
3148c2ecf20Sopenharmony_ci				 const struct fw_img *fw, bool run_in_rfkill)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
3178c2ecf20Sopenharmony_ci	bool hw_rfkill;
3188c2ecf20Sopenharmony_ci	int ret;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	/* This may fail if AMT took ownership of the device */
3218c2ecf20Sopenharmony_ci	if (iwl_pcie_prepare_card_hw(trans)) {
3228c2ecf20Sopenharmony_ci		IWL_WARN(trans, "Exit HW not ready\n");
3238c2ecf20Sopenharmony_ci		return -EIO;
3248c2ecf20Sopenharmony_ci	}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	iwl_enable_rfkill_int(trans);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	/*
3318c2ecf20Sopenharmony_ci	 * We enabled the RF-Kill interrupt and the handler may very
3328c2ecf20Sopenharmony_ci	 * well be running. Disable the interrupts to make sure no other
3338c2ecf20Sopenharmony_ci	 * interrupt can be fired.
3348c2ecf20Sopenharmony_ci	 */
3358c2ecf20Sopenharmony_ci	iwl_disable_interrupts(trans);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	/* Make sure it finished running */
3388c2ecf20Sopenharmony_ci	iwl_pcie_synchronize_irqs(trans);
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	mutex_lock(&trans_pcie->mutex);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	/* If platform's RF_KILL switch is NOT set to KILL */
3438c2ecf20Sopenharmony_ci	hw_rfkill = iwl_pcie_check_hw_rf_kill(trans);
3448c2ecf20Sopenharmony_ci	if (hw_rfkill && !run_in_rfkill) {
3458c2ecf20Sopenharmony_ci		ret = -ERFKILL;
3468c2ecf20Sopenharmony_ci		goto out;
3478c2ecf20Sopenharmony_ci	}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	/* Someone called stop_device, don't try to start_fw */
3508c2ecf20Sopenharmony_ci	if (trans_pcie->is_down) {
3518c2ecf20Sopenharmony_ci		IWL_WARN(trans,
3528c2ecf20Sopenharmony_ci			 "Can't start_fw since the HW hasn't been started\n");
3538c2ecf20Sopenharmony_ci		ret = -EIO;
3548c2ecf20Sopenharmony_ci		goto out;
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	/* make sure rfkill handshake bits are cleared */
3588c2ecf20Sopenharmony_ci	iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
3598c2ecf20Sopenharmony_ci	iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR,
3608c2ecf20Sopenharmony_ci		    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	/* clear (again), then enable host interrupts */
3638c2ecf20Sopenharmony_ci	iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	ret = iwl_pcie_gen2_nic_init(trans);
3668c2ecf20Sopenharmony_ci	if (ret) {
3678c2ecf20Sopenharmony_ci		IWL_ERR(trans, "Unable to init nic\n");
3688c2ecf20Sopenharmony_ci		goto out;
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)
3728c2ecf20Sopenharmony_ci		ret = iwl_pcie_ctxt_info_gen3_init(trans, fw);
3738c2ecf20Sopenharmony_ci	else
3748c2ecf20Sopenharmony_ci		ret = iwl_pcie_ctxt_info_init(trans, fw);
3758c2ecf20Sopenharmony_ci	if (ret)
3768c2ecf20Sopenharmony_ci		goto out;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	iwl_pcie_set_ltr(trans);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)
3818c2ecf20Sopenharmony_ci		iwl_write_umac_prph(trans, UREG_CPU_INIT_RUN, 1);
3828c2ecf20Sopenharmony_ci	else
3838c2ecf20Sopenharmony_ci		iwl_write_prph(trans, UREG_CPU_INIT_RUN, 1);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	/* re-check RF-Kill state since we may have missed the interrupt */
3868c2ecf20Sopenharmony_ci	hw_rfkill = iwl_pcie_check_hw_rf_kill(trans);
3878c2ecf20Sopenharmony_ci	if (hw_rfkill && !run_in_rfkill)
3888c2ecf20Sopenharmony_ci		ret = -ERFKILL;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ciout:
3918c2ecf20Sopenharmony_ci	mutex_unlock(&trans_pcie->mutex);
3928c2ecf20Sopenharmony_ci	return ret;
3938c2ecf20Sopenharmony_ci}
394