1bfcc09ddSBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2bfcc09ddSBjoern A. Zeeb /* 3bfcc09ddSBjoern A. Zeeb * Copyright (C) 2017 Intel Deutschland GmbH 4*a4128aadSBjoern A. Zeeb * Copyright (C) 2019-2021, 2024 Intel Corporation 5bfcc09ddSBjoern A. Zeeb */ 6bfcc09ddSBjoern A. Zeeb #include "iwl-drv.h" 7bfcc09ddSBjoern A. Zeeb #include "runtime.h" 8bfcc09ddSBjoern A. Zeeb #include "dbg.h" 9bfcc09ddSBjoern A. Zeeb #include "debugfs.h" 10bfcc09ddSBjoern A. Zeeb 11d9836fb4SBjoern A. Zeeb #include "fw/api/system.h" 12bfcc09ddSBjoern A. Zeeb #include "fw/api/commands.h" 13bfcc09ddSBjoern A. Zeeb #include "fw/api/rx.h" 14bfcc09ddSBjoern A. Zeeb #include "fw/api/datapath.h" 15bfcc09ddSBjoern A. Zeeb 16bfcc09ddSBjoern A. Zeeb void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans, 17bfcc09ddSBjoern A. Zeeb const struct iwl_fw *fw, 18bfcc09ddSBjoern A. Zeeb const struct iwl_fw_runtime_ops *ops, void *ops_ctx, 19bfcc09ddSBjoern A. Zeeb const struct iwl_dump_sanitize_ops *sanitize_ops, 20bfcc09ddSBjoern A. Zeeb void *sanitize_ctx, 21bfcc09ddSBjoern A. Zeeb struct dentry *dbgfs_dir) 22bfcc09ddSBjoern A. Zeeb { 23bfcc09ddSBjoern A. Zeeb int i; 24bfcc09ddSBjoern A. Zeeb 25bfcc09ddSBjoern A. Zeeb memset(fwrt, 0, sizeof(*fwrt)); 26bfcc09ddSBjoern A. Zeeb fwrt->trans = trans; 27bfcc09ddSBjoern A. Zeeb fwrt->fw = fw; 28bfcc09ddSBjoern A. Zeeb fwrt->dev = trans->dev; 29bfcc09ddSBjoern A. Zeeb fwrt->dump.conf = FW_DBG_INVALID; 30bfcc09ddSBjoern A. Zeeb fwrt->ops = ops; 31bfcc09ddSBjoern A. Zeeb fwrt->sanitize_ops = sanitize_ops; 32bfcc09ddSBjoern A. Zeeb fwrt->sanitize_ctx = sanitize_ctx; 33bfcc09ddSBjoern A. Zeeb fwrt->ops_ctx = ops_ctx; 34bfcc09ddSBjoern A. Zeeb for (i = 0; i < IWL_FW_RUNTIME_DUMP_WK_NUM; i++) { 35bfcc09ddSBjoern A. Zeeb fwrt->dump.wks[i].idx = i; 36bfcc09ddSBjoern A. Zeeb INIT_DELAYED_WORK(&fwrt->dump.wks[i].wk, iwl_fw_error_dump_wk); 37bfcc09ddSBjoern A. Zeeb } 38bfcc09ddSBjoern A. Zeeb iwl_fwrt_dbgfs_register(fwrt, dbgfs_dir); 39bfcc09ddSBjoern A. Zeeb } 40bfcc09ddSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_fw_runtime_init); 41bfcc09ddSBjoern A. Zeeb 42bfcc09ddSBjoern A. Zeeb void iwl_fw_runtime_suspend(struct iwl_fw_runtime *fwrt) 43bfcc09ddSBjoern A. Zeeb { 44bfcc09ddSBjoern A. Zeeb iwl_fw_suspend_timestamp(fwrt); 45bfcc09ddSBjoern A. Zeeb iwl_dbg_tlv_time_point(fwrt, IWL_FW_INI_TIME_POINT_HOST_D3_START, NULL); 46bfcc09ddSBjoern A. Zeeb } 47bfcc09ddSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_fw_runtime_suspend); 48bfcc09ddSBjoern A. Zeeb 49bfcc09ddSBjoern A. Zeeb void iwl_fw_runtime_resume(struct iwl_fw_runtime *fwrt) 50bfcc09ddSBjoern A. Zeeb { 51bfcc09ddSBjoern A. Zeeb iwl_dbg_tlv_time_point(fwrt, IWL_FW_INI_TIME_POINT_HOST_D3_END, NULL); 52bfcc09ddSBjoern A. Zeeb iwl_fw_resume_timestamp(fwrt); 53bfcc09ddSBjoern A. Zeeb } 54bfcc09ddSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_fw_runtime_resume); 55bfcc09ddSBjoern A. Zeeb 56bfcc09ddSBjoern A. Zeeb /* set device type and latency */ 57bfcc09ddSBjoern A. Zeeb int iwl_set_soc_latency(struct iwl_fw_runtime *fwrt) 58bfcc09ddSBjoern A. Zeeb { 59bfcc09ddSBjoern A. Zeeb struct iwl_soc_configuration_cmd cmd = {}; 60bfcc09ddSBjoern A. Zeeb struct iwl_host_cmd hcmd = { 61d9836fb4SBjoern A. Zeeb .id = WIDE_ID(SYSTEM_GROUP, SOC_CONFIGURATION_CMD), 62bfcc09ddSBjoern A. Zeeb .data[0] = &cmd, 63bfcc09ddSBjoern A. Zeeb .len[0] = sizeof(cmd), 64bfcc09ddSBjoern A. Zeeb }; 65bfcc09ddSBjoern A. Zeeb int ret; 66bfcc09ddSBjoern A. Zeeb 67bfcc09ddSBjoern A. Zeeb /* 68bfcc09ddSBjoern A. Zeeb * In VER_1 of this command, the discrete value is considered 69bfcc09ddSBjoern A. Zeeb * an integer; In VER_2, it's a bitmask. Since we have only 2 70bfcc09ddSBjoern A. Zeeb * values in VER_1, this is backwards-compatible with VER_2, 71bfcc09ddSBjoern A. Zeeb * as long as we don't set any other bits. 72bfcc09ddSBjoern A. Zeeb */ 73bfcc09ddSBjoern A. Zeeb if (!fwrt->trans->trans_cfg->integrated) 74bfcc09ddSBjoern A. Zeeb cmd.flags = cpu_to_le32(SOC_CONFIG_CMD_FLAGS_DISCRETE); 75bfcc09ddSBjoern A. Zeeb 76bfcc09ddSBjoern A. Zeeb BUILD_BUG_ON(IWL_CFG_TRANS_LTR_DELAY_NONE != 77bfcc09ddSBjoern A. Zeeb SOC_FLAGS_LTR_APPLY_DELAY_NONE); 78bfcc09ddSBjoern A. Zeeb BUILD_BUG_ON(IWL_CFG_TRANS_LTR_DELAY_200US != 79bfcc09ddSBjoern A. Zeeb SOC_FLAGS_LTR_APPLY_DELAY_200); 80bfcc09ddSBjoern A. Zeeb BUILD_BUG_ON(IWL_CFG_TRANS_LTR_DELAY_2500US != 81bfcc09ddSBjoern A. Zeeb SOC_FLAGS_LTR_APPLY_DELAY_2500); 82bfcc09ddSBjoern A. Zeeb BUILD_BUG_ON(IWL_CFG_TRANS_LTR_DELAY_1820US != 83bfcc09ddSBjoern A. Zeeb SOC_FLAGS_LTR_APPLY_DELAY_1820); 84bfcc09ddSBjoern A. Zeeb 85bfcc09ddSBjoern A. Zeeb if (fwrt->trans->trans_cfg->ltr_delay != IWL_CFG_TRANS_LTR_DELAY_NONE && 86bfcc09ddSBjoern A. Zeeb !WARN_ON(!fwrt->trans->trans_cfg->integrated)) 87bfcc09ddSBjoern A. Zeeb cmd.flags |= le32_encode_bits(fwrt->trans->trans_cfg->ltr_delay, 88bfcc09ddSBjoern A. Zeeb SOC_FLAGS_LTR_APPLY_DELAY_MASK); 89bfcc09ddSBjoern A. Zeeb 90d9836fb4SBjoern A. Zeeb if (iwl_fw_lookup_cmd_ver(fwrt->fw, SCAN_REQ_UMAC, 91bfcc09ddSBjoern A. Zeeb IWL_FW_CMD_VER_UNKNOWN) >= 2 && 92bfcc09ddSBjoern A. Zeeb fwrt->trans->trans_cfg->low_latency_xtal) 93bfcc09ddSBjoern A. Zeeb cmd.flags |= cpu_to_le32(SOC_CONFIG_CMD_FLAGS_LOW_LATENCY); 94bfcc09ddSBjoern A. Zeeb 95bfcc09ddSBjoern A. Zeeb cmd.latency = cpu_to_le32(fwrt->trans->trans_cfg->xtal_latency); 96bfcc09ddSBjoern A. Zeeb 97bfcc09ddSBjoern A. Zeeb ret = iwl_trans_send_cmd(fwrt->trans, &hcmd); 98bfcc09ddSBjoern A. Zeeb if (ret) 99bfcc09ddSBjoern A. Zeeb IWL_ERR(fwrt, "Failed to set soc latency: %d\n", ret); 100bfcc09ddSBjoern A. Zeeb return ret; 101bfcc09ddSBjoern A. Zeeb } 102bfcc09ddSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_set_soc_latency); 103bfcc09ddSBjoern A. Zeeb 104bfcc09ddSBjoern A. Zeeb int iwl_configure_rxq(struct iwl_fw_runtime *fwrt) 105bfcc09ddSBjoern A. Zeeb { 106bfcc09ddSBjoern A. Zeeb int i, num_queues, size, ret; 107bfcc09ddSBjoern A. Zeeb struct iwl_rfh_queue_config *cmd; 108bfcc09ddSBjoern A. Zeeb struct iwl_host_cmd hcmd = { 109bfcc09ddSBjoern A. Zeeb .id = WIDE_ID(DATA_PATH_GROUP, RFH_QUEUE_CONFIG_CMD), 110bfcc09ddSBjoern A. Zeeb .dataflags[0] = IWL_HCMD_DFL_NOCOPY, 111bfcc09ddSBjoern A. Zeeb }; 112bfcc09ddSBjoern A. Zeeb 113bfcc09ddSBjoern A. Zeeb /* 114bfcc09ddSBjoern A. Zeeb * The default queue is configured via context info, so if we 115bfcc09ddSBjoern A. Zeeb * have a single queue, there's nothing to do here. 116bfcc09ddSBjoern A. Zeeb */ 117bfcc09ddSBjoern A. Zeeb if (fwrt->trans->num_rx_queues == 1) 118bfcc09ddSBjoern A. Zeeb return 0; 119bfcc09ddSBjoern A. Zeeb 120bfcc09ddSBjoern A. Zeeb if (fwrt->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_22000) 121bfcc09ddSBjoern A. Zeeb return 0; 122bfcc09ddSBjoern A. Zeeb 123bfcc09ddSBjoern A. Zeeb /* skip the default queue */ 124bfcc09ddSBjoern A. Zeeb num_queues = fwrt->trans->num_rx_queues - 1; 125bfcc09ddSBjoern A. Zeeb 126bfcc09ddSBjoern A. Zeeb size = struct_size(cmd, data, num_queues); 127bfcc09ddSBjoern A. Zeeb 128bfcc09ddSBjoern A. Zeeb cmd = kzalloc(size, GFP_KERNEL); 129bfcc09ddSBjoern A. Zeeb if (!cmd) 130bfcc09ddSBjoern A. Zeeb return -ENOMEM; 131bfcc09ddSBjoern A. Zeeb 132bfcc09ddSBjoern A. Zeeb cmd->num_queues = num_queues; 133bfcc09ddSBjoern A. Zeeb 134bfcc09ddSBjoern A. Zeeb for (i = 0; i < num_queues; i++) { 135bfcc09ddSBjoern A. Zeeb struct iwl_trans_rxq_dma_data data; 136bfcc09ddSBjoern A. Zeeb 137bfcc09ddSBjoern A. Zeeb cmd->data[i].q_num = i + 1; 138*a4128aadSBjoern A. Zeeb ret = iwl_trans_get_rxq_dma_data(fwrt->trans, i + 1, &data); 139*a4128aadSBjoern A. Zeeb if (ret) 140*a4128aadSBjoern A. Zeeb goto out; 141bfcc09ddSBjoern A. Zeeb 142bfcc09ddSBjoern A. Zeeb cmd->data[i].fr_bd_cb = cpu_to_le64(data.fr_bd_cb); 143bfcc09ddSBjoern A. Zeeb cmd->data[i].urbd_stts_wrptr = 144bfcc09ddSBjoern A. Zeeb cpu_to_le64(data.urbd_stts_wrptr); 145bfcc09ddSBjoern A. Zeeb cmd->data[i].ur_bd_cb = cpu_to_le64(data.ur_bd_cb); 146bfcc09ddSBjoern A. Zeeb cmd->data[i].fr_bd_wid = cpu_to_le32(data.fr_bd_wid); 147bfcc09ddSBjoern A. Zeeb } 148bfcc09ddSBjoern A. Zeeb 149bfcc09ddSBjoern A. Zeeb hcmd.data[0] = cmd; 150bfcc09ddSBjoern A. Zeeb hcmd.len[0] = size; 151bfcc09ddSBjoern A. Zeeb 152bfcc09ddSBjoern A. Zeeb ret = iwl_trans_send_cmd(fwrt->trans, &hcmd); 153bfcc09ddSBjoern A. Zeeb 154*a4128aadSBjoern A. Zeeb out: 155bfcc09ddSBjoern A. Zeeb kfree(cmd); 156bfcc09ddSBjoern A. Zeeb 157bfcc09ddSBjoern A. Zeeb if (ret) 158bfcc09ddSBjoern A. Zeeb IWL_ERR(fwrt, "Failed to configure RX queues: %d\n", ret); 159bfcc09ddSBjoern A. Zeeb 160bfcc09ddSBjoern A. Zeeb return ret; 161bfcc09ddSBjoern A. Zeeb } 162bfcc09ddSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_configure_rxq); 163