162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2012-2014, 2018-2021 Intel Corporation 462306a36Sopenharmony_ci * Copyright (C) 2013-2015 Intel Mobile Communications GmbH 562306a36Sopenharmony_ci * Copyright (C) 2016-2017 Intel Deutschland GmbH 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#include "iwl-drv.h" 862306a36Sopenharmony_ci#include "runtime.h" 962306a36Sopenharmony_ci#include "fw/api/commands.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistatic void iwl_parse_shared_mem_22000(struct iwl_fw_runtime *fwrt, 1262306a36Sopenharmony_ci struct iwl_rx_packet *pkt) 1362306a36Sopenharmony_ci{ 1462306a36Sopenharmony_ci struct iwl_shared_mem_cfg *mem_cfg = (void *)pkt->data; 1562306a36Sopenharmony_ci int i, lmac; 1662306a36Sopenharmony_ci int lmac_num = le32_to_cpu(mem_cfg->lmac_num); 1762306a36Sopenharmony_ci u8 api_ver = iwl_fw_lookup_notif_ver(fwrt->fw, SYSTEM_GROUP, 1862306a36Sopenharmony_ci SHARED_MEM_CFG_CMD, 0); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci if (WARN_ON(lmac_num > ARRAY_SIZE(mem_cfg->lmac_smem))) 2162306a36Sopenharmony_ci return; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci fwrt->smem_cfg.num_lmacs = lmac_num; 2462306a36Sopenharmony_ci fwrt->smem_cfg.num_txfifo_entries = 2562306a36Sopenharmony_ci ARRAY_SIZE(mem_cfg->lmac_smem[0].txfifo_size); 2662306a36Sopenharmony_ci fwrt->smem_cfg.rxfifo2_size = le32_to_cpu(mem_cfg->rxfifo2_size); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci if (api_ver >= 4 && 2962306a36Sopenharmony_ci !WARN_ON_ONCE(iwl_rx_packet_payload_len(pkt) < sizeof(*mem_cfg))) { 3062306a36Sopenharmony_ci fwrt->smem_cfg.rxfifo2_control_size = 3162306a36Sopenharmony_ci le32_to_cpu(mem_cfg->rxfifo2_control_size); 3262306a36Sopenharmony_ci } 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci for (lmac = 0; lmac < lmac_num; lmac++) { 3562306a36Sopenharmony_ci struct iwl_shared_mem_lmac_cfg *lmac_cfg = 3662306a36Sopenharmony_ci &mem_cfg->lmac_smem[lmac]; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(lmac_cfg->txfifo_size); i++) 3962306a36Sopenharmony_ci fwrt->smem_cfg.lmac[lmac].txfifo_size[i] = 4062306a36Sopenharmony_ci le32_to_cpu(lmac_cfg->txfifo_size[i]); 4162306a36Sopenharmony_ci fwrt->smem_cfg.lmac[lmac].rxfifo1_size = 4262306a36Sopenharmony_ci le32_to_cpu(lmac_cfg->rxfifo1_size); 4362306a36Sopenharmony_ci } 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic void iwl_parse_shared_mem(struct iwl_fw_runtime *fwrt, 4762306a36Sopenharmony_ci struct iwl_rx_packet *pkt) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci struct iwl_shared_mem_cfg_v2 *mem_cfg = (void *)pkt->data; 5062306a36Sopenharmony_ci int i; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci fwrt->smem_cfg.num_lmacs = 1; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci fwrt->smem_cfg.num_txfifo_entries = ARRAY_SIZE(mem_cfg->txfifo_size); 5562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mem_cfg->txfifo_size); i++) 5662306a36Sopenharmony_ci fwrt->smem_cfg.lmac[0].txfifo_size[i] = 5762306a36Sopenharmony_ci le32_to_cpu(mem_cfg->txfifo_size[i]); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci fwrt->smem_cfg.lmac[0].rxfifo1_size = 6062306a36Sopenharmony_ci le32_to_cpu(mem_cfg->rxfifo_size[0]); 6162306a36Sopenharmony_ci fwrt->smem_cfg.rxfifo2_size = le32_to_cpu(mem_cfg->rxfifo_size[1]); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* new API has more data, from rxfifo_addr field and on */ 6462306a36Sopenharmony_ci if (fw_has_capa(&fwrt->fw->ucode_capa, 6562306a36Sopenharmony_ci IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) { 6662306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(fwrt->smem_cfg.internal_txfifo_size) != 6762306a36Sopenharmony_ci sizeof(mem_cfg->internal_txfifo_size)); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci fwrt->smem_cfg.internal_txfifo_addr = 7062306a36Sopenharmony_ci le32_to_cpu(mem_cfg->internal_txfifo_addr); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci for (i = 0; 7362306a36Sopenharmony_ci i < ARRAY_SIZE(fwrt->smem_cfg.internal_txfifo_size); 7462306a36Sopenharmony_ci i++) 7562306a36Sopenharmony_ci fwrt->smem_cfg.internal_txfifo_size[i] = 7662306a36Sopenharmony_ci le32_to_cpu(mem_cfg->internal_txfifo_size[i]); 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_civoid iwl_get_shared_mem_conf(struct iwl_fw_runtime *fwrt) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci struct iwl_host_cmd cmd = { 8362306a36Sopenharmony_ci .flags = CMD_WANT_SKB, 8462306a36Sopenharmony_ci .data = { NULL, }, 8562306a36Sopenharmony_ci .len = { 0, }, 8662306a36Sopenharmony_ci }; 8762306a36Sopenharmony_ci struct iwl_rx_packet *pkt; 8862306a36Sopenharmony_ci int ret; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci if (fw_has_capa(&fwrt->fw->ucode_capa, 9162306a36Sopenharmony_ci IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) 9262306a36Sopenharmony_ci cmd.id = WIDE_ID(SYSTEM_GROUP, SHARED_MEM_CFG_CMD); 9362306a36Sopenharmony_ci else 9462306a36Sopenharmony_ci cmd.id = SHARED_MEM_CFG; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci ret = iwl_trans_send_cmd(fwrt->trans, &cmd); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (ret) { 9962306a36Sopenharmony_ci WARN(ret != -ERFKILL, 10062306a36Sopenharmony_ci "Could not send the SMEM command: %d\n", ret); 10162306a36Sopenharmony_ci return; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci pkt = cmd.resp_pkt; 10562306a36Sopenharmony_ci if (fwrt->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) 10662306a36Sopenharmony_ci iwl_parse_shared_mem_22000(fwrt, pkt); 10762306a36Sopenharmony_ci else 10862306a36Sopenharmony_ci iwl_parse_shared_mem(fwrt, pkt); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci IWL_DEBUG_INFO(fwrt, "SHARED MEM CFG: got memory offsets/sizes\n"); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci iwl_free_resp(&cmd); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_get_shared_mem_conf); 115