Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[linux-2.6.git] / drivers / net / wireless / rtlwifi / rtl8192de / fw.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  * Larry Finger <Larry.Finger@lwfinger.net>
27  *
28  *****************************************************************************/
29
30 #include "../wifi.h"
31 #include "../pci.h"
32 #include "../base.h"
33 #include "reg.h"
34 #include "def.h"
35 #include "fw.h"
36 #include "sw.h"
37
38 static bool _rtl92d_is_fw_downloaded(struct rtl_priv *rtlpriv)
39 {
40         return (rtl_read_dword(rtlpriv, REG_MCUFWDL) & MCUFWDL_RDY) ?
41                 true : false;
42 }
43
44 static void _rtl92d_enable_fw_download(struct ieee80211_hw *hw, bool enable)
45 {
46         struct rtl_priv *rtlpriv = rtl_priv(hw);
47         u8 tmp;
48
49         if (enable) {
50                 tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
51                 rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04);
52                 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
53                 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
54                 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
55                 rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
56         } else {
57                 tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
58                 rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
59                 /* Reserved for fw extension.
60                  * 0x81[7] is used for mac0 status ,
61                  * so don't write this reg here
62                  * rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);*/
63         }
64 }
65
66 static void _rtl92d_fw_block_write(struct ieee80211_hw *hw,
67                                    const u8 *buffer, u32 size)
68 {
69         struct rtl_priv *rtlpriv = rtl_priv(hw);
70         u32 blocksize = sizeof(u32);
71         u8 *bufferptr = (u8 *) buffer;
72         u32 *pu4BytePtr = (u32 *) buffer;
73         u32 i, offset, blockCount, remainSize;
74
75         blockCount = size / blocksize;
76         remainSize = size % blocksize;
77         for (i = 0; i < blockCount; i++) {
78                 offset = i * blocksize;
79                 rtl_write_dword(rtlpriv, (FW_8192D_START_ADDRESS + offset),
80                                 *(pu4BytePtr + i));
81         }
82         if (remainSize) {
83                 offset = blockCount * blocksize;
84                 bufferptr += offset;
85                 for (i = 0; i < remainSize; i++) {
86                         rtl_write_byte(rtlpriv, (FW_8192D_START_ADDRESS +
87                                                  offset + i), *(bufferptr + i));
88                 }
89         }
90 }
91
92 static void _rtl92d_fw_page_write(struct ieee80211_hw *hw,
93                                   u32 page, const u8 *buffer, u32 size)
94 {
95         struct rtl_priv *rtlpriv = rtl_priv(hw);
96         u8 value8;
97         u8 u8page = (u8) (page & 0x07);
98
99         value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
100         rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
101         _rtl92d_fw_block_write(hw, buffer, size);
102 }
103
104 static void _rtl92d_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
105 {
106         u32 fwlen = *pfwlen;
107         u8 remain = (u8) (fwlen % 4);
108
109         remain = (remain == 0) ? 0 : (4 - remain);
110         while (remain > 0) {
111                 pfwbuf[fwlen] = 0;
112                 fwlen++;
113                 remain--;
114         }
115         *pfwlen = fwlen;
116 }
117
118 static void _rtl92d_write_fw(struct ieee80211_hw *hw,
119                              enum version_8192d version, u8 *buffer, u32 size)
120 {
121         struct rtl_priv *rtlpriv = rtl_priv(hw);
122         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
123         u8 *bufferPtr = (u8 *) buffer;
124         u32 pagenums, remainSize;
125         u32 page, offset;
126
127         RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, ("FW size is %d bytes,\n", size));
128         if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192DE)
129                 _rtl92d_fill_dummy(bufferPtr, &size);
130         pagenums = size / FW_8192D_PAGE_SIZE;
131         remainSize = size % FW_8192D_PAGE_SIZE;
132         if (pagenums > 8) {
133                 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
134                          ("Page numbers should not greater then 8\n"));
135         }
136         for (page = 0; page < pagenums; page++) {
137                 offset = page * FW_8192D_PAGE_SIZE;
138                 _rtl92d_fw_page_write(hw, page, (bufferPtr + offset),
139                                       FW_8192D_PAGE_SIZE);
140         }
141         if (remainSize) {
142                 offset = pagenums * FW_8192D_PAGE_SIZE;
143                 page = pagenums;
144                 _rtl92d_fw_page_write(hw, page, (bufferPtr + offset),
145                                       remainSize);
146         }
147 }
148
149 static int _rtl92d_fw_free_to_go(struct ieee80211_hw *hw)
150 {
151         struct rtl_priv *rtlpriv = rtl_priv(hw);
152         u32 counter = 0;
153         u32 value32;
154
155         do {
156                 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
157         } while ((counter++ < FW_8192D_POLLING_TIMEOUT_COUNT) &&
158                  (!(value32 & FWDL_ChkSum_rpt)));
159         if (counter >= FW_8192D_POLLING_TIMEOUT_COUNT) {
160                 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
161                          ("chksum report faill ! REG_MCUFWDL:0x%08x .\n",
162                          value32));
163                 return -EIO;
164         }
165         RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
166                  ("Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32));
167         value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
168         value32 |= MCUFWDL_RDY;
169         rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
170         return 0;
171 }
172
173 void rtl92d_firmware_selfreset(struct ieee80211_hw *hw)
174 {
175         struct rtl_priv *rtlpriv = rtl_priv(hw);
176         u8 u1b_tmp;
177         u8 delay = 100;
178
179         /* Set (REG_HMETFR + 3) to  0x20 is reset 8051 */
180         rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
181         u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
182         while (u1b_tmp & BIT(2)) {
183                 delay--;
184                 if (delay == 0)
185                         break;
186                 udelay(50);
187                 u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
188         }
189         RT_ASSERT((delay > 0), ("8051 reset failed!\n"));
190         RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
191                  ("=====> 8051 reset success (%d) .\n", delay));
192 }
193
194 static int _rtl92d_fw_init(struct ieee80211_hw *hw)
195 {
196         struct rtl_priv *rtlpriv = rtl_priv(hw);
197         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
198         u32 counter;
199
200         RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, ("FW already have download\n"));
201         /* polling for FW ready */
202         counter = 0;
203         do {
204                 if (rtlhal->interfaceindex == 0) {
205                         if (rtl_read_byte(rtlpriv, FW_MAC0_READY) &
206                             MAC0_READY) {
207                                 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
208                                          ("Polling FW ready success!! "
209                                          "REG_MCUFWDL: 0x%x .\n",
210                                          rtl_read_byte(rtlpriv,
211                                          FW_MAC0_READY)));
212                                 return 0;
213                         }
214                         udelay(5);
215                 } else {
216                         if (rtl_read_byte(rtlpriv, FW_MAC1_READY) &
217                             MAC1_READY) {
218                                 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
219                                          ("Polling FW ready success!! "
220                                          "REG_MCUFWDL: 0x%x .\n",
221                                          rtl_read_byte(rtlpriv,
222                                                        FW_MAC1_READY)));
223                                 return 0;
224                         }
225                         udelay(5);
226                 }
227         } while (counter++ < POLLING_READY_TIMEOUT_COUNT);
228
229         if (rtlhal->interfaceindex == 0) {
230                 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
231                          ("Polling FW ready fail!! MAC0 FW init not ready: "
232                          "0x%x .\n",
233                          rtl_read_byte(rtlpriv, FW_MAC0_READY)));
234         } else {
235                 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
236                          ("Polling FW ready fail!! MAC1 FW init not ready: "
237                          "0x%x .\n",
238                          rtl_read_byte(rtlpriv, FW_MAC1_READY)));
239         }
240         RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
241                  ("Polling FW ready fail!! REG_MCUFWDL:0x%08ul .\n",
242                  rtl_read_dword(rtlpriv, REG_MCUFWDL)));
243         return -1;
244 }
245
246 int rtl92d_download_fw(struct ieee80211_hw *hw)
247 {
248         struct rtl_priv *rtlpriv = rtl_priv(hw);
249         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
250         u8 *pfwheader;
251         u8 *pfwdata;
252         u32 fwsize;
253         int err;
254         enum version_8192d version = rtlhal->version;
255         u8 value;
256         u32 count;
257         bool fw_downloaded = false, fwdl_in_process = false;
258         unsigned long flags;
259
260         if (!rtlhal->pfirmware)
261                 return 1;
262         fwsize = rtlhal->fwsize;
263         pfwheader = (u8 *) rtlhal->pfirmware;
264         pfwdata = (u8 *) rtlhal->pfirmware;
265         rtlhal->fw_version = (u16) GET_FIRMWARE_HDR_VERSION(pfwheader);
266         rtlhal->fw_subversion = (u16) GET_FIRMWARE_HDR_SUB_VER(pfwheader);
267         RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, (" FirmwareVersion(%d),"
268                  "FirmwareSubVersion(%d), Signature(%#x)\n",
269                  rtlhal->fw_version,    rtlhal->fw_subversion,
270                  GET_FIRMWARE_HDR_SIGNATURE(pfwheader)));
271         if (IS_FW_HEADER_EXIST(pfwheader)) {
272                 RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
273                          ("Shift 32 bytes for FW header!!\n"));
274                 pfwdata = pfwdata + 32;
275                 fwsize = fwsize - 32;
276         }
277
278         spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
279         fw_downloaded = _rtl92d_is_fw_downloaded(rtlpriv);
280         if ((rtl_read_byte(rtlpriv, 0x1f) & BIT(5)) == BIT(5))
281                 fwdl_in_process = true;
282         else
283                 fwdl_in_process = false;
284         if (fw_downloaded) {
285                 spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
286                 goto exit;
287         } else if (fwdl_in_process) {
288                 spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
289                 for (count = 0; count < 5000; count++) {
290                         udelay(500);
291                         spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
292                         fw_downloaded = _rtl92d_is_fw_downloaded(rtlpriv);
293                         if ((rtl_read_byte(rtlpriv, 0x1f) & BIT(5)) == BIT(5))
294                                 fwdl_in_process = true;
295                         else
296                                 fwdl_in_process = false;
297                         spin_unlock_irqrestore(&globalmutex_for_fwdownload,
298                                                flags);
299                         if (fw_downloaded)
300                                 goto exit;
301                         else if (!fwdl_in_process)
302                                 break;
303                         else
304                                 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
305                                          ("Wait for another mac "
306                                          "download fw\n"));
307                 }
308                 spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
309                 value = rtl_read_byte(rtlpriv, 0x1f);
310                 value |= BIT(5);
311                 rtl_write_byte(rtlpriv, 0x1f, value);
312                 spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
313         } else {
314                 value = rtl_read_byte(rtlpriv, 0x1f);
315                 value |= BIT(5);
316                 rtl_write_byte(rtlpriv, 0x1f, value);
317                 spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
318         }
319
320         /* If 8051 is running in RAM code, driver should
321          * inform Fw to reset by itself, or it will cause
322          * download Fw fail.*/
323         /* 8051 RAM code */
324         if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
325                 rtl92d_firmware_selfreset(hw);
326                 rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
327         }
328         _rtl92d_enable_fw_download(hw, true);
329         _rtl92d_write_fw(hw, version, pfwdata, fwsize);
330         _rtl92d_enable_fw_download(hw, false);
331         spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
332         err = _rtl92d_fw_free_to_go(hw);
333         /* download fw over,clear 0x1f[5] */
334         value = rtl_read_byte(rtlpriv, 0x1f);
335         value &= (~BIT(5));
336         rtl_write_byte(rtlpriv, 0x1f, value);
337         spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
338         if (err) {
339                 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
340                          ("fw is not ready to run!\n"));
341                 goto exit;
342         } else {
343                 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
344                          ("fw is ready to run!\n"));
345         }
346 exit:
347         err = _rtl92d_fw_init(hw);
348         return err;
349 }
350
351 static bool _rtl92d_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
352 {
353         struct rtl_priv *rtlpriv = rtl_priv(hw);
354         u8 val_hmetfr;
355         bool result = false;
356
357         val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
358         if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
359                 result = true;
360         return result;
361 }
362
363 static void _rtl92d_fill_h2c_command(struct ieee80211_hw *hw,
364                               u8 element_id, u32 cmd_len, u8 *cmdbuffer)
365 {
366         struct rtl_priv *rtlpriv = rtl_priv(hw);
367         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
368         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
369         u8 boxnum;
370         u16 box_reg = 0, box_extreg = 0;
371         u8 u1b_tmp;
372         bool isfw_read = false;
373         u8 buf_index = 0;
374         bool bwrite_sucess = false;
375         u8 wait_h2c_limmit = 100;
376         u8 wait_writeh2c_limmit = 100;
377         u8 boxcontent[4], boxextcontent[2];
378         u32 h2c_waitcounter = 0;
379         unsigned long flag;
380         u8 idx;
381
382         if (ppsc->rfpwr_state == ERFOFF || ppsc->inactive_pwrstate == ERFOFF) {
383                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
384                          ("Return as RF is off!!!\n"));
385                 return;
386         }
387         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("come in\n"));
388         while (true) {
389                 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
390                 if (rtlhal->h2c_setinprogress) {
391                         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
392                                  ("H2C set in progress! Wait to set.."
393                                  "element_id(%d).\n", element_id));
394
395                         while (rtlhal->h2c_setinprogress) {
396                                 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
397                                                        flag);
398                                 h2c_waitcounter++;
399                                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
400                                          ("Wait 100 us (%d times)...\n",
401                                          h2c_waitcounter));
402                                 udelay(100);
403
404                                 if (h2c_waitcounter > 1000)
405                                         return;
406
407                                 spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
408                                                   flag);
409                         }
410                         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
411                 } else {
412                         rtlhal->h2c_setinprogress = true;
413                         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
414                         break;
415                 }
416         }
417         while (!bwrite_sucess) {
418                 wait_writeh2c_limmit--;
419                 if (wait_writeh2c_limmit == 0) {
420                         RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
421                                  ("Write H2C fail because no trigger "
422                                  "for FW INT!\n"));
423                         break;
424                 }
425                 boxnum = rtlhal->last_hmeboxnum;
426                 switch (boxnum) {
427                 case 0:
428                         box_reg = REG_HMEBOX_0;
429                         box_extreg = REG_HMEBOX_EXT_0;
430                         break;
431                 case 1:
432                         box_reg = REG_HMEBOX_1;
433                         box_extreg = REG_HMEBOX_EXT_1;
434                         break;
435                 case 2:
436                         box_reg = REG_HMEBOX_2;
437                         box_extreg = REG_HMEBOX_EXT_2;
438                         break;
439                 case 3:
440                         box_reg = REG_HMEBOX_3;
441                         box_extreg = REG_HMEBOX_EXT_3;
442                         break;
443                 default:
444                         RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
445                                  ("switch case not process\n"));
446                         break;
447                 }
448                 isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum);
449                 while (!isfw_read) {
450                         wait_h2c_limmit--;
451                         if (wait_h2c_limmit == 0) {
452                                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
453                                          ("Wating too long for FW read "
454                                          "clear HMEBox(%d)!\n", boxnum));
455                                 break;
456                         }
457                         udelay(10);
458                         isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum);
459                         u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
460                         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
461                                  ("Wating for FW read clear HMEBox(%d)!!! "
462                                  "0x1BF = %2x\n", boxnum, u1b_tmp));
463                 }
464                 if (!isfw_read) {
465                         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
466                                  ("Write H2C register BOX[%d] fail!!!!! "
467                                  "Fw do not read.\n", boxnum));
468                         break;
469                 }
470                 memset(boxcontent, 0, sizeof(boxcontent));
471                 memset(boxextcontent, 0, sizeof(boxextcontent));
472                 boxcontent[0] = element_id;
473                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
474                          ("Write element_id box_reg(%4x) = %2x\n",
475                          box_reg, element_id));
476                 switch (cmd_len) {
477                 case 1:
478                         boxcontent[0] &= ~(BIT(7));
479                         memcpy(boxcontent + 1, cmdbuffer + buf_index, 1);
480                         for (idx = 0; idx < 4; idx++)
481                                 rtl_write_byte(rtlpriv, box_reg + idx,
482                                                boxcontent[idx]);
483                         break;
484                 case 2:
485                         boxcontent[0] &= ~(BIT(7));
486                         memcpy(boxcontent + 1, cmdbuffer + buf_index, 2);
487                         for (idx = 0; idx < 4; idx++)
488                                 rtl_write_byte(rtlpriv, box_reg + idx,
489                                                boxcontent[idx]);
490                         break;
491                 case 3:
492                         boxcontent[0] &= ~(BIT(7));
493                         memcpy(boxcontent + 1, cmdbuffer + buf_index, 3);
494                         for (idx = 0; idx < 4; idx++)
495                                 rtl_write_byte(rtlpriv, box_reg + idx,
496                                                boxcontent[idx]);
497                         break;
498                 case 4:
499                         boxcontent[0] |= (BIT(7));
500                         memcpy(boxextcontent, cmdbuffer + buf_index, 2);
501                         memcpy(boxcontent + 1, cmdbuffer + buf_index + 2, 2);
502                         for (idx = 0; idx < 2; idx++)
503                                 rtl_write_byte(rtlpriv, box_extreg + idx,
504                                                boxextcontent[idx]);
505                         for (idx = 0; idx < 4; idx++)
506                                 rtl_write_byte(rtlpriv, box_reg + idx,
507                                                boxcontent[idx]);
508                         break;
509                 case 5:
510                         boxcontent[0] |= (BIT(7));
511                         memcpy(boxextcontent, cmdbuffer + buf_index, 2);
512                         memcpy(boxcontent + 1, cmdbuffer + buf_index + 2, 3);
513                         for (idx = 0; idx < 2; idx++)
514                                 rtl_write_byte(rtlpriv, box_extreg + idx,
515                                                boxextcontent[idx]);
516                         for (idx = 0; idx < 4; idx++)
517                                 rtl_write_byte(rtlpriv, box_reg + idx,
518                                                boxcontent[idx]);
519                         break;
520                 default:
521                         RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
522                                 ("switch case not process\n"));
523                         break;
524                 }
525                 bwrite_sucess = true;
526                 rtlhal->last_hmeboxnum = boxnum + 1;
527                 if (rtlhal->last_hmeboxnum == 4)
528                         rtlhal->last_hmeboxnum = 0;
529                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
530                          ("pHalData->last_hmeboxnum  = %d\n",
531                           rtlhal->last_hmeboxnum));
532         }
533         spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
534         rtlhal->h2c_setinprogress = false;
535         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
536         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("go out\n"));
537 }
538
539 void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw,
540                          u8 element_id, u32 cmd_len, u8 *cmdbuffer)
541 {
542         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
543         u32 tmp_cmdbuf[2];
544
545         if (rtlhal->fw_ready == false) {
546                 RT_ASSERT(false, ("return H2C cmd because of Fw "
547                                   "download fail!!!\n"));
548                 return;
549         }
550         memset(tmp_cmdbuf, 0, 8);
551         memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
552         _rtl92d_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
553         return;
554 }
555
556 void rtl92d_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
557 {
558         struct rtl_priv *rtlpriv = rtl_priv(hw);
559         u8 u1_h2c_set_pwrmode[3] = { 0 };
560         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
561
562         RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("FW LPS mode = %d\n", mode));
563         SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
564         SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
565         SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
566                                               ppsc->reg_max_lps_awakeintvl);
567         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
568                       "rtl92d_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
569                       u1_h2c_set_pwrmode, 3);
570         rtl92d_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
571 }
572
573 static bool _rtl92d_cmd_send_packet(struct ieee80211_hw *hw,
574                                     struct sk_buff *skb)
575 {
576         struct rtl_priv *rtlpriv = rtl_priv(hw);
577         struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
578         struct rtl8192_tx_ring *ring;
579         struct rtl_tx_desc *pdesc;
580         u8 idx = 0;
581         unsigned long flags;
582         struct sk_buff *pskb;
583
584         ring = &rtlpci->tx_ring[BEACON_QUEUE];
585         pskb = __skb_dequeue(&ring->queue);
586         if (pskb)
587                 kfree_skb(pskb);
588         spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
589         pdesc = &ring->desc[idx];
590         /* discard output from call below */
591         rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN);
592         rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
593         __skb_queue_tail(&ring->queue, skb);
594         spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
595         rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
596         return true;
597 }
598
599 #define BEACON_PG               0       /*->1 */
600 #define PSPOLL_PG               2
601 #define NULL_PG                 3
602 #define PROBERSP_PG             4       /*->5 */
603 #define TOTAL_RESERVED_PKT_LEN  768
604
605 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
606         /* page 0 beacon */
607         0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
608         0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
609         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
610         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
611         0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
612         0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
613         0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
614         0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
615         0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
616         0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
617         0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
618         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
619         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
620         0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
621         0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
622         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
623
624         /* page 1 beacon */
625         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
626         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
627         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
628         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
629         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
630         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
631         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
632         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
633         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
634         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
635         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
636         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
637         0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
638         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
639         0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
640         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
641
642         /* page 2  ps-poll */
643         0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
644         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
645         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
646         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
647         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
648         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
649         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
650         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
651         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
652         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
653         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
654         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
655         0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
656         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
657         0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
658         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
659
660         /* page 3  null */
661         0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
662         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
663         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
664         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
665         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
666         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
667         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
668         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
669         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
670         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
671         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
672         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
673         0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
674         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
675         0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
676         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
677
678         /* page 4  probe_resp */
679         0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
680         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
681         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
682         0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
683         0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
684         0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
685         0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
686         0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
687         0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
688         0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
689         0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
690         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
691         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
692         0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
693         0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
694         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
695
696         /* page 5  probe_resp */
697         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
698         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
699         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
700         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
701         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
702         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
703         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
704         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
705         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
706         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
707         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
708         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
709         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
710         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
711         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
712         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
713 };
714
715 void rtl92d_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
716 {
717         struct rtl_priv *rtlpriv = rtl_priv(hw);
718         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
719         struct sk_buff *skb = NULL;
720         u32 totalpacketlen;
721         bool rtstatus;
722         u8 u1RsvdPageLoc[3] = { 0 };
723         bool dlok = false;
724         u8 *beacon;
725         u8 *p_pspoll;
726         u8 *nullfunc;
727         u8 *p_probersp;
728         /*---------------------------------------------------------
729                                                 (1) beacon
730         ---------------------------------------------------------*/
731         beacon = &reserved_page_packet[BEACON_PG * 128];
732         SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
733         SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
734         /*-------------------------------------------------------
735                                                 (2) ps-poll
736         --------------------------------------------------------*/
737         p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
738         SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
739         SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
740         SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
741         SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
742         /*--------------------------------------------------------
743                                                 (3) null data
744         ---------------------------------------------------------*/
745         nullfunc = &reserved_page_packet[NULL_PG * 128];
746         SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
747         SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
748         SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
749         SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
750         /*---------------------------------------------------------
751                                                 (4) probe response
752         ----------------------------------------------------------*/
753         p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
754         SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
755         SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
756         SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
757         SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
758         totalpacketlen = TOTAL_RESERVED_PKT_LEN;
759         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
760                       "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
761                       &reserved_page_packet[0], totalpacketlen);
762         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
763                       "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
764                       u1RsvdPageLoc, 3);
765         skb = dev_alloc_skb(totalpacketlen);
766         memcpy((u8 *) skb_put(skb, totalpacketlen), &reserved_page_packet,
767                 totalpacketlen);
768         rtstatus = _rtl92d_cmd_send_packet(hw, skb);
769
770         if (rtstatus)
771                 dlok = true;
772         if (dlok) {
773                 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
774                         ("Set RSVD page location to Fw.\n"));
775                 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
776                               "H2C_RSVDPAGE:\n", u1RsvdPageLoc, 3);
777                 rtl92d_fill_h2c_cmd(hw, H2C_RSVDPAGE,
778                         sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
779         } else
780                 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
781                         ("Set RSVD page location to Fw FAIL!!!!!!.\n"));
782 }
783
784 void rtl92d_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
785 {
786         u8 u1_joinbssrpt_parm[1] = {0};
787
788         SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
789         rtl92d_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
790 }