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