162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2003-2014, 2018-2022 Intel Corporation 462306a36Sopenharmony_ci * Copyright (C) 2015-2016 Intel Deutschland GmbH 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <linux/delay.h> 762306a36Sopenharmony_ci#include <linux/device.h> 862306a36Sopenharmony_ci#include <linux/export.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "iwl-drv.h" 1162306a36Sopenharmony_ci#include "iwl-io.h" 1262306a36Sopenharmony_ci#include "iwl-csr.h" 1362306a36Sopenharmony_ci#include "iwl-debug.h" 1462306a36Sopenharmony_ci#include "iwl-prph.h" 1562306a36Sopenharmony_ci#include "iwl-fh.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_civoid iwl_write8(struct iwl_trans *trans, u32 ofs, u8 val) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci trace_iwlwifi_dev_iowrite8(trans->dev, ofs, val); 2062306a36Sopenharmony_ci iwl_trans_write8(trans, ofs, val); 2162306a36Sopenharmony_ci} 2262306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_write8); 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_civoid iwl_write32(struct iwl_trans *trans, u32 ofs, u32 val) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci trace_iwlwifi_dev_iowrite32(trans->dev, ofs, val); 2762306a36Sopenharmony_ci iwl_trans_write32(trans, ofs, val); 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_write32); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_civoid iwl_write64(struct iwl_trans *trans, u64 ofs, u64 val) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci trace_iwlwifi_dev_iowrite64(trans->dev, ofs, val); 3462306a36Sopenharmony_ci iwl_trans_write32(trans, ofs, lower_32_bits(val)); 3562306a36Sopenharmony_ci iwl_trans_write32(trans, ofs + 4, upper_32_bits(val)); 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_write64); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ciu32 iwl_read32(struct iwl_trans *trans, u32 ofs) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci u32 val = iwl_trans_read32(trans, ofs); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci trace_iwlwifi_dev_ioread32(trans->dev, ofs, val); 4462306a36Sopenharmony_ci return val; 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_read32); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define IWL_POLL_INTERVAL 10 /* microseconds */ 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ciint iwl_poll_bit(struct iwl_trans *trans, u32 addr, 5162306a36Sopenharmony_ci u32 bits, u32 mask, int timeout) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci int t = 0; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci do { 5662306a36Sopenharmony_ci if ((iwl_read32(trans, addr) & mask) == (bits & mask)) 5762306a36Sopenharmony_ci return t; 5862306a36Sopenharmony_ci udelay(IWL_POLL_INTERVAL); 5962306a36Sopenharmony_ci t += IWL_POLL_INTERVAL; 6062306a36Sopenharmony_ci } while (t < timeout); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci return -ETIMEDOUT; 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_poll_bit); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ciu32 iwl_read_direct32(struct iwl_trans *trans, u32 reg) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci if (iwl_trans_grab_nic_access(trans)) { 6962306a36Sopenharmony_ci u32 value = iwl_read32(trans, reg); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci iwl_trans_release_nic_access(trans); 7262306a36Sopenharmony_ci return value; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci /* return as if we have a HW timeout/failure */ 7662306a36Sopenharmony_ci return 0x5a5a5a5a; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_read_direct32); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_civoid iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci if (iwl_trans_grab_nic_access(trans)) { 8362306a36Sopenharmony_ci iwl_write32(trans, reg, value); 8462306a36Sopenharmony_ci iwl_trans_release_nic_access(trans); 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_write_direct32); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_civoid iwl_write_direct64(struct iwl_trans *trans, u64 reg, u64 value) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci if (iwl_trans_grab_nic_access(trans)) { 9262306a36Sopenharmony_ci iwl_write64(trans, reg, value); 9362306a36Sopenharmony_ci iwl_trans_release_nic_access(trans); 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_write_direct64); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ciint iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask, 9962306a36Sopenharmony_ci int timeout) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci int t = 0; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci do { 10462306a36Sopenharmony_ci if ((iwl_read_direct32(trans, addr) & mask) == mask) 10562306a36Sopenharmony_ci return t; 10662306a36Sopenharmony_ci udelay(IWL_POLL_INTERVAL); 10762306a36Sopenharmony_ci t += IWL_POLL_INTERVAL; 10862306a36Sopenharmony_ci } while (t < timeout); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci return -ETIMEDOUT; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_poll_direct_bit); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ciu32 iwl_read_prph_no_grab(struct iwl_trans *trans, u32 ofs) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci u32 val = iwl_trans_read_prph(trans, ofs); 11762306a36Sopenharmony_ci trace_iwlwifi_dev_ioread_prph32(trans->dev, ofs, val); 11862306a36Sopenharmony_ci return val; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_read_prph_no_grab); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_civoid iwl_write_prph_no_grab(struct iwl_trans *trans, u32 ofs, u32 val) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci trace_iwlwifi_dev_iowrite_prph32(trans->dev, ofs, val); 12562306a36Sopenharmony_ci iwl_trans_write_prph(trans, ofs, val); 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_write_prph_no_grab); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_civoid iwl_write_prph64_no_grab(struct iwl_trans *trans, u64 ofs, u64 val) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci trace_iwlwifi_dev_iowrite_prph64(trans->dev, ofs, val); 13262306a36Sopenharmony_ci iwl_write_prph_no_grab(trans, ofs, val & 0xffffffff); 13362306a36Sopenharmony_ci iwl_write_prph_no_grab(trans, ofs + 4, val >> 32); 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_write_prph64_no_grab); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ciu32 iwl_read_prph(struct iwl_trans *trans, u32 ofs) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci if (iwl_trans_grab_nic_access(trans)) { 14062306a36Sopenharmony_ci u32 val = iwl_read_prph_no_grab(trans, ofs); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci iwl_trans_release_nic_access(trans); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci return val; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* return as if we have a HW timeout/failure */ 14862306a36Sopenharmony_ci return 0x5a5a5a5a; 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_read_prph); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_civoid iwl_write_prph_delay(struct iwl_trans *trans, u32 ofs, u32 val, u32 delay_ms) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci if (iwl_trans_grab_nic_access(trans)) { 15562306a36Sopenharmony_ci mdelay(delay_ms); 15662306a36Sopenharmony_ci iwl_write_prph_no_grab(trans, ofs, val); 15762306a36Sopenharmony_ci iwl_trans_release_nic_access(trans); 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_write_prph_delay); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ciint iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr, 16362306a36Sopenharmony_ci u32 bits, u32 mask, int timeout) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci int t = 0; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci do { 16862306a36Sopenharmony_ci if ((iwl_read_prph(trans, addr) & mask) == (bits & mask)) 16962306a36Sopenharmony_ci return t; 17062306a36Sopenharmony_ci udelay(IWL_POLL_INTERVAL); 17162306a36Sopenharmony_ci t += IWL_POLL_INTERVAL; 17262306a36Sopenharmony_ci } while (t < timeout); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci return -ETIMEDOUT; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_civoid iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci if (iwl_trans_grab_nic_access(trans)) { 18062306a36Sopenharmony_ci iwl_write_prph_no_grab(trans, ofs, 18162306a36Sopenharmony_ci iwl_read_prph_no_grab(trans, ofs) | 18262306a36Sopenharmony_ci mask); 18362306a36Sopenharmony_ci iwl_trans_release_nic_access(trans); 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_set_bits_prph); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_civoid iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, 18962306a36Sopenharmony_ci u32 bits, u32 mask) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci if (iwl_trans_grab_nic_access(trans)) { 19262306a36Sopenharmony_ci iwl_write_prph_no_grab(trans, ofs, 19362306a36Sopenharmony_ci (iwl_read_prph_no_grab(trans, ofs) & 19462306a36Sopenharmony_ci mask) | bits); 19562306a36Sopenharmony_ci iwl_trans_release_nic_access(trans); 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_set_bits_mask_prph); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_civoid iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci u32 val; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (iwl_trans_grab_nic_access(trans)) { 20562306a36Sopenharmony_ci val = iwl_read_prph_no_grab(trans, ofs); 20662306a36Sopenharmony_ci iwl_write_prph_no_grab(trans, ofs, (val & ~mask)); 20762306a36Sopenharmony_ci iwl_trans_release_nic_access(trans); 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_clear_bits_prph); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_civoid iwl_force_nmi(struct iwl_trans *trans) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_9000) 21562306a36Sopenharmony_ci iwl_write_prph_delay(trans, DEVICE_SET_NMI_REG, 21662306a36Sopenharmony_ci DEVICE_SET_NMI_VAL_DRV, 1); 21762306a36Sopenharmony_ci else if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) 21862306a36Sopenharmony_ci iwl_write_umac_prph(trans, UREG_NIC_SET_NMI_DRIVER, 21962306a36Sopenharmony_ci UREG_NIC_SET_NMI_DRIVER_NMI_FROM_DRIVER); 22062306a36Sopenharmony_ci else if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_BZ) 22162306a36Sopenharmony_ci iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, 22262306a36Sopenharmony_ci UREG_DOORBELL_TO_ISR6_NMI_BIT); 22362306a36Sopenharmony_ci else 22462306a36Sopenharmony_ci iwl_write32(trans, CSR_DOORBELL_VECTOR, 22562306a36Sopenharmony_ci UREG_DOORBELL_TO_ISR6_NMI_BIT); 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_force_nmi); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic const char *get_rfh_string(int cmd) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci#define IWL_CMD(x) case x: return #x 23262306a36Sopenharmony_ci#define IWL_CMD_MQ(arg, reg, q) { if (arg == reg(q)) return #reg; } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci int i; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci for (i = 0; i < IWL_MAX_RX_HW_QUEUES; i++) { 23762306a36Sopenharmony_ci IWL_CMD_MQ(cmd, RFH_Q_FRBDCB_BA_LSB, i); 23862306a36Sopenharmony_ci IWL_CMD_MQ(cmd, RFH_Q_FRBDCB_WIDX, i); 23962306a36Sopenharmony_ci IWL_CMD_MQ(cmd, RFH_Q_FRBDCB_RIDX, i); 24062306a36Sopenharmony_ci IWL_CMD_MQ(cmd, RFH_Q_URBD_STTS_WPTR_LSB, i); 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci switch (cmd) { 24462306a36Sopenharmony_ci IWL_CMD(RFH_RXF_DMA_CFG); 24562306a36Sopenharmony_ci IWL_CMD(RFH_GEN_CFG); 24662306a36Sopenharmony_ci IWL_CMD(RFH_GEN_STATUS); 24762306a36Sopenharmony_ci IWL_CMD(FH_TSSR_TX_STATUS_REG); 24862306a36Sopenharmony_ci IWL_CMD(FH_TSSR_TX_ERROR_REG); 24962306a36Sopenharmony_ci default: 25062306a36Sopenharmony_ci return "UNKNOWN"; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci#undef IWL_CMD_MQ 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cistruct reg { 25662306a36Sopenharmony_ci u32 addr; 25762306a36Sopenharmony_ci bool is64; 25862306a36Sopenharmony_ci}; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic int iwl_dump_rfh(struct iwl_trans *trans, char **buf) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci int i, q; 26362306a36Sopenharmony_ci int num_q = trans->num_rx_queues; 26462306a36Sopenharmony_ci static const u32 rfh_tbl[] = { 26562306a36Sopenharmony_ci RFH_RXF_DMA_CFG, 26662306a36Sopenharmony_ci RFH_GEN_CFG, 26762306a36Sopenharmony_ci RFH_GEN_STATUS, 26862306a36Sopenharmony_ci FH_TSSR_TX_STATUS_REG, 26962306a36Sopenharmony_ci FH_TSSR_TX_ERROR_REG, 27062306a36Sopenharmony_ci }; 27162306a36Sopenharmony_ci static const struct reg rfh_mq_tbl[] = { 27262306a36Sopenharmony_ci { RFH_Q0_FRBDCB_BA_LSB, true }, 27362306a36Sopenharmony_ci { RFH_Q0_FRBDCB_WIDX, false }, 27462306a36Sopenharmony_ci { RFH_Q0_FRBDCB_RIDX, false }, 27562306a36Sopenharmony_ci { RFH_Q0_URBD_STTS_WPTR_LSB, true }, 27662306a36Sopenharmony_ci }; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci#ifdef CONFIG_IWLWIFI_DEBUGFS 27962306a36Sopenharmony_ci if (buf) { 28062306a36Sopenharmony_ci int pos = 0; 28162306a36Sopenharmony_ci /* 28262306a36Sopenharmony_ci * Register (up to 34 for name + 8 blank/q for MQ): 40 chars 28362306a36Sopenharmony_ci * Colon + space: 2 characters 28462306a36Sopenharmony_ci * 0X%08x: 10 characters 28562306a36Sopenharmony_ci * New line: 1 character 28662306a36Sopenharmony_ci * Total of 53 characters 28762306a36Sopenharmony_ci */ 28862306a36Sopenharmony_ci size_t bufsz = ARRAY_SIZE(rfh_tbl) * 53 + 28962306a36Sopenharmony_ci ARRAY_SIZE(rfh_mq_tbl) * 53 * num_q + 40; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci *buf = kmalloc(bufsz, GFP_KERNEL); 29262306a36Sopenharmony_ci if (!*buf) 29362306a36Sopenharmony_ci return -ENOMEM; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci pos += scnprintf(*buf + pos, bufsz - pos, 29662306a36Sopenharmony_ci "RFH register values:\n"); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rfh_tbl); i++) 29962306a36Sopenharmony_ci pos += scnprintf(*buf + pos, bufsz - pos, 30062306a36Sopenharmony_ci "%40s: 0X%08x\n", 30162306a36Sopenharmony_ci get_rfh_string(rfh_tbl[i]), 30262306a36Sopenharmony_ci iwl_read_prph(trans, rfh_tbl[i])); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rfh_mq_tbl); i++) 30562306a36Sopenharmony_ci for (q = 0; q < num_q; q++) { 30662306a36Sopenharmony_ci u32 addr = rfh_mq_tbl[i].addr; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci addr += q * (rfh_mq_tbl[i].is64 ? 8 : 4); 30962306a36Sopenharmony_ci pos += scnprintf(*buf + pos, bufsz - pos, 31062306a36Sopenharmony_ci "%34s(q %2d): 0X%08x\n", 31162306a36Sopenharmony_ci get_rfh_string(addr), q, 31262306a36Sopenharmony_ci iwl_read_prph(trans, addr)); 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci return pos; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci#endif 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci IWL_ERR(trans, "RFH register values:\n"); 32062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rfh_tbl); i++) 32162306a36Sopenharmony_ci IWL_ERR(trans, " %34s: 0X%08x\n", 32262306a36Sopenharmony_ci get_rfh_string(rfh_tbl[i]), 32362306a36Sopenharmony_ci iwl_read_prph(trans, rfh_tbl[i])); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rfh_mq_tbl); i++) 32662306a36Sopenharmony_ci for (q = 0; q < num_q; q++) { 32762306a36Sopenharmony_ci u32 addr = rfh_mq_tbl[i].addr; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci addr += q * (rfh_mq_tbl[i].is64 ? 8 : 4); 33062306a36Sopenharmony_ci IWL_ERR(trans, " %34s(q %d): 0X%08x\n", 33162306a36Sopenharmony_ci get_rfh_string(addr), q, 33262306a36Sopenharmony_ci iwl_read_prph(trans, addr)); 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci return 0; 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic const char *get_fh_string(int cmd) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci switch (cmd) { 34162306a36Sopenharmony_ci IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG); 34262306a36Sopenharmony_ci IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG); 34362306a36Sopenharmony_ci IWL_CMD(FH_RSCSR_CHNL0_WPTR); 34462306a36Sopenharmony_ci IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG); 34562306a36Sopenharmony_ci IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG); 34662306a36Sopenharmony_ci IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG); 34762306a36Sopenharmony_ci IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV); 34862306a36Sopenharmony_ci IWL_CMD(FH_TSSR_TX_STATUS_REG); 34962306a36Sopenharmony_ci IWL_CMD(FH_TSSR_TX_ERROR_REG); 35062306a36Sopenharmony_ci default: 35162306a36Sopenharmony_ci return "UNKNOWN"; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci#undef IWL_CMD 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ciint iwl_dump_fh(struct iwl_trans *trans, char **buf) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci int i; 35962306a36Sopenharmony_ci static const u32 fh_tbl[] = { 36062306a36Sopenharmony_ci FH_RSCSR_CHNL0_STTS_WPTR_REG, 36162306a36Sopenharmony_ci FH_RSCSR_CHNL0_RBDCB_BASE_REG, 36262306a36Sopenharmony_ci FH_RSCSR_CHNL0_WPTR, 36362306a36Sopenharmony_ci FH_MEM_RCSR_CHNL0_CONFIG_REG, 36462306a36Sopenharmony_ci FH_MEM_RSSR_SHARED_CTRL_REG, 36562306a36Sopenharmony_ci FH_MEM_RSSR_RX_STATUS_REG, 36662306a36Sopenharmony_ci FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV, 36762306a36Sopenharmony_ci FH_TSSR_TX_STATUS_REG, 36862306a36Sopenharmony_ci FH_TSSR_TX_ERROR_REG 36962306a36Sopenharmony_ci }; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (trans->trans_cfg->mq_rx_supported) 37262306a36Sopenharmony_ci return iwl_dump_rfh(trans, buf); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci#ifdef CONFIG_IWLWIFI_DEBUGFS 37562306a36Sopenharmony_ci if (buf) { 37662306a36Sopenharmony_ci int pos = 0; 37762306a36Sopenharmony_ci size_t bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci *buf = kmalloc(bufsz, GFP_KERNEL); 38062306a36Sopenharmony_ci if (!*buf) 38162306a36Sopenharmony_ci return -ENOMEM; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci pos += scnprintf(*buf + pos, bufsz - pos, 38462306a36Sopenharmony_ci "FH register values:\n"); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) 38762306a36Sopenharmony_ci pos += scnprintf(*buf + pos, bufsz - pos, 38862306a36Sopenharmony_ci " %34s: 0X%08x\n", 38962306a36Sopenharmony_ci get_fh_string(fh_tbl[i]), 39062306a36Sopenharmony_ci iwl_read_direct32(trans, fh_tbl[i])); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci return pos; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci#endif 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci IWL_ERR(trans, "FH register values:\n"); 39762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) 39862306a36Sopenharmony_ci IWL_ERR(trans, " %34s: 0X%08x\n", 39962306a36Sopenharmony_ci get_fh_string(fh_tbl[i]), 40062306a36Sopenharmony_ci iwl_read_direct32(trans, fh_tbl[i])); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci return 0; 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci#define IWL_HOST_MON_BLOCK_PEMON 0x00 40662306a36Sopenharmony_ci#define IWL_HOST_MON_BLOCK_HIPM 0x22 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci#define IWL_HOST_MON_BLOCK_PEMON_VEC0 0x00 40962306a36Sopenharmony_ci#define IWL_HOST_MON_BLOCK_PEMON_VEC1 0x01 41062306a36Sopenharmony_ci#define IWL_HOST_MON_BLOCK_PEMON_WFPM 0x06 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic void iwl_dump_host_monitor_block(struct iwl_trans *trans, 41362306a36Sopenharmony_ci u32 block, u32 vec, u32 iter) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci int i; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci IWL_ERR(trans, "Host monitor block 0x%x vector 0x%x\n", block, vec); 41862306a36Sopenharmony_ci iwl_write32(trans, CSR_MONITOR_CFG_REG, (block << 8) | vec); 41962306a36Sopenharmony_ci for (i = 0; i < iter; i++) 42062306a36Sopenharmony_ci IWL_ERR(trans, " value [iter %d]: 0x%08x\n", 42162306a36Sopenharmony_ci i, iwl_read32(trans, CSR_MONITOR_STATUS_REG)); 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic void iwl_dump_host_monitor(struct iwl_trans *trans) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci switch (trans->trans_cfg->device_family) { 42762306a36Sopenharmony_ci case IWL_DEVICE_FAMILY_22000: 42862306a36Sopenharmony_ci case IWL_DEVICE_FAMILY_AX210: 42962306a36Sopenharmony_ci IWL_ERR(trans, "CSR_RESET = 0x%x\n", 43062306a36Sopenharmony_ci iwl_read32(trans, CSR_RESET)); 43162306a36Sopenharmony_ci iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_PEMON, 43262306a36Sopenharmony_ci IWL_HOST_MON_BLOCK_PEMON_VEC0, 15); 43362306a36Sopenharmony_ci iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_PEMON, 43462306a36Sopenharmony_ci IWL_HOST_MON_BLOCK_PEMON_VEC1, 15); 43562306a36Sopenharmony_ci iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_PEMON, 43662306a36Sopenharmony_ci IWL_HOST_MON_BLOCK_PEMON_WFPM, 15); 43762306a36Sopenharmony_ci iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_HIPM, 43862306a36Sopenharmony_ci IWL_HOST_MON_BLOCK_PEMON_VEC0, 1); 43962306a36Sopenharmony_ci break; 44062306a36Sopenharmony_ci default: 44162306a36Sopenharmony_ci /* not supported yet */ 44262306a36Sopenharmony_ci return; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ciint iwl_finish_nic_init(struct iwl_trans *trans) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci const struct iwl_cfg_trans_params *cfg_trans = trans->trans_cfg; 44962306a36Sopenharmony_ci u32 poll_ready; 45062306a36Sopenharmony_ci int err; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (cfg_trans->bisr_workaround) { 45362306a36Sopenharmony_ci /* ensure the TOP FSM isn't still in previous reset */ 45462306a36Sopenharmony_ci mdelay(2); 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* 45862306a36Sopenharmony_ci * Set "initialization complete" bit to move adapter from 45962306a36Sopenharmony_ci * D0U* --> D0A* (powered-up active) state. 46062306a36Sopenharmony_ci */ 46162306a36Sopenharmony_ci if (cfg_trans->device_family >= IWL_DEVICE_FAMILY_BZ) { 46262306a36Sopenharmony_ci iwl_set_bit(trans, CSR_GP_CNTRL, 46362306a36Sopenharmony_ci CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | 46462306a36Sopenharmony_ci CSR_GP_CNTRL_REG_FLAG_MAC_INIT); 46562306a36Sopenharmony_ci poll_ready = CSR_GP_CNTRL_REG_FLAG_MAC_STATUS; 46662306a36Sopenharmony_ci } else { 46762306a36Sopenharmony_ci iwl_set_bit(trans, CSR_GP_CNTRL, 46862306a36Sopenharmony_ci CSR_GP_CNTRL_REG_FLAG_INIT_DONE); 46962306a36Sopenharmony_ci poll_ready = CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY; 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci if (cfg_trans->device_family == IWL_DEVICE_FAMILY_8000) 47362306a36Sopenharmony_ci udelay(2); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci /* 47662306a36Sopenharmony_ci * Wait for clock stabilization; once stabilized, access to 47762306a36Sopenharmony_ci * device-internal resources is supported, e.g. iwl_write_prph() 47862306a36Sopenharmony_ci * and accesses to uCode SRAM. 47962306a36Sopenharmony_ci */ 48062306a36Sopenharmony_ci err = iwl_poll_bit(trans, CSR_GP_CNTRL, poll_ready, poll_ready, 25000); 48162306a36Sopenharmony_ci if (err < 0) { 48262306a36Sopenharmony_ci IWL_DEBUG_INFO(trans, "Failed to wake NIC\n"); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci iwl_dump_host_monitor(trans); 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if (cfg_trans->bisr_workaround) { 48862306a36Sopenharmony_ci /* ensure BISR shift has finished */ 48962306a36Sopenharmony_ci udelay(200); 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci return err < 0 ? err : 0; 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ciIWL_EXPORT_SYMBOL(iwl_finish_nic_init); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_civoid iwl_trans_sync_nmi_with_addr(struct iwl_trans *trans, u32 inta_addr, 49762306a36Sopenharmony_ci u32 sw_err_bit) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci unsigned long timeout = jiffies + IWL_TRANS_NMI_TIMEOUT; 50062306a36Sopenharmony_ci bool interrupts_enabled = test_bit(STATUS_INT_ENABLED, &trans->status); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci /* if the interrupts were already disabled, there is no point in 50362306a36Sopenharmony_ci * calling iwl_disable_interrupts 50462306a36Sopenharmony_ci */ 50562306a36Sopenharmony_ci if (interrupts_enabled) 50662306a36Sopenharmony_ci iwl_trans_interrupts(trans, false); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci iwl_force_nmi(trans); 50962306a36Sopenharmony_ci while (time_after(timeout, jiffies)) { 51062306a36Sopenharmony_ci u32 inta_hw = iwl_read32(trans, inta_addr); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci /* Error detected by uCode */ 51362306a36Sopenharmony_ci if (inta_hw & sw_err_bit) { 51462306a36Sopenharmony_ci /* Clear causes register */ 51562306a36Sopenharmony_ci iwl_write32(trans, inta_addr, inta_hw & sw_err_bit); 51662306a36Sopenharmony_ci break; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci mdelay(1); 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci /* enable interrupts only if there were already enabled before this 52362306a36Sopenharmony_ci * function to avoid a case were the driver enable interrupts before 52462306a36Sopenharmony_ci * proper configurations were made 52562306a36Sopenharmony_ci */ 52662306a36Sopenharmony_ci if (interrupts_enabled) 52762306a36Sopenharmony_ci iwl_trans_interrupts(trans, true); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci iwl_trans_fw_error(trans, false); 53062306a36Sopenharmony_ci} 531