18e99ea8dSJohannes Berg // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 28e99ea8dSJohannes Berg /* 3a7de31d5SMordechay Goodstein * Copyright (C) 2012-2014, 2018-2022 Intel Corporation 48e99ea8dSJohannes Berg * Copyright (C) 2013-2015 Intel Mobile Communications GmbH 58e99ea8dSJohannes Berg * Copyright (C) 2016-2017 Intel Deutschland GmbH 68e99ea8dSJohannes Berg */ 7e705c121SKalle Valo #include <net/mac80211.h> 8854d773eSSara Sharon #include <linux/netdevice.h> 9a2ac0f48SLuca Coelho #include <linux/dmi.h> 10e705c121SKalle Valo 11e705c121SKalle Valo #include "iwl-trans.h" 12e705c121SKalle Valo #include "iwl-op-mode.h" 13d962f9b1SJohannes Berg #include "fw/img.h" 14e705c121SKalle Valo #include "iwl-debug.h" 15e705c121SKalle Valo #include "iwl-prph.h" 16813df5ceSLuca Coelho #include "fw/acpi.h" 17b3e4c0f3SLuca Coelho #include "fw/pnvm.h" 18e705c121SKalle Valo 19e705c121SKalle Valo #include "mvm.h" 207174beb6SJohannes Berg #include "fw/dbg.h" 21e705c121SKalle Valo #include "iwl-phy-db.h" 229c4f7d51SShaul Triebitz #include "iwl-modparams.h" 239c4f7d51SShaul Triebitz #include "iwl-nvm-parse.h" 24e705c121SKalle Valo 25b3e4c0f3SLuca Coelho #define MVM_UCODE_ALIVE_TIMEOUT (HZ) 26e705c121SKalle Valo #define MVM_UCODE_CALIB_TIMEOUT (2 * HZ) 27e705c121SKalle Valo 28c3f40c3eSMiri Korenblit #define IWL_TAS_US_MCC 0x5553 29c3f40c3eSMiri Korenblit #define IWL_TAS_CANADA_MCC 0x4341 30c3f40c3eSMiri Korenblit 31e705c121SKalle Valo struct iwl_mvm_alive_data { 32e705c121SKalle Valo bool valid; 33e705c121SKalle Valo u32 scd_base_addr; 34e705c121SKalle Valo }; 35e705c121SKalle Valo 36e705c121SKalle Valo static int iwl_send_tx_ant_cfg(struct iwl_mvm *mvm, u8 valid_tx_ant) 37e705c121SKalle Valo { 38e705c121SKalle Valo struct iwl_tx_ant_cfg_cmd tx_ant_cmd = { 39e705c121SKalle Valo .valid = cpu_to_le32(valid_tx_ant), 40e705c121SKalle Valo }; 41e705c121SKalle Valo 42e705c121SKalle Valo IWL_DEBUG_FW(mvm, "select valid tx ant: %u\n", valid_tx_ant); 43e705c121SKalle Valo return iwl_mvm_send_cmd_pdu(mvm, TX_ANT_CONFIGURATION_CMD, 0, 44e705c121SKalle Valo sizeof(tx_ant_cmd), &tx_ant_cmd); 45e705c121SKalle Valo } 46e705c121SKalle Valo 4743413a97SSara Sharon static int iwl_send_rss_cfg_cmd(struct iwl_mvm *mvm) 4843413a97SSara Sharon { 4943413a97SSara Sharon int i; 5043413a97SSara Sharon struct iwl_rss_config_cmd cmd = { 5143413a97SSara Sharon .flags = cpu_to_le32(IWL_RSS_ENABLE), 52608dce95SSara Sharon .hash_mask = BIT(IWL_RSS_HASH_TYPE_IPV4_TCP) | 53608dce95SSara Sharon BIT(IWL_RSS_HASH_TYPE_IPV4_UDP) | 54608dce95SSara Sharon BIT(IWL_RSS_HASH_TYPE_IPV4_PAYLOAD) | 55608dce95SSara Sharon BIT(IWL_RSS_HASH_TYPE_IPV6_TCP) | 56608dce95SSara Sharon BIT(IWL_RSS_HASH_TYPE_IPV6_UDP) | 57608dce95SSara Sharon BIT(IWL_RSS_HASH_TYPE_IPV6_PAYLOAD), 5843413a97SSara Sharon }; 5943413a97SSara Sharon 60f43495fdSSara Sharon if (mvm->trans->num_rx_queues == 1) 61f43495fdSSara Sharon return 0; 62f43495fdSSara Sharon 63854d773eSSara Sharon /* Do not direct RSS traffic to Q 0 which is our fallback queue */ 6443413a97SSara Sharon for (i = 0; i < ARRAY_SIZE(cmd.indirection_table); i++) 65854d773eSSara Sharon cmd.indirection_table[i] = 66854d773eSSara Sharon 1 + (i % (mvm->trans->num_rx_queues - 1)); 67854d773eSSara Sharon netdev_rss_key_fill(cmd.secret_key, sizeof(cmd.secret_key)); 6843413a97SSara Sharon 6943413a97SSara Sharon return iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0, sizeof(cmd), &cmd); 7043413a97SSara Sharon } 7143413a97SSara Sharon 7297d5be7eSLiad Kaufman static int iwl_mvm_send_dqa_cmd(struct iwl_mvm *mvm) 7397d5be7eSLiad Kaufman { 7497d5be7eSLiad Kaufman struct iwl_dqa_enable_cmd dqa_cmd = { 7597d5be7eSLiad Kaufman .cmd_queue = cpu_to_le32(IWL_MVM_DQA_CMD_QUEUE), 7697d5be7eSLiad Kaufman }; 77f0c86427SJohannes Berg u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, DQA_ENABLE_CMD); 7897d5be7eSLiad Kaufman int ret; 7997d5be7eSLiad Kaufman 8097d5be7eSLiad Kaufman ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(dqa_cmd), &dqa_cmd); 8197d5be7eSLiad Kaufman if (ret) 8297d5be7eSLiad Kaufman IWL_ERR(mvm, "Failed to send DQA enabling command: %d\n", ret); 8397d5be7eSLiad Kaufman else 8497d5be7eSLiad Kaufman IWL_DEBUG_FW(mvm, "Working in DQA mode\n"); 8597d5be7eSLiad Kaufman 8697d5be7eSLiad Kaufman return ret; 8797d5be7eSLiad Kaufman } 8897d5be7eSLiad Kaufman 89bdccdb85SGolan Ben-Ami void iwl_mvm_mfu_assert_dump_notif(struct iwl_mvm *mvm, 90bdccdb85SGolan Ben-Ami struct iwl_rx_cmd_buffer *rxb) 91bdccdb85SGolan Ben-Ami { 92bdccdb85SGolan Ben-Ami struct iwl_rx_packet *pkt = rxb_addr(rxb); 93bdccdb85SGolan Ben-Ami struct iwl_mfu_assert_dump_notif *mfu_dump_notif = (void *)pkt->data; 94bdccdb85SGolan Ben-Ami __le32 *dump_data = mfu_dump_notif->data; 95bdccdb85SGolan Ben-Ami int n_words = le32_to_cpu(mfu_dump_notif->data_size) / sizeof(__le32); 96bdccdb85SGolan Ben-Ami int i; 97bdccdb85SGolan Ben-Ami 98bdccdb85SGolan Ben-Ami if (mfu_dump_notif->index_num == 0) 99bdccdb85SGolan Ben-Ami IWL_INFO(mvm, "MFUART assert id 0x%x occurred\n", 100bdccdb85SGolan Ben-Ami le32_to_cpu(mfu_dump_notif->assert_id)); 101bdccdb85SGolan Ben-Ami 102bdccdb85SGolan Ben-Ami for (i = 0; i < n_words; i++) 103bdccdb85SGolan Ben-Ami IWL_DEBUG_INFO(mvm, 104bdccdb85SGolan Ben-Ami "MFUART assert dump, dword %u: 0x%08x\n", 105bdccdb85SGolan Ben-Ami le16_to_cpu(mfu_dump_notif->index_num) * 106bdccdb85SGolan Ben-Ami n_words + i, 107bdccdb85SGolan Ben-Ami le32_to_cpu(dump_data[i])); 108bdccdb85SGolan Ben-Ami } 109bdccdb85SGolan Ben-Ami 110e705c121SKalle Valo static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, 111e705c121SKalle Valo struct iwl_rx_packet *pkt, void *data) 112e705c121SKalle Valo { 113fd1c3318SJohannes Berg unsigned int pkt_len = iwl_rx_packet_payload_len(pkt); 114e705c121SKalle Valo struct iwl_mvm *mvm = 115e705c121SKalle Valo container_of(notif_wait, struct iwl_mvm, notif_wait); 116e705c121SKalle Valo struct iwl_mvm_alive_data *alive_data = data; 1175c228d63SSara Sharon struct iwl_umac_alive *umac; 1185c228d63SSara Sharon struct iwl_lmac_alive *lmac1; 1195c228d63SSara Sharon struct iwl_lmac_alive *lmac2 = NULL; 1205c228d63SSara Sharon u16 status; 121cfa5d0caSMordechay Goodstein u32 lmac_error_event_table, umac_error_table; 122708d8c53SJohannes Berg u32 version = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, 123708d8c53SJohannes Berg UCODE_ALIVE_NTFY, 0); 1245053a451SMukesh Sisodiya u32 i; 125e705c121SKalle Valo 126c0941aceSMukesh Sisodiya if (version == 6) { 127c0941aceSMukesh Sisodiya struct iwl_alive_ntf_v6 *palive; 128c0941aceSMukesh Sisodiya 129c0941aceSMukesh Sisodiya if (pkt_len < sizeof(*palive)) 130c0941aceSMukesh Sisodiya return false; 131c0941aceSMukesh Sisodiya 132c0941aceSMukesh Sisodiya palive = (void *)pkt->data; 133c0941aceSMukesh Sisodiya mvm->trans->dbg.imr_data.imr_enable = 134c0941aceSMukesh Sisodiya le32_to_cpu(palive->imr.enabled); 135c0941aceSMukesh Sisodiya mvm->trans->dbg.imr_data.imr_size = 136c0941aceSMukesh Sisodiya le32_to_cpu(palive->imr.size); 137c0941aceSMukesh Sisodiya mvm->trans->dbg.imr_data.imr2sram_remainbyte = 138c0941aceSMukesh Sisodiya mvm->trans->dbg.imr_data.imr_size; 139c0941aceSMukesh Sisodiya mvm->trans->dbg.imr_data.imr_base_addr = 140c0941aceSMukesh Sisodiya palive->imr.base_addr; 141c0941aceSMukesh Sisodiya mvm->trans->dbg.imr_data.imr_curr_addr = 142c0941aceSMukesh Sisodiya le64_to_cpu(mvm->trans->dbg.imr_data.imr_base_addr); 143c0941aceSMukesh Sisodiya IWL_DEBUG_FW(mvm, "IMR Enabled: 0x0%x size 0x0%x Address 0x%016llx\n", 144c0941aceSMukesh Sisodiya mvm->trans->dbg.imr_data.imr_enable, 145c0941aceSMukesh Sisodiya mvm->trans->dbg.imr_data.imr_size, 146c0941aceSMukesh Sisodiya le64_to_cpu(mvm->trans->dbg.imr_data.imr_base_addr)); 1475053a451SMukesh Sisodiya 1485053a451SMukesh Sisodiya if (!mvm->trans->dbg.imr_data.imr_enable) { 1495053a451SMukesh Sisodiya for (i = 0; i < ARRAY_SIZE(mvm->trans->dbg.active_regions); i++) { 1505053a451SMukesh Sisodiya struct iwl_ucode_tlv *reg_tlv; 1515053a451SMukesh Sisodiya struct iwl_fw_ini_region_tlv *reg; 1525053a451SMukesh Sisodiya 1535053a451SMukesh Sisodiya reg_tlv = mvm->trans->dbg.active_regions[i]; 1545053a451SMukesh Sisodiya if (!reg_tlv) 1555053a451SMukesh Sisodiya continue; 1565053a451SMukesh Sisodiya 1575053a451SMukesh Sisodiya reg = (void *)reg_tlv->data; 1585053a451SMukesh Sisodiya /* 1595053a451SMukesh Sisodiya * We have only one DRAM IMR region, so we 1605053a451SMukesh Sisodiya * can break as soon as we find the first 1615053a451SMukesh Sisodiya * one. 1625053a451SMukesh Sisodiya */ 1635053a451SMukesh Sisodiya if (reg->type == IWL_FW_INI_REGION_DRAM_IMR) { 1645053a451SMukesh Sisodiya mvm->trans->dbg.unsupported_region_msk |= BIT(i); 1655053a451SMukesh Sisodiya break; 1665053a451SMukesh Sisodiya } 1675053a451SMukesh Sisodiya } 1685053a451SMukesh Sisodiya } 169c0941aceSMukesh Sisodiya } 170c0941aceSMukesh Sisodiya 171c0941aceSMukesh Sisodiya if (version >= 5) { 17290824f2fSLuca Coelho struct iwl_alive_ntf_v5 *palive; 17390824f2fSLuca Coelho 174fd1c3318SJohannes Berg if (pkt_len < sizeof(*palive)) 175fd1c3318SJohannes Berg return false; 176fd1c3318SJohannes Berg 17790824f2fSLuca Coelho palive = (void *)pkt->data; 17890824f2fSLuca Coelho umac = &palive->umac_data; 17990824f2fSLuca Coelho lmac1 = &palive->lmac_data[0]; 18090824f2fSLuca Coelho lmac2 = &palive->lmac_data[1]; 18190824f2fSLuca Coelho status = le16_to_cpu(palive->status); 18290824f2fSLuca Coelho 18390824f2fSLuca Coelho mvm->trans->sku_id[0] = le32_to_cpu(palive->sku_id.data[0]); 18490824f2fSLuca Coelho mvm->trans->sku_id[1] = le32_to_cpu(palive->sku_id.data[1]); 18590824f2fSLuca Coelho mvm->trans->sku_id[2] = le32_to_cpu(palive->sku_id.data[2]); 18690824f2fSLuca Coelho 18790824f2fSLuca Coelho IWL_DEBUG_FW(mvm, "Got sku_id: 0x0%x 0x0%x 0x0%x\n", 18890824f2fSLuca Coelho mvm->trans->sku_id[0], 18990824f2fSLuca Coelho mvm->trans->sku_id[1], 19090824f2fSLuca Coelho mvm->trans->sku_id[2]); 19190824f2fSLuca Coelho } else if (iwl_rx_packet_payload_len(pkt) == sizeof(struct iwl_alive_ntf_v4)) { 1929422b978SLuca Coelho struct iwl_alive_ntf_v4 *palive; 1939422b978SLuca Coelho 194fd1c3318SJohannes Berg if (pkt_len < sizeof(*palive)) 195fd1c3318SJohannes Berg return false; 196fd1c3318SJohannes Berg 197e705c121SKalle Valo palive = (void *)pkt->data; 1985c228d63SSara Sharon umac = &palive->umac_data; 1995c228d63SSara Sharon lmac1 = &palive->lmac_data[0]; 2005c228d63SSara Sharon lmac2 = &palive->lmac_data[1]; 2015c228d63SSara Sharon status = le16_to_cpu(palive->status); 2029422b978SLuca Coelho } else if (iwl_rx_packet_payload_len(pkt) == 2039422b978SLuca Coelho sizeof(struct iwl_alive_ntf_v3)) { 2049422b978SLuca Coelho struct iwl_alive_ntf_v3 *palive3; 2059422b978SLuca Coelho 206fd1c3318SJohannes Berg if (pkt_len < sizeof(*palive3)) 207fd1c3318SJohannes Berg return false; 208fd1c3318SJohannes Berg 2095c228d63SSara Sharon palive3 = (void *)pkt->data; 2105c228d63SSara Sharon umac = &palive3->umac_data; 2115c228d63SSara Sharon lmac1 = &palive3->lmac_data; 2125c228d63SSara Sharon status = le16_to_cpu(palive3->status); 2139422b978SLuca Coelho } else { 2149422b978SLuca Coelho WARN(1, "unsupported alive notification (size %d)\n", 2159422b978SLuca Coelho iwl_rx_packet_payload_len(pkt)); 2169422b978SLuca Coelho /* get timeout later */ 2179422b978SLuca Coelho return false; 2185c228d63SSara Sharon } 219e705c121SKalle Valo 22022463857SShahar S Matityahu lmac_error_event_table = 22122463857SShahar S Matityahu le32_to_cpu(lmac1->dbg_ptrs.error_event_table_ptr); 22222463857SShahar S Matityahu iwl_fw_lmac1_set_alive_err_table(mvm->trans, lmac_error_event_table); 223e705c121SKalle Valo 22422463857SShahar S Matityahu if (lmac2) 22591c28b83SShahar S Matityahu mvm->trans->dbg.lmac_error_event_table[1] = 22622463857SShahar S Matityahu le32_to_cpu(lmac2->dbg_ptrs.error_event_table_ptr); 22722463857SShahar S Matityahu 2284f7411d6SRoee Goldfiner umac_error_table = le32_to_cpu(umac->dbg_ptrs.error_info_addr) & 2294f7411d6SRoee Goldfiner ~FW_ADDR_CACHE_CONTROL; 2305c228d63SSara Sharon 231cfa5d0caSMordechay Goodstein if (umac_error_table) { 232cfa5d0caSMordechay Goodstein if (umac_error_table >= 2333485e76eSLuca Coelho mvm->trans->cfg->min_umac_error_event_table) { 234cfa5d0caSMordechay Goodstein iwl_fw_umac_set_alive_err_table(mvm->trans, 235cfa5d0caSMordechay Goodstein umac_error_table); 2363485e76eSLuca Coelho } else { 237fb5b2846SLuca Coelho IWL_ERR(mvm, 238fb5b2846SLuca Coelho "Not valid error log pointer 0x%08X for %s uCode\n", 239cfa5d0caSMordechay Goodstein umac_error_table, 240fb5b2846SLuca Coelho (mvm->fwrt.cur_fw_img == IWL_UCODE_INIT) ? 241fb5b2846SLuca Coelho "Init" : "RT"); 2423485e76eSLuca Coelho } 243cfa5d0caSMordechay Goodstein } 24422463857SShahar S Matityahu 24522463857SShahar S Matityahu alive_data->scd_base_addr = le32_to_cpu(lmac1->dbg_ptrs.scd_base_ptr); 2465c228d63SSara Sharon alive_data->valid = status == IWL_ALIVE_STATUS_OK; 247e705c121SKalle Valo 248e705c121SKalle Valo IWL_DEBUG_FW(mvm, 2495c228d63SSara Sharon "Alive ucode status 0x%04x revision 0x%01X 0x%01X\n", 2505c228d63SSara Sharon status, lmac1->ver_type, lmac1->ver_subtype); 2515c228d63SSara Sharon 2525c228d63SSara Sharon if (lmac2) 2535c228d63SSara Sharon IWL_DEBUG_FW(mvm, "Alive ucode CDB\n"); 254e705c121SKalle Valo 255e705c121SKalle Valo IWL_DEBUG_FW(mvm, 256e705c121SKalle Valo "UMAC version: Major - 0x%x, Minor - 0x%x\n", 2575c228d63SSara Sharon le32_to_cpu(umac->umac_major), 2585c228d63SSara Sharon le32_to_cpu(umac->umac_minor)); 259e705c121SKalle Valo 2600a3a3e9eSShahar S Matityahu iwl_fwrt_update_fw_versions(&mvm->fwrt, lmac1, umac); 2610a3a3e9eSShahar S Matityahu 262e705c121SKalle Valo return true; 263e705c121SKalle Valo } 264e705c121SKalle Valo 2651f370650SSara Sharon static bool iwl_wait_init_complete(struct iwl_notif_wait_data *notif_wait, 2661f370650SSara Sharon struct iwl_rx_packet *pkt, void *data) 2671f370650SSara Sharon { 2681f370650SSara Sharon WARN_ON(pkt->hdr.cmd != INIT_COMPLETE_NOTIF); 2691f370650SSara Sharon 2701f370650SSara Sharon return true; 2711f370650SSara Sharon } 2721f370650SSara Sharon 273e705c121SKalle Valo static bool iwl_wait_phy_db_entry(struct iwl_notif_wait_data *notif_wait, 274e705c121SKalle Valo struct iwl_rx_packet *pkt, void *data) 275e705c121SKalle Valo { 276e705c121SKalle Valo struct iwl_phy_db *phy_db = data; 277e705c121SKalle Valo 278e705c121SKalle Valo if (pkt->hdr.cmd != CALIB_RES_NOTIF_PHY_DB) { 279e705c121SKalle Valo WARN_ON(pkt->hdr.cmd != INIT_COMPLETE_NOTIF); 280e705c121SKalle Valo return true; 281e705c121SKalle Valo } 282e705c121SKalle Valo 283ce1f2778SSara Sharon WARN_ON(iwl_phy_db_set_section(phy_db, pkt)); 284e705c121SKalle Valo 285e705c121SKalle Valo return false; 286e705c121SKalle Valo } 287e705c121SKalle Valo 288a7de31d5SMordechay Goodstein static void iwl_mvm_print_pd_notification(struct iwl_mvm *mvm) 289a7de31d5SMordechay Goodstein { 290a7de31d5SMordechay Goodstein struct iwl_trans *trans = mvm->trans; 291a7de31d5SMordechay Goodstein enum iwl_device_family device_family = trans->trans_cfg->device_family; 292a7de31d5SMordechay Goodstein 293a7de31d5SMordechay Goodstein if (device_family < IWL_DEVICE_FAMILY_8000) 294a7de31d5SMordechay Goodstein return; 295a7de31d5SMordechay Goodstein 296a7de31d5SMordechay Goodstein if (device_family <= IWL_DEVICE_FAMILY_9000) 297a7de31d5SMordechay Goodstein IWL_ERR(mvm, "WFPM_ARC1_PD_NOTIFICATION: 0x%x\n", 298a7de31d5SMordechay Goodstein iwl_read_umac_prph(trans, WFPM_ARC1_PD_NOTIFICATION)); 299a7de31d5SMordechay Goodstein else 300a7de31d5SMordechay Goodstein IWL_ERR(mvm, "WFPM_LMAC1_PD_NOTIFICATION: 0x%x\n", 301a7de31d5SMordechay Goodstein iwl_read_umac_prph(trans, WFPM_LMAC1_PD_NOTIFICATION)); 302f2f17ca0SMordechay Goodstein 303f2f17ca0SMordechay Goodstein IWL_ERR(mvm, "HPM_SECONDARY_DEVICE_STATE: 0x%x\n", 304f2f17ca0SMordechay Goodstein iwl_read_umac_prph(trans, HPM_SECONDARY_DEVICE_STATE)); 305f2f17ca0SMordechay Goodstein 306a7de31d5SMordechay Goodstein } 307a7de31d5SMordechay Goodstein 308e705c121SKalle Valo static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, 309e705c121SKalle Valo enum iwl_ucode_type ucode_type) 310e705c121SKalle Valo { 311e705c121SKalle Valo struct iwl_notification_wait alive_wait; 31294a8d87cSLuca Coelho struct iwl_mvm_alive_data alive_data = {}; 313e705c121SKalle Valo const struct fw_img *fw; 314cfbc6c4cSSara Sharon int ret; 315702e975dSJohannes Berg enum iwl_ucode_type old_type = mvm->fwrt.cur_fw_img; 3169422b978SLuca Coelho static const u16 alive_cmd[] = { UCODE_ALIVE_NTFY }; 317b3500b47SEmmanuel Grumbach bool run_in_rfkill = 318b3500b47SEmmanuel Grumbach ucode_type == IWL_UCODE_INIT || iwl_mvm_has_unified_ucode(mvm); 319e705c121SKalle Valo 320e705c121SKalle Valo if (ucode_type == IWL_UCODE_REGULAR && 3213d2d4422SGolan Ben-Ami iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_START_FROM_ALIVE) && 3223d2d4422SGolan Ben-Ami !(fw_has_capa(&mvm->fw->ucode_capa, 3233d2d4422SGolan Ben-Ami IWL_UCODE_TLV_CAPA_USNIFFER_UNIFIED))) 324612da1efSSharon Dvir fw = iwl_get_ucode_image(mvm->fw, IWL_UCODE_REGULAR_USNIFFER); 325e705c121SKalle Valo else 326612da1efSSharon Dvir fw = iwl_get_ucode_image(mvm->fw, ucode_type); 327e705c121SKalle Valo if (WARN_ON(!fw)) 328e705c121SKalle Valo return -EINVAL; 329702e975dSJohannes Berg iwl_fw_set_current_image(&mvm->fwrt, ucode_type); 33065b280feSJohannes Berg clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); 331e705c121SKalle Valo 332e705c121SKalle Valo iwl_init_notification_wait(&mvm->notif_wait, &alive_wait, 333e705c121SKalle Valo alive_cmd, ARRAY_SIZE(alive_cmd), 334e705c121SKalle Valo iwl_alive_fn, &alive_data); 335e705c121SKalle Valo 336b3500b47SEmmanuel Grumbach /* 337b3500b47SEmmanuel Grumbach * We want to load the INIT firmware even in RFKILL 338b3500b47SEmmanuel Grumbach * For the unified firmware case, the ucode_type is not 339b3500b47SEmmanuel Grumbach * INIT, but we still need to run it. 340b3500b47SEmmanuel Grumbach */ 341b3500b47SEmmanuel Grumbach ret = iwl_trans_start_fw(mvm->trans, fw, run_in_rfkill); 342e705c121SKalle Valo if (ret) { 343702e975dSJohannes Berg iwl_fw_set_current_image(&mvm->fwrt, old_type); 344e705c121SKalle Valo iwl_remove_notification(&mvm->notif_wait, &alive_wait); 345e705c121SKalle Valo return ret; 346e705c121SKalle Valo } 347e705c121SKalle Valo 348e705c121SKalle Valo /* 349e705c121SKalle Valo * Some things may run in the background now, but we 350e705c121SKalle Valo * just wait for the ALIVE notification here. 351e705c121SKalle Valo */ 352e705c121SKalle Valo ret = iwl_wait_notification(&mvm->notif_wait, &alive_wait, 353e705c121SKalle Valo MVM_UCODE_ALIVE_TIMEOUT); 354e705c121SKalle Valo if (ret) { 355d6be9c1dSSara Sharon struct iwl_trans *trans = mvm->trans; 356d6be9c1dSSara Sharon 3575667ccc2SMordechay Goodstein /* SecBoot info */ 35820f5aef5SJohannes Berg if (trans->trans_cfg->device_family >= 35920f5aef5SJohannes Berg IWL_DEVICE_FAMILY_22000) { 360e705c121SKalle Valo IWL_ERR(mvm, 361e705c121SKalle Valo "SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n", 362ea695b7cSShaul Triebitz iwl_read_umac_prph(trans, UMAG_SB_CPU_1_STATUS), 363ea695b7cSShaul Triebitz iwl_read_umac_prph(trans, 364ea695b7cSShaul Triebitz UMAG_SB_CPU_2_STATUS)); 3655667ccc2SMordechay Goodstein } else if (trans->trans_cfg->device_family >= 3665667ccc2SMordechay Goodstein IWL_DEVICE_FAMILY_8000) { 3675667ccc2SMordechay Goodstein IWL_ERR(mvm, 3685667ccc2SMordechay Goodstein "SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n", 3695667ccc2SMordechay Goodstein iwl_read_prph(trans, SB_CPU_1_STATUS), 3705667ccc2SMordechay Goodstein iwl_read_prph(trans, SB_CPU_2_STATUS)); 3715667ccc2SMordechay Goodstein } 3725667ccc2SMordechay Goodstein 373a7de31d5SMordechay Goodstein iwl_mvm_print_pd_notification(mvm); 374a7de31d5SMordechay Goodstein 3755667ccc2SMordechay Goodstein /* LMAC/UMAC PC info */ 3765667ccc2SMordechay Goodstein if (trans->trans_cfg->device_family >= 3775667ccc2SMordechay Goodstein IWL_DEVICE_FAMILY_9000) { 37820f5aef5SJohannes Berg IWL_ERR(mvm, "UMAC PC: 0x%x\n", 37920f5aef5SJohannes Berg iwl_read_umac_prph(trans, 38020f5aef5SJohannes Berg UREG_UMAC_CURRENT_PC)); 38120f5aef5SJohannes Berg IWL_ERR(mvm, "LMAC PC: 0x%x\n", 38220f5aef5SJohannes Berg iwl_read_umac_prph(trans, 38320f5aef5SJohannes Berg UREG_LMAC1_CURRENT_PC)); 38420f5aef5SJohannes Berg if (iwl_mvm_is_cdb_supported(mvm)) 38520f5aef5SJohannes Berg IWL_ERR(mvm, "LMAC2 PC: 0x%x\n", 38620f5aef5SJohannes Berg iwl_read_umac_prph(trans, 38720f5aef5SJohannes Berg UREG_LMAC2_CURRENT_PC)); 38820f5aef5SJohannes Berg } 38920f5aef5SJohannes Berg 39020f5aef5SJohannes Berg if (ret == -ETIMEDOUT) 39120f5aef5SJohannes Berg iwl_fw_dbg_error_collect(&mvm->fwrt, 39220f5aef5SJohannes Berg FW_DBG_TRIGGER_ALIVE_TIMEOUT); 39320f5aef5SJohannes Berg 394702e975dSJohannes Berg iwl_fw_set_current_image(&mvm->fwrt, old_type); 395e705c121SKalle Valo return ret; 396e705c121SKalle Valo } 397e705c121SKalle Valo 398e705c121SKalle Valo if (!alive_data.valid) { 399e705c121SKalle Valo IWL_ERR(mvm, "Loaded ucode is not valid!\n"); 400702e975dSJohannes Berg iwl_fw_set_current_image(&mvm->fwrt, old_type); 401e705c121SKalle Valo return -EIO; 402e705c121SKalle Valo } 403e705c121SKalle Valo 404b3e4c0f3SLuca Coelho ret = iwl_pnvm_load(mvm->trans, &mvm->notif_wait); 40570d3ca86SLuca Coelho if (ret) { 40670d3ca86SLuca Coelho IWL_ERR(mvm, "Timeout waiting for PNVM load!\n"); 40770d3ca86SLuca Coelho iwl_fw_set_current_image(&mvm->fwrt, old_type); 40870d3ca86SLuca Coelho return ret; 40970d3ca86SLuca Coelho } 41070d3ca86SLuca Coelho 411e705c121SKalle Valo iwl_trans_fw_alive(mvm->trans, alive_data.scd_base_addr); 412e705c121SKalle Valo 413e705c121SKalle Valo /* 414e705c121SKalle Valo * Note: all the queues are enabled as part of the interface 415e705c121SKalle Valo * initialization, but in firmware restart scenarios they 416e705c121SKalle Valo * could be stopped, so wake them up. In firmware restart, 417e705c121SKalle Valo * mac80211 will have the queues stopped as well until the 418e705c121SKalle Valo * reconfiguration completes. During normal startup, they 419e705c121SKalle Valo * will be empty. 420e705c121SKalle Valo */ 421e705c121SKalle Valo 422e705c121SKalle Valo memset(&mvm->queue_info, 0, sizeof(mvm->queue_info)); 4231c14089eSJohannes Berg /* 4241c14089eSJohannes Berg * Set a 'fake' TID for the command queue, since we use the 4251c14089eSJohannes Berg * hweight() of the tid_bitmap as a refcount now. Not that 4261c14089eSJohannes Berg * we ever even consider the command queue as one we might 4271c14089eSJohannes Berg * want to reuse, but be safe nevertheless. 4281c14089eSJohannes Berg */ 4291c14089eSJohannes Berg mvm->queue_info[IWL_MVM_DQA_CMD_QUEUE].tid_bitmap = 4301c14089eSJohannes Berg BIT(IWL_MAX_TID_COUNT + 2); 431e705c121SKalle Valo 43265b280feSJohannes Berg set_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); 433f7805b33SLior Cohen #ifdef CONFIG_IWLWIFI_DEBUGFS 434f7805b33SLior Cohen iwl_fw_set_dbg_rec_on(&mvm->fwrt); 435f7805b33SLior Cohen #endif 436e705c121SKalle Valo 437d3d9b4fcSEmmanuel Grumbach /* 438d3d9b4fcSEmmanuel Grumbach * All the BSSes in the BSS table include the GP2 in the system 439d3d9b4fcSEmmanuel Grumbach * at the beacon Rx time, this is of course no longer relevant 440d3d9b4fcSEmmanuel Grumbach * since we are resetting the firmware. 441d3d9b4fcSEmmanuel Grumbach * Purge all the BSS table. 442d3d9b4fcSEmmanuel Grumbach */ 443d3d9b4fcSEmmanuel Grumbach cfg80211_bss_flush(mvm->hw->wiphy); 444d3d9b4fcSEmmanuel Grumbach 445e705c121SKalle Valo return 0; 446e705c121SKalle Valo } 447e705c121SKalle Valo 44852b15521SEmmanuel Grumbach static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm) 4498c5f47b1SJohannes Berg { 4508c5f47b1SJohannes Berg struct iwl_notification_wait init_wait; 4518c5f47b1SJohannes Berg struct iwl_nvm_access_complete_cmd nvm_complete = {}; 4528c5f47b1SJohannes Berg struct iwl_init_extended_cfg_cmd init_cfg = { 4538c5f47b1SJohannes Berg .init_flags = cpu_to_le32(BIT(IWL_INIT_NVM)), 4548c5f47b1SJohannes Berg }; 4558c5f47b1SJohannes Berg static const u16 init_complete[] = { 4568c5f47b1SJohannes Berg INIT_COMPLETE_NOTIF, 4578c5f47b1SJohannes Berg }; 4588c5f47b1SJohannes Berg int ret; 4598c5f47b1SJohannes Berg 460a4584729SHaim Dreyfuss if (mvm->trans->cfg->tx_with_siso_diversity) 461a4584729SHaim Dreyfuss init_cfg.init_flags |= cpu_to_le32(BIT(IWL_INIT_PHY)); 462a4584729SHaim Dreyfuss 4638c5f47b1SJohannes Berg lockdep_assert_held(&mvm->mutex); 4648c5f47b1SJohannes Berg 46594022562SEmmanuel Grumbach mvm->rfkill_safe_init_done = false; 46694022562SEmmanuel Grumbach 4678c5f47b1SJohannes Berg iwl_init_notification_wait(&mvm->notif_wait, 4688c5f47b1SJohannes Berg &init_wait, 4698c5f47b1SJohannes Berg init_complete, 4708c5f47b1SJohannes Berg ARRAY_SIZE(init_complete), 4718c5f47b1SJohannes Berg iwl_wait_init_complete, 4728c5f47b1SJohannes Berg NULL); 4738c5f47b1SJohannes Berg 474b108d8c7SShahar S Matityahu iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_EARLY, NULL); 47586ce5c74SShahar S Matityahu 4768c5f47b1SJohannes Berg /* Will also start the device */ 4778c5f47b1SJohannes Berg ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_REGULAR); 4788c5f47b1SJohannes Berg if (ret) { 4798c5f47b1SJohannes Berg IWL_ERR(mvm, "Failed to start RT ucode: %d\n", ret); 4808c5f47b1SJohannes Berg goto error; 4818c5f47b1SJohannes Berg } 482b108d8c7SShahar S Matityahu iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_AFTER_ALIVE, 483b108d8c7SShahar S Matityahu NULL); 4848c5f47b1SJohannes Berg 4858c5f47b1SJohannes Berg /* Send init config command to mark that we are sending NVM access 4868c5f47b1SJohannes Berg * commands 4878c5f47b1SJohannes Berg */ 4888c5f47b1SJohannes Berg ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(SYSTEM_GROUP, 489b3500b47SEmmanuel Grumbach INIT_EXTENDED_CFG_CMD), 490b3500b47SEmmanuel Grumbach CMD_SEND_IN_RFKILL, 4918c5f47b1SJohannes Berg sizeof(init_cfg), &init_cfg); 4928c5f47b1SJohannes Berg if (ret) { 4938c5f47b1SJohannes Berg IWL_ERR(mvm, "Failed to run init config command: %d\n", 4948c5f47b1SJohannes Berg ret); 4958c5f47b1SJohannes Berg goto error; 4968c5f47b1SJohannes Berg } 4978c5f47b1SJohannes Berg 498e9e1ba3dSSara Sharon /* Load NVM to NIC if needed */ 499e9e1ba3dSSara Sharon if (mvm->nvm_file_name) { 5009ce505feSAbhishek Naik ret = iwl_read_external_nvm(mvm->trans, mvm->nvm_file_name, 5019c4f7d51SShaul Triebitz mvm->nvm_sections); 5029ce505feSAbhishek Naik if (ret) 5039ce505feSAbhishek Naik goto error; 5049ce505feSAbhishek Naik ret = iwl_mvm_load_nvm_to_nic(mvm); 5059ce505feSAbhishek Naik if (ret) 5069ce505feSAbhishek Naik goto error; 507e9e1ba3dSSara Sharon } 5088c5f47b1SJohannes Berg 50952b15521SEmmanuel Grumbach if (IWL_MVM_PARSE_NVM && !mvm->nvm_data) { 5105bd1d2c1SLuca Coelho ret = iwl_nvm_init(mvm); 511d4f3695eSSara Sharon if (ret) { 512d4f3695eSSara Sharon IWL_ERR(mvm, "Failed to read NVM: %d\n", ret); 513d4f3695eSSara Sharon goto error; 514d4f3695eSSara Sharon } 515d4f3695eSSara Sharon } 516d4f3695eSSara Sharon 5178c5f47b1SJohannes Berg ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(REGULATORY_AND_NVM_GROUP, 518b3500b47SEmmanuel Grumbach NVM_ACCESS_COMPLETE), 519b3500b47SEmmanuel Grumbach CMD_SEND_IN_RFKILL, 5208c5f47b1SJohannes Berg sizeof(nvm_complete), &nvm_complete); 5218c5f47b1SJohannes Berg if (ret) { 5228c5f47b1SJohannes Berg IWL_ERR(mvm, "Failed to run complete NVM access: %d\n", 5238c5f47b1SJohannes Berg ret); 5248c5f47b1SJohannes Berg goto error; 5258c5f47b1SJohannes Berg } 5268c5f47b1SJohannes Berg 5278c5f47b1SJohannes Berg /* We wait for the INIT complete notification */ 528e9e1ba3dSSara Sharon ret = iwl_wait_notification(&mvm->notif_wait, &init_wait, 5298c5f47b1SJohannes Berg MVM_UCODE_ALIVE_TIMEOUT); 530e9e1ba3dSSara Sharon if (ret) 531e9e1ba3dSSara Sharon return ret; 532e9e1ba3dSSara Sharon 533e9e1ba3dSSara Sharon /* Read the NVM only at driver load time, no need to do this twice */ 53452b15521SEmmanuel Grumbach if (!IWL_MVM_PARSE_NVM && !mvm->nvm_data) { 5354c625c56SShaul Triebitz mvm->nvm_data = iwl_get_nvm(mvm->trans, mvm->fw); 536c135cb56SShaul Triebitz if (IS_ERR(mvm->nvm_data)) { 537c135cb56SShaul Triebitz ret = PTR_ERR(mvm->nvm_data); 538c135cb56SShaul Triebitz mvm->nvm_data = NULL; 539e9e1ba3dSSara Sharon IWL_ERR(mvm, "Failed to read NVM: %d\n", ret); 540e9e1ba3dSSara Sharon return ret; 541e9e1ba3dSSara Sharon } 542e9e1ba3dSSara Sharon } 543e9e1ba3dSSara Sharon 544b3500b47SEmmanuel Grumbach mvm->rfkill_safe_init_done = true; 545b3500b47SEmmanuel Grumbach 546e9e1ba3dSSara Sharon return 0; 5478c5f47b1SJohannes Berg 5488c5f47b1SJohannes Berg error: 5498c5f47b1SJohannes Berg iwl_remove_notification(&mvm->notif_wait, &init_wait); 5508c5f47b1SJohannes Berg return ret; 5518c5f47b1SJohannes Berg } 5528c5f47b1SJohannes Berg 553c4ace426SGil Adam #ifdef CONFIG_ACPI 554c4ace426SGil Adam static void iwl_mvm_phy_filter_init(struct iwl_mvm *mvm, 555c4ace426SGil Adam struct iwl_phy_specific_cfg *phy_filters) 556c4ace426SGil Adam { 557c4ace426SGil Adam /* 558c4ace426SGil Adam * TODO: read specific phy config from BIOS 559c4ace426SGil Adam * ACPI table for this feature has not been defined yet, 560c4ace426SGil Adam * so for now we use hardcoded values. 561c4ace426SGil Adam */ 562c4ace426SGil Adam 563c4ace426SGil Adam if (IWL_MVM_PHY_FILTER_CHAIN_A) { 564c4ace426SGil Adam phy_filters->filter_cfg_chain_a = 565c4ace426SGil Adam cpu_to_le32(IWL_MVM_PHY_FILTER_CHAIN_A); 566c4ace426SGil Adam } 567c4ace426SGil Adam if (IWL_MVM_PHY_FILTER_CHAIN_B) { 568c4ace426SGil Adam phy_filters->filter_cfg_chain_b = 569c4ace426SGil Adam cpu_to_le32(IWL_MVM_PHY_FILTER_CHAIN_B); 570c4ace426SGil Adam } 571c4ace426SGil Adam if (IWL_MVM_PHY_FILTER_CHAIN_C) { 572c4ace426SGil Adam phy_filters->filter_cfg_chain_c = 573c4ace426SGil Adam cpu_to_le32(IWL_MVM_PHY_FILTER_CHAIN_C); 574c4ace426SGil Adam } 575c4ace426SGil Adam if (IWL_MVM_PHY_FILTER_CHAIN_D) { 576c4ace426SGil Adam phy_filters->filter_cfg_chain_d = 577c4ace426SGil Adam cpu_to_le32(IWL_MVM_PHY_FILTER_CHAIN_D); 578c4ace426SGil Adam } 579c4ace426SGil Adam } 580c4ace426SGil Adam #else /* CONFIG_ACPI */ 581c4ace426SGil Adam 582c4ace426SGil Adam static void iwl_mvm_phy_filter_init(struct iwl_mvm *mvm, 583c4ace426SGil Adam struct iwl_phy_specific_cfg *phy_filters) 584c4ace426SGil Adam { 585c4ace426SGil Adam } 586c4ace426SGil Adam #endif /* CONFIG_ACPI */ 587c4ace426SGil Adam 588c593d2faSAyala Barazani #if defined(CONFIG_ACPI) && defined(CONFIG_EFI) 589c593d2faSAyala Barazani static int iwl_mvm_sgom_init(struct iwl_mvm *mvm) 590c593d2faSAyala Barazani { 591c593d2faSAyala Barazani u8 cmd_ver; 592c593d2faSAyala Barazani int ret; 593c593d2faSAyala Barazani struct iwl_host_cmd cmd = { 594c593d2faSAyala Barazani .id = WIDE_ID(REGULATORY_AND_NVM_GROUP, 595c593d2faSAyala Barazani SAR_OFFSET_MAPPING_TABLE_CMD), 596c593d2faSAyala Barazani .flags = 0, 597c593d2faSAyala Barazani .data[0] = &mvm->fwrt.sgom_table, 598c593d2faSAyala Barazani .len[0] = sizeof(mvm->fwrt.sgom_table), 599c593d2faSAyala Barazani .dataflags[0] = IWL_HCMD_DFL_NOCOPY, 600c593d2faSAyala Barazani }; 601c593d2faSAyala Barazani 602c593d2faSAyala Barazani if (!mvm->fwrt.sgom_enabled) { 603c593d2faSAyala Barazani IWL_DEBUG_RADIO(mvm, "SGOM table is disabled\n"); 604c593d2faSAyala Barazani return 0; 605c593d2faSAyala Barazani } 606c593d2faSAyala Barazani 607971cbe50SJohannes Berg cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd.id, 608c593d2faSAyala Barazani IWL_FW_CMD_VER_UNKNOWN); 609c593d2faSAyala Barazani 610c593d2faSAyala Barazani if (cmd_ver != 2) { 611c593d2faSAyala Barazani IWL_DEBUG_RADIO(mvm, "command version is unsupported. version = %d\n", 612c593d2faSAyala Barazani cmd_ver); 613c593d2faSAyala Barazani return 0; 614c593d2faSAyala Barazani } 615c593d2faSAyala Barazani 616c593d2faSAyala Barazani ret = iwl_mvm_send_cmd(mvm, &cmd); 617c593d2faSAyala Barazani if (ret < 0) 618c593d2faSAyala Barazani IWL_ERR(mvm, "failed to send SAR_OFFSET_MAPPING_CMD (%d)\n", ret); 619c593d2faSAyala Barazani 620c593d2faSAyala Barazani return ret; 621c593d2faSAyala Barazani } 622c593d2faSAyala Barazani #else 623c593d2faSAyala Barazani 624c593d2faSAyala Barazani static int iwl_mvm_sgom_init(struct iwl_mvm *mvm) 625c593d2faSAyala Barazani { 626c593d2faSAyala Barazani return 0; 627c593d2faSAyala Barazani } 628c593d2faSAyala Barazani #endif 629c593d2faSAyala Barazani 630e705c121SKalle Valo static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) 631e705c121SKalle Valo { 632971cbe50SJohannes Berg u32 cmd_id = PHY_CONFIGURATION_CMD; 633c4ace426SGil Adam struct iwl_phy_cfg_cmd_v3 phy_cfg_cmd; 634702e975dSJohannes Berg enum iwl_ucode_type ucode_type = mvm->fwrt.cur_fw_img; 635c4ace426SGil Adam struct iwl_phy_specific_cfg phy_filters = {}; 636c4ace426SGil Adam u8 cmd_ver; 637c4ace426SGil Adam size_t cmd_size; 638e705c121SKalle Valo 639bb99ff9bSLuca Coelho if (iwl_mvm_has_unified_ucode(mvm) && 640d923b020SLuca Coelho !mvm->trans->cfg->tx_with_siso_diversity) 641bb99ff9bSLuca Coelho return 0; 642d923b020SLuca Coelho 643d923b020SLuca Coelho if (mvm->trans->cfg->tx_with_siso_diversity) { 644bb99ff9bSLuca Coelho /* 645bb99ff9bSLuca Coelho * TODO: currently we don't set the antenna but letting the NIC 646bb99ff9bSLuca Coelho * to decide which antenna to use. This should come from BIOS. 647bb99ff9bSLuca Coelho */ 648bb99ff9bSLuca Coelho phy_cfg_cmd.phy_cfg = 649bb99ff9bSLuca Coelho cpu_to_le32(FW_PHY_CFG_CHAIN_SAD_ENABLED); 650bb99ff9bSLuca Coelho } 651bb99ff9bSLuca Coelho 652e705c121SKalle Valo /* Set parameters */ 653e705c121SKalle Valo phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_get_phy_config(mvm)); 65486a2b204SLuca Coelho 65586a2b204SLuca Coelho /* set flags extra PHY configuration flags from the device's cfg */ 6567897dfa2SLuca Coelho phy_cfg_cmd.phy_cfg |= 6577897dfa2SLuca Coelho cpu_to_le32(mvm->trans->trans_cfg->extra_phy_cfg_flags); 65886a2b204SLuca Coelho 659e705c121SKalle Valo phy_cfg_cmd.calib_control.event_trigger = 660e705c121SKalle Valo mvm->fw->default_calib[ucode_type].event_trigger; 661e705c121SKalle Valo phy_cfg_cmd.calib_control.flow_trigger = 662e705c121SKalle Valo mvm->fw->default_calib[ucode_type].flow_trigger; 663e705c121SKalle Valo 664971cbe50SJohannes Berg cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 665e80bfd11SMordechay Goodstein IWL_FW_CMD_VER_UNKNOWN); 666c4ace426SGil Adam if (cmd_ver == 3) { 667c4ace426SGil Adam iwl_mvm_phy_filter_init(mvm, &phy_filters); 668c4ace426SGil Adam memcpy(&phy_cfg_cmd.phy_specific_cfg, &phy_filters, 669c4ace426SGil Adam sizeof(struct iwl_phy_specific_cfg)); 670c4ace426SGil Adam } 671c4ace426SGil Adam 672e705c121SKalle Valo IWL_DEBUG_INFO(mvm, "Sending Phy CFG command: 0x%x\n", 673e705c121SKalle Valo phy_cfg_cmd.phy_cfg); 674c4ace426SGil Adam cmd_size = (cmd_ver == 3) ? sizeof(struct iwl_phy_cfg_cmd_v3) : 675c4ace426SGil Adam sizeof(struct iwl_phy_cfg_cmd_v1); 676971cbe50SJohannes Berg return iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, cmd_size, &phy_cfg_cmd); 677e705c121SKalle Valo } 678e705c121SKalle Valo 6793b25f1afSEmmanuel Grumbach int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm) 680e705c121SKalle Valo { 681e705c121SKalle Valo struct iwl_notification_wait calib_wait; 682e705c121SKalle Valo static const u16 init_complete[] = { 683e705c121SKalle Valo INIT_COMPLETE_NOTIF, 684e705c121SKalle Valo CALIB_RES_NOTIF_PHY_DB 685e705c121SKalle Valo }; 686e705c121SKalle Valo int ret; 687e705c121SKalle Valo 6887d6222e2SJohannes Berg if (iwl_mvm_has_unified_ucode(mvm)) 68952b15521SEmmanuel Grumbach return iwl_run_unified_mvm_ucode(mvm); 6908c5f47b1SJohannes Berg 691e705c121SKalle Valo lockdep_assert_held(&mvm->mutex); 692e705c121SKalle Valo 69394022562SEmmanuel Grumbach mvm->rfkill_safe_init_done = false; 694e705c121SKalle Valo 695e705c121SKalle Valo iwl_init_notification_wait(&mvm->notif_wait, 696e705c121SKalle Valo &calib_wait, 697e705c121SKalle Valo init_complete, 698e705c121SKalle Valo ARRAY_SIZE(init_complete), 699e705c121SKalle Valo iwl_wait_phy_db_entry, 700e705c121SKalle Valo mvm->phy_db); 701e705c121SKalle Valo 70211f8c533SLuca Coelho iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_EARLY, NULL); 70311f8c533SLuca Coelho 704e705c121SKalle Valo /* Will also start the device */ 705e705c121SKalle Valo ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_INIT); 706e705c121SKalle Valo if (ret) { 707e705c121SKalle Valo IWL_ERR(mvm, "Failed to start INIT ucode: %d\n", ret); 70800e0c6c8SLuca Coelho goto remove_notif; 709e705c121SKalle Valo } 710e705c121SKalle Valo 7117d34a7d7SLuca Coelho if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_8000) { 712b3de3ef4SEmmanuel Grumbach ret = iwl_mvm_send_bt_init_conf(mvm); 713e705c121SKalle Valo if (ret) 71400e0c6c8SLuca Coelho goto remove_notif; 715b3de3ef4SEmmanuel Grumbach } 716e705c121SKalle Valo 717e705c121SKalle Valo /* Read the NVM only at driver load time, no need to do this twice */ 7183b25f1afSEmmanuel Grumbach if (!mvm->nvm_data) { 7195bd1d2c1SLuca Coelho ret = iwl_nvm_init(mvm); 720e705c121SKalle Valo if (ret) { 721e705c121SKalle Valo IWL_ERR(mvm, "Failed to read NVM: %d\n", ret); 72200e0c6c8SLuca Coelho goto remove_notif; 723e705c121SKalle Valo } 724e705c121SKalle Valo } 725e705c121SKalle Valo 726e705c121SKalle Valo /* In case we read the NVM from external file, load it to the NIC */ 7279ce505feSAbhishek Naik if (mvm->nvm_file_name) { 7289ce505feSAbhishek Naik ret = iwl_mvm_load_nvm_to_nic(mvm); 7299ce505feSAbhishek Naik if (ret) 7309ce505feSAbhishek Naik goto remove_notif; 7319ce505feSAbhishek Naik } 732e705c121SKalle Valo 73364866e5dSLuca Coelho WARN_ONCE(mvm->nvm_data->nvm_version < mvm->trans->cfg->nvm_ver, 73464866e5dSLuca Coelho "Too old NVM version (0x%0x, required = 0x%0x)", 73564866e5dSLuca Coelho mvm->nvm_data->nvm_version, mvm->trans->cfg->nvm_ver); 736e705c121SKalle Valo 737e705c121SKalle Valo /* 738e705c121SKalle Valo * abort after reading the nvm in case RF Kill is on, we will complete 739e705c121SKalle Valo * the init seq later when RF kill will switch to off 740e705c121SKalle Valo */ 741e705c121SKalle Valo if (iwl_mvm_is_radio_hw_killed(mvm)) { 742e705c121SKalle Valo IWL_DEBUG_RF_KILL(mvm, 743e705c121SKalle Valo "jump over all phy activities due to RF kill\n"); 74400e0c6c8SLuca Coelho goto remove_notif; 745e705c121SKalle Valo } 746e705c121SKalle Valo 747b3500b47SEmmanuel Grumbach mvm->rfkill_safe_init_done = true; 748e705c121SKalle Valo 749e705c121SKalle Valo /* Send TX valid antennas before triggering calibrations */ 750e705c121SKalle Valo ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm)); 751e705c121SKalle Valo if (ret) 75200e0c6c8SLuca Coelho goto remove_notif; 753e705c121SKalle Valo 754e705c121SKalle Valo ret = iwl_send_phy_cfg_cmd(mvm); 755e705c121SKalle Valo if (ret) { 756e705c121SKalle Valo IWL_ERR(mvm, "Failed to run INIT calibrations: %d\n", 757e705c121SKalle Valo ret); 75800e0c6c8SLuca Coelho goto remove_notif; 759e705c121SKalle Valo } 760e705c121SKalle Valo 761e705c121SKalle Valo /* 762e705c121SKalle Valo * Some things may run in the background now, but we 763e705c121SKalle Valo * just wait for the calibration complete notification. 764e705c121SKalle Valo */ 765e705c121SKalle Valo ret = iwl_wait_notification(&mvm->notif_wait, &calib_wait, 766e705c121SKalle Valo MVM_UCODE_CALIB_TIMEOUT); 76700e0c6c8SLuca Coelho if (!ret) 768e705c121SKalle Valo goto out; 769e705c121SKalle Valo 77000e0c6c8SLuca Coelho if (iwl_mvm_is_radio_hw_killed(mvm)) { 77100e0c6c8SLuca Coelho IWL_DEBUG_RF_KILL(mvm, "RFKILL while calibrating.\n"); 77200e0c6c8SLuca Coelho ret = 0; 77300e0c6c8SLuca Coelho } else { 77400e0c6c8SLuca Coelho IWL_ERR(mvm, "Failed to run INIT calibrations: %d\n", 77500e0c6c8SLuca Coelho ret); 77600e0c6c8SLuca Coelho } 77700e0c6c8SLuca Coelho 77800e0c6c8SLuca Coelho goto out; 77900e0c6c8SLuca Coelho 78000e0c6c8SLuca Coelho remove_notif: 781e705c121SKalle Valo iwl_remove_notification(&mvm->notif_wait, &calib_wait); 782e705c121SKalle Valo out: 783b3500b47SEmmanuel Grumbach mvm->rfkill_safe_init_done = false; 784e705c121SKalle Valo if (iwlmvm_mod_params.init_dbg && !mvm->nvm_data) { 785e705c121SKalle Valo /* we want to debug INIT and we have no NVM - fake */ 786e705c121SKalle Valo mvm->nvm_data = kzalloc(sizeof(struct iwl_nvm_data) + 787e705c121SKalle Valo sizeof(struct ieee80211_channel) + 788e705c121SKalle Valo sizeof(struct ieee80211_rate), 789e705c121SKalle Valo GFP_KERNEL); 790e705c121SKalle Valo if (!mvm->nvm_data) 791e705c121SKalle Valo return -ENOMEM; 792e705c121SKalle Valo mvm->nvm_data->bands[0].channels = mvm->nvm_data->channels; 793e705c121SKalle Valo mvm->nvm_data->bands[0].n_channels = 1; 794e705c121SKalle Valo mvm->nvm_data->bands[0].n_bitrates = 1; 795e705c121SKalle Valo mvm->nvm_data->bands[0].bitrates = 7963827cb59SJohannes Berg (void *)((u8 *)mvm->nvm_data->channels + 1); 797e705c121SKalle Valo mvm->nvm_data->bands[0].bitrates->hw_value = 10; 798e705c121SKalle Valo } 799e705c121SKalle Valo 800e705c121SKalle Valo return ret; 801e705c121SKalle Valo } 802e705c121SKalle Valo 803e705c121SKalle Valo static int iwl_mvm_config_ltr(struct iwl_mvm *mvm) 804e705c121SKalle Valo { 805e705c121SKalle Valo struct iwl_ltr_config_cmd cmd = { 806e705c121SKalle Valo .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE), 807e705c121SKalle Valo }; 808e705c121SKalle Valo 809e705c121SKalle Valo if (!mvm->trans->ltr_enabled) 810e705c121SKalle Valo return 0; 811e705c121SKalle Valo 812e705c121SKalle Valo return iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0, 813e705c121SKalle Valo sizeof(cmd), &cmd); 814e705c121SKalle Valo } 815e705c121SKalle Valo 816c386dacbSHaim Dreyfuss #ifdef CONFIG_ACPI 81742ce76d6SLuca Coelho int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) 818da2830acSLuca Coelho { 819971cbe50SJohannes Berg u32 cmd_id = REDUCE_TX_POWER_CMD; 820216cdfb5SLuca Coelho struct iwl_dev_tx_power_cmd cmd = { 821216cdfb5SLuca Coelho .common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_CHAINS), 82271e9378bSLuca Coelho }; 8239c08cef8SLuca Coelho __le16 *per_chain; 8241edd56e6SLuca Coelho int ret; 82539c1a972SIhab Zhaika u16 len = 0; 826fbb7957dSLuca Coelho u32 n_subbands; 827971cbe50SJohannes Berg u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 828e80bfd11SMordechay Goodstein IWL_FW_CMD_VER_UNKNOWN); 829b0aa02b3SAyala Barazani if (cmd_ver == 7) { 830b0aa02b3SAyala Barazani len = sizeof(cmd.v7); 831b0aa02b3SAyala Barazani n_subbands = IWL_NUM_SUB_BANDS_V2; 832b0aa02b3SAyala Barazani per_chain = cmd.v7.per_chain[0][0]; 833b0aa02b3SAyala Barazani cmd.v7.flags = cpu_to_le32(mvm->fwrt.reduced_power_flags); 834b0aa02b3SAyala Barazani } else if (cmd_ver == 6) { 835fbb7957dSLuca Coelho len = sizeof(cmd.v6); 836fbb7957dSLuca Coelho n_subbands = IWL_NUM_SUB_BANDS_V2; 837fbb7957dSLuca Coelho per_chain = cmd.v6.per_chain[0][0]; 838fbb7957dSLuca Coelho } else if (fw_has_api(&mvm->fw->ucode_capa, 8399c08cef8SLuca Coelho IWL_UCODE_TLV_API_REDUCE_TX_POWER)) { 8400791c2fcSHaim Dreyfuss len = sizeof(cmd.v5); 841e12cfc7bSMiri Korenblit n_subbands = IWL_NUM_SUB_BANDS_V1; 8429c08cef8SLuca Coelho per_chain = cmd.v5.per_chain[0][0]; 8439c08cef8SLuca Coelho } else if (fw_has_capa(&mvm->fw->ucode_capa, 8449c08cef8SLuca Coelho IWL_UCODE_TLV_CAPA_TX_POWER_ACK)) { 845216cdfb5SLuca Coelho len = sizeof(cmd.v4); 846e12cfc7bSMiri Korenblit n_subbands = IWL_NUM_SUB_BANDS_V1; 8479c08cef8SLuca Coelho per_chain = cmd.v4.per_chain[0][0]; 8489c08cef8SLuca Coelho } else { 849216cdfb5SLuca Coelho len = sizeof(cmd.v3); 850e12cfc7bSMiri Korenblit n_subbands = IWL_NUM_SUB_BANDS_V1; 8519c08cef8SLuca Coelho per_chain = cmd.v3.per_chain[0][0]; 8529c08cef8SLuca Coelho } 85355bfa4b9SLuca Coelho 854216cdfb5SLuca Coelho /* all structs have the same common part, add it */ 855216cdfb5SLuca Coelho len += sizeof(cmd.common); 85642ce76d6SLuca Coelho 857dac7171cSLuca Coelho ret = iwl_sar_select_profile(&mvm->fwrt, per_chain, 858dac7171cSLuca Coelho IWL_NUM_CHAIN_TABLES, 859fbb7957dSLuca Coelho n_subbands, prof_a, prof_b); 8601edd56e6SLuca Coelho 8611edd56e6SLuca Coelho /* return on error or if the profile is disabled (positive number) */ 8621edd56e6SLuca Coelho if (ret) 8631edd56e6SLuca Coelho return ret; 8641edd56e6SLuca Coelho 8656d19a5ebSEmmanuel Grumbach iwl_mei_set_power_limit(per_chain); 8666d19a5ebSEmmanuel Grumbach 86742ce76d6SLuca Coelho IWL_DEBUG_RADIO(mvm, "Sending REDUCE_TX_POWER_CMD per chain\n"); 868971cbe50SJohannes Berg return iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, len, &cmd); 86942ce76d6SLuca Coelho } 87042ce76d6SLuca Coelho 8717fe90e0eSHaim Dreyfuss int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) 8727fe90e0eSHaim Dreyfuss { 873dd2a1256SLuca Coelho union iwl_geo_tx_power_profiles_cmd geo_tx_cmd; 874f604324eSLuca Coelho struct iwl_geo_tx_power_profiles_resp *resp; 8750c3d7282SHaim Dreyfuss u16 len; 87639c1a972SIhab Zhaika int ret; 877c8611331SJohannes Berg struct iwl_host_cmd cmd = { 878c8611331SJohannes Berg .id = WIDE_ID(PHY_OPS_GROUP, PER_CHAIN_LIMIT_OFFSET_CMD), 879c8611331SJohannes Berg .flags = CMD_WANT_SKB, 880c8611331SJohannes Berg .data = { &geo_tx_cmd }, 881c8611331SJohannes Berg }; 882971cbe50SJohannes Berg u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd.id, 883e80bfd11SMordechay Goodstein IWL_FW_CMD_VER_UNKNOWN); 8847fe90e0eSHaim Dreyfuss 885dd2a1256SLuca Coelho /* the ops field is at the same spot for all versions, so set in v1 */ 886dd2a1256SLuca Coelho geo_tx_cmd.v1.ops = 887dd2a1256SLuca Coelho cpu_to_le32(IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE); 888dd2a1256SLuca Coelho 88997f8a3d1SAyala Barazani if (cmd_ver == 5) 89097f8a3d1SAyala Barazani len = sizeof(geo_tx_cmd.v5); 89197f8a3d1SAyala Barazani else if (cmd_ver == 4) 89297f8a3d1SAyala Barazani len = sizeof(geo_tx_cmd.v4); 89397f8a3d1SAyala Barazani else if (cmd_ver == 3) 8940ea788edSLuca Coelho len = sizeof(geo_tx_cmd.v3); 8950ea788edSLuca Coelho else if (fw_has_api(&mvm->fwrt.fw->ucode_capa, 896dd2a1256SLuca Coelho IWL_UCODE_TLV_API_SAR_TABLE_VER)) 897dd2a1256SLuca Coelho len = sizeof(geo_tx_cmd.v2); 898dd2a1256SLuca Coelho else 899dd2a1256SLuca Coelho len = sizeof(geo_tx_cmd.v1); 9000c3d7282SHaim Dreyfuss 90139c1a972SIhab Zhaika if (!iwl_sar_geo_support(&mvm->fwrt)) 90239c1a972SIhab Zhaika return -EOPNOTSUPP; 90339c1a972SIhab Zhaika 904c8611331SJohannes Berg cmd.len[0] = len; 9057fe90e0eSHaim Dreyfuss 9067fe90e0eSHaim Dreyfuss ret = iwl_mvm_send_cmd(mvm, &cmd); 9077fe90e0eSHaim Dreyfuss if (ret) { 9087fe90e0eSHaim Dreyfuss IWL_ERR(mvm, "Failed to get geographic profile info %d\n", ret); 9097fe90e0eSHaim Dreyfuss return ret; 9107fe90e0eSHaim Dreyfuss } 911f604324eSLuca Coelho 912f604324eSLuca Coelho resp = (void *)cmd.resp_pkt->data; 913f604324eSLuca Coelho ret = le32_to_cpu(resp->profile_idx); 914f604324eSLuca Coelho 91597f8a3d1SAyala Barazani if (WARN_ON(ret > ACPI_NUM_GEO_PROFILES_REV3)) 916f604324eSLuca Coelho ret = -EIO; 917f604324eSLuca Coelho 9187fe90e0eSHaim Dreyfuss iwl_free_resp(&cmd); 9197fe90e0eSHaim Dreyfuss return ret; 9207fe90e0eSHaim Dreyfuss } 9217fe90e0eSHaim Dreyfuss 922a6bff3cbSHaim Dreyfuss static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) 923a6bff3cbSHaim Dreyfuss { 924971cbe50SJohannes Berg u32 cmd_id = WIDE_ID(PHY_OPS_GROUP, PER_CHAIN_LIMIT_OFFSET_CMD); 925dd2a1256SLuca Coelho union iwl_geo_tx_power_profiles_cmd cmd; 92639c1a972SIhab Zhaika u16 len; 92745acebf8SNaftali Goldstein u32 n_bands; 92897f8a3d1SAyala Barazani u32 n_profiles; 929ac9952f6SLuca Coelho u32 sk = 0; 9300433ae55SGolan Ben Ami int ret; 931971cbe50SJohannes Berg u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 932e80bfd11SMordechay Goodstein IWL_FW_CMD_VER_UNKNOWN); 933a6bff3cbSHaim Dreyfuss 93445acebf8SNaftali Goldstein BUILD_BUG_ON(offsetof(struct iwl_geo_tx_power_profiles_cmd_v1, ops) != 93545acebf8SNaftali Goldstein offsetof(struct iwl_geo_tx_power_profiles_cmd_v2, ops) || 93645acebf8SNaftali Goldstein offsetof(struct iwl_geo_tx_power_profiles_cmd_v2, ops) != 93797f8a3d1SAyala Barazani offsetof(struct iwl_geo_tx_power_profiles_cmd_v3, ops) || 93897f8a3d1SAyala Barazani offsetof(struct iwl_geo_tx_power_profiles_cmd_v3, ops) != 93997f8a3d1SAyala Barazani offsetof(struct iwl_geo_tx_power_profiles_cmd_v4, ops) || 94097f8a3d1SAyala Barazani offsetof(struct iwl_geo_tx_power_profiles_cmd_v4, ops) != 94197f8a3d1SAyala Barazani offsetof(struct iwl_geo_tx_power_profiles_cmd_v5, ops)); 94297f8a3d1SAyala Barazani 94345acebf8SNaftali Goldstein /* the ops field is at the same spot for all versions, so set in v1 */ 94445acebf8SNaftali Goldstein cmd.v1.ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_SET_TABLES); 94545acebf8SNaftali Goldstein 94697f8a3d1SAyala Barazani if (cmd_ver == 5) { 94797f8a3d1SAyala Barazani len = sizeof(cmd.v5); 94897f8a3d1SAyala Barazani n_bands = ARRAY_SIZE(cmd.v5.table[0]); 94997f8a3d1SAyala Barazani n_profiles = ACPI_NUM_GEO_PROFILES_REV3; 95097f8a3d1SAyala Barazani } else if (cmd_ver == 4) { 95197f8a3d1SAyala Barazani len = sizeof(cmd.v4); 95297f8a3d1SAyala Barazani n_bands = ARRAY_SIZE(cmd.v4.table[0]); 95397f8a3d1SAyala Barazani n_profiles = ACPI_NUM_GEO_PROFILES_REV3; 95497f8a3d1SAyala Barazani } else if (cmd_ver == 3) { 95545acebf8SNaftali Goldstein len = sizeof(cmd.v3); 95645acebf8SNaftali Goldstein n_bands = ARRAY_SIZE(cmd.v3.table[0]); 95797f8a3d1SAyala Barazani n_profiles = ACPI_NUM_GEO_PROFILES; 95845acebf8SNaftali Goldstein } else if (fw_has_api(&mvm->fwrt.fw->ucode_capa, 95945acebf8SNaftali Goldstein IWL_UCODE_TLV_API_SAR_TABLE_VER)) { 96045acebf8SNaftali Goldstein len = sizeof(cmd.v2); 96145acebf8SNaftali Goldstein n_bands = ARRAY_SIZE(cmd.v2.table[0]); 96297f8a3d1SAyala Barazani n_profiles = ACPI_NUM_GEO_PROFILES; 96345acebf8SNaftali Goldstein } else { 96445acebf8SNaftali Goldstein len = sizeof(cmd.v1); 96545acebf8SNaftali Goldstein n_bands = ARRAY_SIZE(cmd.v1.table[0]); 96697f8a3d1SAyala Barazani n_profiles = ACPI_NUM_GEO_PROFILES; 96745acebf8SNaftali Goldstein } 96845acebf8SNaftali Goldstein 96945acebf8SNaftali Goldstein BUILD_BUG_ON(offsetof(struct iwl_geo_tx_power_profiles_cmd_v1, table) != 97045acebf8SNaftali Goldstein offsetof(struct iwl_geo_tx_power_profiles_cmd_v2, table) || 97145acebf8SNaftali Goldstein offsetof(struct iwl_geo_tx_power_profiles_cmd_v2, table) != 97297f8a3d1SAyala Barazani offsetof(struct iwl_geo_tx_power_profiles_cmd_v3, table) || 97397f8a3d1SAyala Barazani offsetof(struct iwl_geo_tx_power_profiles_cmd_v3, table) != 97497f8a3d1SAyala Barazani offsetof(struct iwl_geo_tx_power_profiles_cmd_v4, table) || 97597f8a3d1SAyala Barazani offsetof(struct iwl_geo_tx_power_profiles_cmd_v4, table) != 97697f8a3d1SAyala Barazani offsetof(struct iwl_geo_tx_power_profiles_cmd_v5, table)); 97745acebf8SNaftali Goldstein /* the table is at the same position for all versions, so set use v1 */ 97897f8a3d1SAyala Barazani ret = iwl_sar_geo_init(&mvm->fwrt, &cmd.v1.table[0][0], 97997f8a3d1SAyala Barazani n_bands, n_profiles); 980eca1e56cSEmmanuel Grumbach 9810433ae55SGolan Ben Ami /* 9820433ae55SGolan Ben Ami * It is a valid scenario to not support SAR, or miss wgds table, 9830433ae55SGolan Ben Ami * but in that case there is no need to send the command. 9840433ae55SGolan Ben Ami */ 9850433ae55SGolan Ben Ami if (ret) 9860433ae55SGolan Ben Ami return 0; 987a6bff3cbSHaim Dreyfuss 988ac9952f6SLuca Coelho /* Only set to South Korea if the table revision is 1 */ 989ac9952f6SLuca Coelho if (mvm->fwrt.geo_rev == 1) 990ac9952f6SLuca Coelho sk = 1; 991ac9952f6SLuca Coelho 99228db1862SLuca Coelho /* 993ac9952f6SLuca Coelho * Set the table_revision to South Korea (1) or not (0). The 994ac9952f6SLuca Coelho * element name is misleading, as it doesn't contain the table 995ac9952f6SLuca Coelho * revision number, but whether the South Korea variation 996ac9952f6SLuca Coelho * should be used. 99728db1862SLuca Coelho * This must be done after calling iwl_sar_geo_init(). 99828db1862SLuca Coelho */ 99997f8a3d1SAyala Barazani if (cmd_ver == 5) 1000ac9952f6SLuca Coelho cmd.v5.table_revision = cpu_to_le32(sk); 100197f8a3d1SAyala Barazani else if (cmd_ver == 4) 1002ac9952f6SLuca Coelho cmd.v4.table_revision = cpu_to_le32(sk); 100397f8a3d1SAyala Barazani else if (cmd_ver == 3) 1004ac9952f6SLuca Coelho cmd.v3.table_revision = cpu_to_le32(sk); 100528db1862SLuca Coelho else if (fw_has_api(&mvm->fwrt.fw->ucode_capa, 100628db1862SLuca Coelho IWL_UCODE_TLV_API_SAR_TABLE_VER)) 1007ac9952f6SLuca Coelho cmd.v2.table_revision = cpu_to_le32(sk); 100828db1862SLuca Coelho 1009971cbe50SJohannes Berg return iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, len, &cmd); 1010a6bff3cbSHaim Dreyfuss } 1011a6bff3cbSHaim Dreyfuss 10126ce1e5c0SGil Adam int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) 10136ce1e5c0SGil Adam { 10148bdc52b9SMiri Korenblit union iwl_ppag_table_cmd cmd; 1015*e8e10a37SMatt Chen int ret, cmd_size; 10166ce1e5c0SGil Adam 1017*e8e10a37SMatt Chen ret = iwl_read_ppag_table(&mvm->fwrt, &cmd, &cmd_size); 1018*e8e10a37SMatt Chen if(ret < 0) 1019*e8e10a37SMatt Chen return ret; 1020160bab43SGil Adam 1021f2134f66SGil Adam IWL_DEBUG_RADIO(mvm, "Sending PER_PLATFORM_ANT_GAIN_CMD\n"); 10226ce1e5c0SGil Adam ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(PHY_OPS_GROUP, 10236ce1e5c0SGil Adam PER_PLATFORM_ANT_GAIN_CMD), 10248bdc52b9SMiri Korenblit 0, cmd_size, &cmd); 10256ce1e5c0SGil Adam if (ret < 0) 10266ce1e5c0SGil Adam IWL_ERR(mvm, "failed to send PER_PLATFORM_ANT_GAIN_CMD (%d)\n", 10276ce1e5c0SGil Adam ret); 10286ce1e5c0SGil Adam 10296ce1e5c0SGil Adam return ret; 10306ce1e5c0SGil Adam } 10316ce1e5c0SGil Adam 10326ce1e5c0SGil Adam static int iwl_mvm_ppag_init(struct iwl_mvm *mvm) 10336ce1e5c0SGil Adam { 103478a19d52SMiri Korenblit /* no need to read the table, done in INIT stage */ 1035*e8e10a37SMatt Chen if (!(iwl_acpi_is_ppag_approved(&mvm->fwrt))) 1036a2ac0f48SLuca Coelho return 0; 1037a2ac0f48SLuca Coelho 10386ce1e5c0SGil Adam return iwl_mvm_ppag_send_cmd(mvm); 10396ce1e5c0SGil Adam } 10406ce1e5c0SGil Adam 10412856f623SAyala Barazani static const struct dmi_system_id dmi_tas_approved_list[] = { 10422856f623SAyala Barazani { .ident = "HP", 10432856f623SAyala Barazani .matches = { 10442856f623SAyala Barazani DMI_MATCH(DMI_SYS_VENDOR, "HP"), 10452856f623SAyala Barazani }, 10462856f623SAyala Barazani }, 10472856f623SAyala Barazani { .ident = "SAMSUNG", 10482856f623SAyala Barazani .matches = { 10492856f623SAyala Barazani DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"), 10502856f623SAyala Barazani }, 10512856f623SAyala Barazani }, 10522856f623SAyala Barazani { .ident = "LENOVO", 10532856f623SAyala Barazani .matches = { 10542856f623SAyala Barazani DMI_MATCH(DMI_SYS_VENDOR, "Lenovo"), 10552856f623SAyala Barazani }, 10562856f623SAyala Barazani }, 10572856f623SAyala Barazani { .ident = "DELL", 10582856f623SAyala Barazani .matches = { 10592856f623SAyala Barazani DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 10602856f623SAyala Barazani }, 10612856f623SAyala Barazani }, 10622856f623SAyala Barazani 10632856f623SAyala Barazani /* keep last */ 10642856f623SAyala Barazani {} 10652856f623SAyala Barazani }; 10662856f623SAyala Barazani 1067c3f40c3eSMiri Korenblit static bool iwl_mvm_add_to_tas_block_list(__le32 *list, __le32 *le_size, unsigned int mcc) 1068c3f40c3eSMiri Korenblit { 1069c3f40c3eSMiri Korenblit int i; 1070c3f40c3eSMiri Korenblit u32 size = le32_to_cpu(*le_size); 1071c3f40c3eSMiri Korenblit 1072c3f40c3eSMiri Korenblit /* Verify that there is room for another country */ 1073c3f40c3eSMiri Korenblit if (size >= IWL_TAS_BLOCK_LIST_MAX) 1074c3f40c3eSMiri Korenblit return false; 1075c3f40c3eSMiri Korenblit 1076c3f40c3eSMiri Korenblit for (i = 0; i < size; i++) { 1077c3f40c3eSMiri Korenblit if (list[i] == cpu_to_le32(mcc)) 1078c3f40c3eSMiri Korenblit return true; 1079c3f40c3eSMiri Korenblit } 1080c3f40c3eSMiri Korenblit 1081c3f40c3eSMiri Korenblit list[size++] = cpu_to_le32(mcc); 1082c3f40c3eSMiri Korenblit *le_size = cpu_to_le32(size); 1083c3f40c3eSMiri Korenblit return true; 1084c3f40c3eSMiri Korenblit } 1085c3f40c3eSMiri Korenblit 108628dd7ccdSMordechay Goodstein static void iwl_mvm_tas_init(struct iwl_mvm *mvm) 108728dd7ccdSMordechay Goodstein { 1088971cbe50SJohannes Berg u32 cmd_id = WIDE_ID(REGULATORY_AND_NVM_GROUP, TAS_CONFIG); 108928dd7ccdSMordechay Goodstein int ret; 10906da7ba3aSAyala Barazani union iwl_tas_config_cmd cmd = {}; 10916da7ba3aSAyala Barazani int cmd_size, fw_ver; 109228dd7ccdSMordechay Goodstein 10936da7ba3aSAyala Barazani BUILD_BUG_ON(ARRAY_SIZE(cmd.v3.block_list_array) < 109428dd7ccdSMordechay Goodstein APCI_WTAS_BLACK_LIST_MAX); 109528dd7ccdSMordechay Goodstein 109628dd7ccdSMordechay Goodstein if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TAS_CFG)) { 109728dd7ccdSMordechay Goodstein IWL_DEBUG_RADIO(mvm, "TAS not enabled in FW\n"); 109828dd7ccdSMordechay Goodstein return; 109928dd7ccdSMordechay Goodstein } 110028dd7ccdSMordechay Goodstein 1101971cbe50SJohannes Berg fw_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 1102971cbe50SJohannes Berg IWL_FW_CMD_VER_UNKNOWN); 11036da7ba3aSAyala Barazani 11046da7ba3aSAyala Barazani ret = iwl_acpi_get_tas(&mvm->fwrt, &cmd, fw_ver); 110528dd7ccdSMordechay Goodstein if (ret < 0) { 110628dd7ccdSMordechay Goodstein IWL_DEBUG_RADIO(mvm, 110728dd7ccdSMordechay Goodstein "TAS table invalid or unavailable. (%d)\n", 110828dd7ccdSMordechay Goodstein ret); 110928dd7ccdSMordechay Goodstein return; 111028dd7ccdSMordechay Goodstein } 111128dd7ccdSMordechay Goodstein 11127c530588SMiri Korenblit if (ret == 0) 111328dd7ccdSMordechay Goodstein return; 111428dd7ccdSMordechay Goodstein 1115c3f40c3eSMiri Korenblit if (!dmi_check_system(dmi_tas_approved_list)) { 1116c3f40c3eSMiri Korenblit IWL_DEBUG_RADIO(mvm, 1117c3f40c3eSMiri Korenblit "System vendor '%s' is not in the approved list, disabling TAS in US and Canada.\n", 1118c3f40c3eSMiri Korenblit dmi_get_system_info(DMI_SYS_VENDOR)); 11196da7ba3aSAyala Barazani if ((!iwl_mvm_add_to_tas_block_list(cmd.v4.block_list_array, 11206da7ba3aSAyala Barazani &cmd.v4.block_list_size, 11216da7ba3aSAyala Barazani IWL_TAS_US_MCC)) || 11226da7ba3aSAyala Barazani (!iwl_mvm_add_to_tas_block_list(cmd.v4.block_list_array, 11236da7ba3aSAyala Barazani &cmd.v4.block_list_size, 11246da7ba3aSAyala Barazani IWL_TAS_CANADA_MCC))) { 1125c3f40c3eSMiri Korenblit IWL_DEBUG_RADIO(mvm, 1126c3f40c3eSMiri Korenblit "Unable to add US/Canada to TAS block list, disabling TAS\n"); 1127c3f40c3eSMiri Korenblit return; 1128c3f40c3eSMiri Korenblit } 1129c3f40c3eSMiri Korenblit } 1130c3f40c3eSMiri Korenblit 11316da7ba3aSAyala Barazani /* v4 is the same size as v3, so no need to differentiate here */ 11326da7ba3aSAyala Barazani cmd_size = fw_ver < 3 ? 11337c530588SMiri Korenblit sizeof(struct iwl_tas_config_cmd_v2) : 11347c530588SMiri Korenblit sizeof(struct iwl_tas_config_cmd_v3); 113528dd7ccdSMordechay Goodstein 1136971cbe50SJohannes Berg ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, cmd_size, &cmd); 113728dd7ccdSMordechay Goodstein if (ret < 0) 113828dd7ccdSMordechay Goodstein IWL_DEBUG_RADIO(mvm, "failed to send TAS_CONFIG (%d)\n", ret); 113928dd7ccdSMordechay Goodstein } 1140f5b1cb2eSGil Adam 11414e8fe214SGregory Greenman static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) 11424e8fe214SGregory Greenman { 11434e8fe214SGregory Greenman u8 value; 114445fe1b6bSLuca Coelho int ret = iwl_acpi_get_dsm_u8(mvm->fwrt.dev, 0, DSM_RFI_FUNC_ENABLE, 11454e8fe214SGregory Greenman &iwl_rfi_guid, &value); 11464e8fe214SGregory Greenman 11474e8fe214SGregory Greenman if (ret < 0) { 11484e8fe214SGregory Greenman IWL_DEBUG_RADIO(mvm, "Failed to get DSM RFI, ret=%d\n", ret); 11494e8fe214SGregory Greenman 11504e8fe214SGregory Greenman } else if (value >= DSM_VALUE_RFI_MAX) { 11514e8fe214SGregory Greenman IWL_DEBUG_RADIO(mvm, "DSM RFI got invalid value, ret=%d\n", 11524e8fe214SGregory Greenman value); 11534e8fe214SGregory Greenman 11544e8fe214SGregory Greenman } else if (value == DSM_VALUE_RFI_ENABLE) { 11554e8fe214SGregory Greenman IWL_DEBUG_RADIO(mvm, "DSM RFI is evaluated to enable\n"); 11564e8fe214SGregory Greenman return DSM_VALUE_RFI_ENABLE; 11574e8fe214SGregory Greenman } 11584e8fe214SGregory Greenman 11594e8fe214SGregory Greenman IWL_DEBUG_RADIO(mvm, "DSM RFI is disabled\n"); 11604e8fe214SGregory Greenman 11614e8fe214SGregory Greenman /* default behaviour is disabled */ 11624e8fe214SGregory Greenman return DSM_VALUE_RFI_DISABLE; 11634e8fe214SGregory Greenman } 11644e8fe214SGregory Greenman 1165f5b1cb2eSGil Adam static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) 1166f5b1cb2eSGil Adam { 11677119f02bSMiri Korenblit int ret; 11687119f02bSMiri Korenblit u32 value; 11698f323d06SAyala Barazani struct iwl_lari_config_change_cmd_v6 cmd = {}; 1170f5b1cb2eSGil Adam 1171f21afabaSHarish Mitty cmd.config_bitmap = iwl_acpi_get_lari_config_bitmap(&mvm->fwrt); 1172d2bfda8aSMiri Korenblit 117345fe1b6bSLuca Coelho ret = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0, DSM_FUNC_11AX_ENABLEMENT, 11747119f02bSMiri Korenblit &iwl_guid, &value); 11757119f02bSMiri Korenblit if (!ret) 11767119f02bSMiri Korenblit cmd.oem_11ax_allow_bitmap = cpu_to_le32(value); 1177f5b1cb2eSGil Adam 117845fe1b6bSLuca Coelho ret = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0, 117954b4fda5SAbhishek Naik DSM_FUNC_ENABLE_UNII4_CHAN, 118054b4fda5SAbhishek Naik &iwl_guid, &value); 118154b4fda5SAbhishek Naik if (!ret) 118254b4fda5SAbhishek Naik cmd.oem_unii4_allow_bitmap = cpu_to_le32(value); 118354b4fda5SAbhishek Naik 118445fe1b6bSLuca Coelho ret = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0, 11851f578d4fSMiri Korenblit DSM_FUNC_ACTIVATE_CHANNEL, 11861f578d4fSMiri Korenblit &iwl_guid, &value); 11871f578d4fSMiri Korenblit if (!ret) 11881f578d4fSMiri Korenblit cmd.chan_state_active_bitmap = cpu_to_le32(value); 11891f578d4fSMiri Korenblit 1190698b166eSLuca Coelho ret = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0, 1191698b166eSLuca Coelho DSM_FUNC_ENABLE_6E, 1192698b166eSLuca Coelho &iwl_guid, &value); 1193698b166eSLuca Coelho if (!ret) 1194698b166eSLuca Coelho cmd.oem_uhb_allow_bitmap = cpu_to_le32(value); 1195698b166eSLuca Coelho 11968f323d06SAyala Barazani ret = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0, 11978f323d06SAyala Barazani DSM_FUNC_FORCE_DISABLE_CHANNELS, 11988f323d06SAyala Barazani &iwl_guid, &value); 11998f323d06SAyala Barazani if (!ret) 12008f323d06SAyala Barazani cmd.force_disable_channels_bitmap = cpu_to_le32(value); 12018f323d06SAyala Barazani 120254b4fda5SAbhishek Naik if (cmd.config_bitmap || 1203698b166eSLuca Coelho cmd.oem_uhb_allow_bitmap || 120454b4fda5SAbhishek Naik cmd.oem_11ax_allow_bitmap || 12051f578d4fSMiri Korenblit cmd.oem_unii4_allow_bitmap || 12068f323d06SAyala Barazani cmd.chan_state_active_bitmap || 12078f323d06SAyala Barazani cmd.force_disable_channels_bitmap) { 12083c21990bSMiri Korenblit size_t cmd_size; 12093c21990bSMiri Korenblit u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, 1210971cbe50SJohannes Berg WIDE_ID(REGULATORY_AND_NVM_GROUP, 1211971cbe50SJohannes Berg LARI_CONFIG_CHANGE), 1212971cbe50SJohannes Berg 1); 12138f323d06SAyala Barazani switch (cmd_ver) { 12148f323d06SAyala Barazani case 6: 12158f323d06SAyala Barazani cmd_size = sizeof(struct iwl_lari_config_change_cmd_v6); 12168f323d06SAyala Barazani break; 12178f323d06SAyala Barazani case 5: 12181f578d4fSMiri Korenblit cmd_size = sizeof(struct iwl_lari_config_change_cmd_v5); 12198f323d06SAyala Barazani break; 12208f323d06SAyala Barazani case 4: 122154b4fda5SAbhishek Naik cmd_size = sizeof(struct iwl_lari_config_change_cmd_v4); 12228f323d06SAyala Barazani break; 12238f323d06SAyala Barazani case 3: 12243c21990bSMiri Korenblit cmd_size = sizeof(struct iwl_lari_config_change_cmd_v3); 12258f323d06SAyala Barazani break; 12268f323d06SAyala Barazani case 2: 12273c21990bSMiri Korenblit cmd_size = sizeof(struct iwl_lari_config_change_cmd_v2); 12288f323d06SAyala Barazani break; 12298f323d06SAyala Barazani default: 12303c21990bSMiri Korenblit cmd_size = sizeof(struct iwl_lari_config_change_cmd_v1); 12318f323d06SAyala Barazani break; 12328f323d06SAyala Barazani } 12333c21990bSMiri Korenblit 12343ce88247SMiri Korenblit IWL_DEBUG_RADIO(mvm, 12357119f02bSMiri Korenblit "sending LARI_CONFIG_CHANGE, config_bitmap=0x%x, oem_11ax_allow_bitmap=0x%x\n", 12367119f02bSMiri Korenblit le32_to_cpu(cmd.config_bitmap), 12377119f02bSMiri Korenblit le32_to_cpu(cmd.oem_11ax_allow_bitmap)); 123854b4fda5SAbhishek Naik IWL_DEBUG_RADIO(mvm, 12391f578d4fSMiri Korenblit "sending LARI_CONFIG_CHANGE, oem_unii4_allow_bitmap=0x%x, chan_state_active_bitmap=0x%x, cmd_ver=%d\n", 124054b4fda5SAbhishek Naik le32_to_cpu(cmd.oem_unii4_allow_bitmap), 12411f578d4fSMiri Korenblit le32_to_cpu(cmd.chan_state_active_bitmap), 124254b4fda5SAbhishek Naik cmd_ver); 1243698b166eSLuca Coelho IWL_DEBUG_RADIO(mvm, 12448f323d06SAyala Barazani "sending LARI_CONFIG_CHANGE, oem_uhb_allow_bitmap=0x%x, force_disable_channels_bitmap=0x%x\n", 12458f323d06SAyala Barazani le32_to_cpu(cmd.oem_uhb_allow_bitmap), 12468f323d06SAyala Barazani le32_to_cpu(cmd.force_disable_channels_bitmap)); 12477119f02bSMiri Korenblit ret = iwl_mvm_send_cmd_pdu(mvm, 1248f5b1cb2eSGil Adam WIDE_ID(REGULATORY_AND_NVM_GROUP, 1249f5b1cb2eSGil Adam LARI_CONFIG_CHANGE), 12503ce88247SMiri Korenblit 0, cmd_size, &cmd); 12517119f02bSMiri Korenblit if (ret < 0) 1252f5b1cb2eSGil Adam IWL_DEBUG_RADIO(mvm, 1253f5b1cb2eSGil Adam "Failed to send LARI_CONFIG_CHANGE (%d)\n", 12547119f02bSMiri Korenblit ret); 1255f5b1cb2eSGil Adam } 1256f5b1cb2eSGil Adam } 125778a19d52SMiri Korenblit 125878a19d52SMiri Korenblit void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) 125978a19d52SMiri Korenblit { 126078a19d52SMiri Korenblit int ret; 126178a19d52SMiri Korenblit 126278a19d52SMiri Korenblit /* read PPAG table */ 1263*e8e10a37SMatt Chen ret = iwl_acpi_get_ppag_table(&mvm->fwrt); 126478a19d52SMiri Korenblit if (ret < 0) { 126578a19d52SMiri Korenblit IWL_DEBUG_RADIO(mvm, 126678a19d52SMiri Korenblit "PPAG BIOS table invalid or unavailable. (%d)\n", 126778a19d52SMiri Korenblit ret); 126878a19d52SMiri Korenblit } 126978a19d52SMiri Korenblit 127078a19d52SMiri Korenblit /* read SAR tables */ 127178a19d52SMiri Korenblit ret = iwl_sar_get_wrds_table(&mvm->fwrt); 127278a19d52SMiri Korenblit if (ret < 0) { 127378a19d52SMiri Korenblit IWL_DEBUG_RADIO(mvm, 127478a19d52SMiri Korenblit "WRDS SAR BIOS table invalid or unavailable. (%d)\n", 127578a19d52SMiri Korenblit ret); 127678a19d52SMiri Korenblit /* 127778a19d52SMiri Korenblit * If not available, don't fail and don't bother with EWRD and 127878a19d52SMiri Korenblit * WGDS */ 127978a19d52SMiri Korenblit 128078a19d52SMiri Korenblit if (!iwl_sar_get_wgds_table(&mvm->fwrt)) { 128178a19d52SMiri Korenblit /* 128278a19d52SMiri Korenblit * If basic SAR is not available, we check for WGDS, 128378a19d52SMiri Korenblit * which should *not* be available either. If it is 128478a19d52SMiri Korenblit * available, issue an error, because we can't use SAR 128578a19d52SMiri Korenblit * Geo without basic SAR. 128678a19d52SMiri Korenblit */ 128778a19d52SMiri Korenblit IWL_ERR(mvm, "BIOS contains WGDS but no WRDS\n"); 128878a19d52SMiri Korenblit } 128978a19d52SMiri Korenblit 129078a19d52SMiri Korenblit } else { 129178a19d52SMiri Korenblit ret = iwl_sar_get_ewrd_table(&mvm->fwrt); 129278a19d52SMiri Korenblit /* if EWRD is not available, we can still use 129378a19d52SMiri Korenblit * WRDS, so don't fail */ 129478a19d52SMiri Korenblit if (ret < 0) 129578a19d52SMiri Korenblit IWL_DEBUG_RADIO(mvm, 129678a19d52SMiri Korenblit "EWRD SAR BIOS table invalid or unavailable. (%d)\n", 129778a19d52SMiri Korenblit ret); 129878a19d52SMiri Korenblit 129978a19d52SMiri Korenblit /* read geo SAR table */ 130078a19d52SMiri Korenblit if (iwl_sar_geo_support(&mvm->fwrt)) { 130178a19d52SMiri Korenblit ret = iwl_sar_get_wgds_table(&mvm->fwrt); 130278a19d52SMiri Korenblit if (ret < 0) 130378a19d52SMiri Korenblit IWL_DEBUG_RADIO(mvm, 130478a19d52SMiri Korenblit "Geo SAR BIOS table invalid or unavailable. (%d)\n", 130578a19d52SMiri Korenblit ret); 130678a19d52SMiri Korenblit /* we don't fail if the table is not available */ 130778a19d52SMiri Korenblit } 130878a19d52SMiri Korenblit } 130978a19d52SMiri Korenblit } 131069964905SLuca Coelho #else /* CONFIG_ACPI */ 131139c1a972SIhab Zhaika 131239c1a972SIhab Zhaika inline int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, 131339c1a972SIhab Zhaika int prof_a, int prof_b) 131469964905SLuca Coelho { 131578a19d52SMiri Korenblit return 1; 131669964905SLuca Coelho } 131769964905SLuca Coelho 131839c1a972SIhab Zhaika inline int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) 13195d041c46SLuca Coelho { 13205d041c46SLuca Coelho return -ENOENT; 13215d041c46SLuca Coelho } 13225d041c46SLuca Coelho 1323a6bff3cbSHaim Dreyfuss static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) 1324a6bff3cbSHaim Dreyfuss { 1325a6bff3cbSHaim Dreyfuss return 0; 1326a6bff3cbSHaim Dreyfuss } 132718f1755dSLuca Coelho 13286ce1e5c0SGil Adam int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) 13296ce1e5c0SGil Adam { 13306ce1e5c0SGil Adam return -ENOENT; 13316ce1e5c0SGil Adam } 13326ce1e5c0SGil Adam 13336ce1e5c0SGil Adam static int iwl_mvm_ppag_init(struct iwl_mvm *mvm) 13346ce1e5c0SGil Adam { 13357937fd32SJohannes Berg return 0; 13366ce1e5c0SGil Adam } 133728dd7ccdSMordechay Goodstein 133828dd7ccdSMordechay Goodstein static void iwl_mvm_tas_init(struct iwl_mvm *mvm) 133928dd7ccdSMordechay Goodstein { 134028dd7ccdSMordechay Goodstein } 1341f5b1cb2eSGil Adam 1342f5b1cb2eSGil Adam static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) 1343f5b1cb2eSGil Adam { 1344f5b1cb2eSGil Adam } 13454e8fe214SGregory Greenman 13464e8fe214SGregory Greenman static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) 13474e8fe214SGregory Greenman { 13484e8fe214SGregory Greenman return DSM_VALUE_RFI_DISABLE; 13494e8fe214SGregory Greenman } 135078a19d52SMiri Korenblit 135178a19d52SMiri Korenblit void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) 135278a19d52SMiri Korenblit { 135378a19d52SMiri Korenblit } 1354c593d2faSAyala Barazani 135569964905SLuca Coelho #endif /* CONFIG_ACPI */ 135669964905SLuca Coelho 1357f130bb75SMordechay Goodstein void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags) 1358f130bb75SMordechay Goodstein { 1359f130bb75SMordechay Goodstein u32 error_log_size = mvm->fw->ucode_capa.error_log_size; 1360f130bb75SMordechay Goodstein int ret; 1361f130bb75SMordechay Goodstein u32 resp; 1362f130bb75SMordechay Goodstein 1363f130bb75SMordechay Goodstein struct iwl_fw_error_recovery_cmd recovery_cmd = { 1364f130bb75SMordechay Goodstein .flags = cpu_to_le32(flags), 1365f130bb75SMordechay Goodstein .buf_size = 0, 1366f130bb75SMordechay Goodstein }; 1367f130bb75SMordechay Goodstein struct iwl_host_cmd host_cmd = { 1368f130bb75SMordechay Goodstein .id = WIDE_ID(SYSTEM_GROUP, FW_ERROR_RECOVERY_CMD), 1369f130bb75SMordechay Goodstein .flags = CMD_WANT_SKB, 1370f130bb75SMordechay Goodstein .data = {&recovery_cmd, }, 1371f130bb75SMordechay Goodstein .len = {sizeof(recovery_cmd), }, 1372f130bb75SMordechay Goodstein }; 1373f130bb75SMordechay Goodstein 1374f130bb75SMordechay Goodstein /* no error log was defined in TLV */ 1375f130bb75SMordechay Goodstein if (!error_log_size) 1376f130bb75SMordechay Goodstein return; 1377f130bb75SMordechay Goodstein 1378f130bb75SMordechay Goodstein if (flags & ERROR_RECOVERY_UPDATE_DB) { 1379f130bb75SMordechay Goodstein /* no buf was allocated while HW reset */ 1380f130bb75SMordechay Goodstein if (!mvm->error_recovery_buf) 1381f130bb75SMordechay Goodstein return; 1382f130bb75SMordechay Goodstein 1383f130bb75SMordechay Goodstein host_cmd.data[1] = mvm->error_recovery_buf; 1384f130bb75SMordechay Goodstein host_cmd.len[1] = error_log_size; 1385f130bb75SMordechay Goodstein host_cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY; 1386f130bb75SMordechay Goodstein recovery_cmd.buf_size = cpu_to_le32(error_log_size); 1387f130bb75SMordechay Goodstein } 1388f130bb75SMordechay Goodstein 1389f130bb75SMordechay Goodstein ret = iwl_mvm_send_cmd(mvm, &host_cmd); 1390f130bb75SMordechay Goodstein kfree(mvm->error_recovery_buf); 1391f130bb75SMordechay Goodstein mvm->error_recovery_buf = NULL; 1392f130bb75SMordechay Goodstein 1393f130bb75SMordechay Goodstein if (ret) { 1394f130bb75SMordechay Goodstein IWL_ERR(mvm, "Failed to send recovery cmd %d\n", ret); 1395f130bb75SMordechay Goodstein return; 1396f130bb75SMordechay Goodstein } 1397f130bb75SMordechay Goodstein 1398f130bb75SMordechay Goodstein /* skb respond is only relevant in ERROR_RECOVERY_UPDATE_DB */ 1399f130bb75SMordechay Goodstein if (flags & ERROR_RECOVERY_UPDATE_DB) { 1400f130bb75SMordechay Goodstein resp = le32_to_cpu(*(__le32 *)host_cmd.resp_pkt->data); 1401f130bb75SMordechay Goodstein if (resp) 1402f130bb75SMordechay Goodstein IWL_ERR(mvm, 1403f130bb75SMordechay Goodstein "Failed to send recovery cmd blob was invalid %d\n", 1404f130bb75SMordechay Goodstein resp); 1405f130bb75SMordechay Goodstein } 1406f130bb75SMordechay Goodstein } 1407f130bb75SMordechay Goodstein 140842ce76d6SLuca Coelho static int iwl_mvm_sar_init(struct iwl_mvm *mvm) 140942ce76d6SLuca Coelho { 14101edd56e6SLuca Coelho return iwl_mvm_sar_select_profile(mvm, 1, 1); 1411da2830acSLuca Coelho } 1412da2830acSLuca Coelho 14131f370650SSara Sharon static int iwl_mvm_load_rt_fw(struct iwl_mvm *mvm) 14141f370650SSara Sharon { 14151f370650SSara Sharon int ret; 14161f370650SSara Sharon 14177d6222e2SJohannes Berg if (iwl_mvm_has_unified_ucode(mvm)) 141852b15521SEmmanuel Grumbach return iwl_run_unified_mvm_ucode(mvm); 14191f370650SSara Sharon 14203b25f1afSEmmanuel Grumbach ret = iwl_run_init_mvm_ucode(mvm); 14211f370650SSara Sharon 14221f370650SSara Sharon if (ret) { 14231f370650SSara Sharon IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret); 1424f4744258SLiad Kaufman 1425f4744258SLiad Kaufman if (iwlmvm_mod_params.init_dbg) 1426f4744258SLiad Kaufman return 0; 14271f370650SSara Sharon return ret; 14281f370650SSara Sharon } 14291f370650SSara Sharon 1430203c83d3SShahar S Matityahu iwl_fw_dbg_stop_sync(&mvm->fwrt); 1431bab3cb92SEmmanuel Grumbach iwl_trans_stop_device(mvm->trans); 1432bab3cb92SEmmanuel Grumbach ret = iwl_trans_start_hw(mvm->trans); 14331f370650SSara Sharon if (ret) 14341f370650SSara Sharon return ret; 14351f370650SSara Sharon 143694022562SEmmanuel Grumbach mvm->rfkill_safe_init_done = false; 14371f370650SSara Sharon ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_REGULAR); 14381f370650SSara Sharon if (ret) 14391f370650SSara Sharon return ret; 14401f370650SSara Sharon 144194022562SEmmanuel Grumbach mvm->rfkill_safe_init_done = true; 144294022562SEmmanuel Grumbach 1443b108d8c7SShahar S Matityahu iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_AFTER_ALIVE, 1444b108d8c7SShahar S Matityahu NULL); 1445da2eb669SSara Sharon 1446702e975dSJohannes Berg return iwl_init_paging(&mvm->fwrt, mvm->fwrt.cur_fw_img); 14471f370650SSara Sharon } 14481f370650SSara Sharon 1449e705c121SKalle Valo int iwl_mvm_up(struct iwl_mvm *mvm) 1450e705c121SKalle Valo { 1451e705c121SKalle Valo int ret, i; 1452e705c121SKalle Valo struct ieee80211_channel *chan; 1453e705c121SKalle Valo struct cfg80211_chan_def chandef; 1454dd36a507STova Mussai struct ieee80211_supported_band *sband = NULL; 1455e705c121SKalle Valo 1456e705c121SKalle Valo lockdep_assert_held(&mvm->mutex); 1457e705c121SKalle Valo 1458e705c121SKalle Valo ret = iwl_trans_start_hw(mvm->trans); 1459e705c121SKalle Valo if (ret) 1460e705c121SKalle Valo return ret; 1461e705c121SKalle Valo 14621f370650SSara Sharon ret = iwl_mvm_load_rt_fw(mvm); 1463e705c121SKalle Valo if (ret) { 1464e705c121SKalle Valo IWL_ERR(mvm, "Failed to start RT ucode: %d\n", ret); 146572d3c7bbSJohannes Berg if (ret != -ERFKILL) 146672d3c7bbSJohannes Berg iwl_fw_dbg_error_collect(&mvm->fwrt, 146772d3c7bbSJohannes Berg FW_DBG_TRIGGER_DRIVER); 1468e705c121SKalle Valo goto error; 1469e705c121SKalle Valo } 1470e705c121SKalle Valo 1471d0b813fcSJohannes Berg iwl_get_shared_mem_conf(&mvm->fwrt); 1472e705c121SKalle Valo 1473e705c121SKalle Valo ret = iwl_mvm_sf_update(mvm, NULL, false); 1474e705c121SKalle Valo if (ret) 1475e705c121SKalle Valo IWL_ERR(mvm, "Failed to initialize Smart Fifo\n"); 1476e705c121SKalle Valo 1477a1af4c48SShahar S Matityahu if (!iwl_trans_dbg_ini_valid(mvm->trans)) { 14787174beb6SJohannes Berg mvm->fwrt.dump.conf = FW_DBG_INVALID; 1479e705c121SKalle Valo /* if we have a destination, assume EARLY START */ 148017b809c9SSara Sharon if (mvm->fw->dbg.dest_tlv) 14817174beb6SJohannes Berg mvm->fwrt.dump.conf = FW_DBG_START_FROM_ALIVE; 14827174beb6SJohannes Berg iwl_fw_start_dbg_conf(&mvm->fwrt, FW_DBG_START_FROM_ALIVE); 14837a14c23dSSara Sharon } 1484e705c121SKalle Valo 1485e705c121SKalle Valo ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm)); 1486e705c121SKalle Valo if (ret) 1487e705c121SKalle Valo goto error; 1488e705c121SKalle Valo 14897d6222e2SJohannes Berg if (!iwl_mvm_has_unified_ucode(mvm)) { 1490e705c121SKalle Valo /* Send phy db control command and then phy db calibration */ 1491e705c121SKalle Valo ret = iwl_send_phy_db_data(mvm->phy_db); 1492e705c121SKalle Valo if (ret) 1493e705c121SKalle Valo goto error; 1494bb99ff9bSLuca Coelho } 1495e705c121SKalle Valo 1496e705c121SKalle Valo ret = iwl_send_phy_cfg_cmd(mvm); 1497e705c121SKalle Valo if (ret) 1498e705c121SKalle Valo goto error; 1499e705c121SKalle Valo 1500b3de3ef4SEmmanuel Grumbach ret = iwl_mvm_send_bt_init_conf(mvm); 1501b3de3ef4SEmmanuel Grumbach if (ret) 1502b3de3ef4SEmmanuel Grumbach goto error; 1503b3de3ef4SEmmanuel Grumbach 1504cceb4507SShahar S Matityahu if (fw_has_capa(&mvm->fw->ucode_capa, 1505cceb4507SShahar S Matityahu IWL_UCODE_TLV_CAPA_SOC_LATENCY_SUPPORT)) { 1506a8eb340fSEmmanuel Grumbach ret = iwl_set_soc_latency(&mvm->fwrt); 1507cceb4507SShahar S Matityahu if (ret) 1508cceb4507SShahar S Matityahu goto error; 1509cceb4507SShahar S Matityahu } 1510cceb4507SShahar S Matityahu 151143413a97SSara Sharon /* Init RSS configuration */ 15129cd243f2SMordechay Goodstein ret = iwl_configure_rxq(&mvm->fwrt); 15139cd243f2SMordechay Goodstein if (ret) 15148edbfaa1SSara Sharon goto error; 15158edbfaa1SSara Sharon 15168edbfaa1SSara Sharon if (iwl_mvm_has_new_rx_api(mvm)) { 151743413a97SSara Sharon ret = iwl_send_rss_cfg_cmd(mvm); 151843413a97SSara Sharon if (ret) { 151943413a97SSara Sharon IWL_ERR(mvm, "Failed to configure RSS queues: %d\n", 152043413a97SSara Sharon ret); 152143413a97SSara Sharon goto error; 152243413a97SSara Sharon } 152343413a97SSara Sharon } 152443413a97SSara Sharon 1525e705c121SKalle Valo /* init the fw <-> mac80211 STA mapping */ 1526be9ae34eSNathan Errera for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) 1527e705c121SKalle Valo RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL); 1528e705c121SKalle Valo 15290ae98812SSara Sharon mvm->tdls_cs.peer.sta_id = IWL_MVM_INVALID_STA; 1530e705c121SKalle Valo 1531e705c121SKalle Valo /* reset quota debouncing buffer - 0xff will yield invalid data */ 1532e705c121SKalle Valo memset(&mvm->last_quota_cmd, 0xff, sizeof(mvm->last_quota_cmd)); 1533e705c121SKalle Valo 153479660869SIlia Lin if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_DQA_SUPPORT)) { 153597d5be7eSLiad Kaufman ret = iwl_mvm_send_dqa_cmd(mvm); 153697d5be7eSLiad Kaufman if (ret) 153797d5be7eSLiad Kaufman goto error; 153879660869SIlia Lin } 153997d5be7eSLiad Kaufman 15402c2c3647SNathan Errera /* 15412c2c3647SNathan Errera * Add auxiliary station for scanning. 15422c2c3647SNathan Errera * Newer versions of this command implies that the fw uses 15432c2c3647SNathan Errera * internal aux station for all aux activities that don't 15442c2c3647SNathan Errera * requires a dedicated data queue. 15452c2c3647SNathan Errera */ 1546971cbe50SJohannes Berg if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) < 12) { 15472c2c3647SNathan Errera /* 15482c2c3647SNathan Errera * In old version the aux station uses mac id like other 15492c2c3647SNathan Errera * station and not lmac id 15502c2c3647SNathan Errera */ 15512c2c3647SNathan Errera ret = iwl_mvm_add_aux_sta(mvm, MAC_INDEX_AUX); 1552e705c121SKalle Valo if (ret) 1553e705c121SKalle Valo goto error; 15542c2c3647SNathan Errera } 1555e705c121SKalle Valo 1556e705c121SKalle Valo /* Add all the PHY contexts */ 1557dd36a507STova Mussai i = 0; 1558dd36a507STova Mussai while (!sband && i < NUM_NL80211_BANDS) 1559dd36a507STova Mussai sband = mvm->hw->wiphy->bands[i++]; 1560dd36a507STova Mussai 1561583d1833SDan Carpenter if (WARN_ON_ONCE(!sband)) { 1562583d1833SDan Carpenter ret = -ENODEV; 1563dd36a507STova Mussai goto error; 1564583d1833SDan Carpenter } 1565dd36a507STova Mussai 1566dd36a507STova Mussai chan = &sband->channels[0]; 1567dd36a507STova Mussai 1568e705c121SKalle Valo cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT); 1569e705c121SKalle Valo for (i = 0; i < NUM_PHY_CTX; i++) { 1570e705c121SKalle Valo /* 1571e705c121SKalle Valo * The channel used here isn't relevant as it's 1572e705c121SKalle Valo * going to be overwritten in the other flows. 1573e705c121SKalle Valo * For now use the first channel we have. 1574e705c121SKalle Valo */ 1575e705c121SKalle Valo ret = iwl_mvm_phy_ctxt_add(mvm, &mvm->phy_ctxts[i], 1576e705c121SKalle Valo &chandef, 1, 1); 1577e705c121SKalle Valo if (ret) 1578e705c121SKalle Valo goto error; 1579e705c121SKalle Valo } 1580e705c121SKalle Valo 1581c221daf2SChaya Rachel Ivgi if (iwl_mvm_is_tt_in_fw(mvm)) { 1582c221daf2SChaya Rachel Ivgi /* in order to give the responsibility of ct-kill and 1583c221daf2SChaya Rachel Ivgi * TX backoff to FW we need to send empty temperature reporting 1584c221daf2SChaya Rachel Ivgi * cmd during init time 1585c221daf2SChaya Rachel Ivgi */ 1586c221daf2SChaya Rachel Ivgi iwl_mvm_send_temp_report_ths_cmd(mvm); 1587c221daf2SChaya Rachel Ivgi } else { 1588e705c121SKalle Valo /* Initialize tx backoffs to the minimal possible */ 1589e705c121SKalle Valo iwl_mvm_tt_tx_backoff(mvm, 0); 1590c221daf2SChaya Rachel Ivgi } 15915c89e7bcSChaya Rachel Ivgi 1592242d9c8bSJohannes Berg #ifdef CONFIG_THERMAL 15935c89e7bcSChaya Rachel Ivgi /* TODO: read the budget from BIOS / Platform NVM */ 1594944eafc2SChaya Rachel Ivgi 1595944eafc2SChaya Rachel Ivgi /* 1596944eafc2SChaya Rachel Ivgi * In case there is no budget from BIOS / Platform NVM the default 1597944eafc2SChaya Rachel Ivgi * budget should be 2000mW (cooling state 0). 1598944eafc2SChaya Rachel Ivgi */ 1599944eafc2SChaya Rachel Ivgi if (iwl_mvm_is_ctdp_supported(mvm)) { 16005c89e7bcSChaya Rachel Ivgi ret = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_START, 16015c89e7bcSChaya Rachel Ivgi mvm->cooling_dev.cur_state); 160275cfe338SLuca Coelho if (ret) 160375cfe338SLuca Coelho goto error; 160475cfe338SLuca Coelho } 1605c221daf2SChaya Rachel Ivgi #endif 1606e705c121SKalle Valo 1607aa43ae12SAlex Malamud if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_LTR_GEN2)) 1608e705c121SKalle Valo WARN_ON(iwl_mvm_config_ltr(mvm)); 1609e705c121SKalle Valo 1610e705c121SKalle Valo ret = iwl_mvm_power_update_device(mvm); 1611e705c121SKalle Valo if (ret) 1612e705c121SKalle Valo goto error; 1613e705c121SKalle Valo 1614f5b1cb2eSGil Adam iwl_mvm_lari_cfg(mvm); 1615e705c121SKalle Valo /* 1616e705c121SKalle Valo * RTNL is not taken during Ct-kill, but we don't need to scan/Tx 1617e705c121SKalle Valo * anyway, so don't init MCC. 1618e705c121SKalle Valo */ 1619e705c121SKalle Valo if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) { 1620e705c121SKalle Valo ret = iwl_mvm_init_mcc(mvm); 1621e705c121SKalle Valo if (ret) 1622e705c121SKalle Valo goto error; 1623e705c121SKalle Valo } 1624e705c121SKalle Valo 1625e705c121SKalle Valo if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { 16264ca87a5fSEmmanuel Grumbach mvm->scan_type = IWL_SCAN_TYPE_NOT_SET; 1627b66b5817SSara Sharon mvm->hb_scan_type = IWL_SCAN_TYPE_NOT_SET; 1628e705c121SKalle Valo ret = iwl_mvm_config_scan(mvm); 1629e705c121SKalle Valo if (ret) 1630e705c121SKalle Valo goto error; 1631e705c121SKalle Valo } 1632e705c121SKalle Valo 1633f130bb75SMordechay Goodstein if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) 1634f130bb75SMordechay Goodstein iwl_mvm_send_recovery_cmd(mvm, ERROR_RECOVERY_UPDATE_DB); 1635f130bb75SMordechay Goodstein 163648e775e6SHaim Dreyfuss if (iwl_acpi_get_eckv(mvm->dev, &mvm->ext_clock_valid)) 163748e775e6SHaim Dreyfuss IWL_DEBUG_INFO(mvm, "ECKV table doesn't exist in BIOS\n"); 163848e775e6SHaim Dreyfuss 16396ce1e5c0SGil Adam ret = iwl_mvm_ppag_init(mvm); 16406ce1e5c0SGil Adam if (ret) 16416ce1e5c0SGil Adam goto error; 16426ce1e5c0SGil Adam 1643da2830acSLuca Coelho ret = iwl_mvm_sar_init(mvm); 164478a19d52SMiri Korenblit if (ret == 0) 1645a6bff3cbSHaim Dreyfuss ret = iwl_mvm_sar_geo_init(mvm); 164678a19d52SMiri Korenblit else if (ret < 0) 1647a6bff3cbSHaim Dreyfuss goto error; 1648a6bff3cbSHaim Dreyfuss 1649c593d2faSAyala Barazani ret = iwl_mvm_sgom_init(mvm); 1650c593d2faSAyala Barazani if (ret) 1651c593d2faSAyala Barazani goto error; 1652c593d2faSAyala Barazani 165328dd7ccdSMordechay Goodstein iwl_mvm_tas_init(mvm); 16547089ae63SJohannes Berg iwl_mvm_leds_sync(mvm); 16557089ae63SJohannes Berg 1656b68bd2e3SIlan Peer iwl_mvm_ftm_initiator_smooth_config(mvm); 1657b68bd2e3SIlan Peer 16584e8fe214SGregory Greenman if (fw_has_capa(&mvm->fw->ucode_capa, 16594e8fe214SGregory Greenman IWL_UCODE_TLV_CAPA_RFIM_SUPPORT)) { 16604e8fe214SGregory Greenman if (iwl_mvm_eval_dsm_rfi(mvm) == DSM_VALUE_RFI_ENABLE) 16614e8fe214SGregory Greenman iwl_rfi_send_config_cmd(mvm, NULL); 16624e8fe214SGregory Greenman } 16634e8fe214SGregory Greenman 1664e705c121SKalle Valo IWL_DEBUG_INFO(mvm, "RT uCode started.\n"); 1665e705c121SKalle Valo return 0; 1666e705c121SKalle Valo error: 1667f4744258SLiad Kaufman if (!iwlmvm_mod_params.init_dbg || !ret) 1668fcb6b92aSChaya Rachel Ivgi iwl_mvm_stop_device(mvm); 1669e705c121SKalle Valo return ret; 1670e705c121SKalle Valo } 1671e705c121SKalle Valo 1672e705c121SKalle Valo int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm) 1673e705c121SKalle Valo { 1674e705c121SKalle Valo int ret, i; 1675e705c121SKalle Valo 1676e705c121SKalle Valo lockdep_assert_held(&mvm->mutex); 1677e705c121SKalle Valo 1678e705c121SKalle Valo ret = iwl_trans_start_hw(mvm->trans); 1679e705c121SKalle Valo if (ret) 1680e705c121SKalle Valo return ret; 1681e705c121SKalle Valo 1682e705c121SKalle Valo ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_WOWLAN); 1683e705c121SKalle Valo if (ret) { 1684e705c121SKalle Valo IWL_ERR(mvm, "Failed to start WoWLAN firmware: %d\n", ret); 1685e705c121SKalle Valo goto error; 1686e705c121SKalle Valo } 1687e705c121SKalle Valo 1688e705c121SKalle Valo ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm)); 1689e705c121SKalle Valo if (ret) 1690e705c121SKalle Valo goto error; 1691e705c121SKalle Valo 1692e705c121SKalle Valo /* Send phy db control command and then phy db calibration*/ 1693e705c121SKalle Valo ret = iwl_send_phy_db_data(mvm->phy_db); 1694e705c121SKalle Valo if (ret) 1695e705c121SKalle Valo goto error; 1696e705c121SKalle Valo 1697e705c121SKalle Valo ret = iwl_send_phy_cfg_cmd(mvm); 1698e705c121SKalle Valo if (ret) 1699e705c121SKalle Valo goto error; 1700e705c121SKalle Valo 1701e705c121SKalle Valo /* init the fw <-> mac80211 STA mapping */ 1702be9ae34eSNathan Errera for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) 1703e705c121SKalle Valo RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL); 1704e705c121SKalle Valo 1705971cbe50SJohannes Berg if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) < 12) { 17062c2c3647SNathan Errera /* 17072c2c3647SNathan Errera * Add auxiliary station for scanning. 17082c2c3647SNathan Errera * Newer versions of this command implies that the fw uses 17092c2c3647SNathan Errera * internal aux station for all aux activities that don't 17102c2c3647SNathan Errera * requires a dedicated data queue. 17112c2c3647SNathan Errera * In old version the aux station uses mac id like other 17122c2c3647SNathan Errera * station and not lmac id 17132c2c3647SNathan Errera */ 17142c2c3647SNathan Errera ret = iwl_mvm_add_aux_sta(mvm, MAC_INDEX_AUX); 1715e705c121SKalle Valo if (ret) 1716e705c121SKalle Valo goto error; 17172c2c3647SNathan Errera } 1718e705c121SKalle Valo 1719e705c121SKalle Valo return 0; 1720e705c121SKalle Valo error: 1721fcb6b92aSChaya Rachel Ivgi iwl_mvm_stop_device(mvm); 1722e705c121SKalle Valo return ret; 1723e705c121SKalle Valo } 1724e705c121SKalle Valo 1725e705c121SKalle Valo void iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, 1726e705c121SKalle Valo struct iwl_rx_cmd_buffer *rxb) 1727e705c121SKalle Valo { 1728e705c121SKalle Valo struct iwl_rx_packet *pkt = rxb_addr(rxb); 1729e705c121SKalle Valo struct iwl_mfuart_load_notif *mfuart_notif = (void *)pkt->data; 1730e705c121SKalle Valo 1731e705c121SKalle Valo IWL_DEBUG_INFO(mvm, 1732e705c121SKalle Valo "MFUART: installed ver: 0x%08x, external ver: 0x%08x, status: 0x%08x, duration: 0x%08x\n", 1733e705c121SKalle Valo le32_to_cpu(mfuart_notif->installed_ver), 1734e705c121SKalle Valo le32_to_cpu(mfuart_notif->external_ver), 1735e705c121SKalle Valo le32_to_cpu(mfuart_notif->status), 1736e705c121SKalle Valo le32_to_cpu(mfuart_notif->duration)); 17370c8d0a47SGolan Ben-Ami 17380c8d0a47SGolan Ben-Ami if (iwl_rx_packet_payload_len(pkt) == sizeof(*mfuart_notif)) 17390c8d0a47SGolan Ben-Ami IWL_DEBUG_INFO(mvm, 17400c8d0a47SGolan Ben-Ami "MFUART: image size: 0x%08x\n", 17410c8d0a47SGolan Ben-Ami le32_to_cpu(mfuart_notif->image_size)); 1742e705c121SKalle Valo } 1743