1 /******************************************************************************
3 * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
4 * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
6 * Portions of this file are derived from the ipw3945 project.
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.
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
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
21 * The full GNU General Public License is included in this distribution in the
22 * file called LICENSE.
24 * Contact Information:
25 * Intel Linux Wireless <linuxwifi@intel.com>
26 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
28 *****************************************************************************/
29 #include <linux/delay.h>
30 #include <linux/device.h>
31 #include <linux/export.h>
36 #include "iwl-debug.h"
40 void iwl_write8(struct iwl_trans
*trans
, u32 ofs
, u8 val
)
42 trace_iwlwifi_dev_iowrite8(trans
->dev
, ofs
, val
);
43 iwl_trans_write8(trans
, ofs
, val
);
45 IWL_EXPORT_SYMBOL(iwl_write8
);
47 void iwl_write32(struct iwl_trans
*trans
, u32 ofs
, u32 val
)
49 trace_iwlwifi_dev_iowrite32(trans
->dev
, ofs
, val
);
50 iwl_trans_write32(trans
, ofs
, val
);
52 IWL_EXPORT_SYMBOL(iwl_write32
);
54 void iwl_write64(struct iwl_trans
*trans
, u64 ofs
, u64 val
)
56 trace_iwlwifi_dev_iowrite64(trans
->dev
, ofs
, val
);
57 iwl_trans_write32(trans
, ofs
, val
& 0xffffffff);
58 iwl_trans_write32(trans
, ofs
+ 4, val
>> 32);
60 IWL_EXPORT_SYMBOL(iwl_write64
);
62 u32
iwl_read32(struct iwl_trans
*trans
, u32 ofs
)
64 u32 val
= iwl_trans_read32(trans
, ofs
);
66 trace_iwlwifi_dev_ioread32(trans
->dev
, ofs
, val
);
69 IWL_EXPORT_SYMBOL(iwl_read32
);
71 #define IWL_POLL_INTERVAL 10 /* microseconds */
73 int iwl_poll_bit(struct iwl_trans
*trans
, u32 addr
,
74 u32 bits
, u32 mask
, int timeout
)
79 if ((iwl_read32(trans
, addr
) & mask
) == (bits
& mask
))
81 udelay(IWL_POLL_INTERVAL
);
82 t
+= IWL_POLL_INTERVAL
;
83 } while (t
< timeout
);
87 IWL_EXPORT_SYMBOL(iwl_poll_bit
);
89 u32
iwl_read_direct32(struct iwl_trans
*trans
, u32 reg
)
91 u32 value
= 0x5a5a5a5a;
93 if (iwl_trans_grab_nic_access(trans
, &flags
)) {
94 value
= iwl_read32(trans
, reg
);
95 iwl_trans_release_nic_access(trans
, &flags
);
100 IWL_EXPORT_SYMBOL(iwl_read_direct32
);
102 void iwl_write_direct32(struct iwl_trans
*trans
, u32 reg
, u32 value
)
106 if (iwl_trans_grab_nic_access(trans
, &flags
)) {
107 iwl_write32(trans
, reg
, value
);
108 iwl_trans_release_nic_access(trans
, &flags
);
111 IWL_EXPORT_SYMBOL(iwl_write_direct32
);
113 void iwl_write_direct64(struct iwl_trans
*trans
, u64 reg
, u64 value
)
117 if (iwl_trans_grab_nic_access(trans
, &flags
)) {
118 iwl_write64(trans
, reg
, value
);
119 iwl_trans_release_nic_access(trans
, &flags
);
122 IWL_EXPORT_SYMBOL(iwl_write_direct64
);
124 int iwl_poll_direct_bit(struct iwl_trans
*trans
, u32 addr
, u32 mask
,
130 if ((iwl_read_direct32(trans
, addr
) & mask
) == mask
)
132 udelay(IWL_POLL_INTERVAL
);
133 t
+= IWL_POLL_INTERVAL
;
134 } while (t
< timeout
);
138 IWL_EXPORT_SYMBOL(iwl_poll_direct_bit
);
140 u32
iwl_read_prph_no_grab(struct iwl_trans
*trans
, u32 ofs
)
142 u32 val
= iwl_trans_read_prph(trans
, ofs
);
143 trace_iwlwifi_dev_ioread_prph32(trans
->dev
, ofs
, val
);
146 IWL_EXPORT_SYMBOL(iwl_read_prph_no_grab
);
148 void iwl_write_prph_no_grab(struct iwl_trans
*trans
, u32 ofs
, u32 val
)
150 trace_iwlwifi_dev_iowrite_prph32(trans
->dev
, ofs
, val
);
151 iwl_trans_write_prph(trans
, ofs
, val
);
153 IWL_EXPORT_SYMBOL(iwl_write_prph_no_grab
);
155 void iwl_write_prph64_no_grab(struct iwl_trans
*trans
, u64 ofs
, u64 val
)
157 trace_iwlwifi_dev_iowrite_prph64(trans
->dev
, ofs
, val
);
158 iwl_write_prph_no_grab(trans
, ofs
, val
& 0xffffffff);
159 iwl_write_prph_no_grab(trans
, ofs
+ 4, val
>> 32);
161 IWL_EXPORT_SYMBOL(iwl_write_prph64_no_grab
);
163 u32
iwl_read_prph(struct iwl_trans
*trans
, u32 ofs
)
166 u32 val
= 0x5a5a5a5a;
168 if (iwl_trans_grab_nic_access(trans
, &flags
)) {
169 val
= iwl_read_prph_no_grab(trans
, ofs
);
170 iwl_trans_release_nic_access(trans
, &flags
);
174 IWL_EXPORT_SYMBOL(iwl_read_prph
);
176 void iwl_write_prph(struct iwl_trans
*trans
, u32 ofs
, u32 val
)
180 if (iwl_trans_grab_nic_access(trans
, &flags
)) {
181 iwl_write_prph_no_grab(trans
, ofs
, val
);
182 iwl_trans_release_nic_access(trans
, &flags
);
185 IWL_EXPORT_SYMBOL(iwl_write_prph
);
187 int iwl_poll_prph_bit(struct iwl_trans
*trans
, u32 addr
,
188 u32 bits
, u32 mask
, int timeout
)
193 if ((iwl_read_prph(trans
, addr
) & mask
) == (bits
& mask
))
195 udelay(IWL_POLL_INTERVAL
);
196 t
+= IWL_POLL_INTERVAL
;
197 } while (t
< timeout
);
202 void iwl_set_bits_prph(struct iwl_trans
*trans
, u32 ofs
, u32 mask
)
206 if (iwl_trans_grab_nic_access(trans
, &flags
)) {
207 iwl_write_prph_no_grab(trans
, ofs
,
208 iwl_read_prph_no_grab(trans
, ofs
) |
210 iwl_trans_release_nic_access(trans
, &flags
);
213 IWL_EXPORT_SYMBOL(iwl_set_bits_prph
);
215 void iwl_set_bits_mask_prph(struct iwl_trans
*trans
, u32 ofs
,
220 if (iwl_trans_grab_nic_access(trans
, &flags
)) {
221 iwl_write_prph_no_grab(trans
, ofs
,
222 (iwl_read_prph_no_grab(trans
, ofs
) &
224 iwl_trans_release_nic_access(trans
, &flags
);
227 IWL_EXPORT_SYMBOL(iwl_set_bits_mask_prph
);
229 void iwl_clear_bits_prph(struct iwl_trans
*trans
, u32 ofs
, u32 mask
)
234 if (iwl_trans_grab_nic_access(trans
, &flags
)) {
235 val
= iwl_read_prph_no_grab(trans
, ofs
);
236 iwl_write_prph_no_grab(trans
, ofs
, (val
& ~mask
));
237 iwl_trans_release_nic_access(trans
, &flags
);
240 IWL_EXPORT_SYMBOL(iwl_clear_bits_prph
);
242 void iwl_force_nmi(struct iwl_trans
*trans
)
244 if (trans
->cfg
->device_family
!= IWL_DEVICE_FAMILY_8000
) {
245 iwl_write_prph(trans
, DEVICE_SET_NMI_REG
,
246 DEVICE_SET_NMI_VAL_DRV
);
247 iwl_write_prph(trans
, DEVICE_SET_NMI_REG
,
248 DEVICE_SET_NMI_VAL_HW
);
250 iwl_write_prph(trans
, DEVICE_SET_NMI_8000_REG
,
251 DEVICE_SET_NMI_8000_VAL
);
252 iwl_write_prph(trans
, DEVICE_SET_NMI_REG
,
253 DEVICE_SET_NMI_VAL_DRV
);
256 IWL_EXPORT_SYMBOL(iwl_force_nmi
);
258 static const char *get_rfh_string(int cmd
)
260 #define IWL_CMD(x) case x: return #x
261 #define IWL_CMD_MQ(arg, reg, q) { if (arg == reg(q)) return #reg; }
265 for (i
= 0; i
< IWL_MAX_RX_HW_QUEUES
; i
++) {
266 IWL_CMD_MQ(cmd
, RFH_Q_FRBDCB_BA_LSB
, i
);
267 IWL_CMD_MQ(cmd
, RFH_Q_FRBDCB_WIDX
, i
);
268 IWL_CMD_MQ(cmd
, RFH_Q_FRBDCB_RIDX
, i
);
269 IWL_CMD_MQ(cmd
, RFH_Q_URBD_STTS_WPTR_LSB
, i
);
273 IWL_CMD(RFH_RXF_DMA_CFG
);
274 IWL_CMD(RFH_GEN_CFG
);
275 IWL_CMD(RFH_GEN_STATUS
);
276 IWL_CMD(FH_TSSR_TX_STATUS_REG
);
277 IWL_CMD(FH_TSSR_TX_ERROR_REG
);
289 static int iwl_dump_rfh(struct iwl_trans
*trans
, char **buf
)
292 int num_q
= trans
->num_rx_queues
;
293 static const u32 rfh_tbl
[] = {
297 FH_TSSR_TX_STATUS_REG
,
298 FH_TSSR_TX_ERROR_REG
,
300 static const struct reg rfh_mq_tbl
[] = {
301 { RFH_Q0_FRBDCB_BA_LSB
, true },
302 { RFH_Q0_FRBDCB_WIDX
, false },
303 { RFH_Q0_FRBDCB_RIDX
, false },
304 { RFH_Q0_URBD_STTS_WPTR_LSB
, true },
307 #ifdef CONFIG_IWLWIFI_DEBUGFS
311 * Register (up to 34 for name + 8 blank/q for MQ): 40 chars
312 * Colon + space: 2 characters
313 * 0X%08x: 10 characters
314 * New line: 1 character
315 * Total of 53 characters
317 size_t bufsz
= ARRAY_SIZE(rfh_tbl
) * 53 +
318 ARRAY_SIZE(rfh_mq_tbl
) * 53 * num_q
+ 40;
320 *buf
= kmalloc(bufsz
, GFP_KERNEL
);
324 pos
+= scnprintf(*buf
+ pos
, bufsz
- pos
,
325 "RFH register values:\n");
327 for (i
= 0; i
< ARRAY_SIZE(rfh_tbl
); i
++)
328 pos
+= scnprintf(*buf
+ pos
, bufsz
- pos
,
330 get_rfh_string(rfh_tbl
[i
]),
331 iwl_read_prph(trans
, rfh_tbl
[i
]));
333 for (i
= 0; i
< ARRAY_SIZE(rfh_mq_tbl
); i
++)
334 for (q
= 0; q
< num_q
; q
++) {
335 u32 addr
= rfh_mq_tbl
[i
].addr
;
337 addr
+= q
* (rfh_mq_tbl
[i
].is64
? 8 : 4);
338 pos
+= scnprintf(*buf
+ pos
, bufsz
- pos
,
339 "%34s(q %2d): 0X%08x\n",
340 get_rfh_string(addr
), q
,
341 iwl_read_prph(trans
, addr
));
348 IWL_ERR(trans
, "RFH register values:\n");
349 for (i
= 0; i
< ARRAY_SIZE(rfh_tbl
); i
++)
350 IWL_ERR(trans
, " %34s: 0X%08x\n",
351 get_rfh_string(rfh_tbl
[i
]),
352 iwl_read_prph(trans
, rfh_tbl
[i
]));
354 for (i
= 0; i
< ARRAY_SIZE(rfh_mq_tbl
); i
++)
355 for (q
= 0; q
< num_q
; q
++) {
356 u32 addr
= rfh_mq_tbl
[i
].addr
;
358 addr
+= q
* (rfh_mq_tbl
[i
].is64
? 8 : 4);
359 IWL_ERR(trans
, " %34s(q %d): 0X%08x\n",
360 get_rfh_string(addr
), q
,
361 iwl_read_prph(trans
, addr
));
367 static const char *get_fh_string(int cmd
)
370 IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG
);
371 IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG
);
372 IWL_CMD(FH_RSCSR_CHNL0_WPTR
);
373 IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG
);
374 IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG
);
375 IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG
);
376 IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV
);
377 IWL_CMD(FH_TSSR_TX_STATUS_REG
);
378 IWL_CMD(FH_TSSR_TX_ERROR_REG
);
385 int iwl_dump_fh(struct iwl_trans
*trans
, char **buf
)
388 static const u32 fh_tbl
[] = {
389 FH_RSCSR_CHNL0_STTS_WPTR_REG
,
390 FH_RSCSR_CHNL0_RBDCB_BASE_REG
,
392 FH_MEM_RCSR_CHNL0_CONFIG_REG
,
393 FH_MEM_RSSR_SHARED_CTRL_REG
,
394 FH_MEM_RSSR_RX_STATUS_REG
,
395 FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV
,
396 FH_TSSR_TX_STATUS_REG
,
400 if (trans
->cfg
->mq_rx_supported
)
401 return iwl_dump_rfh(trans
, buf
);
403 #ifdef CONFIG_IWLWIFI_DEBUGFS
406 size_t bufsz
= ARRAY_SIZE(fh_tbl
) * 48 + 40;
408 *buf
= kmalloc(bufsz
, GFP_KERNEL
);
412 pos
+= scnprintf(*buf
+ pos
, bufsz
- pos
,
413 "FH register values:\n");
415 for (i
= 0; i
< ARRAY_SIZE(fh_tbl
); i
++)
416 pos
+= scnprintf(*buf
+ pos
, bufsz
- pos
,
418 get_fh_string(fh_tbl
[i
]),
419 iwl_read_direct32(trans
, fh_tbl
[i
]));
425 IWL_ERR(trans
, "FH register values:\n");
426 for (i
= 0; i
< ARRAY_SIZE(fh_tbl
); i
++)
427 IWL_ERR(trans
, " %34s: 0X%08x\n",
428 get_fh_string(fh_tbl
[i
]),
429 iwl_read_direct32(trans
, fh_tbl
[i
]));