1 /****************************************************************************** 2 * 3 * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. 4 * Copyright(c) 2015 Intel Deutschland GmbH 5 * 6 * Portions of this file are derived from the ipw3945 project. 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of version 2 of the GNU General Public License as 10 * published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 * more details. 16 * 17 * You should have received a copy of the GNU General Public License along with 18 * this program; if not, write to the Free Software Foundation, Inc., 19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 20 * 21 * The full GNU General Public License is included in this distribution in the 22 * file called LICENSE. 23 * 24 * Contact Information: 25 * Intel Linux Wireless <linuxwifi@intel.com> 26 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 27 * 28 *****************************************************************************/ 29 #include <linux/delay.h> 30 #include <linux/device.h> 31 #include <linux/export.h> 32 33 #include "iwl-drv.h" 34 #include "iwl-io.h" 35 #include "iwl-csr.h" 36 #include "iwl-debug.h" 37 #include "iwl-prph.h" 38 #include "iwl-fh.h" 39 40 void iwl_write8(struct iwl_trans *trans, u32 ofs, u8 val) 41 { 42 trace_iwlwifi_dev_iowrite8(trans->dev, ofs, val); 43 iwl_trans_write8(trans, ofs, val); 44 } 45 IWL_EXPORT_SYMBOL(iwl_write8); 46 47 void iwl_write32(struct iwl_trans *trans, u32 ofs, u32 val) 48 { 49 trace_iwlwifi_dev_iowrite32(trans->dev, ofs, val); 50 iwl_trans_write32(trans, ofs, val); 51 } 52 IWL_EXPORT_SYMBOL(iwl_write32); 53 54 u32 iwl_read32(struct iwl_trans *trans, u32 ofs) 55 { 56 u32 val = iwl_trans_read32(trans, ofs); 57 58 trace_iwlwifi_dev_ioread32(trans->dev, ofs, val); 59 return val; 60 } 61 IWL_EXPORT_SYMBOL(iwl_read32); 62 63 #define IWL_POLL_INTERVAL 10 /* microseconds */ 64 65 int iwl_poll_bit(struct iwl_trans *trans, u32 addr, 66 u32 bits, u32 mask, int timeout) 67 { 68 int t = 0; 69 70 do { 71 if ((iwl_read32(trans, addr) & mask) == (bits & mask)) 72 return t; 73 udelay(IWL_POLL_INTERVAL); 74 t += IWL_POLL_INTERVAL; 75 } while (t < timeout); 76 77 return -ETIMEDOUT; 78 } 79 IWL_EXPORT_SYMBOL(iwl_poll_bit); 80 81 u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg) 82 { 83 u32 value = 0x5a5a5a5a; 84 unsigned long flags; 85 if (iwl_trans_grab_nic_access(trans, &flags)) { 86 value = iwl_read32(trans, reg); 87 iwl_trans_release_nic_access(trans, &flags); 88 } 89 90 return value; 91 } 92 IWL_EXPORT_SYMBOL(iwl_read_direct32); 93 94 void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value) 95 { 96 unsigned long flags; 97 98 if (iwl_trans_grab_nic_access(trans, &flags)) { 99 iwl_write32(trans, reg, value); 100 iwl_trans_release_nic_access(trans, &flags); 101 } 102 } 103 IWL_EXPORT_SYMBOL(iwl_write_direct32); 104 105 int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask, 106 int timeout) 107 { 108 int t = 0; 109 110 do { 111 if ((iwl_read_direct32(trans, addr) & mask) == mask) 112 return t; 113 udelay(IWL_POLL_INTERVAL); 114 t += IWL_POLL_INTERVAL; 115 } while (t < timeout); 116 117 return -ETIMEDOUT; 118 } 119 IWL_EXPORT_SYMBOL(iwl_poll_direct_bit); 120 121 u32 iwl_read_prph_no_grab(struct iwl_trans *trans, u32 ofs) 122 { 123 u32 val = iwl_trans_read_prph(trans, ofs); 124 trace_iwlwifi_dev_ioread_prph32(trans->dev, ofs, val); 125 return val; 126 } 127 IWL_EXPORT_SYMBOL(iwl_read_prph_no_grab); 128 129 void iwl_write_prph_no_grab(struct iwl_trans *trans, u32 ofs, u32 val) 130 { 131 trace_iwlwifi_dev_iowrite_prph32(trans->dev, ofs, val); 132 iwl_trans_write_prph(trans, ofs, val); 133 } 134 IWL_EXPORT_SYMBOL(iwl_write_prph_no_grab); 135 136 u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs) 137 { 138 unsigned long flags; 139 u32 val = 0x5a5a5a5a; 140 141 if (iwl_trans_grab_nic_access(trans, &flags)) { 142 val = iwl_read_prph_no_grab(trans, ofs); 143 iwl_trans_release_nic_access(trans, &flags); 144 } 145 return val; 146 } 147 IWL_EXPORT_SYMBOL(iwl_read_prph); 148 149 void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) 150 { 151 unsigned long flags; 152 153 if (iwl_trans_grab_nic_access(trans, &flags)) { 154 iwl_write_prph_no_grab(trans, ofs, val); 155 iwl_trans_release_nic_access(trans, &flags); 156 } 157 } 158 IWL_EXPORT_SYMBOL(iwl_write_prph); 159 160 int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr, 161 u32 bits, u32 mask, int timeout) 162 { 163 int t = 0; 164 165 do { 166 if ((iwl_read_prph(trans, addr) & mask) == (bits & mask)) 167 return t; 168 udelay(IWL_POLL_INTERVAL); 169 t += IWL_POLL_INTERVAL; 170 } while (t < timeout); 171 172 return -ETIMEDOUT; 173 } 174 175 void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) 176 { 177 unsigned long flags; 178 179 if (iwl_trans_grab_nic_access(trans, &flags)) { 180 iwl_write_prph_no_grab(trans, ofs, 181 iwl_read_prph_no_grab(trans, ofs) | 182 mask); 183 iwl_trans_release_nic_access(trans, &flags); 184 } 185 } 186 IWL_EXPORT_SYMBOL(iwl_set_bits_prph); 187 188 void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, 189 u32 bits, u32 mask) 190 { 191 unsigned long flags; 192 193 if (iwl_trans_grab_nic_access(trans, &flags)) { 194 iwl_write_prph_no_grab(trans, ofs, 195 (iwl_read_prph_no_grab(trans, ofs) & 196 mask) | bits); 197 iwl_trans_release_nic_access(trans, &flags); 198 } 199 } 200 IWL_EXPORT_SYMBOL(iwl_set_bits_mask_prph); 201 202 void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) 203 { 204 unsigned long flags; 205 u32 val; 206 207 if (iwl_trans_grab_nic_access(trans, &flags)) { 208 val = iwl_read_prph_no_grab(trans, ofs); 209 iwl_write_prph_no_grab(trans, ofs, (val & ~mask)); 210 iwl_trans_release_nic_access(trans, &flags); 211 } 212 } 213 IWL_EXPORT_SYMBOL(iwl_clear_bits_prph); 214 215 void iwl_force_nmi(struct iwl_trans *trans) 216 { 217 if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) { 218 iwl_write_prph(trans, DEVICE_SET_NMI_REG, 219 DEVICE_SET_NMI_VAL_DRV); 220 iwl_write_prph(trans, DEVICE_SET_NMI_REG, 221 DEVICE_SET_NMI_VAL_HW); 222 } else { 223 iwl_write_prph(trans, DEVICE_SET_NMI_8000_REG, 224 DEVICE_SET_NMI_8000_VAL); 225 iwl_write_prph(trans, DEVICE_SET_NMI_REG, 226 DEVICE_SET_NMI_VAL_DRV); 227 } 228 } 229 IWL_EXPORT_SYMBOL(iwl_force_nmi); 230 231 static const char *get_fh_string(int cmd) 232 { 233 #define IWL_CMD(x) case x: return #x 234 switch (cmd) { 235 IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG); 236 IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG); 237 IWL_CMD(FH_RSCSR_CHNL0_WPTR); 238 IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG); 239 IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG); 240 IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG); 241 IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV); 242 IWL_CMD(FH_TSSR_TX_STATUS_REG); 243 IWL_CMD(FH_TSSR_TX_ERROR_REG); 244 default: 245 return "UNKNOWN"; 246 } 247 #undef IWL_CMD 248 } 249 250 int iwl_dump_fh(struct iwl_trans *trans, char **buf) 251 { 252 int i; 253 static const u32 fh_tbl[] = { 254 FH_RSCSR_CHNL0_STTS_WPTR_REG, 255 FH_RSCSR_CHNL0_RBDCB_BASE_REG, 256 FH_RSCSR_CHNL0_WPTR, 257 FH_MEM_RCSR_CHNL0_CONFIG_REG, 258 FH_MEM_RSSR_SHARED_CTRL_REG, 259 FH_MEM_RSSR_RX_STATUS_REG, 260 FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV, 261 FH_TSSR_TX_STATUS_REG, 262 FH_TSSR_TX_ERROR_REG 263 }; 264 265 #ifdef CONFIG_IWLWIFI_DEBUGFS 266 if (buf) { 267 int pos = 0; 268 size_t bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40; 269 270 *buf = kmalloc(bufsz, GFP_KERNEL); 271 if (!*buf) 272 return -ENOMEM; 273 274 pos += scnprintf(*buf + pos, bufsz - pos, 275 "FH register values:\n"); 276 277 for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) 278 pos += scnprintf(*buf + pos, bufsz - pos, 279 " %34s: 0X%08x\n", 280 get_fh_string(fh_tbl[i]), 281 iwl_read_direct32(trans, fh_tbl[i])); 282 283 return pos; 284 } 285 #endif 286 287 IWL_ERR(trans, "FH register values:\n"); 288 for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) 289 IWL_ERR(trans, " %34s: 0X%08x\n", 290 get_fh_string(fh_tbl[i]), 291 iwl_read_direct32(trans, fh_tbl[i])); 292 293 return 0; 294 } 295