18e99ea8dSJohannes Berg // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 28e99ea8dSJohannes Berg /* 3*b8221b0fSJohannes Berg * Copyright (C) 2003-2014, 2018-2021 Intel Corporation 48e99ea8dSJohannes Berg * Copyright (C) 2015-2016 Intel Deutschland GmbH 58e99ea8dSJohannes Berg */ 6e705c121SKalle Valo #include <linux/delay.h> 7e705c121SKalle Valo #include <linux/device.h> 8e705c121SKalle Valo #include <linux/export.h> 9e705c121SKalle Valo 10e705c121SKalle Valo #include "iwl-drv.h" 11e705c121SKalle Valo #include "iwl-io.h" 12e705c121SKalle Valo #include "iwl-csr.h" 13e705c121SKalle Valo #include "iwl-debug.h" 14e705c121SKalle Valo #include "iwl-prph.h" 15e705c121SKalle Valo #include "iwl-fh.h" 16e705c121SKalle Valo 17e705c121SKalle Valo void iwl_write8(struct iwl_trans *trans, u32 ofs, u8 val) 18e705c121SKalle Valo { 19e705c121SKalle Valo trace_iwlwifi_dev_iowrite8(trans->dev, ofs, val); 20e705c121SKalle Valo iwl_trans_write8(trans, ofs, val); 21e705c121SKalle Valo } 22e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_write8); 23e705c121SKalle Valo 24e705c121SKalle Valo void iwl_write32(struct iwl_trans *trans, u32 ofs, u32 val) 25e705c121SKalle Valo { 26e705c121SKalle Valo trace_iwlwifi_dev_iowrite32(trans->dev, ofs, val); 27e705c121SKalle Valo iwl_trans_write32(trans, ofs, val); 28e705c121SKalle Valo } 29e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_write32); 30e705c121SKalle Valo 3112a17458SSara Sharon void iwl_write64(struct iwl_trans *trans, u64 ofs, u64 val) 3212a17458SSara Sharon { 3312a17458SSara Sharon trace_iwlwifi_dev_iowrite64(trans->dev, ofs, val); 34bd31dd9dSJohannes Berg iwl_trans_write32(trans, ofs, lower_32_bits(val)); 35bd31dd9dSJohannes Berg iwl_trans_write32(trans, ofs + 4, upper_32_bits(val)); 3612a17458SSara Sharon } 3712a17458SSara Sharon IWL_EXPORT_SYMBOL(iwl_write64); 3812a17458SSara Sharon 39e705c121SKalle Valo u32 iwl_read32(struct iwl_trans *trans, u32 ofs) 40e705c121SKalle Valo { 41e705c121SKalle Valo u32 val = iwl_trans_read32(trans, ofs); 42e705c121SKalle Valo 43e705c121SKalle Valo trace_iwlwifi_dev_ioread32(trans->dev, ofs, val); 44e705c121SKalle Valo return val; 45e705c121SKalle Valo } 46e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_read32); 47e705c121SKalle Valo 48e705c121SKalle Valo #define IWL_POLL_INTERVAL 10 /* microseconds */ 49e705c121SKalle Valo 50e705c121SKalle Valo int iwl_poll_bit(struct iwl_trans *trans, u32 addr, 51e705c121SKalle Valo u32 bits, u32 mask, int timeout) 52e705c121SKalle Valo { 53e705c121SKalle Valo int t = 0; 54e705c121SKalle Valo 55e705c121SKalle Valo do { 56e705c121SKalle Valo if ((iwl_read32(trans, addr) & mask) == (bits & mask)) 57e705c121SKalle Valo return t; 58e705c121SKalle Valo udelay(IWL_POLL_INTERVAL); 59e705c121SKalle Valo t += IWL_POLL_INTERVAL; 60e705c121SKalle Valo } while (t < timeout); 61e705c121SKalle Valo 62e705c121SKalle Valo return -ETIMEDOUT; 63e705c121SKalle Valo } 64e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_poll_bit); 65e705c121SKalle Valo 66e705c121SKalle Valo u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg) 67e705c121SKalle Valo { 68e705c121SKalle Valo u32 value = 0x5a5a5a5a; 691ed08f6fSJohannes Berg 701ed08f6fSJohannes Berg if (iwl_trans_grab_nic_access(trans)) { 71e705c121SKalle Valo value = iwl_read32(trans, reg); 721ed08f6fSJohannes Berg iwl_trans_release_nic_access(trans); 73e705c121SKalle Valo } 74e705c121SKalle Valo 75e705c121SKalle Valo return value; 76e705c121SKalle Valo } 77e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_read_direct32); 78e705c121SKalle Valo 79e705c121SKalle Valo void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value) 80e705c121SKalle Valo { 811ed08f6fSJohannes Berg if (iwl_trans_grab_nic_access(trans)) { 82e705c121SKalle Valo iwl_write32(trans, reg, value); 831ed08f6fSJohannes Berg iwl_trans_release_nic_access(trans); 84e705c121SKalle Valo } 85e705c121SKalle Valo } 86e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_write_direct32); 87e705c121SKalle Valo 8812a17458SSara Sharon void iwl_write_direct64(struct iwl_trans *trans, u64 reg, u64 value) 8912a17458SSara Sharon { 901ed08f6fSJohannes Berg if (iwl_trans_grab_nic_access(trans)) { 9112a17458SSara Sharon iwl_write64(trans, reg, value); 921ed08f6fSJohannes Berg iwl_trans_release_nic_access(trans); 9312a17458SSara Sharon } 9412a17458SSara Sharon } 9512a17458SSara Sharon IWL_EXPORT_SYMBOL(iwl_write_direct64); 9612a17458SSara Sharon 97e705c121SKalle Valo int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask, 98e705c121SKalle Valo int timeout) 99e705c121SKalle Valo { 100e705c121SKalle Valo int t = 0; 101e705c121SKalle Valo 102e705c121SKalle Valo do { 103e705c121SKalle Valo if ((iwl_read_direct32(trans, addr) & mask) == mask) 104e705c121SKalle Valo return t; 105e705c121SKalle Valo udelay(IWL_POLL_INTERVAL); 106e705c121SKalle Valo t += IWL_POLL_INTERVAL; 107e705c121SKalle Valo } while (t < timeout); 108e705c121SKalle Valo 109e705c121SKalle Valo return -ETIMEDOUT; 110e705c121SKalle Valo } 111e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_poll_direct_bit); 112e705c121SKalle Valo 11314ef1b43SGolan Ben-Ami u32 iwl_read_prph_no_grab(struct iwl_trans *trans, u32 ofs) 114e705c121SKalle Valo { 115e705c121SKalle Valo u32 val = iwl_trans_read_prph(trans, ofs); 116e705c121SKalle Valo trace_iwlwifi_dev_ioread_prph32(trans->dev, ofs, val); 117e705c121SKalle Valo return val; 118e705c121SKalle Valo } 11914ef1b43SGolan Ben-Ami IWL_EXPORT_SYMBOL(iwl_read_prph_no_grab); 120e705c121SKalle Valo 12114ef1b43SGolan Ben-Ami void iwl_write_prph_no_grab(struct iwl_trans *trans, u32 ofs, u32 val) 122e705c121SKalle Valo { 123e705c121SKalle Valo trace_iwlwifi_dev_iowrite_prph32(trans->dev, ofs, val); 124e705c121SKalle Valo iwl_trans_write_prph(trans, ofs, val); 125e705c121SKalle Valo } 12614ef1b43SGolan Ben-Ami IWL_EXPORT_SYMBOL(iwl_write_prph_no_grab); 127e705c121SKalle Valo 12812a17458SSara Sharon void iwl_write_prph64_no_grab(struct iwl_trans *trans, u64 ofs, u64 val) 12912a17458SSara Sharon { 13012a17458SSara Sharon trace_iwlwifi_dev_iowrite_prph64(trans->dev, ofs, val); 13112a17458SSara Sharon iwl_write_prph_no_grab(trans, ofs, val & 0xffffffff); 13212a17458SSara Sharon iwl_write_prph_no_grab(trans, ofs + 4, val >> 32); 13312a17458SSara Sharon } 13412a17458SSara Sharon IWL_EXPORT_SYMBOL(iwl_write_prph64_no_grab); 13512a17458SSara Sharon 136e705c121SKalle Valo u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs) 137e705c121SKalle Valo { 138e705c121SKalle Valo u32 val = 0x5a5a5a5a; 139e705c121SKalle Valo 1401ed08f6fSJohannes Berg if (iwl_trans_grab_nic_access(trans)) { 14114ef1b43SGolan Ben-Ami val = iwl_read_prph_no_grab(trans, ofs); 1421ed08f6fSJohannes Berg iwl_trans_release_nic_access(trans); 143e705c121SKalle Valo } 144e705c121SKalle Valo return val; 145e705c121SKalle Valo } 146e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_read_prph); 147e705c121SKalle Valo 148a800f958SEmmanuel Grumbach void iwl_write_prph_delay(struct iwl_trans *trans, u32 ofs, u32 val, u32 delay_ms) 149e705c121SKalle Valo { 1501ed08f6fSJohannes Berg if (iwl_trans_grab_nic_access(trans)) { 151a800f958SEmmanuel Grumbach mdelay(delay_ms); 15214ef1b43SGolan Ben-Ami iwl_write_prph_no_grab(trans, ofs, val); 1531ed08f6fSJohannes Berg iwl_trans_release_nic_access(trans); 154e705c121SKalle Valo } 155e705c121SKalle Valo } 156a800f958SEmmanuel Grumbach IWL_EXPORT_SYMBOL(iwl_write_prph_delay); 157e705c121SKalle Valo 158e705c121SKalle Valo int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr, 159e705c121SKalle Valo u32 bits, u32 mask, int timeout) 160e705c121SKalle Valo { 161e705c121SKalle Valo int t = 0; 162e705c121SKalle Valo 163e705c121SKalle Valo do { 164e705c121SKalle Valo if ((iwl_read_prph(trans, addr) & mask) == (bits & mask)) 165e705c121SKalle Valo return t; 166e705c121SKalle Valo udelay(IWL_POLL_INTERVAL); 167e705c121SKalle Valo t += IWL_POLL_INTERVAL; 168e705c121SKalle Valo } while (t < timeout); 169e705c121SKalle Valo 170e705c121SKalle Valo return -ETIMEDOUT; 171e705c121SKalle Valo } 172e705c121SKalle Valo 173e705c121SKalle Valo void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) 174e705c121SKalle Valo { 1751ed08f6fSJohannes Berg if (iwl_trans_grab_nic_access(trans)) { 17614ef1b43SGolan Ben-Ami iwl_write_prph_no_grab(trans, ofs, 17714ef1b43SGolan Ben-Ami iwl_read_prph_no_grab(trans, ofs) | 17814ef1b43SGolan Ben-Ami mask); 1791ed08f6fSJohannes Berg iwl_trans_release_nic_access(trans); 180e705c121SKalle Valo } 181e705c121SKalle Valo } 182e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_set_bits_prph); 183e705c121SKalle Valo 184e705c121SKalle Valo void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, 185e705c121SKalle Valo u32 bits, u32 mask) 186e705c121SKalle Valo { 1871ed08f6fSJohannes Berg if (iwl_trans_grab_nic_access(trans)) { 18814ef1b43SGolan Ben-Ami iwl_write_prph_no_grab(trans, ofs, 18914ef1b43SGolan Ben-Ami (iwl_read_prph_no_grab(trans, ofs) & 19014ef1b43SGolan Ben-Ami mask) | bits); 1911ed08f6fSJohannes Berg iwl_trans_release_nic_access(trans); 192e705c121SKalle Valo } 193e705c121SKalle Valo } 194e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_set_bits_mask_prph); 195e705c121SKalle Valo 196e705c121SKalle Valo void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) 197e705c121SKalle Valo { 198e705c121SKalle Valo u32 val; 199e705c121SKalle Valo 2001ed08f6fSJohannes Berg if (iwl_trans_grab_nic_access(trans)) { 20114ef1b43SGolan Ben-Ami val = iwl_read_prph_no_grab(trans, ofs); 20214ef1b43SGolan Ben-Ami iwl_write_prph_no_grab(trans, ofs, (val & ~mask)); 2031ed08f6fSJohannes Berg iwl_trans_release_nic_access(trans); 204e705c121SKalle Valo } 205e705c121SKalle Valo } 206e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_clear_bits_prph); 207e705c121SKalle Valo 208e705c121SKalle Valo void iwl_force_nmi(struct iwl_trans *trans) 209e705c121SKalle Valo { 210286ca8ebSLuca Coelho if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_9000) 211a800f958SEmmanuel Grumbach iwl_write_prph_delay(trans, DEVICE_SET_NMI_REG, 212a800f958SEmmanuel Grumbach DEVICE_SET_NMI_VAL_DRV, 1); 213286ca8ebSLuca Coelho else if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) 214ea695b7cSShaul Triebitz iwl_write_umac_prph(trans, UREG_NIC_SET_NMI_DRIVER, 2159e8338adSJohannes Berg UREG_NIC_SET_NMI_DRIVER_NMI_FROM_DRIVER); 216c8177fedSShaul Triebitz else 217c8177fedSShaul Triebitz iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, 218c8177fedSShaul Triebitz UREG_DOORBELL_TO_ISR6_NMI_BIT); 219e705c121SKalle Valo } 220e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_force_nmi); 221e705c121SKalle Valo 222f65ebd88SSara Sharon static const char *get_rfh_string(int cmd) 223e705c121SKalle Valo { 224e705c121SKalle Valo #define IWL_CMD(x) case x: return #x 225f65ebd88SSara Sharon #define IWL_CMD_MQ(arg, reg, q) { if (arg == reg(q)) return #reg; } 226f65ebd88SSara Sharon 227f65ebd88SSara Sharon int i; 228f65ebd88SSara Sharon 229f65ebd88SSara Sharon for (i = 0; i < IWL_MAX_RX_HW_QUEUES; i++) { 230f65ebd88SSara Sharon IWL_CMD_MQ(cmd, RFH_Q_FRBDCB_BA_LSB, i); 231f65ebd88SSara Sharon IWL_CMD_MQ(cmd, RFH_Q_FRBDCB_WIDX, i); 232f65ebd88SSara Sharon IWL_CMD_MQ(cmd, RFH_Q_FRBDCB_RIDX, i); 233f65ebd88SSara Sharon IWL_CMD_MQ(cmd, RFH_Q_URBD_STTS_WPTR_LSB, i); 234c0ed8aa4Skbuild test robot } 235f65ebd88SSara Sharon 236f65ebd88SSara Sharon switch (cmd) { 237f65ebd88SSara Sharon IWL_CMD(RFH_RXF_DMA_CFG); 238f65ebd88SSara Sharon IWL_CMD(RFH_GEN_CFG); 239f65ebd88SSara Sharon IWL_CMD(RFH_GEN_STATUS); 240f65ebd88SSara Sharon IWL_CMD(FH_TSSR_TX_STATUS_REG); 241f65ebd88SSara Sharon IWL_CMD(FH_TSSR_TX_ERROR_REG); 242f65ebd88SSara Sharon default: 243f65ebd88SSara Sharon return "UNKNOWN"; 244f65ebd88SSara Sharon } 245f65ebd88SSara Sharon #undef IWL_CMD_MQ 246f65ebd88SSara Sharon } 247f65ebd88SSara Sharon 248f65ebd88SSara Sharon struct reg { 249f65ebd88SSara Sharon u32 addr; 250f65ebd88SSara Sharon bool is64; 251f65ebd88SSara Sharon }; 252f65ebd88SSara Sharon 253f65ebd88SSara Sharon static int iwl_dump_rfh(struct iwl_trans *trans, char **buf) 254f65ebd88SSara Sharon { 255f65ebd88SSara Sharon int i, q; 256f65ebd88SSara Sharon int num_q = trans->num_rx_queues; 257f65ebd88SSara Sharon static const u32 rfh_tbl[] = { 258f65ebd88SSara Sharon RFH_RXF_DMA_CFG, 259f65ebd88SSara Sharon RFH_GEN_CFG, 260f65ebd88SSara Sharon RFH_GEN_STATUS, 261f65ebd88SSara Sharon FH_TSSR_TX_STATUS_REG, 262f65ebd88SSara Sharon FH_TSSR_TX_ERROR_REG, 263f65ebd88SSara Sharon }; 264f65ebd88SSara Sharon static const struct reg rfh_mq_tbl[] = { 265f65ebd88SSara Sharon { RFH_Q0_FRBDCB_BA_LSB, true }, 266f65ebd88SSara Sharon { RFH_Q0_FRBDCB_WIDX, false }, 267f65ebd88SSara Sharon { RFH_Q0_FRBDCB_RIDX, false }, 268f65ebd88SSara Sharon { RFH_Q0_URBD_STTS_WPTR_LSB, true }, 269f65ebd88SSara Sharon }; 270f65ebd88SSara Sharon 271f65ebd88SSara Sharon #ifdef CONFIG_IWLWIFI_DEBUGFS 272f65ebd88SSara Sharon if (buf) { 273f65ebd88SSara Sharon int pos = 0; 274f65ebd88SSara Sharon /* 275f65ebd88SSara Sharon * Register (up to 34 for name + 8 blank/q for MQ): 40 chars 276f65ebd88SSara Sharon * Colon + space: 2 characters 277f65ebd88SSara Sharon * 0X%08x: 10 characters 278f65ebd88SSara Sharon * New line: 1 character 279f65ebd88SSara Sharon * Total of 53 characters 280f65ebd88SSara Sharon */ 281f65ebd88SSara Sharon size_t bufsz = ARRAY_SIZE(rfh_tbl) * 53 + 282f65ebd88SSara Sharon ARRAY_SIZE(rfh_mq_tbl) * 53 * num_q + 40; 283f65ebd88SSara Sharon 284f65ebd88SSara Sharon *buf = kmalloc(bufsz, GFP_KERNEL); 285f65ebd88SSara Sharon if (!*buf) 286f65ebd88SSara Sharon return -ENOMEM; 287f65ebd88SSara Sharon 288f65ebd88SSara Sharon pos += scnprintf(*buf + pos, bufsz - pos, 289f65ebd88SSara Sharon "RFH register values:\n"); 290f65ebd88SSara Sharon 291f65ebd88SSara Sharon for (i = 0; i < ARRAY_SIZE(rfh_tbl); i++) 292f65ebd88SSara Sharon pos += scnprintf(*buf + pos, bufsz - pos, 293f65ebd88SSara Sharon "%40s: 0X%08x\n", 294f65ebd88SSara Sharon get_rfh_string(rfh_tbl[i]), 295f65ebd88SSara Sharon iwl_read_prph(trans, rfh_tbl[i])); 296f65ebd88SSara Sharon 297f65ebd88SSara Sharon for (i = 0; i < ARRAY_SIZE(rfh_mq_tbl); i++) 298f65ebd88SSara Sharon for (q = 0; q < num_q; q++) { 299f65ebd88SSara Sharon u32 addr = rfh_mq_tbl[i].addr; 300f65ebd88SSara Sharon 301f65ebd88SSara Sharon addr += q * (rfh_mq_tbl[i].is64 ? 8 : 4); 302f65ebd88SSara Sharon pos += scnprintf(*buf + pos, bufsz - pos, 303f65ebd88SSara Sharon "%34s(q %2d): 0X%08x\n", 304f65ebd88SSara Sharon get_rfh_string(addr), q, 305f65ebd88SSara Sharon iwl_read_prph(trans, addr)); 306f65ebd88SSara Sharon } 307f65ebd88SSara Sharon 308f65ebd88SSara Sharon return pos; 309f65ebd88SSara Sharon } 310f65ebd88SSara Sharon #endif 311f65ebd88SSara Sharon 312f65ebd88SSara Sharon IWL_ERR(trans, "RFH register values:\n"); 313f65ebd88SSara Sharon for (i = 0; i < ARRAY_SIZE(rfh_tbl); i++) 314f65ebd88SSara Sharon IWL_ERR(trans, " %34s: 0X%08x\n", 315f65ebd88SSara Sharon get_rfh_string(rfh_tbl[i]), 316f65ebd88SSara Sharon iwl_read_prph(trans, rfh_tbl[i])); 317f65ebd88SSara Sharon 318f65ebd88SSara Sharon for (i = 0; i < ARRAY_SIZE(rfh_mq_tbl); i++) 319f65ebd88SSara Sharon for (q = 0; q < num_q; q++) { 320f65ebd88SSara Sharon u32 addr = rfh_mq_tbl[i].addr; 321f65ebd88SSara Sharon 322f65ebd88SSara Sharon addr += q * (rfh_mq_tbl[i].is64 ? 8 : 4); 323f65ebd88SSara Sharon IWL_ERR(trans, " %34s(q %d): 0X%08x\n", 324f65ebd88SSara Sharon get_rfh_string(addr), q, 325f65ebd88SSara Sharon iwl_read_prph(trans, addr)); 326f65ebd88SSara Sharon } 327f65ebd88SSara Sharon 328f65ebd88SSara Sharon return 0; 329f65ebd88SSara Sharon } 330f65ebd88SSara Sharon 331f65ebd88SSara Sharon static const char *get_fh_string(int cmd) 332f65ebd88SSara Sharon { 333e705c121SKalle Valo switch (cmd) { 334e705c121SKalle Valo IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG); 335e705c121SKalle Valo IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG); 336e705c121SKalle Valo IWL_CMD(FH_RSCSR_CHNL0_WPTR); 337e705c121SKalle Valo IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG); 338e705c121SKalle Valo IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG); 339e705c121SKalle Valo IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG); 340e705c121SKalle Valo IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV); 341e705c121SKalle Valo IWL_CMD(FH_TSSR_TX_STATUS_REG); 342e705c121SKalle Valo IWL_CMD(FH_TSSR_TX_ERROR_REG); 343e705c121SKalle Valo default: 344e705c121SKalle Valo return "UNKNOWN"; 345e705c121SKalle Valo } 346e705c121SKalle Valo #undef IWL_CMD 347e705c121SKalle Valo } 348e705c121SKalle Valo 349e705c121SKalle Valo int iwl_dump_fh(struct iwl_trans *trans, char **buf) 350e705c121SKalle Valo { 351e705c121SKalle Valo int i; 352e705c121SKalle Valo static const u32 fh_tbl[] = { 353e705c121SKalle Valo FH_RSCSR_CHNL0_STTS_WPTR_REG, 354e705c121SKalle Valo FH_RSCSR_CHNL0_RBDCB_BASE_REG, 355e705c121SKalle Valo FH_RSCSR_CHNL0_WPTR, 356e705c121SKalle Valo FH_MEM_RCSR_CHNL0_CONFIG_REG, 357e705c121SKalle Valo FH_MEM_RSSR_SHARED_CTRL_REG, 358e705c121SKalle Valo FH_MEM_RSSR_RX_STATUS_REG, 359e705c121SKalle Valo FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV, 360e705c121SKalle Valo FH_TSSR_TX_STATUS_REG, 361e705c121SKalle Valo FH_TSSR_TX_ERROR_REG 362e705c121SKalle Valo }; 363e705c121SKalle Valo 364286ca8ebSLuca Coelho if (trans->trans_cfg->mq_rx_supported) 365f65ebd88SSara Sharon return iwl_dump_rfh(trans, buf); 366f65ebd88SSara Sharon 367e705c121SKalle Valo #ifdef CONFIG_IWLWIFI_DEBUGFS 368e705c121SKalle Valo if (buf) { 369e705c121SKalle Valo int pos = 0; 370e705c121SKalle Valo size_t bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40; 371e705c121SKalle Valo 372e705c121SKalle Valo *buf = kmalloc(bufsz, GFP_KERNEL); 373e705c121SKalle Valo if (!*buf) 374e705c121SKalle Valo return -ENOMEM; 375e705c121SKalle Valo 376e705c121SKalle Valo pos += scnprintf(*buf + pos, bufsz - pos, 377e705c121SKalle Valo "FH register values:\n"); 378e705c121SKalle Valo 379e705c121SKalle Valo for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) 380e705c121SKalle Valo pos += scnprintf(*buf + pos, bufsz - pos, 381e705c121SKalle Valo " %34s: 0X%08x\n", 382e705c121SKalle Valo get_fh_string(fh_tbl[i]), 383e705c121SKalle Valo iwl_read_direct32(trans, fh_tbl[i])); 384e705c121SKalle Valo 385e705c121SKalle Valo return pos; 386e705c121SKalle Valo } 387e705c121SKalle Valo #endif 388e705c121SKalle Valo 389e705c121SKalle Valo IWL_ERR(trans, "FH register values:\n"); 390e705c121SKalle Valo for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) 391e705c121SKalle Valo IWL_ERR(trans, " %34s: 0X%08x\n", 392e705c121SKalle Valo get_fh_string(fh_tbl[i]), 393e705c121SKalle Valo iwl_read_direct32(trans, fh_tbl[i])); 394e705c121SKalle Valo 395e705c121SKalle Valo return 0; 396e705c121SKalle Valo } 397c96b5eecSJohannes Berg 39879b6c8feSLuca Coelho int iwl_finish_nic_init(struct iwl_trans *trans, 39979b6c8feSLuca Coelho const struct iwl_cfg_trans_params *cfg_trans) 400c96b5eecSJohannes Berg { 401c96b5eecSJohannes Berg int err; 402c96b5eecSJohannes Berg 40379b6c8feSLuca Coelho if (cfg_trans->bisr_workaround) { 404b998fbbdSJohannes Berg /* ensure the TOP FSM isn't still in previous reset */ 405b998fbbdSJohannes Berg mdelay(2); 406b998fbbdSJohannes Berg } 407b998fbbdSJohannes Berg 408c96b5eecSJohannes Berg /* 409c96b5eecSJohannes Berg * Set "initialization complete" bit to move adapter from 410c96b5eecSJohannes Berg * D0U* --> D0A* (powered-up active) state. 411c96b5eecSJohannes Berg */ 4126dece0e9SLuca Coelho iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); 413c96b5eecSJohannes Berg 41479b6c8feSLuca Coelho if (cfg_trans->device_family == IWL_DEVICE_FAMILY_8000) 415c96b5eecSJohannes Berg udelay(2); 416c96b5eecSJohannes Berg 417c96b5eecSJohannes Berg /* 418c96b5eecSJohannes Berg * Wait for clock stabilization; once stabilized, access to 419c96b5eecSJohannes Berg * device-internal resources is supported, e.g. iwl_write_prph() 420c96b5eecSJohannes Berg * and accesses to uCode SRAM. 421c96b5eecSJohannes Berg */ 422c96b5eecSJohannes Berg err = iwl_poll_bit(trans, CSR_GP_CNTRL, 4236dece0e9SLuca Coelho CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 4246dece0e9SLuca Coelho CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 425c96b5eecSJohannes Berg 25000); 426c96b5eecSJohannes Berg if (err < 0) 427c96b5eecSJohannes Berg IWL_DEBUG_INFO(trans, "Failed to wake NIC\n"); 428c96b5eecSJohannes Berg 42979b6c8feSLuca Coelho if (cfg_trans->bisr_workaround) { 430b998fbbdSJohannes Berg /* ensure BISR shift has finished */ 431b998fbbdSJohannes Berg udelay(200); 432b998fbbdSJohannes Berg } 433b998fbbdSJohannes Berg 434c96b5eecSJohannes Berg return err < 0 ? err : 0; 435c96b5eecSJohannes Berg } 436c96b5eecSJohannes Berg IWL_EXPORT_SYMBOL(iwl_finish_nic_init); 4373161a34dSMordechay Goodstein 4383161a34dSMordechay Goodstein void iwl_trans_sync_nmi_with_addr(struct iwl_trans *trans, u32 inta_addr, 4393161a34dSMordechay Goodstein u32 sw_err_bit) 4403161a34dSMordechay Goodstein { 4413161a34dSMordechay Goodstein unsigned long timeout = jiffies + IWL_TRANS_NMI_TIMEOUT; 4423161a34dSMordechay Goodstein bool interrupts_enabled = test_bit(STATUS_INT_ENABLED, &trans->status); 4433161a34dSMordechay Goodstein 4443161a34dSMordechay Goodstein /* if the interrupts were already disabled, there is no point in 4453161a34dSMordechay Goodstein * calling iwl_disable_interrupts 4463161a34dSMordechay Goodstein */ 4473161a34dSMordechay Goodstein if (interrupts_enabled) 4483161a34dSMordechay Goodstein iwl_trans_interrupts(trans, false); 4493161a34dSMordechay Goodstein 4503161a34dSMordechay Goodstein iwl_force_nmi(trans); 4513161a34dSMordechay Goodstein while (time_after(timeout, jiffies)) { 4523161a34dSMordechay Goodstein u32 inta_hw = iwl_read32(trans, inta_addr); 4533161a34dSMordechay Goodstein 4543161a34dSMordechay Goodstein /* Error detected by uCode */ 4553161a34dSMordechay Goodstein if (inta_hw & sw_err_bit) { 4563161a34dSMordechay Goodstein /* Clear causes register */ 4573161a34dSMordechay Goodstein iwl_write32(trans, inta_addr, inta_hw & sw_err_bit); 4583161a34dSMordechay Goodstein break; 4593161a34dSMordechay Goodstein } 4603161a34dSMordechay Goodstein 4613161a34dSMordechay Goodstein mdelay(1); 4623161a34dSMordechay Goodstein } 4633161a34dSMordechay Goodstein 4643161a34dSMordechay Goodstein /* enable interrupts only if there were already enabled before this 4653161a34dSMordechay Goodstein * function to avoid a case were the driver enable interrupts before 4663161a34dSMordechay Goodstein * proper configurations were made 4673161a34dSMordechay Goodstein */ 4683161a34dSMordechay Goodstein if (interrupts_enabled) 4693161a34dSMordechay Goodstein iwl_trans_interrupts(trans, true); 4703161a34dSMordechay Goodstein 471*b8221b0fSJohannes Berg iwl_trans_fw_error(trans, false); 4723161a34dSMordechay Goodstein } 473