Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[pandora-kernel.git] / drivers / net / wireless / rtlwifi / cam.c
1 /******************************************************************************
2  *
3  * Copyright(c) 2009-2010  Realtek Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17  *
18  * The full GNU General Public License is included in this distribution in the
19  * file called LICENSE.
20  *
21  * Contact Information:
22  * wlanfae <wlanfae@realtek.com>
23  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
24  * Hsinchu 300, Taiwan.
25  *
26  *****************************************************************************/
27
28 #include "wifi.h"
29 #include "cam.h"
30
31 void rtl_cam_reset_sec_info(struct ieee80211_hw *hw)
32 {
33         struct rtl_priv *rtlpriv = rtl_priv(hw);
34
35         rtlpriv->sec.use_defaultkey = false;
36         rtlpriv->sec.pairwise_enc_algorithm = NO_ENCRYPTION;
37         rtlpriv->sec.group_enc_algorithm = NO_ENCRYPTION;
38         memset(rtlpriv->sec.key_buf, 0, KEY_BUF_SIZE * MAX_KEY_LEN);
39         memset(rtlpriv->sec.key_len, 0, KEY_BUF_SIZE);
40         rtlpriv->sec.pairwise_key = NULL;
41 }
42
43 static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no,
44                            u8 *mac_addr, u8 *key_cont_128, u16 us_config)
45 {
46         struct rtl_priv *rtlpriv = rtl_priv(hw);
47
48         u32 target_command;
49         u32 target_content = 0;
50         u8 entry_i;
51
52         RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
53                  ("key_cont_128:\n %x:%x:%x:%x:%x:%x\n",
54                   key_cont_128[0], key_cont_128[1],
55                   key_cont_128[2], key_cont_128[3],
56                   key_cont_128[4], key_cont_128[5]));
57
58         for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {
59                 target_command = entry_i + CAM_CONTENT_COUNT * entry_no;
60                 target_command = target_command | BIT(31) | BIT(16);
61
62                 if (entry_i == 0) {
63                         target_content = (u32) (*(mac_addr + 0)) << 16 |
64                             (u32) (*(mac_addr + 1)) << 24 | (u32) us_config;
65
66                         rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI],
67                                         target_content);
68                         rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
69                                         target_command);
70
71                         RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
72                                  ("rtl_cam_program_entry(): "
73                                   "WRITE %x: %x\n",
74                                   rtlpriv->cfg->maps[WCAMI], target_content));
75                         RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
76                                  ("The Key ID is %d\n", entry_no));
77                         RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
78                                  ("rtl_cam_program_entry(): "
79                                   "WRITE %x: %x\n",
80                                   rtlpriv->cfg->maps[RWCAM], target_command));
81
82                 } else if (entry_i == 1) {
83
84                         target_content = (u32) (*(mac_addr + 5)) << 24 |
85                             (u32) (*(mac_addr + 4)) << 16 |
86                             (u32) (*(mac_addr + 3)) << 8 |
87                             (u32) (*(mac_addr + 2));
88
89                         rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI],
90                                         target_content);
91                         rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
92                                         target_command);
93
94                         RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
95                                  ("rtl_cam_program_entry(): WRITE A4: %x\n",
96                                   target_content));
97                         RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
98                                  ("rtl_cam_program_entry(): WRITE A0: %x\n",
99                                   target_command));
100
101                 } else {
102
103                         target_content =
104                             (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 3)) <<
105                             24 | (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 2))
106                             << 16 |
107                             (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 1)) << 8
108                             | (u32) (*(key_cont_128 + (entry_i * 4 - 8) + 0));
109
110                         rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI],
111                                         target_content);
112                         rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
113                                         target_command);
114                         udelay(100);
115
116                         RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
117                                  ("rtl_cam_program_entry(): WRITE A4: %x\n",
118                                   target_content));
119                         RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
120                                  ("rtl_cam_program_entry(): WRITE A0: %x\n",
121                                   target_command));
122                 }
123         }
124
125         RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
126                  ("after set key, usconfig:%x\n", us_config));
127 }
128
129 u8 rtl_cam_add_one_entry(struct ieee80211_hw *hw, u8 *mac_addr,
130                          u32 ul_key_id, u32 ul_entry_idx, u32 ul_enc_alg,
131                          u32 ul_default_key, u8 *key_content)
132 {
133         u32 us_config;
134         struct rtl_priv *rtlpriv = rtl_priv(hw);
135
136         RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
137                  ("EntryNo:%x, ulKeyId=%x, ulEncAlg=%x, "
138                   "ulUseDK=%x MacAddr" MAC_FMT "\n",
139                   ul_entry_idx, ul_key_id, ul_enc_alg,
140                   ul_default_key, MAC_ARG(mac_addr)));
141
142         if (ul_key_id == TOTAL_CAM_ENTRY) {
143                 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
144                          ("<=== ulKeyId exceed!\n"));
145                 return 0;
146         }
147
148         if (ul_default_key == 1) {
149                 us_config = CFG_VALID | ((u16) (ul_enc_alg) << 2);
150         } else {
151                 us_config = CFG_VALID | ((ul_enc_alg) << 2) | ul_key_id;
152         }
153
154         rtl_cam_program_entry(hw, ul_entry_idx, mac_addr,
155                               (u8 *) key_content, us_config);
156
157         RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("<===\n"));
158
159         return 1;
160
161 }
162 EXPORT_SYMBOL(rtl_cam_add_one_entry);
163
164 int rtl_cam_delete_one_entry(struct ieee80211_hw *hw,
165                              u8 *mac_addr, u32 ul_key_id)
166 {
167         u32 ul_command;
168         struct rtl_priv *rtlpriv = rtl_priv(hw);
169
170         RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("key_idx:%d\n", ul_key_id));
171
172         ul_command = ul_key_id * CAM_CONTENT_COUNT;
173         ul_command = ul_command | BIT(31) | BIT(16);
174
175         rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], 0);
176         rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);
177
178         RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
179                  ("rtl_cam_delete_one_entry(): WRITE A4: %x\n", 0));
180         RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
181                  ("rtl_cam_delete_one_entry(): WRITE A0: %x\n", ul_command));
182
183         return 0;
184
185 }
186 EXPORT_SYMBOL(rtl_cam_delete_one_entry);
187
188 void rtl_cam_reset_all_entry(struct ieee80211_hw *hw)
189 {
190         u32 ul_command;
191         struct rtl_priv *rtlpriv = rtl_priv(hw);
192
193         ul_command = BIT(31) | BIT(30);
194         rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);
195 }
196 EXPORT_SYMBOL(rtl_cam_reset_all_entry);
197
198 void rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index)
199 {
200         struct rtl_priv *rtlpriv = rtl_priv(hw);
201
202         u32 ul_command;
203         u32 ul_content;
204         u32 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES];
205
206         switch (rtlpriv->sec.pairwise_enc_algorithm) {
207         case WEP40_ENCRYPTION:
208                 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_WEP40];
209                 break;
210         case WEP104_ENCRYPTION:
211                 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_WEP104];
212                 break;
213         case TKIP_ENCRYPTION:
214                 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_TKIP];
215                 break;
216         case AESCCMP_ENCRYPTION:
217                 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES];
218                 break;
219         default:
220                 ul_enc_algo = rtlpriv->cfg->maps[SEC_CAM_AES];
221         }
222
223         ul_content = (uc_index & 3) | ((u16) (ul_enc_algo) << 2);
224
225         ul_content |= BIT(15);
226         ul_command = CAM_CONTENT_COUNT * uc_index;
227         ul_command = ul_command | BIT(31) | BIT(16);
228
229         rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], ul_content);
230         rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);
231
232         RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
233                  ("rtl_cam_mark_invalid(): WRITE A4: %x\n", ul_content));
234         RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
235                  ("rtl_cam_mark_invalid(): WRITE A0: %x\n", ul_command));
236 }
237 EXPORT_SYMBOL(rtl_cam_mark_invalid);
238
239 void rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index)
240 {
241         struct rtl_priv *rtlpriv = rtl_priv(hw);
242
243         u32 ul_command;
244         u32 ul_content;
245         u32 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES];
246         u8 entry_i;
247
248         switch (rtlpriv->sec.pairwise_enc_algorithm) {
249         case WEP40_ENCRYPTION:
250                 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_WEP40];
251                 break;
252         case WEP104_ENCRYPTION:
253                 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_WEP104];
254                 break;
255         case TKIP_ENCRYPTION:
256                 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_TKIP];
257                 break;
258         case AESCCMP_ENCRYPTION:
259                 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES];
260                 break;
261         default:
262                 ul_encalgo = rtlpriv->cfg->maps[SEC_CAM_AES];
263         }
264
265         for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {
266
267                 if (entry_i == 0) {
268                         ul_content =
269                             (uc_index & 0x03) | ((u16) (ul_encalgo) << 2);
270                         ul_content |= BIT(15);
271
272                 } else {
273                         ul_content = 0;
274                 }
275
276                 ul_command = CAM_CONTENT_COUNT * uc_index + entry_i;
277                 ul_command = ul_command | BIT(31) | BIT(16);
278
279                 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[WCAMI], ul_content);
280                 rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], ul_command);
281
282                 RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
283                          ("rtl_cam_empty_entry(): WRITE A4: %x\n",
284                           ul_content));
285                 RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
286                          ("rtl_cam_empty_entry(): WRITE A0: %x\n",
287                           ul_command));
288         }
289
290 }
291 EXPORT_SYMBOL(rtl_cam_empty_entry);