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