]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/net/wireless/rtlwifi/rtl8192de/fw.c
rtlwifi: Convert RT_TRACE macro to use ##__VA_ARGS__
[mv-sheeva.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!! REG_MCUFWDL: 0x%x\n",
209                                          rtl_read_byte(rtlpriv,
210                                                        FW_MAC0_READY));
211                                 return 0;
212                         }
213                         udelay(5);
214                 } else {
215                         if (rtl_read_byte(rtlpriv, FW_MAC1_READY) &
216                             MAC1_READY) {
217                                 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
218                                          "Polling FW ready success!! REG_MCUFWDL: 0x%x\n",
219                                          rtl_read_byte(rtlpriv,
220                                                        FW_MAC1_READY));
221                                 return 0;
222                         }
223                         udelay(5);
224                 }
225         } while (counter++ < POLLING_READY_TIMEOUT_COUNT);
226
227         if (rtlhal->interfaceindex == 0) {
228                 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
229                          "Polling FW ready fail!! MAC0 FW init not ready: 0x%x\n",
230                          rtl_read_byte(rtlpriv, FW_MAC0_READY));
231         } else {
232                 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
233                          "Polling FW ready fail!! MAC1 FW init not ready: 0x%x\n",
234                          rtl_read_byte(rtlpriv, FW_MAC1_READY));
235         }
236         RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
237                  "Polling FW ready fail!! REG_MCUFWDL:0x%08ul\n",
238                  rtl_read_dword(rtlpriv, REG_MCUFWDL));
239         return -1;
240 }
241
242 int rtl92d_download_fw(struct ieee80211_hw *hw)
243 {
244         struct rtl_priv *rtlpriv = rtl_priv(hw);
245         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
246         u8 *pfwheader;
247         u8 *pfwdata;
248         u32 fwsize;
249         int err;
250         enum version_8192d version = rtlhal->version;
251         u8 value;
252         u32 count;
253         bool fw_downloaded = false, fwdl_in_process = false;
254         unsigned long flags;
255
256         if (!rtlhal->pfirmware)
257                 return 1;
258         fwsize = rtlhal->fwsize;
259         pfwheader = (u8 *) rtlhal->pfirmware;
260         pfwdata = (u8 *) rtlhal->pfirmware;
261         rtlhal->fw_version = (u16) GET_FIRMWARE_HDR_VERSION(pfwheader);
262         rtlhal->fw_subversion = (u16) GET_FIRMWARE_HDR_SUB_VER(pfwheader);
263         RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
264                  "FirmwareVersion(%d), FirmwareSubVersion(%d), Signature(%#x)\n",
265                  rtlhal->fw_version, rtlhal->fw_subversion,
266                  GET_FIRMWARE_HDR_SIGNATURE(pfwheader));
267         if (IS_FW_HEADER_EXIST(pfwheader)) {
268                 RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
269                          "Shift 32 bytes for FW header!!\n");
270                 pfwdata = pfwdata + 32;
271                 fwsize = fwsize - 32;
272         }
273
274         spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
275         fw_downloaded = _rtl92d_is_fw_downloaded(rtlpriv);
276         if ((rtl_read_byte(rtlpriv, 0x1f) & BIT(5)) == BIT(5))
277                 fwdl_in_process = true;
278         else
279                 fwdl_in_process = false;
280         if (fw_downloaded) {
281                 spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
282                 goto exit;
283         } else if (fwdl_in_process) {
284                 spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
285                 for (count = 0; count < 5000; count++) {
286                         udelay(500);
287                         spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
288                         fw_downloaded = _rtl92d_is_fw_downloaded(rtlpriv);
289                         if ((rtl_read_byte(rtlpriv, 0x1f) & BIT(5)) == BIT(5))
290                                 fwdl_in_process = true;
291                         else
292                                 fwdl_in_process = false;
293                         spin_unlock_irqrestore(&globalmutex_for_fwdownload,
294                                                flags);
295                         if (fw_downloaded)
296                                 goto exit;
297                         else if (!fwdl_in_process)
298                                 break;
299                         else
300                                 RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
301                                          "Wait for another mac download fw\n");
302                 }
303                 spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
304                 value = rtl_read_byte(rtlpriv, 0x1f);
305                 value |= BIT(5);
306                 rtl_write_byte(rtlpriv, 0x1f, value);
307                 spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
308         } else {
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         }
314
315         /* If 8051 is running in RAM code, driver should
316          * inform Fw to reset by itself, or it will cause
317          * download Fw fail.*/
318         /* 8051 RAM code */
319         if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
320                 rtl92d_firmware_selfreset(hw);
321                 rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
322         }
323         _rtl92d_enable_fw_download(hw, true);
324         _rtl92d_write_fw(hw, version, pfwdata, fwsize);
325         _rtl92d_enable_fw_download(hw, false);
326         spin_lock_irqsave(&globalmutex_for_fwdownload, flags);
327         err = _rtl92d_fw_free_to_go(hw);
328         /* download fw over,clear 0x1f[5] */
329         value = rtl_read_byte(rtlpriv, 0x1f);
330         value &= (~BIT(5));
331         rtl_write_byte(rtlpriv, 0x1f, value);
332         spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
333         if (err) {
334                 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
335                          "fw is not ready to run!\n");
336                 goto exit;
337         } else {
338                 RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "fw is ready to run!\n");
339         }
340 exit:
341         err = _rtl92d_fw_init(hw);
342         return err;
343 }
344
345 static bool _rtl92d_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
346 {
347         struct rtl_priv *rtlpriv = rtl_priv(hw);
348         u8 val_hmetfr;
349         bool result = false;
350
351         val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
352         if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
353                 result = true;
354         return result;
355 }
356
357 static void _rtl92d_fill_h2c_command(struct ieee80211_hw *hw,
358                               u8 element_id, u32 cmd_len, u8 *cmdbuffer)
359 {
360         struct rtl_priv *rtlpriv = rtl_priv(hw);
361         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
362         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
363         u8 boxnum;
364         u16 box_reg = 0, box_extreg = 0;
365         u8 u1b_tmp;
366         bool isfw_read = false;
367         u8 buf_index = 0;
368         bool bwrite_sucess = false;
369         u8 wait_h2c_limmit = 100;
370         u8 wait_writeh2c_limmit = 100;
371         u8 boxcontent[4], boxextcontent[2];
372         u32 h2c_waitcounter = 0;
373         unsigned long flag;
374         u8 idx;
375
376         if (ppsc->rfpwr_state == ERFOFF || ppsc->inactive_pwrstate == ERFOFF) {
377                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
378                          "Return as RF is off!!!\n");
379                 return;
380         }
381         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
382         while (true) {
383                 spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
384                 if (rtlhal->h2c_setinprogress) {
385                         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
386                                  "H2C set in progress! Wait to set..element_id(%d)\n",
387                                  element_id);
388
389                         while (rtlhal->h2c_setinprogress) {
390                                 spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
391                                                        flag);
392                                 h2c_waitcounter++;
393                                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
394                                          "Wait 100 us (%d times)...\n",
395                                          h2c_waitcounter);
396                                 udelay(100);
397
398                                 if (h2c_waitcounter > 1000)
399                                         return;
400
401                                 spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
402                                                   flag);
403                         }
404                         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
405                 } else {
406                         rtlhal->h2c_setinprogress = true;
407                         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
408                         break;
409                 }
410         }
411         while (!bwrite_sucess) {
412                 wait_writeh2c_limmit--;
413                 if (wait_writeh2c_limmit == 0) {
414                         RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
415                                  "Write H2C fail because no trigger for FW INT!\n");
416                         break;
417                 }
418                 boxnum = rtlhal->last_hmeboxnum;
419                 switch (boxnum) {
420                 case 0:
421                         box_reg = REG_HMEBOX_0;
422                         box_extreg = REG_HMEBOX_EXT_0;
423                         break;
424                 case 1:
425                         box_reg = REG_HMEBOX_1;
426                         box_extreg = REG_HMEBOX_EXT_1;
427                         break;
428                 case 2:
429                         box_reg = REG_HMEBOX_2;
430                         box_extreg = REG_HMEBOX_EXT_2;
431                         break;
432                 case 3:
433                         box_reg = REG_HMEBOX_3;
434                         box_extreg = REG_HMEBOX_EXT_3;
435                         break;
436                 default:
437                         RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
438                                  "switch case not processed\n");
439                         break;
440                 }
441                 isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum);
442                 while (!isfw_read) {
443                         wait_h2c_limmit--;
444                         if (wait_h2c_limmit == 0) {
445                                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
446                                          "Waiting too long for FW read clear HMEBox(%d)!\n",
447                                          boxnum);
448                                 break;
449                         }
450                         udelay(10);
451                         isfw_read = _rtl92d_check_fw_read_last_h2c(hw, boxnum);
452                         u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
453                         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
454                                  "Waiting for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n",
455                                  boxnum, u1b_tmp);
456                 }
457                 if (!isfw_read) {
458                         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
459                                  "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
460                                  boxnum);
461                         break;
462                 }
463                 memset(boxcontent, 0, sizeof(boxcontent));
464                 memset(boxextcontent, 0, sizeof(boxextcontent));
465                 boxcontent[0] = element_id;
466                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
467                          "Write element_id box_reg(%4x) = %2x\n",
468                          box_reg, element_id);
469                 switch (cmd_len) {
470                 case 1:
471                         boxcontent[0] &= ~(BIT(7));
472                         memcpy(boxcontent + 1, cmdbuffer + buf_index, 1);
473                         for (idx = 0; idx < 4; idx++)
474                                 rtl_write_byte(rtlpriv, box_reg + idx,
475                                                boxcontent[idx]);
476                         break;
477                 case 2:
478                         boxcontent[0] &= ~(BIT(7));
479                         memcpy(boxcontent + 1, cmdbuffer + buf_index, 2);
480                         for (idx = 0; idx < 4; idx++)
481                                 rtl_write_byte(rtlpriv, box_reg + idx,
482                                                boxcontent[idx]);
483                         break;
484                 case 3:
485                         boxcontent[0] &= ~(BIT(7));
486                         memcpy(boxcontent + 1, cmdbuffer + buf_index, 3);
487                         for (idx = 0; idx < 4; idx++)
488                                 rtl_write_byte(rtlpriv, box_reg + idx,
489                                                boxcontent[idx]);
490                         break;
491                 case 4:
492                         boxcontent[0] |= (BIT(7));
493                         memcpy(boxextcontent, cmdbuffer + buf_index, 2);
494                         memcpy(boxcontent + 1, cmdbuffer + buf_index + 2, 2);
495                         for (idx = 0; idx < 2; idx++)
496                                 rtl_write_byte(rtlpriv, box_extreg + idx,
497                                                boxextcontent[idx]);
498                         for (idx = 0; idx < 4; idx++)
499                                 rtl_write_byte(rtlpriv, box_reg + idx,
500                                                boxcontent[idx]);
501                         break;
502                 case 5:
503                         boxcontent[0] |= (BIT(7));
504                         memcpy(boxextcontent, cmdbuffer + buf_index, 2);
505                         memcpy(boxcontent + 1, cmdbuffer + buf_index + 2, 3);
506                         for (idx = 0; idx < 2; idx++)
507                                 rtl_write_byte(rtlpriv, box_extreg + idx,
508                                                boxextcontent[idx]);
509                         for (idx = 0; idx < 4; idx++)
510                                 rtl_write_byte(rtlpriv, box_reg + idx,
511                                                boxcontent[idx]);
512                         break;
513                 default:
514                         RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
515                                  "switch case not processed\n");
516                         break;
517                 }
518                 bwrite_sucess = true;
519                 rtlhal->last_hmeboxnum = boxnum + 1;
520                 if (rtlhal->last_hmeboxnum == 4)
521                         rtlhal->last_hmeboxnum = 0;
522                 RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
523                          "pHalData->last_hmeboxnum  = %d\n",
524                          rtlhal->last_hmeboxnum);
525         }
526         spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
527         rtlhal->h2c_setinprogress = false;
528         spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
529         RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
530 }
531
532 void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw,
533                          u8 element_id, u32 cmd_len, u8 *cmdbuffer)
534 {
535         struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
536         u32 tmp_cmdbuf[2];
537
538         if (rtlhal->fw_ready == false) {
539                 RT_ASSERT(false, ("return H2C cmd because of Fw "
540                                   "download fail!!!\n"));
541                 return;
542         }
543         memset(tmp_cmdbuf, 0, 8);
544         memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
545         _rtl92d_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
546         return;
547 }
548
549 void rtl92d_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
550 {
551         struct rtl_priv *rtlpriv = rtl_priv(hw);
552         u8 u1_h2c_set_pwrmode[3] = { 0 };
553         struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
554
555         RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
556         SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
557         SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
558         SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
559                                               ppsc->reg_max_lps_awakeintvl);
560         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
561                       "rtl92d_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode",
562                       u1_h2c_set_pwrmode, 3);
563         rtl92d_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
564 }
565
566 static bool _rtl92d_cmd_send_packet(struct ieee80211_hw *hw,
567                                     struct sk_buff *skb)
568 {
569         struct rtl_priv *rtlpriv = rtl_priv(hw);
570         struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
571         struct rtl8192_tx_ring *ring;
572         struct rtl_tx_desc *pdesc;
573         u8 idx = 0;
574         unsigned long flags;
575         struct sk_buff *pskb;
576
577         ring = &rtlpci->tx_ring[BEACON_QUEUE];
578         pskb = __skb_dequeue(&ring->queue);
579         if (pskb)
580                 kfree_skb(pskb);
581         spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
582         pdesc = &ring->desc[idx];
583         /* discard output from call below */
584         rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN);
585         rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
586         __skb_queue_tail(&ring->queue, skb);
587         spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
588         rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
589         return true;
590 }
591
592 #define BEACON_PG               0       /*->1 */
593 #define PSPOLL_PG               2
594 #define NULL_PG                 3
595 #define PROBERSP_PG             4       /*->5 */
596 #define TOTAL_RESERVED_PKT_LEN  768
597
598 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
599         /* page 0 beacon */
600         0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
601         0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
602         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
603         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
604         0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
605         0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
606         0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
607         0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
608         0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
609         0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
610         0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
611         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
612         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
613         0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
614         0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
615         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
616
617         /* page 1 beacon */
618         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
619         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
620         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
621         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
622         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
623         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
624         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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         0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
631         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
632         0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
633         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
634
635         /* page 2  ps-poll */
636         0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
637         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
638         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
639         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
640         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
641         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
642         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
643         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
644         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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         0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
649         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
650         0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
651         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
652
653         /* page 3  null */
654         0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
655         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
656         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
657         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
658         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
659         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
660         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
661         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
662         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
663         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
664         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
665         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
666         0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
667         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
668         0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
669         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
670
671         /* page 4  probe_resp */
672         0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
673         0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
674         0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
675         0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
676         0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
677         0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
678         0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
679         0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
680         0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
681         0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
682         0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
683         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
684         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
685         0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
686         0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
687         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
688
689         /* page 5  probe_resp */
690         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
691         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
692         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
693         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
694         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
695         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
696         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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 };
707
708 void rtl92d_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
709 {
710         struct rtl_priv *rtlpriv = rtl_priv(hw);
711         struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
712         struct sk_buff *skb = NULL;
713         u32 totalpacketlen;
714         bool rtstatus;
715         u8 u1RsvdPageLoc[3] = { 0 };
716         bool dlok = false;
717         u8 *beacon;
718         u8 *p_pspoll;
719         u8 *nullfunc;
720         u8 *p_probersp;
721         /*---------------------------------------------------------
722                                                 (1) beacon
723         ---------------------------------------------------------*/
724         beacon = &reserved_page_packet[BEACON_PG * 128];
725         SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
726         SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
727         /*-------------------------------------------------------
728                                                 (2) ps-poll
729         --------------------------------------------------------*/
730         p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
731         SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
732         SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
733         SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
734         SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
735         /*--------------------------------------------------------
736                                                 (3) null data
737         ---------------------------------------------------------*/
738         nullfunc = &reserved_page_packet[NULL_PG * 128];
739         SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
740         SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
741         SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
742         SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
743         /*---------------------------------------------------------
744                                                 (4) probe response
745         ----------------------------------------------------------*/
746         p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
747         SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
748         SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
749         SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
750         SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
751         totalpacketlen = TOTAL_RESERVED_PKT_LEN;
752         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
753                       "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL",
754                       &reserved_page_packet[0], totalpacketlen);
755         RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
756                       "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL",
757                       u1RsvdPageLoc, 3);
758         skb = dev_alloc_skb(totalpacketlen);
759         memcpy((u8 *) skb_put(skb, totalpacketlen), &reserved_page_packet,
760                 totalpacketlen);
761         rtstatus = _rtl92d_cmd_send_packet(hw, skb);
762
763         if (rtstatus)
764                 dlok = true;
765         if (dlok) {
766                 RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
767                          "Set RSVD page location to Fw\n");
768                 RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
769                               "H2C_RSVDPAGE", u1RsvdPageLoc, 3);
770                 rtl92d_fill_h2c_cmd(hw, H2C_RSVDPAGE,
771                         sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
772         } else
773                 RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
774                          "Set RSVD page location to Fw FAIL!!!!!!\n");
775 }
776
777 void rtl92d_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
778 {
779         u8 u1_joinbssrpt_parm[1] = {0};
780
781         SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
782         rtl92d_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
783 }