1bfcc09ddSBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2bfcc09ddSBjoern A. Zeeb /* 3bfcc09ddSBjoern A. Zeeb * Copyright (C) 2015 Intel Mobile Communications GmbH 4bfcc09ddSBjoern A. Zeeb * Copyright (C) 2016-2017 Intel Deutschland GmbH 5*a4128aadSBjoern A. Zeeb * Copyright (C) 2019-2021, 2023-2024 Intel Corporation 6bfcc09ddSBjoern A. Zeeb */ 7bfcc09ddSBjoern A. Zeeb #include <linux/kernel.h> 8bfcc09ddSBjoern A. Zeeb #include <linux/bsearch.h> 9bfcc09ddSBjoern A. Zeeb 10bfcc09ddSBjoern A. Zeeb #include "fw/api/tx.h" 11bfcc09ddSBjoern A. Zeeb #include "iwl-trans.h" 12bfcc09ddSBjoern A. Zeeb #include "iwl-drv.h" 13bfcc09ddSBjoern A. Zeeb #include "iwl-fh.h" 14bfcc09ddSBjoern A. Zeeb #include <linux/dmapool.h> 15bfcc09ddSBjoern A. Zeeb #include "fw/api/commands.h" 16*a4128aadSBjoern A. Zeeb #include "pcie/internal.h" 17*a4128aadSBjoern A. Zeeb #include "iwl-context-info-gen3.h" 18bfcc09ddSBjoern A. Zeeb 19bfcc09ddSBjoern A. Zeeb struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, 20bfcc09ddSBjoern A. Zeeb struct device *dev, 21bfcc09ddSBjoern A. Zeeb const struct iwl_cfg_trans_params *cfg_trans) 22bfcc09ddSBjoern A. Zeeb { 23bfcc09ddSBjoern A. Zeeb struct iwl_trans *trans; 24bfcc09ddSBjoern A. Zeeb #ifdef CONFIG_LOCKDEP 25bfcc09ddSBjoern A. Zeeb static struct lock_class_key __key; 26bfcc09ddSBjoern A. Zeeb #endif 27bfcc09ddSBjoern A. Zeeb 28bfcc09ddSBjoern A. Zeeb trans = devm_kzalloc(dev, sizeof(*trans) + priv_size, GFP_KERNEL); 29bfcc09ddSBjoern A. Zeeb if (!trans) 30bfcc09ddSBjoern A. Zeeb return NULL; 31bfcc09ddSBjoern A. Zeeb 32bfcc09ddSBjoern A. Zeeb trans->trans_cfg = cfg_trans; 33bfcc09ddSBjoern A. Zeeb 34bfcc09ddSBjoern A. Zeeb #ifdef CONFIG_LOCKDEP 35bfcc09ddSBjoern A. Zeeb lockdep_init_map(&trans->sync_cmd_lockdep_map, "sync_cmd_lockdep_map", 36bfcc09ddSBjoern A. Zeeb &__key, 0); 37bfcc09ddSBjoern A. Zeeb #endif 38bfcc09ddSBjoern A. Zeeb 39bfcc09ddSBjoern A. Zeeb trans->dev = dev; 40bfcc09ddSBjoern A. Zeeb trans->num_rx_queues = 1; 41bfcc09ddSBjoern A. Zeeb 42bfcc09ddSBjoern A. Zeeb return trans; 43bfcc09ddSBjoern A. Zeeb } 44bfcc09ddSBjoern A. Zeeb 45bfcc09ddSBjoern A. Zeeb int iwl_trans_init(struct iwl_trans *trans) 46bfcc09ddSBjoern A. Zeeb { 47bfcc09ddSBjoern A. Zeeb int txcmd_size, txcmd_align; 48bfcc09ddSBjoern A. Zeeb 49bfcc09ddSBjoern A. Zeeb if (!trans->trans_cfg->gen2) { 50bfcc09ddSBjoern A. Zeeb txcmd_size = sizeof(struct iwl_tx_cmd); 51bfcc09ddSBjoern A. Zeeb txcmd_align = sizeof(void *); 52bfcc09ddSBjoern A. Zeeb } else if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) { 53bfcc09ddSBjoern A. Zeeb txcmd_size = sizeof(struct iwl_tx_cmd_gen2); 54bfcc09ddSBjoern A. Zeeb txcmd_align = 64; 55bfcc09ddSBjoern A. Zeeb } else { 56bfcc09ddSBjoern A. Zeeb txcmd_size = sizeof(struct iwl_tx_cmd_gen3); 57bfcc09ddSBjoern A. Zeeb txcmd_align = 128; 58bfcc09ddSBjoern A. Zeeb } 59bfcc09ddSBjoern A. Zeeb 60bfcc09ddSBjoern A. Zeeb txcmd_size += sizeof(struct iwl_cmd_header); 61bfcc09ddSBjoern A. Zeeb txcmd_size += 36; /* biggest possible 802.11 header */ 62bfcc09ddSBjoern A. Zeeb 63bfcc09ddSBjoern A. Zeeb /* Ensure device TX cmd cannot reach/cross a page boundary in gen2 */ 64bfcc09ddSBjoern A. Zeeb if (WARN_ON(trans->trans_cfg->gen2 && txcmd_size >= txcmd_align)) 65bfcc09ddSBjoern A. Zeeb return -EINVAL; 66bfcc09ddSBjoern A. Zeeb 67bfcc09ddSBjoern A. Zeeb snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name), 68bfcc09ddSBjoern A. Zeeb "iwl_cmd_pool:%s", dev_name(trans->dev)); 69bfcc09ddSBjoern A. Zeeb trans->dev_cmd_pool = 70bfcc09ddSBjoern A. Zeeb kmem_cache_create(trans->dev_cmd_pool_name, 71bfcc09ddSBjoern A. Zeeb txcmd_size, txcmd_align, 72bfcc09ddSBjoern A. Zeeb SLAB_HWCACHE_ALIGN, NULL); 73bfcc09ddSBjoern A. Zeeb if (!trans->dev_cmd_pool) 74bfcc09ddSBjoern A. Zeeb return -ENOMEM; 75bfcc09ddSBjoern A. Zeeb 76bfcc09ddSBjoern A. Zeeb /* Initialize the wait queue for commands */ 77bfcc09ddSBjoern A. Zeeb init_waitqueue_head(&trans->wait_command_queue); 78bfcc09ddSBjoern A. Zeeb 79bfcc09ddSBjoern A. Zeeb return 0; 80bfcc09ddSBjoern A. Zeeb } 81bfcc09ddSBjoern A. Zeeb 82bfcc09ddSBjoern A. Zeeb void iwl_trans_free(struct iwl_trans *trans) 83bfcc09ddSBjoern A. Zeeb { 84bfcc09ddSBjoern A. Zeeb kmem_cache_destroy(trans->dev_cmd_pool); 85bfcc09ddSBjoern A. Zeeb } 86bfcc09ddSBjoern A. Zeeb 87bfcc09ddSBjoern A. Zeeb int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) 88bfcc09ddSBjoern A. Zeeb { 89bfcc09ddSBjoern A. Zeeb int ret; 90bfcc09ddSBjoern A. Zeeb 91bfcc09ddSBjoern A. Zeeb if (unlikely(!(cmd->flags & CMD_SEND_IN_RFKILL) && 92bfcc09ddSBjoern A. Zeeb test_bit(STATUS_RFKILL_OPMODE, &trans->status))) 93bfcc09ddSBjoern A. Zeeb return -ERFKILL; 94bfcc09ddSBjoern A. Zeeb 95bfcc09ddSBjoern A. Zeeb /* 96bfcc09ddSBjoern A. Zeeb * We can't test IWL_MVM_STATUS_IN_D3 in mvm->status because this 97bfcc09ddSBjoern A. Zeeb * bit is set early in the D3 flow, before we send all the commands 98bfcc09ddSBjoern A. Zeeb * that configure the firmware for D3 operation (power, patterns, ...) 99bfcc09ddSBjoern A. Zeeb * and we don't want to flag all those with CMD_SEND_IN_D3. 100bfcc09ddSBjoern A. Zeeb * So use the system_pm_mode instead. The only command sent after 101bfcc09ddSBjoern A. Zeeb * we set system_pm_mode is D3_CONFIG_CMD, which we now flag with 102bfcc09ddSBjoern A. Zeeb * CMD_SEND_IN_D3. 103bfcc09ddSBjoern A. Zeeb */ 104bfcc09ddSBjoern A. Zeeb if (unlikely(trans->system_pm_mode == IWL_PLAT_PM_MODE_D3 && 105bfcc09ddSBjoern A. Zeeb !(cmd->flags & CMD_SEND_IN_D3))) 106bfcc09ddSBjoern A. Zeeb return -EHOSTDOWN; 107bfcc09ddSBjoern A. Zeeb 108bfcc09ddSBjoern A. Zeeb if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status))) 109bfcc09ddSBjoern A. Zeeb return -EIO; 110bfcc09ddSBjoern A. Zeeb 111*a4128aadSBjoern A. Zeeb if (WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, 112*a4128aadSBjoern A. Zeeb "bad state = %d\n", trans->state)) 113bfcc09ddSBjoern A. Zeeb return -EIO; 114bfcc09ddSBjoern A. Zeeb 115bfcc09ddSBjoern A. Zeeb if (!(cmd->flags & CMD_ASYNC)) 116bfcc09ddSBjoern A. Zeeb lock_map_acquire_read(&trans->sync_cmd_lockdep_map); 117bfcc09ddSBjoern A. Zeeb 118bfcc09ddSBjoern A. Zeeb if (trans->wide_cmd_header && !iwl_cmd_groupid(cmd->id)) { 119bfcc09ddSBjoern A. Zeeb if (cmd->id != REPLY_ERROR) 120bfcc09ddSBjoern A. Zeeb cmd->id = DEF_ID(cmd->id); 121bfcc09ddSBjoern A. Zeeb } 122bfcc09ddSBjoern A. Zeeb 123*a4128aadSBjoern A. Zeeb ret = iwl_trans_pcie_send_hcmd(trans, cmd); 124bfcc09ddSBjoern A. Zeeb 125bfcc09ddSBjoern A. Zeeb if (!(cmd->flags & CMD_ASYNC)) 126bfcc09ddSBjoern A. Zeeb lock_map_release(&trans->sync_cmd_lockdep_map); 127bfcc09ddSBjoern A. Zeeb 128bfcc09ddSBjoern A. Zeeb if (WARN_ON((cmd->flags & CMD_WANT_SKB) && !ret && !cmd->resp_pkt)) 129bfcc09ddSBjoern A. Zeeb return -EIO; 130bfcc09ddSBjoern A. Zeeb 131bfcc09ddSBjoern A. Zeeb return ret; 132bfcc09ddSBjoern A. Zeeb } 133bfcc09ddSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_send_cmd); 134bfcc09ddSBjoern A. Zeeb 135bfcc09ddSBjoern A. Zeeb /* Comparator for struct iwl_hcmd_names. 136bfcc09ddSBjoern A. Zeeb * Used in the binary search over a list of host commands. 137bfcc09ddSBjoern A. Zeeb * 138bfcc09ddSBjoern A. Zeeb * @key: command_id that we're looking for. 139bfcc09ddSBjoern A. Zeeb * @elt: struct iwl_hcmd_names candidate for match. 140bfcc09ddSBjoern A. Zeeb * 141bfcc09ddSBjoern A. Zeeb * @return 0 iff equal. 142bfcc09ddSBjoern A. Zeeb */ 143bfcc09ddSBjoern A. Zeeb static int iwl_hcmd_names_cmp(const void *key, const void *elt) 144bfcc09ddSBjoern A. Zeeb { 145bfcc09ddSBjoern A. Zeeb const struct iwl_hcmd_names *name = elt; 146bfcc09ddSBjoern A. Zeeb const u8 *cmd1 = key; 147bfcc09ddSBjoern A. Zeeb u8 cmd2 = name->cmd_id; 148bfcc09ddSBjoern A. Zeeb 149bfcc09ddSBjoern A. Zeeb return (*cmd1 - cmd2); 150bfcc09ddSBjoern A. Zeeb } 151bfcc09ddSBjoern A. Zeeb 152bfcc09ddSBjoern A. Zeeb const char *iwl_get_cmd_string(struct iwl_trans *trans, u32 id) 153bfcc09ddSBjoern A. Zeeb { 154bfcc09ddSBjoern A. Zeeb u8 grp, cmd; 155bfcc09ddSBjoern A. Zeeb struct iwl_hcmd_names *ret; 156bfcc09ddSBjoern A. Zeeb const struct iwl_hcmd_arr *arr; 157bfcc09ddSBjoern A. Zeeb size_t size = sizeof(struct iwl_hcmd_names); 158bfcc09ddSBjoern A. Zeeb 159bfcc09ddSBjoern A. Zeeb grp = iwl_cmd_groupid(id); 160bfcc09ddSBjoern A. Zeeb cmd = iwl_cmd_opcode(id); 161bfcc09ddSBjoern A. Zeeb 162bfcc09ddSBjoern A. Zeeb if (!trans->command_groups || grp >= trans->command_groups_size || 163bfcc09ddSBjoern A. Zeeb !trans->command_groups[grp].arr) 164bfcc09ddSBjoern A. Zeeb return "UNKNOWN"; 165bfcc09ddSBjoern A. Zeeb 166bfcc09ddSBjoern A. Zeeb arr = &trans->command_groups[grp]; 167bfcc09ddSBjoern A. Zeeb ret = bsearch(&cmd, arr->arr, arr->size, size, iwl_hcmd_names_cmp); 168bfcc09ddSBjoern A. Zeeb if (!ret) 169bfcc09ddSBjoern A. Zeeb return "UNKNOWN"; 170bfcc09ddSBjoern A. Zeeb return ret->cmd_name; 171bfcc09ddSBjoern A. Zeeb } 172bfcc09ddSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_get_cmd_string); 173bfcc09ddSBjoern A. Zeeb 174bfcc09ddSBjoern A. Zeeb int iwl_cmd_groups_verify_sorted(const struct iwl_trans_config *trans) 175bfcc09ddSBjoern A. Zeeb { 176bfcc09ddSBjoern A. Zeeb int i, j; 177bfcc09ddSBjoern A. Zeeb const struct iwl_hcmd_arr *arr; 178bfcc09ddSBjoern A. Zeeb 179bfcc09ddSBjoern A. Zeeb for (i = 0; i < trans->command_groups_size; i++) { 180bfcc09ddSBjoern A. Zeeb arr = &trans->command_groups[i]; 181bfcc09ddSBjoern A. Zeeb if (!arr->arr) 182bfcc09ddSBjoern A. Zeeb continue; 183bfcc09ddSBjoern A. Zeeb for (j = 0; j < arr->size - 1; j++) 184bfcc09ddSBjoern A. Zeeb if (arr->arr[j].cmd_id > arr->arr[j + 1].cmd_id) 185bfcc09ddSBjoern A. Zeeb return -1; 186bfcc09ddSBjoern A. Zeeb } 187bfcc09ddSBjoern A. Zeeb return 0; 188bfcc09ddSBjoern A. Zeeb } 189bfcc09ddSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_cmd_groups_verify_sorted); 190*a4128aadSBjoern A. Zeeb 191*a4128aadSBjoern A. Zeeb void iwl_trans_configure(struct iwl_trans *trans, 192*a4128aadSBjoern A. Zeeb const struct iwl_trans_config *trans_cfg) 193*a4128aadSBjoern A. Zeeb { 194*a4128aadSBjoern A. Zeeb trans->op_mode = trans_cfg->op_mode; 195*a4128aadSBjoern A. Zeeb 196*a4128aadSBjoern A. Zeeb iwl_trans_pcie_configure(trans, trans_cfg); 197*a4128aadSBjoern A. Zeeb WARN_ON(iwl_cmd_groups_verify_sorted(trans_cfg)); 198*a4128aadSBjoern A. Zeeb } 199*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_configure); 200*a4128aadSBjoern A. Zeeb 201*a4128aadSBjoern A. Zeeb int iwl_trans_start_hw(struct iwl_trans *trans) 202*a4128aadSBjoern A. Zeeb { 203*a4128aadSBjoern A. Zeeb might_sleep(); 204*a4128aadSBjoern A. Zeeb 205*a4128aadSBjoern A. Zeeb return iwl_trans_pcie_start_hw(trans); 206*a4128aadSBjoern A. Zeeb } 207*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_start_hw); 208*a4128aadSBjoern A. Zeeb 209*a4128aadSBjoern A. Zeeb void iwl_trans_op_mode_leave(struct iwl_trans *trans) 210*a4128aadSBjoern A. Zeeb { 211*a4128aadSBjoern A. Zeeb might_sleep(); 212*a4128aadSBjoern A. Zeeb 213*a4128aadSBjoern A. Zeeb iwl_trans_pcie_op_mode_leave(trans); 214*a4128aadSBjoern A. Zeeb 215*a4128aadSBjoern A. Zeeb trans->op_mode = NULL; 216*a4128aadSBjoern A. Zeeb 217*a4128aadSBjoern A. Zeeb trans->state = IWL_TRANS_NO_FW; 218*a4128aadSBjoern A. Zeeb } 219*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_op_mode_leave); 220*a4128aadSBjoern A. Zeeb 221*a4128aadSBjoern A. Zeeb void iwl_trans_write8(struct iwl_trans *trans, u32 ofs, u8 val) 222*a4128aadSBjoern A. Zeeb { 223*a4128aadSBjoern A. Zeeb iwl_trans_pcie_write8(trans, ofs, val); 224*a4128aadSBjoern A. Zeeb } 225*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_write8); 226*a4128aadSBjoern A. Zeeb 227*a4128aadSBjoern A. Zeeb void iwl_trans_write32(struct iwl_trans *trans, u32 ofs, u32 val) 228*a4128aadSBjoern A. Zeeb { 229*a4128aadSBjoern A. Zeeb iwl_trans_pcie_write32(trans, ofs, val); 230*a4128aadSBjoern A. Zeeb } 231*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_write32); 232*a4128aadSBjoern A. Zeeb 233*a4128aadSBjoern A. Zeeb u32 iwl_trans_read32(struct iwl_trans *trans, u32 ofs) 234*a4128aadSBjoern A. Zeeb { 235*a4128aadSBjoern A. Zeeb return iwl_trans_pcie_read32(trans, ofs); 236*a4128aadSBjoern A. Zeeb } 237*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_read32); 238*a4128aadSBjoern A. Zeeb 239*a4128aadSBjoern A. Zeeb u32 iwl_trans_read_prph(struct iwl_trans *trans, u32 ofs) 240*a4128aadSBjoern A. Zeeb { 241*a4128aadSBjoern A. Zeeb return iwl_trans_pcie_read_prph(trans, ofs); 242*a4128aadSBjoern A. Zeeb } 243*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_read_prph); 244*a4128aadSBjoern A. Zeeb 245*a4128aadSBjoern A. Zeeb void iwl_trans_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) 246*a4128aadSBjoern A. Zeeb { 247*a4128aadSBjoern A. Zeeb return iwl_trans_pcie_write_prph(trans, ofs, val); 248*a4128aadSBjoern A. Zeeb } 249*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_write_prph); 250*a4128aadSBjoern A. Zeeb 251*a4128aadSBjoern A. Zeeb int iwl_trans_read_mem(struct iwl_trans *trans, u32 addr, 252*a4128aadSBjoern A. Zeeb void *buf, int dwords) 253*a4128aadSBjoern A. Zeeb { 254*a4128aadSBjoern A. Zeeb return iwl_trans_pcie_read_mem(trans, addr, buf, dwords); 255*a4128aadSBjoern A. Zeeb } 256*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_read_mem); 257*a4128aadSBjoern A. Zeeb 258*a4128aadSBjoern A. Zeeb int iwl_trans_write_mem(struct iwl_trans *trans, u32 addr, 259*a4128aadSBjoern A. Zeeb const void *buf, int dwords) 260*a4128aadSBjoern A. Zeeb { 261*a4128aadSBjoern A. Zeeb return iwl_trans_pcie_write_mem(trans, addr, buf, dwords); 262*a4128aadSBjoern A. Zeeb } 263*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_write_mem); 264*a4128aadSBjoern A. Zeeb 265*a4128aadSBjoern A. Zeeb void iwl_trans_set_pmi(struct iwl_trans *trans, bool state) 266*a4128aadSBjoern A. Zeeb { 267*a4128aadSBjoern A. Zeeb if (state) 268*a4128aadSBjoern A. Zeeb set_bit(STATUS_TPOWER_PMI, &trans->status); 269*a4128aadSBjoern A. Zeeb else 270*a4128aadSBjoern A. Zeeb clear_bit(STATUS_TPOWER_PMI, &trans->status); 271*a4128aadSBjoern A. Zeeb } 272*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_set_pmi); 273*a4128aadSBjoern A. Zeeb 274*a4128aadSBjoern A. Zeeb int iwl_trans_sw_reset(struct iwl_trans *trans, bool retake_ownership) 275*a4128aadSBjoern A. Zeeb { 276*a4128aadSBjoern A. Zeeb return iwl_trans_pcie_sw_reset(trans, retake_ownership); 277*a4128aadSBjoern A. Zeeb } 278*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_sw_reset); 279*a4128aadSBjoern A. Zeeb 280*a4128aadSBjoern A. Zeeb struct iwl_trans_dump_data * 281*a4128aadSBjoern A. Zeeb iwl_trans_dump_data(struct iwl_trans *trans, u32 dump_mask, 282*a4128aadSBjoern A. Zeeb const struct iwl_dump_sanitize_ops *sanitize_ops, 283*a4128aadSBjoern A. Zeeb void *sanitize_ctx) 284*a4128aadSBjoern A. Zeeb { 285*a4128aadSBjoern A. Zeeb return iwl_trans_pcie_dump_data(trans, dump_mask, 286*a4128aadSBjoern A. Zeeb sanitize_ops, sanitize_ctx); 287*a4128aadSBjoern A. Zeeb } 288*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_dump_data); 289*a4128aadSBjoern A. Zeeb 290*a4128aadSBjoern A. Zeeb int iwl_trans_d3_suspend(struct iwl_trans *trans, bool test, bool reset) 291*a4128aadSBjoern A. Zeeb { 292*a4128aadSBjoern A. Zeeb might_sleep(); 293*a4128aadSBjoern A. Zeeb 294*a4128aadSBjoern A. Zeeb return iwl_trans_pcie_d3_suspend(trans, test, reset); 295*a4128aadSBjoern A. Zeeb } 296*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_d3_suspend); 297*a4128aadSBjoern A. Zeeb 298*a4128aadSBjoern A. Zeeb int iwl_trans_d3_resume(struct iwl_trans *trans, enum iwl_d3_status *status, 299*a4128aadSBjoern A. Zeeb bool test, bool reset) 300*a4128aadSBjoern A. Zeeb { 301*a4128aadSBjoern A. Zeeb might_sleep(); 302*a4128aadSBjoern A. Zeeb 303*a4128aadSBjoern A. Zeeb return iwl_trans_pcie_d3_resume(trans, status, test, reset); 304*a4128aadSBjoern A. Zeeb } 305*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_d3_resume); 306*a4128aadSBjoern A. Zeeb 307*a4128aadSBjoern A. Zeeb void iwl_trans_interrupts(struct iwl_trans *trans, bool enable) 308*a4128aadSBjoern A. Zeeb { 309*a4128aadSBjoern A. Zeeb iwl_trans_pci_interrupts(trans, enable); 310*a4128aadSBjoern A. Zeeb } 311*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_interrupts); 312*a4128aadSBjoern A. Zeeb 313*a4128aadSBjoern A. Zeeb void iwl_trans_sync_nmi(struct iwl_trans *trans) 314*a4128aadSBjoern A. Zeeb { 315*a4128aadSBjoern A. Zeeb iwl_trans_pcie_sync_nmi(trans); 316*a4128aadSBjoern A. Zeeb } 317*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_sync_nmi); 318*a4128aadSBjoern A. Zeeb 319*a4128aadSBjoern A. Zeeb int iwl_trans_write_imr_mem(struct iwl_trans *trans, u32 dst_addr, 320*a4128aadSBjoern A. Zeeb u64 src_addr, u32 byte_cnt) 321*a4128aadSBjoern A. Zeeb { 322*a4128aadSBjoern A. Zeeb return iwl_trans_pcie_copy_imr(trans, dst_addr, src_addr, byte_cnt); 323*a4128aadSBjoern A. Zeeb } 324*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_write_imr_mem); 325*a4128aadSBjoern A. Zeeb 326*a4128aadSBjoern A. Zeeb void iwl_trans_set_bits_mask(struct iwl_trans *trans, u32 reg, 327*a4128aadSBjoern A. Zeeb u32 mask, u32 value) 328*a4128aadSBjoern A. Zeeb { 329*a4128aadSBjoern A. Zeeb iwl_trans_pcie_set_bits_mask(trans, reg, mask, value); 330*a4128aadSBjoern A. Zeeb } 331*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_set_bits_mask); 332*a4128aadSBjoern A. Zeeb 333*a4128aadSBjoern A. Zeeb int iwl_trans_read_config32(struct iwl_trans *trans, u32 ofs, 334*a4128aadSBjoern A. Zeeb u32 *val) 335*a4128aadSBjoern A. Zeeb { 336*a4128aadSBjoern A. Zeeb return iwl_trans_pcie_read_config32(trans, ofs, val); 337*a4128aadSBjoern A. Zeeb } 338*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_read_config32); 339*a4128aadSBjoern A. Zeeb 340*a4128aadSBjoern A. Zeeb bool _iwl_trans_grab_nic_access(struct iwl_trans *trans) 341*a4128aadSBjoern A. Zeeb { 342*a4128aadSBjoern A. Zeeb return iwl_trans_pcie_grab_nic_access(trans); 343*a4128aadSBjoern A. Zeeb } 344*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(_iwl_trans_grab_nic_access); 345*a4128aadSBjoern A. Zeeb 346*a4128aadSBjoern A. Zeeb void __releases(nic_access) 347*a4128aadSBjoern A. Zeeb iwl_trans_release_nic_access(struct iwl_trans *trans) 348*a4128aadSBjoern A. Zeeb { 349*a4128aadSBjoern A. Zeeb iwl_trans_pcie_release_nic_access(trans); 350*a4128aadSBjoern A. Zeeb __release(nic_access); 351*a4128aadSBjoern A. Zeeb } 352*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_release_nic_access); 353*a4128aadSBjoern A. Zeeb 354*a4128aadSBjoern A. Zeeb void iwl_trans_fw_alive(struct iwl_trans *trans, u32 scd_addr) 355*a4128aadSBjoern A. Zeeb { 356*a4128aadSBjoern A. Zeeb might_sleep(); 357*a4128aadSBjoern A. Zeeb 358*a4128aadSBjoern A. Zeeb trans->state = IWL_TRANS_FW_ALIVE; 359*a4128aadSBjoern A. Zeeb 360*a4128aadSBjoern A. Zeeb if (trans->trans_cfg->gen2) 361*a4128aadSBjoern A. Zeeb iwl_trans_pcie_gen2_fw_alive(trans); 362*a4128aadSBjoern A. Zeeb else 363*a4128aadSBjoern A. Zeeb iwl_trans_pcie_fw_alive(trans, scd_addr); 364*a4128aadSBjoern A. Zeeb } 365*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_fw_alive); 366*a4128aadSBjoern A. Zeeb 367*a4128aadSBjoern A. Zeeb int iwl_trans_start_fw(struct iwl_trans *trans, const struct fw_img *fw, 368*a4128aadSBjoern A. Zeeb bool run_in_rfkill) 369*a4128aadSBjoern A. Zeeb { 370*a4128aadSBjoern A. Zeeb int ret; 371*a4128aadSBjoern A. Zeeb 372*a4128aadSBjoern A. Zeeb might_sleep(); 373*a4128aadSBjoern A. Zeeb 374*a4128aadSBjoern A. Zeeb WARN_ON_ONCE(!trans->rx_mpdu_cmd); 375*a4128aadSBjoern A. Zeeb 376*a4128aadSBjoern A. Zeeb clear_bit(STATUS_FW_ERROR, &trans->status); 377*a4128aadSBjoern A. Zeeb 378*a4128aadSBjoern A. Zeeb if (trans->trans_cfg->gen2) 379*a4128aadSBjoern A. Zeeb ret = iwl_trans_pcie_gen2_start_fw(trans, fw, run_in_rfkill); 380*a4128aadSBjoern A. Zeeb else 381*a4128aadSBjoern A. Zeeb ret = iwl_trans_pcie_start_fw(trans, fw, run_in_rfkill); 382*a4128aadSBjoern A. Zeeb 383*a4128aadSBjoern A. Zeeb if (ret == 0) 384*a4128aadSBjoern A. Zeeb trans->state = IWL_TRANS_FW_STARTED; 385*a4128aadSBjoern A. Zeeb 386*a4128aadSBjoern A. Zeeb return ret; 387*a4128aadSBjoern A. Zeeb } 388*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_start_fw); 389*a4128aadSBjoern A. Zeeb 390*a4128aadSBjoern A. Zeeb void iwl_trans_stop_device(struct iwl_trans *trans) 391*a4128aadSBjoern A. Zeeb { 392*a4128aadSBjoern A. Zeeb might_sleep(); 393*a4128aadSBjoern A. Zeeb 394*a4128aadSBjoern A. Zeeb if (trans->trans_cfg->gen2) 395*a4128aadSBjoern A. Zeeb iwl_trans_pcie_gen2_stop_device(trans); 396*a4128aadSBjoern A. Zeeb else 397*a4128aadSBjoern A. Zeeb iwl_trans_pcie_stop_device(trans); 398*a4128aadSBjoern A. Zeeb 399*a4128aadSBjoern A. Zeeb trans->state = IWL_TRANS_NO_FW; 400*a4128aadSBjoern A. Zeeb } 401*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_stop_device); 402*a4128aadSBjoern A. Zeeb 403*a4128aadSBjoern A. Zeeb int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb, 404*a4128aadSBjoern A. Zeeb struct iwl_device_tx_cmd *dev_cmd, int queue) 405*a4128aadSBjoern A. Zeeb { 406*a4128aadSBjoern A. Zeeb if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status))) 407*a4128aadSBjoern A. Zeeb return -EIO; 408*a4128aadSBjoern A. Zeeb 409*a4128aadSBjoern A. Zeeb if (WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, 410*a4128aadSBjoern A. Zeeb "bad state = %d\n", trans->state)) 411*a4128aadSBjoern A. Zeeb return -EIO; 412*a4128aadSBjoern A. Zeeb 413*a4128aadSBjoern A. Zeeb if (trans->trans_cfg->gen2) 414*a4128aadSBjoern A. Zeeb return iwl_txq_gen2_tx(trans, skb, dev_cmd, queue); 415*a4128aadSBjoern A. Zeeb 416*a4128aadSBjoern A. Zeeb return iwl_trans_pcie_tx(trans, skb, dev_cmd, queue); 417*a4128aadSBjoern A. Zeeb } 418*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_tx); 419*a4128aadSBjoern A. Zeeb 420*a4128aadSBjoern A. Zeeb void iwl_trans_reclaim(struct iwl_trans *trans, int queue, int ssn, 421*a4128aadSBjoern A. Zeeb struct sk_buff_head *skbs, bool is_flush) 422*a4128aadSBjoern A. Zeeb { 423*a4128aadSBjoern A. Zeeb if (WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, 424*a4128aadSBjoern A. Zeeb "bad state = %d\n", trans->state)) 425*a4128aadSBjoern A. Zeeb return; 426*a4128aadSBjoern A. Zeeb 427*a4128aadSBjoern A. Zeeb iwl_pcie_reclaim(trans, queue, ssn, skbs, is_flush); 428*a4128aadSBjoern A. Zeeb } 429*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_reclaim); 430*a4128aadSBjoern A. Zeeb 431*a4128aadSBjoern A. Zeeb void iwl_trans_txq_disable(struct iwl_trans *trans, int queue, 432*a4128aadSBjoern A. Zeeb bool configure_scd) 433*a4128aadSBjoern A. Zeeb { 434*a4128aadSBjoern A. Zeeb iwl_trans_pcie_txq_disable(trans, queue, configure_scd); 435*a4128aadSBjoern A. Zeeb } 436*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_txq_disable); 437*a4128aadSBjoern A. Zeeb 438*a4128aadSBjoern A. Zeeb bool iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn, 439*a4128aadSBjoern A. Zeeb const struct iwl_trans_txq_scd_cfg *cfg, 440*a4128aadSBjoern A. Zeeb unsigned int queue_wdg_timeout) 441*a4128aadSBjoern A. Zeeb { 442*a4128aadSBjoern A. Zeeb might_sleep(); 443*a4128aadSBjoern A. Zeeb 444*a4128aadSBjoern A. Zeeb if (WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, 445*a4128aadSBjoern A. Zeeb "bad state = %d\n", trans->state)) 446*a4128aadSBjoern A. Zeeb return false; 447*a4128aadSBjoern A. Zeeb 448*a4128aadSBjoern A. Zeeb return iwl_trans_pcie_txq_enable(trans, queue, ssn, 449*a4128aadSBjoern A. Zeeb cfg, queue_wdg_timeout); 450*a4128aadSBjoern A. Zeeb } 451*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_txq_enable_cfg); 452*a4128aadSBjoern A. Zeeb 453*a4128aadSBjoern A. Zeeb int iwl_trans_wait_txq_empty(struct iwl_trans *trans, int queue) 454*a4128aadSBjoern A. Zeeb { 455*a4128aadSBjoern A. Zeeb if (WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, 456*a4128aadSBjoern A. Zeeb "bad state = %d\n", trans->state)) 457*a4128aadSBjoern A. Zeeb return -EIO; 458*a4128aadSBjoern A. Zeeb 459*a4128aadSBjoern A. Zeeb return iwl_trans_pcie_wait_txq_empty(trans, queue); 460*a4128aadSBjoern A. Zeeb } 461*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_wait_txq_empty); 462*a4128aadSBjoern A. Zeeb 463*a4128aadSBjoern A. Zeeb int iwl_trans_wait_tx_queues_empty(struct iwl_trans *trans, u32 txqs) 464*a4128aadSBjoern A. Zeeb { 465*a4128aadSBjoern A. Zeeb if (WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, 466*a4128aadSBjoern A. Zeeb "bad state = %d\n", trans->state)) 467*a4128aadSBjoern A. Zeeb return -EIO; 468*a4128aadSBjoern A. Zeeb 469*a4128aadSBjoern A. Zeeb return iwl_trans_pcie_wait_txqs_empty(trans, txqs); 470*a4128aadSBjoern A. Zeeb } 471*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_wait_tx_queues_empty); 472*a4128aadSBjoern A. Zeeb 473*a4128aadSBjoern A. Zeeb void iwl_trans_freeze_txq_timer(struct iwl_trans *trans, 474*a4128aadSBjoern A. Zeeb unsigned long txqs, bool freeze) 475*a4128aadSBjoern A. Zeeb { 476*a4128aadSBjoern A. Zeeb if (WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, 477*a4128aadSBjoern A. Zeeb "bad state = %d\n", trans->state)) 478*a4128aadSBjoern A. Zeeb return; 479*a4128aadSBjoern A. Zeeb 480*a4128aadSBjoern A. Zeeb iwl_pcie_freeze_txq_timer(trans, txqs, freeze); 481*a4128aadSBjoern A. Zeeb } 482*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_freeze_txq_timer); 483*a4128aadSBjoern A. Zeeb 484*a4128aadSBjoern A. Zeeb void iwl_trans_txq_set_shared_mode(struct iwl_trans *trans, 485*a4128aadSBjoern A. Zeeb int txq_id, bool shared_mode) 486*a4128aadSBjoern A. Zeeb { 487*a4128aadSBjoern A. Zeeb iwl_trans_pcie_txq_set_shared_mode(trans, txq_id, shared_mode); 488*a4128aadSBjoern A. Zeeb } 489*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_txq_set_shared_mode); 490*a4128aadSBjoern A. Zeeb 491*a4128aadSBjoern A. Zeeb #ifdef CONFIG_IWLWIFI_DEBUGFS 492*a4128aadSBjoern A. Zeeb void iwl_trans_debugfs_cleanup(struct iwl_trans *trans) 493*a4128aadSBjoern A. Zeeb { 494*a4128aadSBjoern A. Zeeb iwl_trans_pcie_debugfs_cleanup(trans); 495*a4128aadSBjoern A. Zeeb } 496*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_debugfs_cleanup); 497*a4128aadSBjoern A. Zeeb #endif 498*a4128aadSBjoern A. Zeeb 499*a4128aadSBjoern A. Zeeb void iwl_trans_set_q_ptrs(struct iwl_trans *trans, int queue, int ptr) 500*a4128aadSBjoern A. Zeeb { 501*a4128aadSBjoern A. Zeeb if (WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, 502*a4128aadSBjoern A. Zeeb "bad state = %d\n", trans->state)) 503*a4128aadSBjoern A. Zeeb return; 504*a4128aadSBjoern A. Zeeb 505*a4128aadSBjoern A. Zeeb iwl_pcie_set_q_ptrs(trans, queue, ptr); 506*a4128aadSBjoern A. Zeeb } 507*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_set_q_ptrs); 508*a4128aadSBjoern A. Zeeb 509*a4128aadSBjoern A. Zeeb int iwl_trans_txq_alloc(struct iwl_trans *trans, u32 flags, u32 sta_mask, 510*a4128aadSBjoern A. Zeeb u8 tid, int size, unsigned int wdg_timeout) 511*a4128aadSBjoern A. Zeeb { 512*a4128aadSBjoern A. Zeeb might_sleep(); 513*a4128aadSBjoern A. Zeeb 514*a4128aadSBjoern A. Zeeb if (WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, 515*a4128aadSBjoern A. Zeeb "bad state = %d\n", trans->state)) 516*a4128aadSBjoern A. Zeeb return -EIO; 517*a4128aadSBjoern A. Zeeb 518*a4128aadSBjoern A. Zeeb return iwl_txq_dyn_alloc(trans, flags, sta_mask, tid, 519*a4128aadSBjoern A. Zeeb size, wdg_timeout); 520*a4128aadSBjoern A. Zeeb } 521*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_txq_alloc); 522*a4128aadSBjoern A. Zeeb 523*a4128aadSBjoern A. Zeeb void iwl_trans_txq_free(struct iwl_trans *trans, int queue) 524*a4128aadSBjoern A. Zeeb { 525*a4128aadSBjoern A. Zeeb iwl_txq_dyn_free(trans, queue); 526*a4128aadSBjoern A. Zeeb } 527*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_txq_free); 528*a4128aadSBjoern A. Zeeb 529*a4128aadSBjoern A. Zeeb int iwl_trans_get_rxq_dma_data(struct iwl_trans *trans, int queue, 530*a4128aadSBjoern A. Zeeb struct iwl_trans_rxq_dma_data *data) 531*a4128aadSBjoern A. Zeeb { 532*a4128aadSBjoern A. Zeeb return iwl_trans_pcie_rxq_dma_data(trans, queue, data); 533*a4128aadSBjoern A. Zeeb } 534*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_get_rxq_dma_data); 535*a4128aadSBjoern A. Zeeb 536*a4128aadSBjoern A. Zeeb int iwl_trans_load_pnvm(struct iwl_trans *trans, 537*a4128aadSBjoern A. Zeeb const struct iwl_pnvm_image *pnvm_data, 538*a4128aadSBjoern A. Zeeb const struct iwl_ucode_capabilities *capa) 539*a4128aadSBjoern A. Zeeb { 540*a4128aadSBjoern A. Zeeb return iwl_trans_pcie_ctx_info_gen3_load_pnvm(trans, pnvm_data, capa); 541*a4128aadSBjoern A. Zeeb } 542*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_load_pnvm); 543*a4128aadSBjoern A. Zeeb 544*a4128aadSBjoern A. Zeeb void iwl_trans_set_pnvm(struct iwl_trans *trans, 545*a4128aadSBjoern A. Zeeb const struct iwl_ucode_capabilities *capa) 546*a4128aadSBjoern A. Zeeb { 547*a4128aadSBjoern A. Zeeb iwl_trans_pcie_ctx_info_gen3_set_pnvm(trans, capa); 548*a4128aadSBjoern A. Zeeb } 549*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_set_pnvm); 550*a4128aadSBjoern A. Zeeb 551*a4128aadSBjoern A. Zeeb int iwl_trans_load_reduce_power(struct iwl_trans *trans, 552*a4128aadSBjoern A. Zeeb const struct iwl_pnvm_image *payloads, 553*a4128aadSBjoern A. Zeeb const struct iwl_ucode_capabilities *capa) 554*a4128aadSBjoern A. Zeeb { 555*a4128aadSBjoern A. Zeeb return iwl_trans_pcie_ctx_info_gen3_load_reduce_power(trans, payloads, 556*a4128aadSBjoern A. Zeeb capa); 557*a4128aadSBjoern A. Zeeb } 558*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_load_reduce_power); 559*a4128aadSBjoern A. Zeeb 560*a4128aadSBjoern A. Zeeb void iwl_trans_set_reduce_power(struct iwl_trans *trans, 561*a4128aadSBjoern A. Zeeb const struct iwl_ucode_capabilities *capa) 562*a4128aadSBjoern A. Zeeb { 563*a4128aadSBjoern A. Zeeb iwl_trans_pcie_ctx_info_gen3_set_reduce_power(trans, capa); 564*a4128aadSBjoern A. Zeeb } 565*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_trans_set_reduce_power); 566