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