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) 2013 - 2015 Intel Mobile Communications GmbH 98c2ecf20Sopenharmony_ci * Copyright(c) 2016 - 2017 Intel Deutschland GmbH 108c2ecf20Sopenharmony_ci * Copyright(c) 2012 - 2014, 2018 - 2020 Intel Corporation 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 138c2ecf20Sopenharmony_ci * it under the terms of version 2 of the GNU General Public License as 148c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but 178c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 188c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 198c2ecf20Sopenharmony_ci * General Public License for more details. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * The full GNU General Public License is included in this distribution 228c2ecf20Sopenharmony_ci * in the file called COPYING. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * Contact Information: 258c2ecf20Sopenharmony_ci * Intel Linux Wireless <linuxwifi@intel.com> 268c2ecf20Sopenharmony_ci * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci * BSD LICENSE 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH 318c2ecf20Sopenharmony_ci * Copyright(c) 2016 - 2017 Intel Deutschland GmbH 328c2ecf20Sopenharmony_ci * Copyright(c) 2012 - 2014, 2018 - 2020 Intel Corporation 338c2ecf20Sopenharmony_ci * All rights reserved. 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 368c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 378c2ecf20Sopenharmony_ci * are met: 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci * * Redistributions of source code must retain the above copyright 408c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 418c2ecf20Sopenharmony_ci * * Redistributions in binary form must reproduce the above copyright 428c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in 438c2ecf20Sopenharmony_ci * the documentation and/or other materials provided with the 448c2ecf20Sopenharmony_ci * distribution. 458c2ecf20Sopenharmony_ci * * Neither the name Intel Corporation nor the names of its 468c2ecf20Sopenharmony_ci * contributors may be used to endorse or promote products derived 478c2ecf20Sopenharmony_ci * from this software without specific prior written permission. 488c2ecf20Sopenharmony_ci * 498c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 508c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 518c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 528c2ecf20Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 538c2ecf20Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 548c2ecf20Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 558c2ecf20Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 568c2ecf20Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 578c2ecf20Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 588c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 598c2ecf20Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 608c2ecf20Sopenharmony_ci * 618c2ecf20Sopenharmony_ci *****************************************************************************/ 628c2ecf20Sopenharmony_ci#include <net/mac80211.h> 638c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#include "iwl-trans.h" 668c2ecf20Sopenharmony_ci#include "iwl-op-mode.h" 678c2ecf20Sopenharmony_ci#include "fw/img.h" 688c2ecf20Sopenharmony_ci#include "iwl-debug.h" 698c2ecf20Sopenharmony_ci#include "iwl-csr.h" /* for iwl_mvm_rx_card_state_notif */ 708c2ecf20Sopenharmony_ci#include "iwl-io.h" /* for iwl_mvm_rx_card_state_notif */ 718c2ecf20Sopenharmony_ci#include "iwl-prph.h" 728c2ecf20Sopenharmony_ci#include "fw/acpi.h" 738c2ecf20Sopenharmony_ci#include "fw/pnvm.h" 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci#include "mvm.h" 768c2ecf20Sopenharmony_ci#include "fw/dbg.h" 778c2ecf20Sopenharmony_ci#include "iwl-phy-db.h" 788c2ecf20Sopenharmony_ci#include "iwl-modparams.h" 798c2ecf20Sopenharmony_ci#include "iwl-nvm-parse.h" 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci#define MVM_UCODE_ALIVE_TIMEOUT (HZ) 828c2ecf20Sopenharmony_ci#define MVM_UCODE_CALIB_TIMEOUT (2 * HZ) 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#define UCODE_VALID_OK cpu_to_le32(0x1) 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistruct iwl_mvm_alive_data { 878c2ecf20Sopenharmony_ci bool valid; 888c2ecf20Sopenharmony_ci u32 scd_base_addr; 898c2ecf20Sopenharmony_ci}; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic int iwl_send_tx_ant_cfg(struct iwl_mvm *mvm, u8 valid_tx_ant) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci struct iwl_tx_ant_cfg_cmd tx_ant_cmd = { 948c2ecf20Sopenharmony_ci .valid = cpu_to_le32(valid_tx_ant), 958c2ecf20Sopenharmony_ci }; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci IWL_DEBUG_FW(mvm, "select valid tx ant: %u\n", valid_tx_ant); 988c2ecf20Sopenharmony_ci return iwl_mvm_send_cmd_pdu(mvm, TX_ANT_CONFIGURATION_CMD, 0, 998c2ecf20Sopenharmony_ci sizeof(tx_ant_cmd), &tx_ant_cmd); 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic int iwl_send_rss_cfg_cmd(struct iwl_mvm *mvm) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci int i; 1058c2ecf20Sopenharmony_ci struct iwl_rss_config_cmd cmd = { 1068c2ecf20Sopenharmony_ci .flags = cpu_to_le32(IWL_RSS_ENABLE), 1078c2ecf20Sopenharmony_ci .hash_mask = BIT(IWL_RSS_HASH_TYPE_IPV4_TCP) | 1088c2ecf20Sopenharmony_ci BIT(IWL_RSS_HASH_TYPE_IPV4_UDP) | 1098c2ecf20Sopenharmony_ci BIT(IWL_RSS_HASH_TYPE_IPV4_PAYLOAD) | 1108c2ecf20Sopenharmony_ci BIT(IWL_RSS_HASH_TYPE_IPV6_TCP) | 1118c2ecf20Sopenharmony_ci BIT(IWL_RSS_HASH_TYPE_IPV6_UDP) | 1128c2ecf20Sopenharmony_ci BIT(IWL_RSS_HASH_TYPE_IPV6_PAYLOAD), 1138c2ecf20Sopenharmony_ci }; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (mvm->trans->num_rx_queues == 1) 1168c2ecf20Sopenharmony_ci return 0; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* Do not direct RSS traffic to Q 0 which is our fallback queue */ 1198c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cmd.indirection_table); i++) 1208c2ecf20Sopenharmony_ci cmd.indirection_table[i] = 1218c2ecf20Sopenharmony_ci 1 + (i % (mvm->trans->num_rx_queues - 1)); 1228c2ecf20Sopenharmony_ci netdev_rss_key_fill(cmd.secret_key, sizeof(cmd.secret_key)); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci return iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0, sizeof(cmd), &cmd); 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic int iwl_configure_rxq(struct iwl_mvm *mvm) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci int i, num_queues, size, ret; 1308c2ecf20Sopenharmony_ci struct iwl_rfh_queue_config *cmd; 1318c2ecf20Sopenharmony_ci struct iwl_host_cmd hcmd = { 1328c2ecf20Sopenharmony_ci .id = WIDE_ID(DATA_PATH_GROUP, RFH_QUEUE_CONFIG_CMD), 1338c2ecf20Sopenharmony_ci .dataflags[0] = IWL_HCMD_DFL_NOCOPY, 1348c2ecf20Sopenharmony_ci }; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci /* 1378c2ecf20Sopenharmony_ci * The default queue is configured via context info, so if we 1388c2ecf20Sopenharmony_ci * have a single queue, there's nothing to do here. 1398c2ecf20Sopenharmony_ci */ 1408c2ecf20Sopenharmony_ci if (mvm->trans->num_rx_queues == 1) 1418c2ecf20Sopenharmony_ci return 0; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* skip the default queue */ 1448c2ecf20Sopenharmony_ci num_queues = mvm->trans->num_rx_queues - 1; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci size = struct_size(cmd, data, num_queues); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci cmd = kzalloc(size, GFP_KERNEL); 1498c2ecf20Sopenharmony_ci if (!cmd) 1508c2ecf20Sopenharmony_ci return -ENOMEM; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci cmd->num_queues = num_queues; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci for (i = 0; i < num_queues; i++) { 1558c2ecf20Sopenharmony_ci struct iwl_trans_rxq_dma_data data; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci cmd->data[i].q_num = i + 1; 1588c2ecf20Sopenharmony_ci iwl_trans_get_rxq_dma_data(mvm->trans, i + 1, &data); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci cmd->data[i].fr_bd_cb = cpu_to_le64(data.fr_bd_cb); 1618c2ecf20Sopenharmony_ci cmd->data[i].urbd_stts_wrptr = 1628c2ecf20Sopenharmony_ci cpu_to_le64(data.urbd_stts_wrptr); 1638c2ecf20Sopenharmony_ci cmd->data[i].ur_bd_cb = cpu_to_le64(data.ur_bd_cb); 1648c2ecf20Sopenharmony_ci cmd->data[i].fr_bd_wid = cpu_to_le32(data.fr_bd_wid); 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci hcmd.data[0] = cmd; 1688c2ecf20Sopenharmony_ci hcmd.len[0] = size; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci ret = iwl_mvm_send_cmd(mvm, &hcmd); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci kfree(cmd); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci return ret; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic int iwl_mvm_send_dqa_cmd(struct iwl_mvm *mvm) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci struct iwl_dqa_enable_cmd dqa_cmd = { 1808c2ecf20Sopenharmony_ci .cmd_queue = cpu_to_le32(IWL_MVM_DQA_CMD_QUEUE), 1818c2ecf20Sopenharmony_ci }; 1828c2ecf20Sopenharmony_ci u32 cmd_id = iwl_cmd_id(DQA_ENABLE_CMD, DATA_PATH_GROUP, 0); 1838c2ecf20Sopenharmony_ci int ret; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(dqa_cmd), &dqa_cmd); 1868c2ecf20Sopenharmony_ci if (ret) 1878c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Failed to send DQA enabling command: %d\n", ret); 1888c2ecf20Sopenharmony_ci else 1898c2ecf20Sopenharmony_ci IWL_DEBUG_FW(mvm, "Working in DQA mode\n"); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci return ret; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_civoid iwl_mvm_mfu_assert_dump_notif(struct iwl_mvm *mvm, 1958c2ecf20Sopenharmony_ci struct iwl_rx_cmd_buffer *rxb) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci struct iwl_rx_packet *pkt = rxb_addr(rxb); 1988c2ecf20Sopenharmony_ci struct iwl_mfu_assert_dump_notif *mfu_dump_notif = (void *)pkt->data; 1998c2ecf20Sopenharmony_ci __le32 *dump_data = mfu_dump_notif->data; 2008c2ecf20Sopenharmony_ci int n_words = le32_to_cpu(mfu_dump_notif->data_size) / sizeof(__le32); 2018c2ecf20Sopenharmony_ci int i; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (mfu_dump_notif->index_num == 0) 2048c2ecf20Sopenharmony_ci IWL_INFO(mvm, "MFUART assert id 0x%x occurred\n", 2058c2ecf20Sopenharmony_ci le32_to_cpu(mfu_dump_notif->assert_id)); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci for (i = 0; i < n_words; i++) 2088c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(mvm, 2098c2ecf20Sopenharmony_ci "MFUART assert dump, dword %u: 0x%08x\n", 2108c2ecf20Sopenharmony_ci le16_to_cpu(mfu_dump_notif->index_num) * 2118c2ecf20Sopenharmony_ci n_words + i, 2128c2ecf20Sopenharmony_ci le32_to_cpu(dump_data[i])); 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, 2168c2ecf20Sopenharmony_ci struct iwl_rx_packet *pkt, void *data) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct iwl_mvm *mvm = 2198c2ecf20Sopenharmony_ci container_of(notif_wait, struct iwl_mvm, notif_wait); 2208c2ecf20Sopenharmony_ci struct iwl_mvm_alive_data *alive_data = data; 2218c2ecf20Sopenharmony_ci struct iwl_umac_alive *umac; 2228c2ecf20Sopenharmony_ci struct iwl_lmac_alive *lmac1; 2238c2ecf20Sopenharmony_ci struct iwl_lmac_alive *lmac2 = NULL; 2248c2ecf20Sopenharmony_ci u16 status; 2258c2ecf20Sopenharmony_ci u32 lmac_error_event_table, umac_error_table; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* 2288c2ecf20Sopenharmony_ci * For v5 and above, we can check the version, for older 2298c2ecf20Sopenharmony_ci * versions we need to check the size. 2308c2ecf20Sopenharmony_ci */ 2318c2ecf20Sopenharmony_ci if (iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, 2328c2ecf20Sopenharmony_ci UCODE_ALIVE_NTFY, 0) == 5) { 2338c2ecf20Sopenharmony_ci struct iwl_alive_ntf_v5 *palive; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci palive = (void *)pkt->data; 2368c2ecf20Sopenharmony_ci umac = &palive->umac_data; 2378c2ecf20Sopenharmony_ci lmac1 = &palive->lmac_data[0]; 2388c2ecf20Sopenharmony_ci lmac2 = &palive->lmac_data[1]; 2398c2ecf20Sopenharmony_ci status = le16_to_cpu(palive->status); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci mvm->trans->sku_id[0] = le32_to_cpu(palive->sku_id.data[0]); 2428c2ecf20Sopenharmony_ci mvm->trans->sku_id[1] = le32_to_cpu(palive->sku_id.data[1]); 2438c2ecf20Sopenharmony_ci mvm->trans->sku_id[2] = le32_to_cpu(palive->sku_id.data[2]); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci IWL_DEBUG_FW(mvm, "Got sku_id: 0x0%x 0x0%x 0x0%x\n", 2468c2ecf20Sopenharmony_ci mvm->trans->sku_id[0], 2478c2ecf20Sopenharmony_ci mvm->trans->sku_id[1], 2488c2ecf20Sopenharmony_ci mvm->trans->sku_id[2]); 2498c2ecf20Sopenharmony_ci } else if (iwl_rx_packet_payload_len(pkt) == sizeof(struct iwl_alive_ntf_v4)) { 2508c2ecf20Sopenharmony_ci struct iwl_alive_ntf_v4 *palive; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci palive = (void *)pkt->data; 2538c2ecf20Sopenharmony_ci umac = &palive->umac_data; 2548c2ecf20Sopenharmony_ci lmac1 = &palive->lmac_data[0]; 2558c2ecf20Sopenharmony_ci lmac2 = &palive->lmac_data[1]; 2568c2ecf20Sopenharmony_ci status = le16_to_cpu(palive->status); 2578c2ecf20Sopenharmony_ci } else if (iwl_rx_packet_payload_len(pkt) == 2588c2ecf20Sopenharmony_ci sizeof(struct iwl_alive_ntf_v3)) { 2598c2ecf20Sopenharmony_ci struct iwl_alive_ntf_v3 *palive3; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci palive3 = (void *)pkt->data; 2628c2ecf20Sopenharmony_ci umac = &palive3->umac_data; 2638c2ecf20Sopenharmony_ci lmac1 = &palive3->lmac_data; 2648c2ecf20Sopenharmony_ci status = le16_to_cpu(palive3->status); 2658c2ecf20Sopenharmony_ci } else { 2668c2ecf20Sopenharmony_ci WARN(1, "unsupported alive notification (size %d)\n", 2678c2ecf20Sopenharmony_ci iwl_rx_packet_payload_len(pkt)); 2688c2ecf20Sopenharmony_ci /* get timeout later */ 2698c2ecf20Sopenharmony_ci return false; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci lmac_error_event_table = 2738c2ecf20Sopenharmony_ci le32_to_cpu(lmac1->dbg_ptrs.error_event_table_ptr); 2748c2ecf20Sopenharmony_ci iwl_fw_lmac1_set_alive_err_table(mvm->trans, lmac_error_event_table); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (lmac2) 2778c2ecf20Sopenharmony_ci mvm->trans->dbg.lmac_error_event_table[1] = 2788c2ecf20Sopenharmony_ci le32_to_cpu(lmac2->dbg_ptrs.error_event_table_ptr); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci umac_error_table = le32_to_cpu(umac->dbg_ptrs.error_info_addr); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (umac_error_table) { 2838c2ecf20Sopenharmony_ci if (umac_error_table >= 2848c2ecf20Sopenharmony_ci mvm->trans->cfg->min_umac_error_event_table) { 2858c2ecf20Sopenharmony_ci iwl_fw_umac_set_alive_err_table(mvm->trans, 2868c2ecf20Sopenharmony_ci umac_error_table); 2878c2ecf20Sopenharmony_ci } else { 2888c2ecf20Sopenharmony_ci IWL_ERR(mvm, 2898c2ecf20Sopenharmony_ci "Not valid error log pointer 0x%08X for %s uCode\n", 2908c2ecf20Sopenharmony_ci umac_error_table, 2918c2ecf20Sopenharmony_ci (mvm->fwrt.cur_fw_img == IWL_UCODE_INIT) ? 2928c2ecf20Sopenharmony_ci "Init" : "RT"); 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci alive_data->scd_base_addr = le32_to_cpu(lmac1->dbg_ptrs.scd_base_ptr); 2978c2ecf20Sopenharmony_ci alive_data->valid = status == IWL_ALIVE_STATUS_OK; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci IWL_DEBUG_FW(mvm, 3008c2ecf20Sopenharmony_ci "Alive ucode status 0x%04x revision 0x%01X 0x%01X\n", 3018c2ecf20Sopenharmony_ci status, lmac1->ver_type, lmac1->ver_subtype); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (lmac2) 3048c2ecf20Sopenharmony_ci IWL_DEBUG_FW(mvm, "Alive ucode CDB\n"); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci IWL_DEBUG_FW(mvm, 3078c2ecf20Sopenharmony_ci "UMAC version: Major - 0x%x, Minor - 0x%x\n", 3088c2ecf20Sopenharmony_ci le32_to_cpu(umac->umac_major), 3098c2ecf20Sopenharmony_ci le32_to_cpu(umac->umac_minor)); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci iwl_fwrt_update_fw_versions(&mvm->fwrt, lmac1, umac); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci return true; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic bool iwl_wait_init_complete(struct iwl_notif_wait_data *notif_wait, 3178c2ecf20Sopenharmony_ci struct iwl_rx_packet *pkt, void *data) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci WARN_ON(pkt->hdr.cmd != INIT_COMPLETE_NOTIF); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci return true; 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic bool iwl_wait_phy_db_entry(struct iwl_notif_wait_data *notif_wait, 3258c2ecf20Sopenharmony_ci struct iwl_rx_packet *pkt, void *data) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci struct iwl_phy_db *phy_db = data; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (pkt->hdr.cmd != CALIB_RES_NOTIF_PHY_DB) { 3308c2ecf20Sopenharmony_ci WARN_ON(pkt->hdr.cmd != INIT_COMPLETE_NOTIF); 3318c2ecf20Sopenharmony_ci return true; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci WARN_ON(iwl_phy_db_set_section(phy_db, pkt)); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci return false; 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, 3408c2ecf20Sopenharmony_ci enum iwl_ucode_type ucode_type) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci struct iwl_notification_wait alive_wait; 3438c2ecf20Sopenharmony_ci struct iwl_mvm_alive_data alive_data = {}; 3448c2ecf20Sopenharmony_ci const struct fw_img *fw; 3458c2ecf20Sopenharmony_ci int ret; 3468c2ecf20Sopenharmony_ci enum iwl_ucode_type old_type = mvm->fwrt.cur_fw_img; 3478c2ecf20Sopenharmony_ci static const u16 alive_cmd[] = { UCODE_ALIVE_NTFY }; 3488c2ecf20Sopenharmony_ci bool run_in_rfkill = 3498c2ecf20Sopenharmony_ci ucode_type == IWL_UCODE_INIT || iwl_mvm_has_unified_ucode(mvm); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (ucode_type == IWL_UCODE_REGULAR && 3528c2ecf20Sopenharmony_ci iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_START_FROM_ALIVE) && 3538c2ecf20Sopenharmony_ci !(fw_has_capa(&mvm->fw->ucode_capa, 3548c2ecf20Sopenharmony_ci IWL_UCODE_TLV_CAPA_USNIFFER_UNIFIED))) 3558c2ecf20Sopenharmony_ci fw = iwl_get_ucode_image(mvm->fw, IWL_UCODE_REGULAR_USNIFFER); 3568c2ecf20Sopenharmony_ci else 3578c2ecf20Sopenharmony_ci fw = iwl_get_ucode_image(mvm->fw, ucode_type); 3588c2ecf20Sopenharmony_ci if (WARN_ON(!fw)) 3598c2ecf20Sopenharmony_ci return -EINVAL; 3608c2ecf20Sopenharmony_ci iwl_fw_set_current_image(&mvm->fwrt, ucode_type); 3618c2ecf20Sopenharmony_ci clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci iwl_init_notification_wait(&mvm->notif_wait, &alive_wait, 3648c2ecf20Sopenharmony_ci alive_cmd, ARRAY_SIZE(alive_cmd), 3658c2ecf20Sopenharmony_ci iwl_alive_fn, &alive_data); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci /* 3688c2ecf20Sopenharmony_ci * We want to load the INIT firmware even in RFKILL 3698c2ecf20Sopenharmony_ci * For the unified firmware case, the ucode_type is not 3708c2ecf20Sopenharmony_ci * INIT, but we still need to run it. 3718c2ecf20Sopenharmony_ci */ 3728c2ecf20Sopenharmony_ci ret = iwl_trans_start_fw(mvm->trans, fw, run_in_rfkill); 3738c2ecf20Sopenharmony_ci if (ret) { 3748c2ecf20Sopenharmony_ci iwl_fw_set_current_image(&mvm->fwrt, old_type); 3758c2ecf20Sopenharmony_ci iwl_remove_notification(&mvm->notif_wait, &alive_wait); 3768c2ecf20Sopenharmony_ci return ret; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci /* 3808c2ecf20Sopenharmony_ci * Some things may run in the background now, but we 3818c2ecf20Sopenharmony_ci * just wait for the ALIVE notification here. 3828c2ecf20Sopenharmony_ci */ 3838c2ecf20Sopenharmony_ci ret = iwl_wait_notification(&mvm->notif_wait, &alive_wait, 3848c2ecf20Sopenharmony_ci MVM_UCODE_ALIVE_TIMEOUT); 3858c2ecf20Sopenharmony_ci if (ret) { 3868c2ecf20Sopenharmony_ci struct iwl_trans *trans = mvm->trans; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (trans->trans_cfg->device_family >= 3898c2ecf20Sopenharmony_ci IWL_DEVICE_FAMILY_22000) { 3908c2ecf20Sopenharmony_ci IWL_ERR(mvm, 3918c2ecf20Sopenharmony_ci "SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n", 3928c2ecf20Sopenharmony_ci iwl_read_umac_prph(trans, UMAG_SB_CPU_1_STATUS), 3938c2ecf20Sopenharmony_ci iwl_read_umac_prph(trans, 3948c2ecf20Sopenharmony_ci UMAG_SB_CPU_2_STATUS)); 3958c2ecf20Sopenharmony_ci IWL_ERR(mvm, "UMAC PC: 0x%x\n", 3968c2ecf20Sopenharmony_ci iwl_read_umac_prph(trans, 3978c2ecf20Sopenharmony_ci UREG_UMAC_CURRENT_PC)); 3988c2ecf20Sopenharmony_ci IWL_ERR(mvm, "LMAC PC: 0x%x\n", 3998c2ecf20Sopenharmony_ci iwl_read_umac_prph(trans, 4008c2ecf20Sopenharmony_ci UREG_LMAC1_CURRENT_PC)); 4018c2ecf20Sopenharmony_ci if (iwl_mvm_is_cdb_supported(mvm)) 4028c2ecf20Sopenharmony_ci IWL_ERR(mvm, "LMAC2 PC: 0x%x\n", 4038c2ecf20Sopenharmony_ci iwl_read_umac_prph(trans, 4048c2ecf20Sopenharmony_ci UREG_LMAC2_CURRENT_PC)); 4058c2ecf20Sopenharmony_ci } else if (trans->trans_cfg->device_family >= 4068c2ecf20Sopenharmony_ci IWL_DEVICE_FAMILY_8000) { 4078c2ecf20Sopenharmony_ci IWL_ERR(mvm, 4088c2ecf20Sopenharmony_ci "SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n", 4098c2ecf20Sopenharmony_ci iwl_read_prph(trans, SB_CPU_1_STATUS), 4108c2ecf20Sopenharmony_ci iwl_read_prph(trans, SB_CPU_2_STATUS)); 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (ret == -ETIMEDOUT) 4148c2ecf20Sopenharmony_ci iwl_fw_dbg_error_collect(&mvm->fwrt, 4158c2ecf20Sopenharmony_ci FW_DBG_TRIGGER_ALIVE_TIMEOUT); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci iwl_fw_set_current_image(&mvm->fwrt, old_type); 4188c2ecf20Sopenharmony_ci return ret; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (!alive_data.valid) { 4228c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Loaded ucode is not valid!\n"); 4238c2ecf20Sopenharmony_ci iwl_fw_set_current_image(&mvm->fwrt, old_type); 4248c2ecf20Sopenharmony_ci return -EIO; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci ret = iwl_pnvm_load(mvm->trans, &mvm->notif_wait); 4288c2ecf20Sopenharmony_ci if (ret) { 4298c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Timeout waiting for PNVM load!\n"); 4308c2ecf20Sopenharmony_ci iwl_fw_set_current_image(&mvm->fwrt, old_type); 4318c2ecf20Sopenharmony_ci return ret; 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci iwl_trans_fw_alive(mvm->trans, alive_data.scd_base_addr); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci /* 4378c2ecf20Sopenharmony_ci * Note: all the queues are enabled as part of the interface 4388c2ecf20Sopenharmony_ci * initialization, but in firmware restart scenarios they 4398c2ecf20Sopenharmony_ci * could be stopped, so wake them up. In firmware restart, 4408c2ecf20Sopenharmony_ci * mac80211 will have the queues stopped as well until the 4418c2ecf20Sopenharmony_ci * reconfiguration completes. During normal startup, they 4428c2ecf20Sopenharmony_ci * will be empty. 4438c2ecf20Sopenharmony_ci */ 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci memset(&mvm->queue_info, 0, sizeof(mvm->queue_info)); 4468c2ecf20Sopenharmony_ci /* 4478c2ecf20Sopenharmony_ci * Set a 'fake' TID for the command queue, since we use the 4488c2ecf20Sopenharmony_ci * hweight() of the tid_bitmap as a refcount now. Not that 4498c2ecf20Sopenharmony_ci * we ever even consider the command queue as one we might 4508c2ecf20Sopenharmony_ci * want to reuse, but be safe nevertheless. 4518c2ecf20Sopenharmony_ci */ 4528c2ecf20Sopenharmony_ci mvm->queue_info[IWL_MVM_DQA_CMD_QUEUE].tid_bitmap = 4538c2ecf20Sopenharmony_ci BIT(IWL_MAX_TID_COUNT + 2); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci set_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); 4568c2ecf20Sopenharmony_ci#ifdef CONFIG_IWLWIFI_DEBUGFS 4578c2ecf20Sopenharmony_ci iwl_fw_set_dbg_rec_on(&mvm->fwrt); 4588c2ecf20Sopenharmony_ci#endif 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci return 0; 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci struct iwl_notification_wait init_wait; 4668c2ecf20Sopenharmony_ci struct iwl_nvm_access_complete_cmd nvm_complete = {}; 4678c2ecf20Sopenharmony_ci struct iwl_init_extended_cfg_cmd init_cfg = { 4688c2ecf20Sopenharmony_ci .init_flags = cpu_to_le32(BIT(IWL_INIT_NVM)), 4698c2ecf20Sopenharmony_ci }; 4708c2ecf20Sopenharmony_ci static const u16 init_complete[] = { 4718c2ecf20Sopenharmony_ci INIT_COMPLETE_NOTIF, 4728c2ecf20Sopenharmony_ci }; 4738c2ecf20Sopenharmony_ci int ret; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci if (mvm->trans->cfg->tx_with_siso_diversity) 4768c2ecf20Sopenharmony_ci init_cfg.init_flags |= cpu_to_le32(BIT(IWL_INIT_PHY)); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci lockdep_assert_held(&mvm->mutex); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci mvm->rfkill_safe_init_done = false; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci iwl_init_notification_wait(&mvm->notif_wait, 4838c2ecf20Sopenharmony_ci &init_wait, 4848c2ecf20Sopenharmony_ci init_complete, 4858c2ecf20Sopenharmony_ci ARRAY_SIZE(init_complete), 4868c2ecf20Sopenharmony_ci iwl_wait_init_complete, 4878c2ecf20Sopenharmony_ci NULL); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_EARLY, NULL); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci /* Will also start the device */ 4928c2ecf20Sopenharmony_ci ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_REGULAR); 4938c2ecf20Sopenharmony_ci if (ret) { 4948c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Failed to start RT ucode: %d\n", ret); 4958c2ecf20Sopenharmony_ci goto error; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_AFTER_ALIVE, 4988c2ecf20Sopenharmony_ci NULL); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci /* Send init config command to mark that we are sending NVM access 5018c2ecf20Sopenharmony_ci * commands 5028c2ecf20Sopenharmony_ci */ 5038c2ecf20Sopenharmony_ci ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(SYSTEM_GROUP, 5048c2ecf20Sopenharmony_ci INIT_EXTENDED_CFG_CMD), 5058c2ecf20Sopenharmony_ci CMD_SEND_IN_RFKILL, 5068c2ecf20Sopenharmony_ci sizeof(init_cfg), &init_cfg); 5078c2ecf20Sopenharmony_ci if (ret) { 5088c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Failed to run init config command: %d\n", 5098c2ecf20Sopenharmony_ci ret); 5108c2ecf20Sopenharmony_ci goto error; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci /* Load NVM to NIC if needed */ 5148c2ecf20Sopenharmony_ci if (mvm->nvm_file_name) { 5158c2ecf20Sopenharmony_ci iwl_read_external_nvm(mvm->trans, mvm->nvm_file_name, 5168c2ecf20Sopenharmony_ci mvm->nvm_sections); 5178c2ecf20Sopenharmony_ci iwl_mvm_load_nvm_to_nic(mvm); 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (IWL_MVM_PARSE_NVM && read_nvm) { 5218c2ecf20Sopenharmony_ci ret = iwl_nvm_init(mvm); 5228c2ecf20Sopenharmony_ci if (ret) { 5238c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Failed to read NVM: %d\n", ret); 5248c2ecf20Sopenharmony_ci goto error; 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(REGULATORY_AND_NVM_GROUP, 5298c2ecf20Sopenharmony_ci NVM_ACCESS_COMPLETE), 5308c2ecf20Sopenharmony_ci CMD_SEND_IN_RFKILL, 5318c2ecf20Sopenharmony_ci sizeof(nvm_complete), &nvm_complete); 5328c2ecf20Sopenharmony_ci if (ret) { 5338c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Failed to run complete NVM access: %d\n", 5348c2ecf20Sopenharmony_ci ret); 5358c2ecf20Sopenharmony_ci goto error; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci /* We wait for the INIT complete notification */ 5398c2ecf20Sopenharmony_ci ret = iwl_wait_notification(&mvm->notif_wait, &init_wait, 5408c2ecf20Sopenharmony_ci MVM_UCODE_ALIVE_TIMEOUT); 5418c2ecf20Sopenharmony_ci if (ret) 5428c2ecf20Sopenharmony_ci return ret; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci /* Read the NVM only at driver load time, no need to do this twice */ 5458c2ecf20Sopenharmony_ci if (!IWL_MVM_PARSE_NVM && read_nvm) { 5468c2ecf20Sopenharmony_ci mvm->nvm_data = iwl_get_nvm(mvm->trans, mvm->fw); 5478c2ecf20Sopenharmony_ci if (IS_ERR(mvm->nvm_data)) { 5488c2ecf20Sopenharmony_ci ret = PTR_ERR(mvm->nvm_data); 5498c2ecf20Sopenharmony_ci mvm->nvm_data = NULL; 5508c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Failed to read NVM: %d\n", ret); 5518c2ecf20Sopenharmony_ci return ret; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci mvm->rfkill_safe_init_done = true; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci return 0; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cierror: 5608c2ecf20Sopenharmony_ci iwl_remove_notification(&mvm->notif_wait, &init_wait); 5618c2ecf20Sopenharmony_ci return ret; 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI 5658c2ecf20Sopenharmony_cistatic void iwl_mvm_phy_filter_init(struct iwl_mvm *mvm, 5668c2ecf20Sopenharmony_ci struct iwl_phy_specific_cfg *phy_filters) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci /* 5698c2ecf20Sopenharmony_ci * TODO: read specific phy config from BIOS 5708c2ecf20Sopenharmony_ci * ACPI table for this feature has not been defined yet, 5718c2ecf20Sopenharmony_ci * so for now we use hardcoded values. 5728c2ecf20Sopenharmony_ci */ 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if (IWL_MVM_PHY_FILTER_CHAIN_A) { 5758c2ecf20Sopenharmony_ci phy_filters->filter_cfg_chain_a = 5768c2ecf20Sopenharmony_ci cpu_to_le32(IWL_MVM_PHY_FILTER_CHAIN_A); 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci if (IWL_MVM_PHY_FILTER_CHAIN_B) { 5798c2ecf20Sopenharmony_ci phy_filters->filter_cfg_chain_b = 5808c2ecf20Sopenharmony_ci cpu_to_le32(IWL_MVM_PHY_FILTER_CHAIN_B); 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci if (IWL_MVM_PHY_FILTER_CHAIN_C) { 5838c2ecf20Sopenharmony_ci phy_filters->filter_cfg_chain_c = 5848c2ecf20Sopenharmony_ci cpu_to_le32(IWL_MVM_PHY_FILTER_CHAIN_C); 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci if (IWL_MVM_PHY_FILTER_CHAIN_D) { 5878c2ecf20Sopenharmony_ci phy_filters->filter_cfg_chain_d = 5888c2ecf20Sopenharmony_ci cpu_to_le32(IWL_MVM_PHY_FILTER_CHAIN_D); 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci#else /* CONFIG_ACPI */ 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cistatic void iwl_mvm_phy_filter_init(struct iwl_mvm *mvm, 5958c2ecf20Sopenharmony_ci struct iwl_phy_specific_cfg *phy_filters) 5968c2ecf20Sopenharmony_ci{ 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci#endif /* CONFIG_ACPI */ 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_cistatic int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) 6018c2ecf20Sopenharmony_ci{ 6028c2ecf20Sopenharmony_ci struct iwl_phy_cfg_cmd_v3 phy_cfg_cmd; 6038c2ecf20Sopenharmony_ci enum iwl_ucode_type ucode_type = mvm->fwrt.cur_fw_img; 6048c2ecf20Sopenharmony_ci struct iwl_phy_specific_cfg phy_filters = {}; 6058c2ecf20Sopenharmony_ci u8 cmd_ver; 6068c2ecf20Sopenharmony_ci size_t cmd_size; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci if (iwl_mvm_has_unified_ucode(mvm) && 6098c2ecf20Sopenharmony_ci !mvm->trans->cfg->tx_with_siso_diversity) 6108c2ecf20Sopenharmony_ci return 0; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (mvm->trans->cfg->tx_with_siso_diversity) { 6138c2ecf20Sopenharmony_ci /* 6148c2ecf20Sopenharmony_ci * TODO: currently we don't set the antenna but letting the NIC 6158c2ecf20Sopenharmony_ci * to decide which antenna to use. This should come from BIOS. 6168c2ecf20Sopenharmony_ci */ 6178c2ecf20Sopenharmony_ci phy_cfg_cmd.phy_cfg = 6188c2ecf20Sopenharmony_ci cpu_to_le32(FW_PHY_CFG_CHAIN_SAD_ENABLED); 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci /* Set parameters */ 6228c2ecf20Sopenharmony_ci phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_get_phy_config(mvm)); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci /* set flags extra PHY configuration flags from the device's cfg */ 6258c2ecf20Sopenharmony_ci phy_cfg_cmd.phy_cfg |= 6268c2ecf20Sopenharmony_ci cpu_to_le32(mvm->trans->trans_cfg->extra_phy_cfg_flags); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci phy_cfg_cmd.calib_control.event_trigger = 6298c2ecf20Sopenharmony_ci mvm->fw->default_calib[ucode_type].event_trigger; 6308c2ecf20Sopenharmony_ci phy_cfg_cmd.calib_control.flow_trigger = 6318c2ecf20Sopenharmony_ci mvm->fw->default_calib[ucode_type].flow_trigger; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, IWL_ALWAYS_LONG_GROUP, 6348c2ecf20Sopenharmony_ci PHY_CONFIGURATION_CMD, 6358c2ecf20Sopenharmony_ci IWL_FW_CMD_VER_UNKNOWN); 6368c2ecf20Sopenharmony_ci if (cmd_ver == 3) { 6378c2ecf20Sopenharmony_ci iwl_mvm_phy_filter_init(mvm, &phy_filters); 6388c2ecf20Sopenharmony_ci memcpy(&phy_cfg_cmd.phy_specific_cfg, &phy_filters, 6398c2ecf20Sopenharmony_ci sizeof(struct iwl_phy_specific_cfg)); 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(mvm, "Sending Phy CFG command: 0x%x\n", 6438c2ecf20Sopenharmony_ci phy_cfg_cmd.phy_cfg); 6448c2ecf20Sopenharmony_ci cmd_size = (cmd_ver == 3) ? sizeof(struct iwl_phy_cfg_cmd_v3) : 6458c2ecf20Sopenharmony_ci sizeof(struct iwl_phy_cfg_cmd_v1); 6468c2ecf20Sopenharmony_ci return iwl_mvm_send_cmd_pdu(mvm, PHY_CONFIGURATION_CMD, 0, 6478c2ecf20Sopenharmony_ci cmd_size, &phy_cfg_cmd); 6488c2ecf20Sopenharmony_ci} 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ciint iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) 6518c2ecf20Sopenharmony_ci{ 6528c2ecf20Sopenharmony_ci struct iwl_notification_wait calib_wait; 6538c2ecf20Sopenharmony_ci static const u16 init_complete[] = { 6548c2ecf20Sopenharmony_ci INIT_COMPLETE_NOTIF, 6558c2ecf20Sopenharmony_ci CALIB_RES_NOTIF_PHY_DB 6568c2ecf20Sopenharmony_ci }; 6578c2ecf20Sopenharmony_ci int ret; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci if (iwl_mvm_has_unified_ucode(mvm)) 6608c2ecf20Sopenharmony_ci return iwl_run_unified_mvm_ucode(mvm, true); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci lockdep_assert_held(&mvm->mutex); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci mvm->rfkill_safe_init_done = false; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci iwl_init_notification_wait(&mvm->notif_wait, 6678c2ecf20Sopenharmony_ci &calib_wait, 6688c2ecf20Sopenharmony_ci init_complete, 6698c2ecf20Sopenharmony_ci ARRAY_SIZE(init_complete), 6708c2ecf20Sopenharmony_ci iwl_wait_phy_db_entry, 6718c2ecf20Sopenharmony_ci mvm->phy_db); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci /* Will also start the device */ 6748c2ecf20Sopenharmony_ci ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_INIT); 6758c2ecf20Sopenharmony_ci if (ret) { 6768c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Failed to start INIT ucode: %d\n", ret); 6778c2ecf20Sopenharmony_ci goto remove_notif; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_8000) { 6818c2ecf20Sopenharmony_ci ret = iwl_mvm_send_bt_init_conf(mvm); 6828c2ecf20Sopenharmony_ci if (ret) 6838c2ecf20Sopenharmony_ci goto remove_notif; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci /* Read the NVM only at driver load time, no need to do this twice */ 6878c2ecf20Sopenharmony_ci if (read_nvm) { 6888c2ecf20Sopenharmony_ci ret = iwl_nvm_init(mvm); 6898c2ecf20Sopenharmony_ci if (ret) { 6908c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Failed to read NVM: %d\n", ret); 6918c2ecf20Sopenharmony_ci goto remove_notif; 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci /* In case we read the NVM from external file, load it to the NIC */ 6968c2ecf20Sopenharmony_ci if (mvm->nvm_file_name) 6978c2ecf20Sopenharmony_ci iwl_mvm_load_nvm_to_nic(mvm); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci WARN_ONCE(mvm->nvm_data->nvm_version < mvm->trans->cfg->nvm_ver, 7008c2ecf20Sopenharmony_ci "Too old NVM version (0x%0x, required = 0x%0x)", 7018c2ecf20Sopenharmony_ci mvm->nvm_data->nvm_version, mvm->trans->cfg->nvm_ver); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci /* 7048c2ecf20Sopenharmony_ci * abort after reading the nvm in case RF Kill is on, we will complete 7058c2ecf20Sopenharmony_ci * the init seq later when RF kill will switch to off 7068c2ecf20Sopenharmony_ci */ 7078c2ecf20Sopenharmony_ci if (iwl_mvm_is_radio_hw_killed(mvm)) { 7088c2ecf20Sopenharmony_ci IWL_DEBUG_RF_KILL(mvm, 7098c2ecf20Sopenharmony_ci "jump over all phy activities due to RF kill\n"); 7108c2ecf20Sopenharmony_ci goto remove_notif; 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci mvm->rfkill_safe_init_done = true; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci /* Send TX valid antennas before triggering calibrations */ 7168c2ecf20Sopenharmony_ci ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm)); 7178c2ecf20Sopenharmony_ci if (ret) 7188c2ecf20Sopenharmony_ci goto remove_notif; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci ret = iwl_send_phy_cfg_cmd(mvm); 7218c2ecf20Sopenharmony_ci if (ret) { 7228c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Failed to run INIT calibrations: %d\n", 7238c2ecf20Sopenharmony_ci ret); 7248c2ecf20Sopenharmony_ci goto remove_notif; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci /* 7288c2ecf20Sopenharmony_ci * Some things may run in the background now, but we 7298c2ecf20Sopenharmony_ci * just wait for the calibration complete notification. 7308c2ecf20Sopenharmony_ci */ 7318c2ecf20Sopenharmony_ci ret = iwl_wait_notification(&mvm->notif_wait, &calib_wait, 7328c2ecf20Sopenharmony_ci MVM_UCODE_CALIB_TIMEOUT); 7338c2ecf20Sopenharmony_ci if (!ret) 7348c2ecf20Sopenharmony_ci goto out; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci if (iwl_mvm_is_radio_hw_killed(mvm)) { 7378c2ecf20Sopenharmony_ci IWL_DEBUG_RF_KILL(mvm, "RFKILL while calibrating.\n"); 7388c2ecf20Sopenharmony_ci ret = 0; 7398c2ecf20Sopenharmony_ci } else { 7408c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Failed to run INIT calibrations: %d\n", 7418c2ecf20Sopenharmony_ci ret); 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci goto out; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ciremove_notif: 7478c2ecf20Sopenharmony_ci iwl_remove_notification(&mvm->notif_wait, &calib_wait); 7488c2ecf20Sopenharmony_ciout: 7498c2ecf20Sopenharmony_ci mvm->rfkill_safe_init_done = false; 7508c2ecf20Sopenharmony_ci if (iwlmvm_mod_params.init_dbg && !mvm->nvm_data) { 7518c2ecf20Sopenharmony_ci /* we want to debug INIT and we have no NVM - fake */ 7528c2ecf20Sopenharmony_ci mvm->nvm_data = kzalloc(sizeof(struct iwl_nvm_data) + 7538c2ecf20Sopenharmony_ci sizeof(struct ieee80211_channel) + 7548c2ecf20Sopenharmony_ci sizeof(struct ieee80211_rate), 7558c2ecf20Sopenharmony_ci GFP_KERNEL); 7568c2ecf20Sopenharmony_ci if (!mvm->nvm_data) 7578c2ecf20Sopenharmony_ci return -ENOMEM; 7588c2ecf20Sopenharmony_ci mvm->nvm_data->bands[0].channels = mvm->nvm_data->channels; 7598c2ecf20Sopenharmony_ci mvm->nvm_data->bands[0].n_channels = 1; 7608c2ecf20Sopenharmony_ci mvm->nvm_data->bands[0].n_bitrates = 1; 7618c2ecf20Sopenharmony_ci mvm->nvm_data->bands[0].bitrates = 7628c2ecf20Sopenharmony_ci (void *)mvm->nvm_data->channels + 1; 7638c2ecf20Sopenharmony_ci mvm->nvm_data->bands[0].bitrates->hw_value = 10; 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci return ret; 7678c2ecf20Sopenharmony_ci} 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_cistatic int iwl_mvm_config_ltr(struct iwl_mvm *mvm) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci struct iwl_ltr_config_cmd cmd = { 7728c2ecf20Sopenharmony_ci .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE), 7738c2ecf20Sopenharmony_ci }; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci if (!mvm->trans->ltr_enabled) 7768c2ecf20Sopenharmony_ci return 0; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci return iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0, 7798c2ecf20Sopenharmony_ci sizeof(cmd), &cmd); 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI 7838c2ecf20Sopenharmony_ciint iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) 7848c2ecf20Sopenharmony_ci{ 7858c2ecf20Sopenharmony_ci struct iwl_dev_tx_power_cmd cmd = { 7868c2ecf20Sopenharmony_ci .common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_CHAINS), 7878c2ecf20Sopenharmony_ci }; 7888c2ecf20Sopenharmony_ci __le16 *per_chain; 7898c2ecf20Sopenharmony_ci int ret; 7908c2ecf20Sopenharmony_ci u16 len = 0; 7918c2ecf20Sopenharmony_ci u32 n_subbands; 7928c2ecf20Sopenharmony_ci u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, 7938c2ecf20Sopenharmony_ci REDUCE_TX_POWER_CMD, 7948c2ecf20Sopenharmony_ci IWL_FW_CMD_VER_UNKNOWN); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci if (cmd_ver == 6) { 7978c2ecf20Sopenharmony_ci len = sizeof(cmd.v6); 7988c2ecf20Sopenharmony_ci n_subbands = IWL_NUM_SUB_BANDS_V2; 7998c2ecf20Sopenharmony_ci per_chain = cmd.v6.per_chain[0][0]; 8008c2ecf20Sopenharmony_ci } else if (fw_has_api(&mvm->fw->ucode_capa, 8018c2ecf20Sopenharmony_ci IWL_UCODE_TLV_API_REDUCE_TX_POWER)) { 8028c2ecf20Sopenharmony_ci len = sizeof(cmd.v5); 8038c2ecf20Sopenharmony_ci n_subbands = IWL_NUM_SUB_BANDS; 8048c2ecf20Sopenharmony_ci per_chain = cmd.v5.per_chain[0][0]; 8058c2ecf20Sopenharmony_ci } else if (fw_has_capa(&mvm->fw->ucode_capa, 8068c2ecf20Sopenharmony_ci IWL_UCODE_TLV_CAPA_TX_POWER_ACK)) { 8078c2ecf20Sopenharmony_ci len = sizeof(cmd.v4); 8088c2ecf20Sopenharmony_ci n_subbands = IWL_NUM_SUB_BANDS; 8098c2ecf20Sopenharmony_ci per_chain = cmd.v4.per_chain[0][0]; 8108c2ecf20Sopenharmony_ci } else { 8118c2ecf20Sopenharmony_ci len = sizeof(cmd.v3); 8128c2ecf20Sopenharmony_ci n_subbands = IWL_NUM_SUB_BANDS; 8138c2ecf20Sopenharmony_ci per_chain = cmd.v3.per_chain[0][0]; 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci /* all structs have the same common part, add it */ 8178c2ecf20Sopenharmony_ci len += sizeof(cmd.common); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci ret = iwl_sar_select_profile(&mvm->fwrt, per_chain, ACPI_SAR_NUM_TABLES, 8208c2ecf20Sopenharmony_ci n_subbands, prof_a, prof_b); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci /* return on error or if the profile is disabled (positive number) */ 8238c2ecf20Sopenharmony_ci if (ret) 8248c2ecf20Sopenharmony_ci return ret; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, "Sending REDUCE_TX_POWER_CMD per chain\n"); 8278c2ecf20Sopenharmony_ci return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd); 8288c2ecf20Sopenharmony_ci} 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ciint iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) 8318c2ecf20Sopenharmony_ci{ 8328c2ecf20Sopenharmony_ci union iwl_geo_tx_power_profiles_cmd geo_tx_cmd; 8338c2ecf20Sopenharmony_ci struct iwl_geo_tx_power_profiles_resp *resp; 8348c2ecf20Sopenharmony_ci u16 len; 8358c2ecf20Sopenharmony_ci int ret; 8368c2ecf20Sopenharmony_ci struct iwl_host_cmd cmd; 8378c2ecf20Sopenharmony_ci u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, PHY_OPS_GROUP, 8388c2ecf20Sopenharmony_ci GEO_TX_POWER_LIMIT, 8398c2ecf20Sopenharmony_ci IWL_FW_CMD_VER_UNKNOWN); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci /* the ops field is at the same spot for all versions, so set in v1 */ 8428c2ecf20Sopenharmony_ci geo_tx_cmd.v1.ops = 8438c2ecf20Sopenharmony_ci cpu_to_le32(IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE); 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci if (cmd_ver == 3) 8468c2ecf20Sopenharmony_ci len = sizeof(geo_tx_cmd.v3); 8478c2ecf20Sopenharmony_ci else if (fw_has_api(&mvm->fwrt.fw->ucode_capa, 8488c2ecf20Sopenharmony_ci IWL_UCODE_TLV_API_SAR_TABLE_VER)) 8498c2ecf20Sopenharmony_ci len = sizeof(geo_tx_cmd.v2); 8508c2ecf20Sopenharmony_ci else 8518c2ecf20Sopenharmony_ci len = sizeof(geo_tx_cmd.v1); 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci if (!iwl_sar_geo_support(&mvm->fwrt)) 8548c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci cmd = (struct iwl_host_cmd){ 8578c2ecf20Sopenharmony_ci .id = WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT), 8588c2ecf20Sopenharmony_ci .len = { len, }, 8598c2ecf20Sopenharmony_ci .flags = CMD_WANT_SKB, 8608c2ecf20Sopenharmony_ci .data = { &geo_tx_cmd }, 8618c2ecf20Sopenharmony_ci }; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci ret = iwl_mvm_send_cmd(mvm, &cmd); 8648c2ecf20Sopenharmony_ci if (ret) { 8658c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Failed to get geographic profile info %d\n", ret); 8668c2ecf20Sopenharmony_ci return ret; 8678c2ecf20Sopenharmony_ci } 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci resp = (void *)cmd.resp_pkt->data; 8708c2ecf20Sopenharmony_ci ret = le32_to_cpu(resp->profile_idx); 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci if (WARN_ON(ret > ACPI_NUM_GEO_PROFILES)) 8738c2ecf20Sopenharmony_ci ret = -EIO; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci iwl_free_resp(&cmd); 8768c2ecf20Sopenharmony_ci return ret; 8778c2ecf20Sopenharmony_ci} 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_cistatic int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) 8808c2ecf20Sopenharmony_ci{ 8818c2ecf20Sopenharmony_ci union iwl_geo_tx_power_profiles_cmd cmd; 8828c2ecf20Sopenharmony_ci u16 len; 8838c2ecf20Sopenharmony_ci u32 n_bands; 8848c2ecf20Sopenharmony_ci int ret; 8858c2ecf20Sopenharmony_ci u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, PHY_OPS_GROUP, 8868c2ecf20Sopenharmony_ci GEO_TX_POWER_LIMIT, 8878c2ecf20Sopenharmony_ci IWL_FW_CMD_VER_UNKNOWN); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci BUILD_BUG_ON(offsetof(struct iwl_geo_tx_power_profiles_cmd_v1, ops) != 8908c2ecf20Sopenharmony_ci offsetof(struct iwl_geo_tx_power_profiles_cmd_v2, ops) || 8918c2ecf20Sopenharmony_ci offsetof(struct iwl_geo_tx_power_profiles_cmd_v2, ops) != 8928c2ecf20Sopenharmony_ci offsetof(struct iwl_geo_tx_power_profiles_cmd_v3, ops)); 8938c2ecf20Sopenharmony_ci /* the ops field is at the same spot for all versions, so set in v1 */ 8948c2ecf20Sopenharmony_ci cmd.v1.ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_SET_TABLES); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci if (cmd_ver == 3) { 8978c2ecf20Sopenharmony_ci len = sizeof(cmd.v3); 8988c2ecf20Sopenharmony_ci n_bands = ARRAY_SIZE(cmd.v3.table[0]); 8998c2ecf20Sopenharmony_ci } else if (fw_has_api(&mvm->fwrt.fw->ucode_capa, 9008c2ecf20Sopenharmony_ci IWL_UCODE_TLV_API_SAR_TABLE_VER)) { 9018c2ecf20Sopenharmony_ci len = sizeof(cmd.v2); 9028c2ecf20Sopenharmony_ci n_bands = ARRAY_SIZE(cmd.v2.table[0]); 9038c2ecf20Sopenharmony_ci } else { 9048c2ecf20Sopenharmony_ci len = sizeof(cmd.v1); 9058c2ecf20Sopenharmony_ci n_bands = ARRAY_SIZE(cmd.v1.table[0]); 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci BUILD_BUG_ON(offsetof(struct iwl_geo_tx_power_profiles_cmd_v1, table) != 9098c2ecf20Sopenharmony_ci offsetof(struct iwl_geo_tx_power_profiles_cmd_v2, table) || 9108c2ecf20Sopenharmony_ci offsetof(struct iwl_geo_tx_power_profiles_cmd_v2, table) != 9118c2ecf20Sopenharmony_ci offsetof(struct iwl_geo_tx_power_profiles_cmd_v3, table)); 9128c2ecf20Sopenharmony_ci /* the table is at the same position for all versions, so set use v1 */ 9138c2ecf20Sopenharmony_ci ret = iwl_sar_geo_init(&mvm->fwrt, &cmd.v1.table[0][0], n_bands); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci /* 9168c2ecf20Sopenharmony_ci * It is a valid scenario to not support SAR, or miss wgds table, 9178c2ecf20Sopenharmony_ci * but in that case there is no need to send the command. 9188c2ecf20Sopenharmony_ci */ 9198c2ecf20Sopenharmony_ci if (ret) 9208c2ecf20Sopenharmony_ci return 0; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci /* 9238c2ecf20Sopenharmony_ci * Set the revision on versions that contain it. 9248c2ecf20Sopenharmony_ci * This must be done after calling iwl_sar_geo_init(). 9258c2ecf20Sopenharmony_ci */ 9268c2ecf20Sopenharmony_ci if (cmd_ver == 3) 9278c2ecf20Sopenharmony_ci cmd.v3.table_revision = cpu_to_le32(mvm->fwrt.geo_rev); 9288c2ecf20Sopenharmony_ci else if (fw_has_api(&mvm->fwrt.fw->ucode_capa, 9298c2ecf20Sopenharmony_ci IWL_UCODE_TLV_API_SAR_TABLE_VER)) 9308c2ecf20Sopenharmony_ci cmd.v2.table_revision = cpu_to_le32(mvm->fwrt.geo_rev); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci return iwl_mvm_send_cmd_pdu(mvm, 9338c2ecf20Sopenharmony_ci WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT), 9348c2ecf20Sopenharmony_ci 0, len, &cmd); 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_cistatic int iwl_mvm_get_ppag_table(struct iwl_mvm *mvm) 9388c2ecf20Sopenharmony_ci{ 9398c2ecf20Sopenharmony_ci union acpi_object *wifi_pkg, *data, *enabled; 9408c2ecf20Sopenharmony_ci int i, j, ret, tbl_rev, num_sub_bands; 9418c2ecf20Sopenharmony_ci int idx = 2; 9428c2ecf20Sopenharmony_ci s8 *gain; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci /* 9458c2ecf20Sopenharmony_ci * The 'enabled' field is the same in v1 and v2 so we can just 9468c2ecf20Sopenharmony_ci * use v1 to access it. 9478c2ecf20Sopenharmony_ci */ 9488c2ecf20Sopenharmony_ci mvm->fwrt.ppag_table.v1.enabled = cpu_to_le32(0); 9498c2ecf20Sopenharmony_ci data = iwl_acpi_get_object(mvm->dev, ACPI_PPAG_METHOD); 9508c2ecf20Sopenharmony_ci if (IS_ERR(data)) 9518c2ecf20Sopenharmony_ci return PTR_ERR(data); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci /* try to read ppag table revision 1 */ 9548c2ecf20Sopenharmony_ci wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data, 9558c2ecf20Sopenharmony_ci ACPI_PPAG_WIFI_DATA_SIZE_V2, &tbl_rev); 9568c2ecf20Sopenharmony_ci if (!IS_ERR(wifi_pkg)) { 9578c2ecf20Sopenharmony_ci if (tbl_rev != 1) { 9588c2ecf20Sopenharmony_ci ret = -EINVAL; 9598c2ecf20Sopenharmony_ci goto out_free; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci num_sub_bands = IWL_NUM_SUB_BANDS_V2; 9628c2ecf20Sopenharmony_ci gain = mvm->fwrt.ppag_table.v2.gain[0]; 9638c2ecf20Sopenharmony_ci mvm->fwrt.ppag_ver = 2; 9648c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, "Reading PPAG table v2 (tbl_rev=1)\n"); 9658c2ecf20Sopenharmony_ci goto read_table; 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci /* try to read ppag table revision 0 */ 9698c2ecf20Sopenharmony_ci wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data, 9708c2ecf20Sopenharmony_ci ACPI_PPAG_WIFI_DATA_SIZE, &tbl_rev); 9718c2ecf20Sopenharmony_ci if (!IS_ERR(wifi_pkg)) { 9728c2ecf20Sopenharmony_ci if (tbl_rev != 0) { 9738c2ecf20Sopenharmony_ci ret = -EINVAL; 9748c2ecf20Sopenharmony_ci goto out_free; 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci num_sub_bands = IWL_NUM_SUB_BANDS; 9778c2ecf20Sopenharmony_ci gain = mvm->fwrt.ppag_table.v1.gain[0]; 9788c2ecf20Sopenharmony_ci mvm->fwrt.ppag_ver = 1; 9798c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, "Reading PPAG table v1 (tbl_rev=0)\n"); 9808c2ecf20Sopenharmony_ci goto read_table; 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci ret = PTR_ERR(wifi_pkg); 9838c2ecf20Sopenharmony_ci goto out_free; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ciread_table: 9868c2ecf20Sopenharmony_ci enabled = &wifi_pkg->package.elements[1]; 9878c2ecf20Sopenharmony_ci if (enabled->type != ACPI_TYPE_INTEGER || 9888c2ecf20Sopenharmony_ci (enabled->integer.value != 0 && enabled->integer.value != 1)) { 9898c2ecf20Sopenharmony_ci ret = -EINVAL; 9908c2ecf20Sopenharmony_ci goto out_free; 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci mvm->fwrt.ppag_table.v1.enabled = cpu_to_le32(enabled->integer.value); 9948c2ecf20Sopenharmony_ci if (!mvm->fwrt.ppag_table.v1.enabled) { 9958c2ecf20Sopenharmony_ci ret = 0; 9968c2ecf20Sopenharmony_ci goto out_free; 9978c2ecf20Sopenharmony_ci } 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci /* 10008c2ecf20Sopenharmony_ci * read, verify gain values and save them into the PPAG table. 10018c2ecf20Sopenharmony_ci * first sub-band (j=0) corresponds to Low-Band (2.4GHz), and the 10028c2ecf20Sopenharmony_ci * following sub-bands to High-Band (5GHz). 10038c2ecf20Sopenharmony_ci */ 10048c2ecf20Sopenharmony_ci for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { 10058c2ecf20Sopenharmony_ci for (j = 0; j < num_sub_bands; j++) { 10068c2ecf20Sopenharmony_ci union acpi_object *ent; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci ent = &wifi_pkg->package.elements[idx++]; 10098c2ecf20Sopenharmony_ci if (ent->type != ACPI_TYPE_INTEGER) { 10108c2ecf20Sopenharmony_ci ret = -EINVAL; 10118c2ecf20Sopenharmony_ci goto out_free; 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci gain[i * num_sub_bands + j] = ent->integer.value; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci if ((j == 0 && 10178c2ecf20Sopenharmony_ci (gain[i * num_sub_bands + j] > ACPI_PPAG_MAX_LB || 10188c2ecf20Sopenharmony_ci gain[i * num_sub_bands + j] < ACPI_PPAG_MIN_LB)) || 10198c2ecf20Sopenharmony_ci (j != 0 && 10208c2ecf20Sopenharmony_ci (gain[i * num_sub_bands + j] > ACPI_PPAG_MAX_HB || 10218c2ecf20Sopenharmony_ci gain[i * num_sub_bands + j] < ACPI_PPAG_MIN_HB))) { 10228c2ecf20Sopenharmony_ci mvm->fwrt.ppag_table.v1.enabled = cpu_to_le32(0); 10238c2ecf20Sopenharmony_ci ret = -EINVAL; 10248c2ecf20Sopenharmony_ci goto out_free; 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci } 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci ret = 0; 10298c2ecf20Sopenharmony_ciout_free: 10308c2ecf20Sopenharmony_ci kfree(data); 10318c2ecf20Sopenharmony_ci return ret; 10328c2ecf20Sopenharmony_ci} 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ciint iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) 10358c2ecf20Sopenharmony_ci{ 10368c2ecf20Sopenharmony_ci u8 cmd_ver; 10378c2ecf20Sopenharmony_ci int i, j, ret, num_sub_bands, cmd_size; 10388c2ecf20Sopenharmony_ci s8 *gain; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_PPAG)) { 10418c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, 10428c2ecf20Sopenharmony_ci "PPAG capability not supported by FW, command not sent.\n"); 10438c2ecf20Sopenharmony_ci return 0; 10448c2ecf20Sopenharmony_ci } 10458c2ecf20Sopenharmony_ci if (!mvm->fwrt.ppag_table.v1.enabled) { 10468c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, "PPAG not enabled, command not sent.\n"); 10478c2ecf20Sopenharmony_ci return 0; 10488c2ecf20Sopenharmony_ci } 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, PHY_OPS_GROUP, 10518c2ecf20Sopenharmony_ci PER_PLATFORM_ANT_GAIN_CMD, 10528c2ecf20Sopenharmony_ci IWL_FW_CMD_VER_UNKNOWN); 10538c2ecf20Sopenharmony_ci if (cmd_ver == 1) { 10548c2ecf20Sopenharmony_ci num_sub_bands = IWL_NUM_SUB_BANDS; 10558c2ecf20Sopenharmony_ci gain = mvm->fwrt.ppag_table.v1.gain[0]; 10568c2ecf20Sopenharmony_ci cmd_size = sizeof(mvm->fwrt.ppag_table.v1); 10578c2ecf20Sopenharmony_ci if (mvm->fwrt.ppag_ver == 2) { 10588c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, 10598c2ecf20Sopenharmony_ci "PPAG table is v2 but FW supports v1, sending truncated table\n"); 10608c2ecf20Sopenharmony_ci } 10618c2ecf20Sopenharmony_ci } else if (cmd_ver == 2) { 10628c2ecf20Sopenharmony_ci num_sub_bands = IWL_NUM_SUB_BANDS_V2; 10638c2ecf20Sopenharmony_ci gain = mvm->fwrt.ppag_table.v2.gain[0]; 10648c2ecf20Sopenharmony_ci cmd_size = sizeof(mvm->fwrt.ppag_table.v2); 10658c2ecf20Sopenharmony_ci if (mvm->fwrt.ppag_ver == 1) { 10668c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, 10678c2ecf20Sopenharmony_ci "PPAG table is v1 but FW supports v2, sending padded table\n"); 10688c2ecf20Sopenharmony_ci } 10698c2ecf20Sopenharmony_ci } else { 10708c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, "Unsupported PPAG command version\n"); 10718c2ecf20Sopenharmony_ci return 0; 10728c2ecf20Sopenharmony_ci } 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { 10758c2ecf20Sopenharmony_ci for (j = 0; j < num_sub_bands; j++) { 10768c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, 10778c2ecf20Sopenharmony_ci "PPAG table: chain[%d] band[%d]: gain = %d\n", 10788c2ecf20Sopenharmony_ci i, j, gain[i * num_sub_bands + j]); 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci } 10818c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, "Sending PER_PLATFORM_ANT_GAIN_CMD\n"); 10828c2ecf20Sopenharmony_ci ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(PHY_OPS_GROUP, 10838c2ecf20Sopenharmony_ci PER_PLATFORM_ANT_GAIN_CMD), 10848c2ecf20Sopenharmony_ci 0, cmd_size, &mvm->fwrt.ppag_table); 10858c2ecf20Sopenharmony_ci if (ret < 0) 10868c2ecf20Sopenharmony_ci IWL_ERR(mvm, "failed to send PER_PLATFORM_ANT_GAIN_CMD (%d)\n", 10878c2ecf20Sopenharmony_ci ret); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci return ret; 10908c2ecf20Sopenharmony_ci} 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_cistatic int iwl_mvm_ppag_init(struct iwl_mvm *mvm) 10938c2ecf20Sopenharmony_ci{ 10948c2ecf20Sopenharmony_ci int ret; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci ret = iwl_mvm_get_ppag_table(mvm); 10978c2ecf20Sopenharmony_ci if (ret < 0) { 10988c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, 10998c2ecf20Sopenharmony_ci "PPAG BIOS table invalid or unavailable. (%d)\n", 11008c2ecf20Sopenharmony_ci ret); 11018c2ecf20Sopenharmony_ci return 0; 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci return iwl_mvm_ppag_send_cmd(mvm); 11048c2ecf20Sopenharmony_ci} 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_cistatic void iwl_mvm_tas_init(struct iwl_mvm *mvm) 11078c2ecf20Sopenharmony_ci{ 11088c2ecf20Sopenharmony_ci int ret; 11098c2ecf20Sopenharmony_ci struct iwl_tas_config_cmd cmd = {}; 11108c2ecf20Sopenharmony_ci int list_size; 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(cmd.block_list_array) < 11138c2ecf20Sopenharmony_ci APCI_WTAS_BLACK_LIST_MAX); 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TAS_CFG)) { 11168c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, "TAS not enabled in FW\n"); 11178c2ecf20Sopenharmony_ci return; 11188c2ecf20Sopenharmony_ci } 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci ret = iwl_acpi_get_tas(&mvm->fwrt, cmd.block_list_array, &list_size); 11218c2ecf20Sopenharmony_ci if (ret < 0) { 11228c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, 11238c2ecf20Sopenharmony_ci "TAS table invalid or unavailable. (%d)\n", 11248c2ecf20Sopenharmony_ci ret); 11258c2ecf20Sopenharmony_ci return; 11268c2ecf20Sopenharmony_ci } 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci if (list_size < 0) 11298c2ecf20Sopenharmony_ci return; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci /* list size if TAS enabled can only be non-negative */ 11328c2ecf20Sopenharmony_ci cmd.block_list_size = cpu_to_le32((u32)list_size); 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(REGULATORY_AND_NVM_GROUP, 11358c2ecf20Sopenharmony_ci TAS_CONFIG), 11368c2ecf20Sopenharmony_ci 0, sizeof(cmd), &cmd); 11378c2ecf20Sopenharmony_ci if (ret < 0) 11388c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, "failed to send TAS_CONFIG (%d)\n", ret); 11398c2ecf20Sopenharmony_ci} 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_cistatic u8 iwl_mvm_eval_dsm_indonesia_5g2(struct iwl_mvm *mvm) 11428c2ecf20Sopenharmony_ci{ 11438c2ecf20Sopenharmony_ci int ret = iwl_acpi_get_dsm_u8((&mvm->fwrt)->dev, 0, 11448c2ecf20Sopenharmony_ci DSM_FUNC_ENABLE_INDONESIA_5G2); 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci if (ret < 0) 11478c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, 11488c2ecf20Sopenharmony_ci "Failed to evaluate DSM function ENABLE_INDONESIA_5G2, ret=%d\n", 11498c2ecf20Sopenharmony_ci ret); 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci else if (ret >= DSM_VALUE_INDONESIA_MAX) 11528c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, 11538c2ecf20Sopenharmony_ci "DSM function ENABLE_INDONESIA_5G2 return invalid value, ret=%d\n", 11548c2ecf20Sopenharmony_ci ret); 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci else if (ret == DSM_VALUE_INDONESIA_ENABLE) { 11578c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, 11588c2ecf20Sopenharmony_ci "Evaluated DSM function ENABLE_INDONESIA_5G2: Enabling 5g2\n"); 11598c2ecf20Sopenharmony_ci return DSM_VALUE_INDONESIA_ENABLE; 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci /* default behaviour is disabled */ 11628c2ecf20Sopenharmony_ci return DSM_VALUE_INDONESIA_DISABLE; 11638c2ecf20Sopenharmony_ci} 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_cistatic u8 iwl_mvm_eval_dsm_disable_srd(struct iwl_mvm *mvm) 11668c2ecf20Sopenharmony_ci{ 11678c2ecf20Sopenharmony_ci int ret = iwl_acpi_get_dsm_u8((&mvm->fwrt)->dev, 0, 11688c2ecf20Sopenharmony_ci DSM_FUNC_DISABLE_SRD); 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci if (ret < 0) 11718c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, 11728c2ecf20Sopenharmony_ci "Failed to evaluate DSM function DISABLE_SRD, ret=%d\n", 11738c2ecf20Sopenharmony_ci ret); 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci else if (ret >= DSM_VALUE_SRD_MAX) 11768c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, 11778c2ecf20Sopenharmony_ci "DSM function DISABLE_SRD return invalid value, ret=%d\n", 11788c2ecf20Sopenharmony_ci ret); 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci else if (ret == DSM_VALUE_SRD_PASSIVE) { 11818c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, 11828c2ecf20Sopenharmony_ci "Evaluated DSM function DISABLE_SRD: setting SRD to passive\n"); 11838c2ecf20Sopenharmony_ci return DSM_VALUE_SRD_PASSIVE; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci } else if (ret == DSM_VALUE_SRD_DISABLE) { 11868c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, 11878c2ecf20Sopenharmony_ci "Evaluated DSM function DISABLE_SRD: disabling SRD\n"); 11888c2ecf20Sopenharmony_ci return DSM_VALUE_SRD_DISABLE; 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci /* default behaviour is active */ 11918c2ecf20Sopenharmony_ci return DSM_VALUE_SRD_ACTIVE; 11928c2ecf20Sopenharmony_ci} 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_cistatic void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) 11958c2ecf20Sopenharmony_ci{ 11968c2ecf20Sopenharmony_ci u8 ret; 11978c2ecf20Sopenharmony_ci int cmd_ret; 11988c2ecf20Sopenharmony_ci struct iwl_lari_config_change_cmd cmd = {}; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci if (iwl_mvm_eval_dsm_indonesia_5g2(mvm) == DSM_VALUE_INDONESIA_ENABLE) 12018c2ecf20Sopenharmony_ci cmd.config_bitmap |= 12028c2ecf20Sopenharmony_ci cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci ret = iwl_mvm_eval_dsm_disable_srd(mvm); 12058c2ecf20Sopenharmony_ci if (ret == DSM_VALUE_SRD_PASSIVE) 12068c2ecf20Sopenharmony_ci cmd.config_bitmap |= 12078c2ecf20Sopenharmony_ci cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK); 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci else if (ret == DSM_VALUE_SRD_DISABLE) 12108c2ecf20Sopenharmony_ci cmd.config_bitmap |= 12118c2ecf20Sopenharmony_ci cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK); 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci /* apply more config masks here */ 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci if (cmd.config_bitmap) { 12168c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, "sending LARI_CONFIG_CHANGE\n"); 12178c2ecf20Sopenharmony_ci cmd_ret = iwl_mvm_send_cmd_pdu(mvm, 12188c2ecf20Sopenharmony_ci WIDE_ID(REGULATORY_AND_NVM_GROUP, 12198c2ecf20Sopenharmony_ci LARI_CONFIG_CHANGE), 12208c2ecf20Sopenharmony_ci 0, sizeof(cmd), &cmd); 12218c2ecf20Sopenharmony_ci if (cmd_ret < 0) 12228c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, 12238c2ecf20Sopenharmony_ci "Failed to send LARI_CONFIG_CHANGE (%d)\n", 12248c2ecf20Sopenharmony_ci cmd_ret); 12258c2ecf20Sopenharmony_ci } 12268c2ecf20Sopenharmony_ci} 12278c2ecf20Sopenharmony_ci#else /* CONFIG_ACPI */ 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ciinline int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, 12308c2ecf20Sopenharmony_ci int prof_a, int prof_b) 12318c2ecf20Sopenharmony_ci{ 12328c2ecf20Sopenharmony_ci return -ENOENT; 12338c2ecf20Sopenharmony_ci} 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ciinline int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) 12368c2ecf20Sopenharmony_ci{ 12378c2ecf20Sopenharmony_ci return -ENOENT; 12388c2ecf20Sopenharmony_ci} 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_cistatic int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) 12418c2ecf20Sopenharmony_ci{ 12428c2ecf20Sopenharmony_ci return 0; 12438c2ecf20Sopenharmony_ci} 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ciint iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) 12468c2ecf20Sopenharmony_ci{ 12478c2ecf20Sopenharmony_ci return -ENOENT; 12488c2ecf20Sopenharmony_ci} 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_cistatic int iwl_mvm_ppag_init(struct iwl_mvm *mvm) 12518c2ecf20Sopenharmony_ci{ 12528c2ecf20Sopenharmony_ci return 0; 12538c2ecf20Sopenharmony_ci} 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_cistatic void iwl_mvm_tas_init(struct iwl_mvm *mvm) 12568c2ecf20Sopenharmony_ci{ 12578c2ecf20Sopenharmony_ci} 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_cistatic void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) 12608c2ecf20Sopenharmony_ci{ 12618c2ecf20Sopenharmony_ci} 12628c2ecf20Sopenharmony_ci#endif /* CONFIG_ACPI */ 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_civoid iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags) 12658c2ecf20Sopenharmony_ci{ 12668c2ecf20Sopenharmony_ci u32 error_log_size = mvm->fw->ucode_capa.error_log_size; 12678c2ecf20Sopenharmony_ci int ret; 12688c2ecf20Sopenharmony_ci u32 resp; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci struct iwl_fw_error_recovery_cmd recovery_cmd = { 12718c2ecf20Sopenharmony_ci .flags = cpu_to_le32(flags), 12728c2ecf20Sopenharmony_ci .buf_size = 0, 12738c2ecf20Sopenharmony_ci }; 12748c2ecf20Sopenharmony_ci struct iwl_host_cmd host_cmd = { 12758c2ecf20Sopenharmony_ci .id = WIDE_ID(SYSTEM_GROUP, FW_ERROR_RECOVERY_CMD), 12768c2ecf20Sopenharmony_ci .flags = CMD_WANT_SKB, 12778c2ecf20Sopenharmony_ci .data = {&recovery_cmd, }, 12788c2ecf20Sopenharmony_ci .len = {sizeof(recovery_cmd), }, 12798c2ecf20Sopenharmony_ci }; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci /* no error log was defined in TLV */ 12828c2ecf20Sopenharmony_ci if (!error_log_size) 12838c2ecf20Sopenharmony_ci return; 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci if (flags & ERROR_RECOVERY_UPDATE_DB) { 12868c2ecf20Sopenharmony_ci /* no buf was allocated while HW reset */ 12878c2ecf20Sopenharmony_ci if (!mvm->error_recovery_buf) 12888c2ecf20Sopenharmony_ci return; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci host_cmd.data[1] = mvm->error_recovery_buf; 12918c2ecf20Sopenharmony_ci host_cmd.len[1] = error_log_size; 12928c2ecf20Sopenharmony_ci host_cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY; 12938c2ecf20Sopenharmony_ci recovery_cmd.buf_size = cpu_to_le32(error_log_size); 12948c2ecf20Sopenharmony_ci } 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci ret = iwl_mvm_send_cmd(mvm, &host_cmd); 12978c2ecf20Sopenharmony_ci kfree(mvm->error_recovery_buf); 12988c2ecf20Sopenharmony_ci mvm->error_recovery_buf = NULL; 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci if (ret) { 13018c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Failed to send recovery cmd %d\n", ret); 13028c2ecf20Sopenharmony_ci return; 13038c2ecf20Sopenharmony_ci } 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci /* skb respond is only relevant in ERROR_RECOVERY_UPDATE_DB */ 13068c2ecf20Sopenharmony_ci if (flags & ERROR_RECOVERY_UPDATE_DB) { 13078c2ecf20Sopenharmony_ci resp = le32_to_cpu(*(__le32 *)host_cmd.resp_pkt->data); 13088c2ecf20Sopenharmony_ci if (resp) 13098c2ecf20Sopenharmony_ci IWL_ERR(mvm, 13108c2ecf20Sopenharmony_ci "Failed to send recovery cmd blob was invalid %d\n", 13118c2ecf20Sopenharmony_ci resp); 13128c2ecf20Sopenharmony_ci } 13138c2ecf20Sopenharmony_ci} 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_cistatic int iwl_mvm_sar_init(struct iwl_mvm *mvm) 13168c2ecf20Sopenharmony_ci{ 13178c2ecf20Sopenharmony_ci int ret; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci ret = iwl_sar_get_wrds_table(&mvm->fwrt); 13208c2ecf20Sopenharmony_ci if (ret < 0) { 13218c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, 13228c2ecf20Sopenharmony_ci "WRDS SAR BIOS table invalid or unavailable. (%d)\n", 13238c2ecf20Sopenharmony_ci ret); 13248c2ecf20Sopenharmony_ci /* 13258c2ecf20Sopenharmony_ci * If not available, don't fail and don't bother with EWRD. 13268c2ecf20Sopenharmony_ci * Return 1 to tell that we can't use WGDS either. 13278c2ecf20Sopenharmony_ci */ 13288c2ecf20Sopenharmony_ci return 1; 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci ret = iwl_sar_get_ewrd_table(&mvm->fwrt); 13328c2ecf20Sopenharmony_ci /* if EWRD is not available, we can still use WRDS, so don't fail */ 13338c2ecf20Sopenharmony_ci if (ret < 0) 13348c2ecf20Sopenharmony_ci IWL_DEBUG_RADIO(mvm, 13358c2ecf20Sopenharmony_ci "EWRD SAR BIOS table invalid or unavailable. (%d)\n", 13368c2ecf20Sopenharmony_ci ret); 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci return iwl_mvm_sar_select_profile(mvm, 1, 1); 13398c2ecf20Sopenharmony_ci} 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_cistatic int iwl_mvm_load_rt_fw(struct iwl_mvm *mvm) 13428c2ecf20Sopenharmony_ci{ 13438c2ecf20Sopenharmony_ci int ret; 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci if (iwl_mvm_has_unified_ucode(mvm)) 13468c2ecf20Sopenharmony_ci return iwl_run_unified_mvm_ucode(mvm, false); 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci ret = iwl_run_init_mvm_ucode(mvm, false); 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci if (ret) { 13518c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret); 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci if (iwlmvm_mod_params.init_dbg) 13548c2ecf20Sopenharmony_ci return 0; 13558c2ecf20Sopenharmony_ci return ret; 13568c2ecf20Sopenharmony_ci } 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci iwl_fw_dbg_stop_sync(&mvm->fwrt); 13598c2ecf20Sopenharmony_ci iwl_trans_stop_device(mvm->trans); 13608c2ecf20Sopenharmony_ci ret = iwl_trans_start_hw(mvm->trans); 13618c2ecf20Sopenharmony_ci if (ret) 13628c2ecf20Sopenharmony_ci return ret; 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_EARLY, NULL); 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci mvm->rfkill_safe_init_done = false; 13678c2ecf20Sopenharmony_ci ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_REGULAR); 13688c2ecf20Sopenharmony_ci if (ret) 13698c2ecf20Sopenharmony_ci return ret; 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci mvm->rfkill_safe_init_done = true; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_AFTER_ALIVE, 13748c2ecf20Sopenharmony_ci NULL); 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci return iwl_init_paging(&mvm->fwrt, mvm->fwrt.cur_fw_img); 13778c2ecf20Sopenharmony_ci} 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ciint iwl_mvm_up(struct iwl_mvm *mvm) 13808c2ecf20Sopenharmony_ci{ 13818c2ecf20Sopenharmony_ci int ret, i; 13828c2ecf20Sopenharmony_ci struct ieee80211_channel *chan; 13838c2ecf20Sopenharmony_ci struct cfg80211_chan_def chandef; 13848c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband = NULL; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci lockdep_assert_held(&mvm->mutex); 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci ret = iwl_trans_start_hw(mvm->trans); 13898c2ecf20Sopenharmony_ci if (ret) 13908c2ecf20Sopenharmony_ci return ret; 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci ret = iwl_mvm_load_rt_fw(mvm); 13938c2ecf20Sopenharmony_ci if (ret) { 13948c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Failed to start RT ucode: %d\n", ret); 13958c2ecf20Sopenharmony_ci if (ret != -ERFKILL) 13968c2ecf20Sopenharmony_ci iwl_fw_dbg_error_collect(&mvm->fwrt, 13978c2ecf20Sopenharmony_ci FW_DBG_TRIGGER_DRIVER); 13988c2ecf20Sopenharmony_ci goto error; 13998c2ecf20Sopenharmony_ci } 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci iwl_get_shared_mem_conf(&mvm->fwrt); 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci ret = iwl_mvm_sf_update(mvm, NULL, false); 14048c2ecf20Sopenharmony_ci if (ret) 14058c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Failed to initialize Smart Fifo\n"); 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci if (!iwl_trans_dbg_ini_valid(mvm->trans)) { 14088c2ecf20Sopenharmony_ci mvm->fwrt.dump.conf = FW_DBG_INVALID; 14098c2ecf20Sopenharmony_ci /* if we have a destination, assume EARLY START */ 14108c2ecf20Sopenharmony_ci if (mvm->fw->dbg.dest_tlv) 14118c2ecf20Sopenharmony_ci mvm->fwrt.dump.conf = FW_DBG_START_FROM_ALIVE; 14128c2ecf20Sopenharmony_ci iwl_fw_start_dbg_conf(&mvm->fwrt, FW_DBG_START_FROM_ALIVE); 14138c2ecf20Sopenharmony_ci } 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm)); 14168c2ecf20Sopenharmony_ci if (ret) 14178c2ecf20Sopenharmony_ci goto error; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci if (!iwl_mvm_has_unified_ucode(mvm)) { 14208c2ecf20Sopenharmony_ci /* Send phy db control command and then phy db calibration */ 14218c2ecf20Sopenharmony_ci ret = iwl_send_phy_db_data(mvm->phy_db); 14228c2ecf20Sopenharmony_ci if (ret) 14238c2ecf20Sopenharmony_ci goto error; 14248c2ecf20Sopenharmony_ci } 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci ret = iwl_send_phy_cfg_cmd(mvm); 14278c2ecf20Sopenharmony_ci if (ret) 14288c2ecf20Sopenharmony_ci goto error; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci ret = iwl_mvm_send_bt_init_conf(mvm); 14318c2ecf20Sopenharmony_ci if (ret) 14328c2ecf20Sopenharmony_ci goto error; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci if (fw_has_capa(&mvm->fw->ucode_capa, 14358c2ecf20Sopenharmony_ci IWL_UCODE_TLV_CAPA_SOC_LATENCY_SUPPORT)) { 14368c2ecf20Sopenharmony_ci ret = iwl_set_soc_latency(&mvm->fwrt); 14378c2ecf20Sopenharmony_ci if (ret) 14388c2ecf20Sopenharmony_ci goto error; 14398c2ecf20Sopenharmony_ci } 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci /* Init RSS configuration */ 14428c2ecf20Sopenharmony_ci if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) { 14438c2ecf20Sopenharmony_ci ret = iwl_configure_rxq(mvm); 14448c2ecf20Sopenharmony_ci if (ret) { 14458c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Failed to configure RX queues: %d\n", 14468c2ecf20Sopenharmony_ci ret); 14478c2ecf20Sopenharmony_ci goto error; 14488c2ecf20Sopenharmony_ci } 14498c2ecf20Sopenharmony_ci } 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci if (iwl_mvm_has_new_rx_api(mvm)) { 14528c2ecf20Sopenharmony_ci ret = iwl_send_rss_cfg_cmd(mvm); 14538c2ecf20Sopenharmony_ci if (ret) { 14548c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Failed to configure RSS queues: %d\n", 14558c2ecf20Sopenharmony_ci ret); 14568c2ecf20Sopenharmony_ci goto error; 14578c2ecf20Sopenharmony_ci } 14588c2ecf20Sopenharmony_ci } 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci /* init the fw <-> mac80211 STA mapping */ 14618c2ecf20Sopenharmony_ci for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) 14628c2ecf20Sopenharmony_ci RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL); 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci mvm->tdls_cs.peer.sta_id = IWL_MVM_INVALID_STA; 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci /* reset quota debouncing buffer - 0xff will yield invalid data */ 14678c2ecf20Sopenharmony_ci memset(&mvm->last_quota_cmd, 0xff, sizeof(mvm->last_quota_cmd)); 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_DQA_SUPPORT)) { 14708c2ecf20Sopenharmony_ci ret = iwl_mvm_send_dqa_cmd(mvm); 14718c2ecf20Sopenharmony_ci if (ret) 14728c2ecf20Sopenharmony_ci goto error; 14738c2ecf20Sopenharmony_ci } 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci /* 14768c2ecf20Sopenharmony_ci * Add auxiliary station for scanning. 14778c2ecf20Sopenharmony_ci * Newer versions of this command implies that the fw uses 14788c2ecf20Sopenharmony_ci * internal aux station for all aux activities that don't 14798c2ecf20Sopenharmony_ci * requires a dedicated data queue. 14808c2ecf20Sopenharmony_ci */ 14818c2ecf20Sopenharmony_ci if (iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, 14828c2ecf20Sopenharmony_ci ADD_STA, 14838c2ecf20Sopenharmony_ci 0) < 12) { 14848c2ecf20Sopenharmony_ci /* 14858c2ecf20Sopenharmony_ci * In old version the aux station uses mac id like other 14868c2ecf20Sopenharmony_ci * station and not lmac id 14878c2ecf20Sopenharmony_ci */ 14888c2ecf20Sopenharmony_ci ret = iwl_mvm_add_aux_sta(mvm, MAC_INDEX_AUX); 14898c2ecf20Sopenharmony_ci if (ret) 14908c2ecf20Sopenharmony_ci goto error; 14918c2ecf20Sopenharmony_ci } 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci /* Add all the PHY contexts */ 14948c2ecf20Sopenharmony_ci i = 0; 14958c2ecf20Sopenharmony_ci while (!sband && i < NUM_NL80211_BANDS) 14968c2ecf20Sopenharmony_ci sband = mvm->hw->wiphy->bands[i++]; 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!sband)) { 14998c2ecf20Sopenharmony_ci ret = -ENODEV; 15008c2ecf20Sopenharmony_ci goto error; 15018c2ecf20Sopenharmony_ci } 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci chan = &sband->channels[0]; 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT); 15068c2ecf20Sopenharmony_ci for (i = 0; i < NUM_PHY_CTX; i++) { 15078c2ecf20Sopenharmony_ci /* 15088c2ecf20Sopenharmony_ci * The channel used here isn't relevant as it's 15098c2ecf20Sopenharmony_ci * going to be overwritten in the other flows. 15108c2ecf20Sopenharmony_ci * For now use the first channel we have. 15118c2ecf20Sopenharmony_ci */ 15128c2ecf20Sopenharmony_ci ret = iwl_mvm_phy_ctxt_add(mvm, &mvm->phy_ctxts[i], 15138c2ecf20Sopenharmony_ci &chandef, 1, 1); 15148c2ecf20Sopenharmony_ci if (ret) 15158c2ecf20Sopenharmony_ci goto error; 15168c2ecf20Sopenharmony_ci } 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci if (iwl_mvm_is_tt_in_fw(mvm)) { 15198c2ecf20Sopenharmony_ci /* in order to give the responsibility of ct-kill and 15208c2ecf20Sopenharmony_ci * TX backoff to FW we need to send empty temperature reporting 15218c2ecf20Sopenharmony_ci * cmd during init time 15228c2ecf20Sopenharmony_ci */ 15238c2ecf20Sopenharmony_ci iwl_mvm_send_temp_report_ths_cmd(mvm); 15248c2ecf20Sopenharmony_ci } else { 15258c2ecf20Sopenharmony_ci /* Initialize tx backoffs to the minimal possible */ 15268c2ecf20Sopenharmony_ci iwl_mvm_tt_tx_backoff(mvm, 0); 15278c2ecf20Sopenharmony_ci } 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci#ifdef CONFIG_THERMAL 15308c2ecf20Sopenharmony_ci /* TODO: read the budget from BIOS / Platform NVM */ 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci /* 15338c2ecf20Sopenharmony_ci * In case there is no budget from BIOS / Platform NVM the default 15348c2ecf20Sopenharmony_ci * budget should be 2000mW (cooling state 0). 15358c2ecf20Sopenharmony_ci */ 15368c2ecf20Sopenharmony_ci if (iwl_mvm_is_ctdp_supported(mvm)) { 15378c2ecf20Sopenharmony_ci ret = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_START, 15388c2ecf20Sopenharmony_ci mvm->cooling_dev.cur_state); 15398c2ecf20Sopenharmony_ci if (ret) 15408c2ecf20Sopenharmony_ci goto error; 15418c2ecf20Sopenharmony_ci } 15428c2ecf20Sopenharmony_ci#endif 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_LTR_GEN2)) 15458c2ecf20Sopenharmony_ci WARN_ON(iwl_mvm_config_ltr(mvm)); 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci ret = iwl_mvm_power_update_device(mvm); 15488c2ecf20Sopenharmony_ci if (ret) 15498c2ecf20Sopenharmony_ci goto error; 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci iwl_mvm_lari_cfg(mvm); 15528c2ecf20Sopenharmony_ci /* 15538c2ecf20Sopenharmony_ci * RTNL is not taken during Ct-kill, but we don't need to scan/Tx 15548c2ecf20Sopenharmony_ci * anyway, so don't init MCC. 15558c2ecf20Sopenharmony_ci */ 15568c2ecf20Sopenharmony_ci if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) { 15578c2ecf20Sopenharmony_ci ret = iwl_mvm_init_mcc(mvm); 15588c2ecf20Sopenharmony_ci if (ret) 15598c2ecf20Sopenharmony_ci goto error; 15608c2ecf20Sopenharmony_ci } 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { 15638c2ecf20Sopenharmony_ci mvm->scan_type = IWL_SCAN_TYPE_NOT_SET; 15648c2ecf20Sopenharmony_ci mvm->hb_scan_type = IWL_SCAN_TYPE_NOT_SET; 15658c2ecf20Sopenharmony_ci ret = iwl_mvm_config_scan(mvm); 15668c2ecf20Sopenharmony_ci if (ret) 15678c2ecf20Sopenharmony_ci goto error; 15688c2ecf20Sopenharmony_ci } 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) 15718c2ecf20Sopenharmony_ci iwl_mvm_send_recovery_cmd(mvm, ERROR_RECOVERY_UPDATE_DB); 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci if (iwl_acpi_get_eckv(mvm->dev, &mvm->ext_clock_valid)) 15748c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(mvm, "ECKV table doesn't exist in BIOS\n"); 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci ret = iwl_mvm_ppag_init(mvm); 15778c2ecf20Sopenharmony_ci if (ret) 15788c2ecf20Sopenharmony_ci goto error; 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci ret = iwl_mvm_sar_init(mvm); 15818c2ecf20Sopenharmony_ci if (ret == 0) { 15828c2ecf20Sopenharmony_ci ret = iwl_mvm_sar_geo_init(mvm); 15838c2ecf20Sopenharmony_ci } else if (ret == -ENOENT && !iwl_sar_get_wgds_table(&mvm->fwrt)) { 15848c2ecf20Sopenharmony_ci /* 15858c2ecf20Sopenharmony_ci * If basic SAR is not available, we check for WGDS, 15868c2ecf20Sopenharmony_ci * which should *not* be available either. If it is 15878c2ecf20Sopenharmony_ci * available, issue an error, because we can't use SAR 15888c2ecf20Sopenharmony_ci * Geo without basic SAR. 15898c2ecf20Sopenharmony_ci */ 15908c2ecf20Sopenharmony_ci IWL_ERR(mvm, "BIOS contains WGDS but no WRDS\n"); 15918c2ecf20Sopenharmony_ci } 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci if (ret < 0) 15948c2ecf20Sopenharmony_ci goto error; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci iwl_mvm_tas_init(mvm); 15978c2ecf20Sopenharmony_ci iwl_mvm_leds_sync(mvm); 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci iwl_mvm_ftm_initiator_smooth_config(mvm); 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(mvm, "RT uCode started.\n"); 16028c2ecf20Sopenharmony_ci return 0; 16038c2ecf20Sopenharmony_ci error: 16048c2ecf20Sopenharmony_ci if (!iwlmvm_mod_params.init_dbg || !ret) 16058c2ecf20Sopenharmony_ci iwl_mvm_stop_device(mvm); 16068c2ecf20Sopenharmony_ci return ret; 16078c2ecf20Sopenharmony_ci} 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ciint iwl_mvm_load_d3_fw(struct iwl_mvm *mvm) 16108c2ecf20Sopenharmony_ci{ 16118c2ecf20Sopenharmony_ci int ret, i; 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci lockdep_assert_held(&mvm->mutex); 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci ret = iwl_trans_start_hw(mvm->trans); 16168c2ecf20Sopenharmony_ci if (ret) 16178c2ecf20Sopenharmony_ci return ret; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_WOWLAN); 16208c2ecf20Sopenharmony_ci if (ret) { 16218c2ecf20Sopenharmony_ci IWL_ERR(mvm, "Failed to start WoWLAN firmware: %d\n", ret); 16228c2ecf20Sopenharmony_ci goto error; 16238c2ecf20Sopenharmony_ci } 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm)); 16268c2ecf20Sopenharmony_ci if (ret) 16278c2ecf20Sopenharmony_ci goto error; 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci /* Send phy db control command and then phy db calibration*/ 16308c2ecf20Sopenharmony_ci ret = iwl_send_phy_db_data(mvm->phy_db); 16318c2ecf20Sopenharmony_ci if (ret) 16328c2ecf20Sopenharmony_ci goto error; 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci ret = iwl_send_phy_cfg_cmd(mvm); 16358c2ecf20Sopenharmony_ci if (ret) 16368c2ecf20Sopenharmony_ci goto error; 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci /* init the fw <-> mac80211 STA mapping */ 16398c2ecf20Sopenharmony_ci for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) 16408c2ecf20Sopenharmony_ci RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL); 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci if (iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, 16438c2ecf20Sopenharmony_ci ADD_STA, 16448c2ecf20Sopenharmony_ci 0) < 12) { 16458c2ecf20Sopenharmony_ci /* 16468c2ecf20Sopenharmony_ci * Add auxiliary station for scanning. 16478c2ecf20Sopenharmony_ci * Newer versions of this command implies that the fw uses 16488c2ecf20Sopenharmony_ci * internal aux station for all aux activities that don't 16498c2ecf20Sopenharmony_ci * requires a dedicated data queue. 16508c2ecf20Sopenharmony_ci * In old version the aux station uses mac id like other 16518c2ecf20Sopenharmony_ci * station and not lmac id 16528c2ecf20Sopenharmony_ci */ 16538c2ecf20Sopenharmony_ci ret = iwl_mvm_add_aux_sta(mvm, MAC_INDEX_AUX); 16548c2ecf20Sopenharmony_ci if (ret) 16558c2ecf20Sopenharmony_ci goto error; 16568c2ecf20Sopenharmony_ci } 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci return 0; 16598c2ecf20Sopenharmony_ci error: 16608c2ecf20Sopenharmony_ci iwl_mvm_stop_device(mvm); 16618c2ecf20Sopenharmony_ci return ret; 16628c2ecf20Sopenharmony_ci} 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_civoid iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, 16658c2ecf20Sopenharmony_ci struct iwl_rx_cmd_buffer *rxb) 16668c2ecf20Sopenharmony_ci{ 16678c2ecf20Sopenharmony_ci struct iwl_rx_packet *pkt = rxb_addr(rxb); 16688c2ecf20Sopenharmony_ci struct iwl_card_state_notif *card_state_notif = (void *)pkt->data; 16698c2ecf20Sopenharmony_ci u32 flags = le32_to_cpu(card_state_notif->flags); 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci IWL_DEBUG_RF_KILL(mvm, "Card state received: HW:%s SW:%s CT:%s\n", 16728c2ecf20Sopenharmony_ci (flags & HW_CARD_DISABLED) ? "Kill" : "On", 16738c2ecf20Sopenharmony_ci (flags & SW_CARD_DISABLED) ? "Kill" : "On", 16748c2ecf20Sopenharmony_ci (flags & CT_KILL_CARD_DISABLED) ? 16758c2ecf20Sopenharmony_ci "Reached" : "Not reached"); 16768c2ecf20Sopenharmony_ci} 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_civoid iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, 16798c2ecf20Sopenharmony_ci struct iwl_rx_cmd_buffer *rxb) 16808c2ecf20Sopenharmony_ci{ 16818c2ecf20Sopenharmony_ci struct iwl_rx_packet *pkt = rxb_addr(rxb); 16828c2ecf20Sopenharmony_ci struct iwl_mfuart_load_notif *mfuart_notif = (void *)pkt->data; 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(mvm, 16858c2ecf20Sopenharmony_ci "MFUART: installed ver: 0x%08x, external ver: 0x%08x, status: 0x%08x, duration: 0x%08x\n", 16868c2ecf20Sopenharmony_ci le32_to_cpu(mfuart_notif->installed_ver), 16878c2ecf20Sopenharmony_ci le32_to_cpu(mfuart_notif->external_ver), 16888c2ecf20Sopenharmony_ci le32_to_cpu(mfuart_notif->status), 16898c2ecf20Sopenharmony_ci le32_to_cpu(mfuart_notif->duration)); 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci if (iwl_rx_packet_payload_len(pkt) == sizeof(*mfuart_notif)) 16928c2ecf20Sopenharmony_ci IWL_DEBUG_INFO(mvm, 16938c2ecf20Sopenharmony_ci "MFUART: image size: 0x%08x\n", 16948c2ecf20Sopenharmony_ci le32_to_cpu(mfuart_notif->image_size)); 16958c2ecf20Sopenharmony_ci} 1696