]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/net/wireless/iwlwifi/iwl-io.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/ide
[karo-tx-linux.git] / drivers / net / wireless / iwlwifi / iwl-io.c
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
39 void 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 }
44 IWL_EXPORT_SYMBOL(iwl_write8);
45
46 void 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 }
51 IWL_EXPORT_SYMBOL(iwl_write32);
52
53 u32 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 }
60 IWL_EXPORT_SYMBOL(iwl_read32);
61
62 #define IWL_POLL_INTERVAL 10    /* microseconds */
63
64 int 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 }
78 IWL_EXPORT_SYMBOL(iwl_poll_bit);
79
80 u32 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 }
91 IWL_EXPORT_SYMBOL(iwl_read_direct32);
92
93 void 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 }
102 IWL_EXPORT_SYMBOL(iwl_write_direct32);
103
104 int 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 }
118 IWL_EXPORT_SYMBOL(iwl_poll_direct_bit);
119
120 u32 __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
127 void __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
133 u32 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 }
144 IWL_EXPORT_SYMBOL(iwl_read_prph);
145
146 void 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 }
155 IWL_EXPORT_SYMBOL(iwl_write_prph);
156
157 int 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
172 void 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 }
182 IWL_EXPORT_SYMBOL(iwl_set_bits_prph);
183
184 void 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 }
195 IWL_EXPORT_SYMBOL(iwl_set_bits_mask_prph);
196
197 void 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 }
208 IWL_EXPORT_SYMBOL(iwl_clear_bits_prph);
209
210 void 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 }
224 IWL_EXPORT_SYMBOL(iwl_force_nmi);
225
226 static 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
245 int 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 }