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