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