18e99ea8dSJohannes Berg // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 28e99ea8dSJohannes Berg /* 38e99ea8dSJohannes Berg * Copyright (C) 2003-2014, 2018-2020 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; 69e705c121SKalle Valo unsigned long flags; 7023ba9340SEmmanuel Grumbach if (iwl_trans_grab_nic_access(trans, &flags)) { 71e705c121SKalle Valo value = iwl_read32(trans, reg); 72e705c121SKalle Valo iwl_trans_release_nic_access(trans, &flags); 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 { 81e705c121SKalle Valo unsigned long flags; 82e705c121SKalle Valo 8323ba9340SEmmanuel Grumbach if (iwl_trans_grab_nic_access(trans, &flags)) { 84e705c121SKalle Valo iwl_write32(trans, reg, value); 85e705c121SKalle Valo iwl_trans_release_nic_access(trans, &flags); 86e705c121SKalle Valo } 87e705c121SKalle Valo } 88e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_write_direct32); 89e705c121SKalle Valo 9012a17458SSara Sharon void iwl_write_direct64(struct iwl_trans *trans, u64 reg, u64 value) 9112a17458SSara Sharon { 9212a17458SSara Sharon unsigned long flags; 9312a17458SSara Sharon 9412a17458SSara Sharon if (iwl_trans_grab_nic_access(trans, &flags)) { 9512a17458SSara Sharon iwl_write64(trans, reg, value); 9612a17458SSara Sharon iwl_trans_release_nic_access(trans, &flags); 9712a17458SSara Sharon } 9812a17458SSara Sharon } 9912a17458SSara Sharon IWL_EXPORT_SYMBOL(iwl_write_direct64); 10012a17458SSara Sharon 101e705c121SKalle Valo int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask, 102e705c121SKalle Valo int timeout) 103e705c121SKalle Valo { 104e705c121SKalle Valo int t = 0; 105e705c121SKalle Valo 106e705c121SKalle Valo do { 107e705c121SKalle Valo if ((iwl_read_direct32(trans, addr) & mask) == mask) 108e705c121SKalle Valo return t; 109e705c121SKalle Valo udelay(IWL_POLL_INTERVAL); 110e705c121SKalle Valo t += IWL_POLL_INTERVAL; 111e705c121SKalle Valo } while (t < timeout); 112e705c121SKalle Valo 113e705c121SKalle Valo return -ETIMEDOUT; 114e705c121SKalle Valo } 115e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_poll_direct_bit); 116e705c121SKalle Valo 11714ef1b43SGolan Ben-Ami u32 iwl_read_prph_no_grab(struct iwl_trans *trans, u32 ofs) 118e705c121SKalle Valo { 119e705c121SKalle Valo u32 val = iwl_trans_read_prph(trans, ofs); 120e705c121SKalle Valo trace_iwlwifi_dev_ioread_prph32(trans->dev, ofs, val); 121e705c121SKalle Valo return val; 122e705c121SKalle Valo } 12314ef1b43SGolan Ben-Ami IWL_EXPORT_SYMBOL(iwl_read_prph_no_grab); 124e705c121SKalle Valo 12514ef1b43SGolan Ben-Ami void iwl_write_prph_no_grab(struct iwl_trans *trans, u32 ofs, u32 val) 126e705c121SKalle Valo { 127e705c121SKalle Valo trace_iwlwifi_dev_iowrite_prph32(trans->dev, ofs, val); 128e705c121SKalle Valo iwl_trans_write_prph(trans, ofs, val); 129e705c121SKalle Valo } 13014ef1b43SGolan Ben-Ami IWL_EXPORT_SYMBOL(iwl_write_prph_no_grab); 131e705c121SKalle Valo 13212a17458SSara Sharon void iwl_write_prph64_no_grab(struct iwl_trans *trans, u64 ofs, u64 val) 13312a17458SSara Sharon { 13412a17458SSara Sharon trace_iwlwifi_dev_iowrite_prph64(trans->dev, ofs, val); 13512a17458SSara Sharon iwl_write_prph_no_grab(trans, ofs, val & 0xffffffff); 13612a17458SSara Sharon iwl_write_prph_no_grab(trans, ofs + 4, val >> 32); 13712a17458SSara Sharon } 13812a17458SSara Sharon IWL_EXPORT_SYMBOL(iwl_write_prph64_no_grab); 13912a17458SSara Sharon 140e705c121SKalle Valo u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs) 141e705c121SKalle Valo { 142e705c121SKalle Valo unsigned long flags; 143e705c121SKalle Valo u32 val = 0x5a5a5a5a; 144e705c121SKalle Valo 14523ba9340SEmmanuel Grumbach if (iwl_trans_grab_nic_access(trans, &flags)) { 14614ef1b43SGolan Ben-Ami val = iwl_read_prph_no_grab(trans, ofs); 147e705c121SKalle Valo iwl_trans_release_nic_access(trans, &flags); 148e705c121SKalle Valo } 149e705c121SKalle Valo return val; 150e705c121SKalle Valo } 151e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_read_prph); 152e705c121SKalle Valo 153e705c121SKalle Valo void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) 154e705c121SKalle Valo { 155e705c121SKalle Valo unsigned long flags; 156e705c121SKalle Valo 15723ba9340SEmmanuel Grumbach if (iwl_trans_grab_nic_access(trans, &flags)) { 15814ef1b43SGolan Ben-Ami iwl_write_prph_no_grab(trans, ofs, val); 159e705c121SKalle Valo iwl_trans_release_nic_access(trans, &flags); 160e705c121SKalle Valo } 161e705c121SKalle Valo } 162e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_write_prph); 163e705c121SKalle Valo 164e705c121SKalle Valo int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr, 165e705c121SKalle Valo u32 bits, u32 mask, int timeout) 166e705c121SKalle Valo { 167e705c121SKalle Valo int t = 0; 168e705c121SKalle Valo 169e705c121SKalle Valo do { 170e705c121SKalle Valo if ((iwl_read_prph(trans, addr) & mask) == (bits & mask)) 171e705c121SKalle Valo return t; 172e705c121SKalle Valo udelay(IWL_POLL_INTERVAL); 173e705c121SKalle Valo t += IWL_POLL_INTERVAL; 174e705c121SKalle Valo } while (t < timeout); 175e705c121SKalle Valo 176e705c121SKalle Valo return -ETIMEDOUT; 177e705c121SKalle Valo } 178e705c121SKalle Valo 179e705c121SKalle Valo void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) 180e705c121SKalle Valo { 181e705c121SKalle Valo unsigned long flags; 182e705c121SKalle Valo 18323ba9340SEmmanuel Grumbach if (iwl_trans_grab_nic_access(trans, &flags)) { 18414ef1b43SGolan Ben-Ami iwl_write_prph_no_grab(trans, ofs, 18514ef1b43SGolan Ben-Ami iwl_read_prph_no_grab(trans, ofs) | 18614ef1b43SGolan Ben-Ami mask); 187e705c121SKalle Valo iwl_trans_release_nic_access(trans, &flags); 188e705c121SKalle Valo } 189e705c121SKalle Valo } 190e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_set_bits_prph); 191e705c121SKalle Valo 192e705c121SKalle Valo void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, 193e705c121SKalle Valo u32 bits, u32 mask) 194e705c121SKalle Valo { 195e705c121SKalle Valo unsigned long flags; 196e705c121SKalle Valo 19723ba9340SEmmanuel Grumbach if (iwl_trans_grab_nic_access(trans, &flags)) { 19814ef1b43SGolan Ben-Ami iwl_write_prph_no_grab(trans, ofs, 19914ef1b43SGolan Ben-Ami (iwl_read_prph_no_grab(trans, ofs) & 20014ef1b43SGolan Ben-Ami mask) | bits); 201e705c121SKalle Valo iwl_trans_release_nic_access(trans, &flags); 202e705c121SKalle Valo } 203e705c121SKalle Valo } 204e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_set_bits_mask_prph); 205e705c121SKalle Valo 206e705c121SKalle Valo void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) 207e705c121SKalle Valo { 208e705c121SKalle Valo unsigned long flags; 209e705c121SKalle Valo u32 val; 210e705c121SKalle Valo 21123ba9340SEmmanuel Grumbach if (iwl_trans_grab_nic_access(trans, &flags)) { 21214ef1b43SGolan Ben-Ami val = iwl_read_prph_no_grab(trans, ofs); 21314ef1b43SGolan Ben-Ami iwl_write_prph_no_grab(trans, ofs, (val & ~mask)); 214e705c121SKalle Valo iwl_trans_release_nic_access(trans, &flags); 215e705c121SKalle Valo } 216e705c121SKalle Valo } 217e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_clear_bits_prph); 218e705c121SKalle Valo 219e705c121SKalle Valo void iwl_force_nmi(struct iwl_trans *trans) 220e705c121SKalle Valo { 221286ca8ebSLuca Coelho if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_9000) 222e705c121SKalle Valo iwl_write_prph(trans, DEVICE_SET_NMI_REG, 223e705c121SKalle Valo DEVICE_SET_NMI_VAL_DRV); 224286ca8ebSLuca Coelho else if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) 225ea695b7cSShaul Triebitz iwl_write_umac_prph(trans, UREG_NIC_SET_NMI_DRIVER, 2269e8338adSJohannes Berg UREG_NIC_SET_NMI_DRIVER_NMI_FROM_DRIVER); 227c8177fedSShaul Triebitz else 228c8177fedSShaul Triebitz iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, 229c8177fedSShaul Triebitz UREG_DOORBELL_TO_ISR6_NMI_BIT); 230e705c121SKalle Valo } 231e705c121SKalle Valo IWL_EXPORT_SYMBOL(iwl_force_nmi); 232e705c121SKalle Valo 233f65ebd88SSara Sharon static const char *get_rfh_string(int cmd) 234e705c121SKalle Valo { 235e705c121SKalle Valo #define IWL_CMD(x) case x: return #x 236f65ebd88SSara Sharon #define IWL_CMD_MQ(arg, reg, q) { if (arg == reg(q)) return #reg; } 237f65ebd88SSara Sharon 238f65ebd88SSara Sharon int i; 239f65ebd88SSara Sharon 240f65ebd88SSara Sharon for (i = 0; i < IWL_MAX_RX_HW_QUEUES; i++) { 241f65ebd88SSara Sharon IWL_CMD_MQ(cmd, RFH_Q_FRBDCB_BA_LSB, i); 242f65ebd88SSara Sharon IWL_CMD_MQ(cmd, RFH_Q_FRBDCB_WIDX, i); 243f65ebd88SSara Sharon IWL_CMD_MQ(cmd, RFH_Q_FRBDCB_RIDX, i); 244f65ebd88SSara Sharon IWL_CMD_MQ(cmd, RFH_Q_URBD_STTS_WPTR_LSB, i); 245c0ed8aa4Skbuild test robot } 246f65ebd88SSara Sharon 247f65ebd88SSara Sharon switch (cmd) { 248f65ebd88SSara Sharon IWL_CMD(RFH_RXF_DMA_CFG); 249f65ebd88SSara Sharon IWL_CMD(RFH_GEN_CFG); 250f65ebd88SSara Sharon IWL_CMD(RFH_GEN_STATUS); 251f65ebd88SSara Sharon IWL_CMD(FH_TSSR_TX_STATUS_REG); 252f65ebd88SSara Sharon IWL_CMD(FH_TSSR_TX_ERROR_REG); 253f65ebd88SSara Sharon default: 254f65ebd88SSara Sharon return "UNKNOWN"; 255f65ebd88SSara Sharon } 256f65ebd88SSara Sharon #undef IWL_CMD_MQ 257f65ebd88SSara Sharon } 258f65ebd88SSara Sharon 259f65ebd88SSara Sharon struct reg { 260f65ebd88SSara Sharon u32 addr; 261f65ebd88SSara Sharon bool is64; 262f65ebd88SSara Sharon }; 263f65ebd88SSara Sharon 264f65ebd88SSara Sharon static int iwl_dump_rfh(struct iwl_trans *trans, char **buf) 265f65ebd88SSara Sharon { 266f65ebd88SSara Sharon int i, q; 267f65ebd88SSara Sharon int num_q = trans->num_rx_queues; 268f65ebd88SSara Sharon static const u32 rfh_tbl[] = { 269f65ebd88SSara Sharon RFH_RXF_DMA_CFG, 270f65ebd88SSara Sharon RFH_GEN_CFG, 271f65ebd88SSara Sharon RFH_GEN_STATUS, 272f65ebd88SSara Sharon FH_TSSR_TX_STATUS_REG, 273f65ebd88SSara Sharon FH_TSSR_TX_ERROR_REG, 274f65ebd88SSara Sharon }; 275f65ebd88SSara Sharon static const struct reg rfh_mq_tbl[] = { 276f65ebd88SSara Sharon { RFH_Q0_FRBDCB_BA_LSB, true }, 277f65ebd88SSara Sharon { RFH_Q0_FRBDCB_WIDX, false }, 278f65ebd88SSara Sharon { RFH_Q0_FRBDCB_RIDX, false }, 279f65ebd88SSara Sharon { RFH_Q0_URBD_STTS_WPTR_LSB, true }, 280f65ebd88SSara Sharon }; 281f65ebd88SSara Sharon 282f65ebd88SSara Sharon #ifdef CONFIG_IWLWIFI_DEBUGFS 283f65ebd88SSara Sharon if (buf) { 284f65ebd88SSara Sharon int pos = 0; 285f65ebd88SSara Sharon /* 286f65ebd88SSara Sharon * Register (up to 34 for name + 8 blank/q for MQ): 40 chars 287f65ebd88SSara Sharon * Colon + space: 2 characters 288f65ebd88SSara Sharon * 0X%08x: 10 characters 289f65ebd88SSara Sharon * New line: 1 character 290f65ebd88SSara Sharon * Total of 53 characters 291f65ebd88SSara Sharon */ 292f65ebd88SSara Sharon size_t bufsz = ARRAY_SIZE(rfh_tbl) * 53 + 293f65ebd88SSara Sharon ARRAY_SIZE(rfh_mq_tbl) * 53 * num_q + 40; 294f65ebd88SSara Sharon 295f65ebd88SSara Sharon *buf = kmalloc(bufsz, GFP_KERNEL); 296f65ebd88SSara Sharon if (!*buf) 297f65ebd88SSara Sharon return -ENOMEM; 298f65ebd88SSara Sharon 299f65ebd88SSara Sharon pos += scnprintf(*buf + pos, bufsz - pos, 300f65ebd88SSara Sharon "RFH register values:\n"); 301f65ebd88SSara Sharon 302f65ebd88SSara Sharon for (i = 0; i < ARRAY_SIZE(rfh_tbl); i++) 303f65ebd88SSara Sharon pos += scnprintf(*buf + pos, bufsz - pos, 304f65ebd88SSara Sharon "%40s: 0X%08x\n", 305f65ebd88SSara Sharon get_rfh_string(rfh_tbl[i]), 306f65ebd88SSara Sharon iwl_read_prph(trans, rfh_tbl[i])); 307f65ebd88SSara Sharon 308f65ebd88SSara Sharon for (i = 0; i < ARRAY_SIZE(rfh_mq_tbl); i++) 309f65ebd88SSara Sharon for (q = 0; q < num_q; q++) { 310f65ebd88SSara Sharon u32 addr = rfh_mq_tbl[i].addr; 311f65ebd88SSara Sharon 312f65ebd88SSara Sharon addr += q * (rfh_mq_tbl[i].is64 ? 8 : 4); 313f65ebd88SSara Sharon pos += scnprintf(*buf + pos, bufsz - pos, 314f65ebd88SSara Sharon "%34s(q %2d): 0X%08x\n", 315f65ebd88SSara Sharon get_rfh_string(addr), q, 316f65ebd88SSara Sharon iwl_read_prph(trans, addr)); 317f65ebd88SSara Sharon } 318f65ebd88SSara Sharon 319f65ebd88SSara Sharon return pos; 320f65ebd88SSara Sharon } 321f65ebd88SSara Sharon #endif 322f65ebd88SSara Sharon 323f65ebd88SSara Sharon IWL_ERR(trans, "RFH register values:\n"); 324f65ebd88SSara Sharon for (i = 0; i < ARRAY_SIZE(rfh_tbl); i++) 325f65ebd88SSara Sharon IWL_ERR(trans, " %34s: 0X%08x\n", 326f65ebd88SSara Sharon get_rfh_string(rfh_tbl[i]), 327f65ebd88SSara Sharon iwl_read_prph(trans, rfh_tbl[i])); 328f65ebd88SSara Sharon 329f65ebd88SSara Sharon for (i = 0; i < ARRAY_SIZE(rfh_mq_tbl); i++) 330f65ebd88SSara Sharon for (q = 0; q < num_q; q++) { 331f65ebd88SSara Sharon u32 addr = rfh_mq_tbl[i].addr; 332f65ebd88SSara Sharon 333f65ebd88SSara Sharon addr += q * (rfh_mq_tbl[i].is64 ? 8 : 4); 334f65ebd88SSara Sharon IWL_ERR(trans, " %34s(q %d): 0X%08x\n", 335f65ebd88SSara Sharon get_rfh_string(addr), q, 336f65ebd88SSara Sharon iwl_read_prph(trans, addr)); 337f65ebd88SSara Sharon } 338f65ebd88SSara Sharon 339f65ebd88SSara Sharon return 0; 340f65ebd88SSara Sharon } 341f65ebd88SSara Sharon 342f65ebd88SSara Sharon static const char *get_fh_string(int cmd) 343f65ebd88SSara Sharon { 344e705c121SKalle Valo switch (cmd) { 345e705c121SKalle Valo IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG); 346e705c121SKalle Valo IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG); 347e705c121SKalle Valo IWL_CMD(FH_RSCSR_CHNL0_WPTR); 348e705c121SKalle Valo IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG); 349e705c121SKalle Valo IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG); 350e705c121SKalle Valo IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG); 351e705c121SKalle Valo IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV); 352e705c121SKalle Valo IWL_CMD(FH_TSSR_TX_STATUS_REG); 353e705c121SKalle Valo IWL_CMD(FH_TSSR_TX_ERROR_REG); 354e705c121SKalle Valo default: 355e705c121SKalle Valo return "UNKNOWN"; 356e705c121SKalle Valo } 357e705c121SKalle Valo #undef IWL_CMD 358e705c121SKalle Valo } 359e705c121SKalle Valo 360e705c121SKalle Valo int iwl_dump_fh(struct iwl_trans *trans, char **buf) 361e705c121SKalle Valo { 362e705c121SKalle Valo int i; 363e705c121SKalle Valo static const u32 fh_tbl[] = { 364e705c121SKalle Valo FH_RSCSR_CHNL0_STTS_WPTR_REG, 365e705c121SKalle Valo FH_RSCSR_CHNL0_RBDCB_BASE_REG, 366e705c121SKalle Valo FH_RSCSR_CHNL0_WPTR, 367e705c121SKalle Valo FH_MEM_RCSR_CHNL0_CONFIG_REG, 368e705c121SKalle Valo FH_MEM_RSSR_SHARED_CTRL_REG, 369e705c121SKalle Valo FH_MEM_RSSR_RX_STATUS_REG, 370e705c121SKalle Valo FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV, 371e705c121SKalle Valo FH_TSSR_TX_STATUS_REG, 372e705c121SKalle Valo FH_TSSR_TX_ERROR_REG 373e705c121SKalle Valo }; 374e705c121SKalle Valo 375286ca8ebSLuca Coelho if (trans->trans_cfg->mq_rx_supported) 376f65ebd88SSara Sharon return iwl_dump_rfh(trans, buf); 377f65ebd88SSara Sharon 378e705c121SKalle Valo #ifdef CONFIG_IWLWIFI_DEBUGFS 379e705c121SKalle Valo if (buf) { 380e705c121SKalle Valo int pos = 0; 381e705c121SKalle Valo size_t bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40; 382e705c121SKalle Valo 383e705c121SKalle Valo *buf = kmalloc(bufsz, GFP_KERNEL); 384e705c121SKalle Valo if (!*buf) 385e705c121SKalle Valo return -ENOMEM; 386e705c121SKalle Valo 387e705c121SKalle Valo pos += scnprintf(*buf + pos, bufsz - pos, 388e705c121SKalle Valo "FH register values:\n"); 389e705c121SKalle Valo 390e705c121SKalle Valo for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) 391e705c121SKalle Valo pos += scnprintf(*buf + pos, bufsz - pos, 392e705c121SKalle Valo " %34s: 0X%08x\n", 393e705c121SKalle Valo get_fh_string(fh_tbl[i]), 394e705c121SKalle Valo iwl_read_direct32(trans, fh_tbl[i])); 395e705c121SKalle Valo 396e705c121SKalle Valo return pos; 397e705c121SKalle Valo } 398e705c121SKalle Valo #endif 399e705c121SKalle Valo 400e705c121SKalle Valo IWL_ERR(trans, "FH register values:\n"); 401e705c121SKalle Valo for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) 402e705c121SKalle Valo IWL_ERR(trans, " %34s: 0X%08x\n", 403e705c121SKalle Valo get_fh_string(fh_tbl[i]), 404e705c121SKalle Valo iwl_read_direct32(trans, fh_tbl[i])); 405e705c121SKalle Valo 406e705c121SKalle Valo return 0; 407e705c121SKalle Valo } 408c96b5eecSJohannes Berg 40979b6c8feSLuca Coelho int iwl_finish_nic_init(struct iwl_trans *trans, 41079b6c8feSLuca Coelho const struct iwl_cfg_trans_params *cfg_trans) 411c96b5eecSJohannes Berg { 412c96b5eecSJohannes Berg int err; 413c96b5eecSJohannes Berg 41479b6c8feSLuca Coelho if (cfg_trans->bisr_workaround) { 415b998fbbdSJohannes Berg /* ensure the TOP FSM isn't still in previous reset */ 416b998fbbdSJohannes Berg mdelay(2); 417b998fbbdSJohannes Berg } 418b998fbbdSJohannes Berg 419c96b5eecSJohannes Berg /* 420c96b5eecSJohannes Berg * Set "initialization complete" bit to move adapter from 421c96b5eecSJohannes Berg * D0U* --> D0A* (powered-up active) state. 422c96b5eecSJohannes Berg */ 4236dece0e9SLuca Coelho iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); 424c96b5eecSJohannes Berg 42579b6c8feSLuca Coelho if (cfg_trans->device_family == IWL_DEVICE_FAMILY_8000) 426c96b5eecSJohannes Berg udelay(2); 427c96b5eecSJohannes Berg 428c96b5eecSJohannes Berg /* 429c96b5eecSJohannes Berg * Wait for clock stabilization; once stabilized, access to 430c96b5eecSJohannes Berg * device-internal resources is supported, e.g. iwl_write_prph() 431c96b5eecSJohannes Berg * and accesses to uCode SRAM. 432c96b5eecSJohannes Berg */ 433c96b5eecSJohannes Berg err = iwl_poll_bit(trans, CSR_GP_CNTRL, 4346dece0e9SLuca Coelho CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 4356dece0e9SLuca Coelho CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 436c96b5eecSJohannes Berg 25000); 437c96b5eecSJohannes Berg if (err < 0) 438c96b5eecSJohannes Berg IWL_DEBUG_INFO(trans, "Failed to wake NIC\n"); 439c96b5eecSJohannes Berg 44079b6c8feSLuca Coelho if (cfg_trans->bisr_workaround) { 441b998fbbdSJohannes Berg /* ensure BISR shift has finished */ 442b998fbbdSJohannes Berg udelay(200); 443b998fbbdSJohannes Berg } 444b998fbbdSJohannes Berg 445c96b5eecSJohannes Berg return err < 0 ? err : 0; 446c96b5eecSJohannes Berg } 447c96b5eecSJohannes Berg IWL_EXPORT_SYMBOL(iwl_finish_nic_init); 448*3161a34dSMordechay Goodstein 449*3161a34dSMordechay Goodstein void iwl_trans_sync_nmi_with_addr(struct iwl_trans *trans, u32 inta_addr, 450*3161a34dSMordechay Goodstein u32 sw_err_bit) 451*3161a34dSMordechay Goodstein { 452*3161a34dSMordechay Goodstein unsigned long timeout = jiffies + IWL_TRANS_NMI_TIMEOUT; 453*3161a34dSMordechay Goodstein bool interrupts_enabled = test_bit(STATUS_INT_ENABLED, &trans->status); 454*3161a34dSMordechay Goodstein 455*3161a34dSMordechay Goodstein /* if the interrupts were already disabled, there is no point in 456*3161a34dSMordechay Goodstein * calling iwl_disable_interrupts 457*3161a34dSMordechay Goodstein */ 458*3161a34dSMordechay Goodstein if (interrupts_enabled) 459*3161a34dSMordechay Goodstein iwl_trans_interrupts(trans, false); 460*3161a34dSMordechay Goodstein 461*3161a34dSMordechay Goodstein iwl_force_nmi(trans); 462*3161a34dSMordechay Goodstein while (time_after(timeout, jiffies)) { 463*3161a34dSMordechay Goodstein u32 inta_hw = iwl_read32(trans, inta_addr); 464*3161a34dSMordechay Goodstein 465*3161a34dSMordechay Goodstein /* Error detected by uCode */ 466*3161a34dSMordechay Goodstein if (inta_hw & sw_err_bit) { 467*3161a34dSMordechay Goodstein /* Clear causes register */ 468*3161a34dSMordechay Goodstein iwl_write32(trans, inta_addr, inta_hw & sw_err_bit); 469*3161a34dSMordechay Goodstein break; 470*3161a34dSMordechay Goodstein } 471*3161a34dSMordechay Goodstein 472*3161a34dSMordechay Goodstein mdelay(1); 473*3161a34dSMordechay Goodstein } 474*3161a34dSMordechay Goodstein 475*3161a34dSMordechay Goodstein /* enable interrupts only if there were already enabled before this 476*3161a34dSMordechay Goodstein * function to avoid a case were the driver enable interrupts before 477*3161a34dSMordechay Goodstein * proper configurations were made 478*3161a34dSMordechay Goodstein */ 479*3161a34dSMordechay Goodstein if (interrupts_enabled) 480*3161a34dSMordechay Goodstein iwl_trans_interrupts(trans, true); 481*3161a34dSMordechay Goodstein 482*3161a34dSMordechay Goodstein iwl_trans_fw_error(trans); 483*3161a34dSMordechay Goodstein } 484