1 /******************************************************************************
2  *
3  * Copyright(c) 2009-2010  Realtek Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17  *
18  * The full GNU General Public License is included in this distribution in the
19  * file called LICENSE.
20  *
21  * Contact Information:
22  * wlanfae <wlanfae@realtek.com>
23  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
24  * Hsinchu 300, Taiwan.
25  *
26  * Larry Finger <Larry.Finger@lwfinger.net>
27  *
28  *****************************************************************************/
29 
30 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
31 
32 #include <linux/firmware.h>
33 #include <linux/export.h>
34 #include "../wifi.h"
35 #include "../pci.h"
36 #include "../base.h"
37 #include "../rtl8192ce/reg.h"
38 #include "../rtl8192ce/def.h"
39 #include "fw_common.h"
40 
_rtl92c_enable_fw_download(struct ieee80211_hw * hw,bool enable)41 static void _rtl92c_enable_fw_download(struct ieee80211_hw *hw, bool enable)
42 {
43 	struct rtl_priv *rtlpriv = rtl_priv(hw);
44 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
45 
46 	if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CU) {
47 		u32 value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
48 		if (enable)
49 			value32 |= MCUFWDL_EN;
50 		else
51 			value32 &= ~MCUFWDL_EN;
52 		rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
53 	} else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE) {
54 		u8 tmp;
55 		if (enable) {
56 
57 			tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
58 			rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1,
59 				       tmp | 0x04);
60 
61 			tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
62 			rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
63 
64 			tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
65 			rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
66 		} else {
67 
68 			tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
69 			rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
70 
71 			rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
72 		}
73 	}
74 }
75 
rtl_block_fw_writeN(struct ieee80211_hw * hw,const u8 * buffer,u32 size)76 static void rtl_block_fw_writeN(struct ieee80211_hw *hw, const u8 *buffer,
77 				u32 size)
78 {
79 	struct rtl_priv *rtlpriv = rtl_priv(hw);
80 	u32 blockSize = REALTEK_USB_VENQT_MAX_BUF_SIZE - 20;
81 	u8 *bufferPtr = (u8 *) buffer;
82 	u32 i, offset, blockCount, remainSize;
83 
84 	blockCount = size / blockSize;
85 	remainSize = size % blockSize;
86 
87 	for (i = 0; i < blockCount; i++) {
88 		offset = i * blockSize;
89 		rtlpriv->io.writeN_sync(rtlpriv,
90 					(FW_8192C_START_ADDRESS + offset),
91 					(void *)(bufferPtr + offset),
92 					blockSize);
93 	}
94 
95 	if (remainSize) {
96 		offset = blockCount * blockSize;
97 		rtlpriv->io.writeN_sync(rtlpriv,
98 					(FW_8192C_START_ADDRESS + offset),
99 					(void *)(bufferPtr + offset),
100 					remainSize);
101 	}
102 }
103 
_rtl92c_fw_block_write(struct ieee80211_hw * hw,const u8 * buffer,u32 size)104 static void _rtl92c_fw_block_write(struct ieee80211_hw *hw,
105 				   const u8 *buffer, u32 size)
106 {
107 	struct rtl_priv *rtlpriv = rtl_priv(hw);
108 	u32 blockSize = sizeof(u32);
109 	u8 *bufferPtr = (u8 *) buffer;
110 	u32 *pu4BytePtr = (u32 *) buffer;
111 	u32 i, offset, blockCount, remainSize;
112 	u32 data;
113 
114 	if (rtlpriv->io.writeN_sync) {
115 		rtl_block_fw_writeN(hw, buffer, size);
116 		return;
117 	}
118 	blockCount = size / blockSize;
119 	remainSize = size % blockSize;
120 	if (remainSize) {
121 		/* the last word is < 4 bytes - pad it with zeros */
122 		for (i = 0; i < 4 - remainSize; i++)
123 			*(bufferPtr + size + i) = 0;
124 		blockCount++;
125 	}
126 
127 	for (i = 0; i < blockCount; i++) {
128 		offset = i * blockSize;
129 		/* for big-endian platforms, the firmware data need to be byte
130 		 * swapped as it was read as a byte string and will be written
131 		 * as 32-bit dwords and byte swapped when written
132 		 */
133 		data = le32_to_cpu(*(__le32 *)(pu4BytePtr + i));
134 		rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
135 				data);
136 	}
137 }
138 
_rtl92c_fw_page_write(struct ieee80211_hw * hw,u32 page,const u8 * buffer,u32 size)139 static void _rtl92c_fw_page_write(struct ieee80211_hw *hw,
140 				  u32 page, const u8 *buffer, u32 size)
141 {
142 	struct rtl_priv *rtlpriv = rtl_priv(hw);
143 	u8 value8;
144 	u8 u8page = (u8) (page & 0x07);
145 
146 	value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
147 
148 	rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
149 	_rtl92c_fw_block_write(hw, buffer, size);
150 }
151 
_rtl92c_fill_dummy(u8 * pfwbuf,u32 * pfwlen)152 static void _rtl92c_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
153 {
154 	u32 fwlen = *pfwlen;
155 	u8 remain = (u8) (fwlen % 4);
156 
157 	remain = (remain == 0) ? 0 : (4 - remain);
158 
159 	while (remain > 0) {
160 		pfwbuf[fwlen] = 0;
161 		fwlen++;
162 		remain--;
163 	}
164 
165 	*pfwlen = fwlen;
166 }
167 
_rtl92c_write_fw(struct ieee80211_hw * hw,enum version_8192c version,u8 * buffer,u32 size)168 static void _rtl92c_write_fw(struct ieee80211_hw *hw,
169 			     enum version_8192c version, u8 *buffer, u32 size)
170 {
171 	struct rtl_priv *rtlpriv = rtl_priv(hw);
172 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
173 	u8 *bufferPtr = (u8 *) buffer;
174 
175 	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, ("FW size is %d bytes,\n", size));
176 
177 	if (IS_CHIP_VER_B(version)) {
178 		u32 pageNums, remainSize;
179 		u32 page, offset;
180 
181 		if (IS_HARDWARE_TYPE_8192CE(rtlhal))
182 			_rtl92c_fill_dummy(bufferPtr, &size);
183 
184 		pageNums = size / FW_8192C_PAGE_SIZE;
185 		remainSize = size % FW_8192C_PAGE_SIZE;
186 
187 		if (pageNums > 4) {
188 			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
189 				 ("Page numbers should not greater then 4\n"));
190 		}
191 
192 		for (page = 0; page < pageNums; page++) {
193 			offset = page * FW_8192C_PAGE_SIZE;
194 			_rtl92c_fw_page_write(hw, page, (bufferPtr + offset),
195 					      FW_8192C_PAGE_SIZE);
196 		}
197 
198 		if (remainSize) {
199 			offset = pageNums * FW_8192C_PAGE_SIZE;
200 			page = pageNums;
201 			_rtl92c_fw_page_write(hw, page, (bufferPtr + offset),
202 					      remainSize);
203 		}
204 	} else {
205 		_rtl92c_fw_block_write(hw, buffer, size);
206 	}
207 }
208 
_rtl92c_fw_free_to_go(struct ieee80211_hw * hw)209 static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
210 {
211 	struct rtl_priv *rtlpriv = rtl_priv(hw);
212 	u32 counter = 0;
213 	u32 value32;
214 
215 	do {
216 		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
217 	} while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
218 		 (!(value32 & FWDL_ChkSum_rpt)));
219 
220 	if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
221 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
222 			 ("chksum report faill ! REG_MCUFWDL:0x%08x .\n",
223 			  value32));
224 		return -EIO;
225 	}
226 
227 	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
228 		 ("Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32));
229 
230 	value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
231 	value32 |= MCUFWDL_RDY;
232 	value32 &= ~WINTINI_RDY;
233 	rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
234 
235 	counter = 0;
236 
237 	do {
238 		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
239 		if (value32 & WINTINI_RDY) {
240 			RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
241 				 ("Polling FW ready success!!"
242 				 " REG_MCUFWDL:0x%08x .\n",
243 				 value32));
244 			return 0;
245 		}
246 
247 		mdelay(FW_8192C_POLLING_DELAY);
248 
249 	} while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
250 
251 	RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
252 		 ("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32));
253 	return -EIO;
254 }
255 
rtl92c_download_fw(struct ieee80211_hw * hw)256 int rtl92c_download_fw(struct ieee80211_hw *hw)
257 {
258 	struct rtl_priv *rtlpriv = rtl_priv(hw);
259 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
260 	struct rtl92c_firmware_header *pfwheader;
261 	u8 *pfwdata;
262 	u32 fwsize;
263 	enum version_8192c version = rtlhal->version;
264 
265 	if (!rtlhal->pfirmware)
266 		return 1;
267 
268 	pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name);
269 	pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
270 	pfwdata = (u8 *) rtlhal->pfirmware;
271 	fwsize = rtlhal->fwsize;
272 
273 	if (IS_FW_HEADER_EXIST(pfwheader)) {
274 		RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
275 			 ("Firmware Version(%d), Signature(%#x),Size(%d)\n",
276 			 le16_to_cpu(pfwheader->version),
277 			 le16_to_cpu(pfwheader->signature),
278 			 (uint)sizeof(struct rtl92c_firmware_header)));
279 
280 		pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
281 		fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
282 	}
283 
284 	_rtl92c_enable_fw_download(hw, true);
285 	_rtl92c_write_fw(hw, version, pfwdata, fwsize);
286 	_rtl92c_enable_fw_download(hw, false);
287 
288 	if (_rtl92c_fw_free_to_go(hw)) {
289 		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
290 			 ("Firmware is not ready to run!\n"));
291 	} else {
292 		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
293 			 ("Firmware is ready to run!\n"));
294 	}
295 
296 	return 0;
297 }
298 EXPORT_SYMBOL(rtl92c_download_fw);
299 
_rtl92c_check_fw_read_last_h2c(struct ieee80211_hw * hw,u8 boxnum)300 static bool _rtl92c_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
301 {
302 	struct rtl_priv *rtlpriv = rtl_priv(hw);
303 	u8 val_hmetfr, val_mcutst_1;
304 	bool result = false;
305 
306 	val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
307 	val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum));
308 
309 	if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0)
310 		result = true;
311 	return result;
312 }
313 
_rtl92c_fill_h2c_command(struct ieee80211_hw * hw,u8 element_id,u32 cmd_len,u8 * p_cmdbuffer)314 static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
315 			      u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
316 {
317 	struct rtl_priv *rtlpriv = rtl_priv(hw);
318 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
319 	u8 boxnum;
320 	u16 box_reg = 0, box_extreg = 0;
321 	u8 u1b_tmp;
322 	bool isfw_read = false;
323 	bool bwrite_sucess = false;
324 	u8 wait_h2c_limmit = 100;
325 	u8 wait_writeh2c_limmit = 100;
326 	u8 boxcontent[4], boxextcontent[2];
327 	u32 h2c_waitcounter = 0;
328 	unsigned long flag;
329 	u8 idx;
330 
331 	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("come in\n"));
332 
333 	while (true) {
334 		spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
335 		if (rtlhal->h2c_setinprogress) {
336 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
337 				 ("H2C set in progress! Wait to set.."
338 				  "element_id(%d).\n", element_id));
339 
340 			while (rtlhal->h2c_setinprogress) {
341 				spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
342 						       flag);
343 				h2c_waitcounter++;
344 				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
345 					 ("Wait 100 us (%d times)...\n",
346 					  h2c_waitcounter));
347 				udelay(100);
348 
349 				if (h2c_waitcounter > 1000)
350 					return;
351 				spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
352 						  flag);
353 			}
354 			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
355 		} else {
356 			rtlhal->h2c_setinprogress = true;
357 			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
358 			break;
359 		}
360 	}
361 
362 	while (!bwrite_sucess) {
363 		wait_writeh2c_limmit--;
364 		if (wait_writeh2c_limmit == 0) {
365 			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
366 				 ("Write H2C fail because no trigger "
367 				  "for FW INT!\n"));
368 			break;
369 		}
370 
371 		boxnum = rtlhal->last_hmeboxnum;
372 		switch (boxnum) {
373 		case 0:
374 			box_reg = REG_HMEBOX_0;
375 			box_extreg = REG_HMEBOX_EXT_0;
376 			break;
377 		case 1:
378 			box_reg = REG_HMEBOX_1;
379 			box_extreg = REG_HMEBOX_EXT_1;
380 			break;
381 		case 2:
382 			box_reg = REG_HMEBOX_2;
383 			box_extreg = REG_HMEBOX_EXT_2;
384 			break;
385 		case 3:
386 			box_reg = REG_HMEBOX_3;
387 			box_extreg = REG_HMEBOX_EXT_3;
388 			break;
389 		default:
390 			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
391 				 ("switch case not process\n"));
392 			break;
393 		}
394 
395 		isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
396 		while (!isfw_read) {
397 
398 			wait_h2c_limmit--;
399 			if (wait_h2c_limmit == 0) {
400 				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
401 					 ("Wating too long for FW read "
402 					  "clear HMEBox(%d)!\n", boxnum));
403 				break;
404 			}
405 
406 			udelay(10);
407 
408 			isfw_read = _rtl92c_check_fw_read_last_h2c(hw, boxnum);
409 			u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
410 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
411 				 ("Wating for FW read clear HMEBox(%d)!!! "
412 				  "0x1BF = %2x\n", boxnum, u1b_tmp));
413 		}
414 
415 		if (!isfw_read) {
416 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
417 				 ("Write H2C register BOX[%d] fail!!!!! "
418 				  "Fw do not read.\n", boxnum));
419 			break;
420 		}
421 
422 		memset(boxcontent, 0, sizeof(boxcontent));
423 		memset(boxextcontent, 0, sizeof(boxextcontent));
424 		boxcontent[0] = element_id;
425 		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
426 			 ("Write element_id box_reg(%4x) = %2x\n",
427 			  box_reg, element_id));
428 
429 		switch (cmd_len) {
430 		case 1:
431 			boxcontent[0] &= ~(BIT(7));
432 			memcpy((u8 *) (boxcontent) + 1,
433 			       p_cmdbuffer, 1);
434 
435 			for (idx = 0; idx < 4; idx++) {
436 				rtl_write_byte(rtlpriv, box_reg + idx,
437 					       boxcontent[idx]);
438 			}
439 			break;
440 		case 2:
441 			boxcontent[0] &= ~(BIT(7));
442 			memcpy((u8 *) (boxcontent) + 1,
443 			       p_cmdbuffer, 2);
444 
445 			for (idx = 0; idx < 4; idx++) {
446 				rtl_write_byte(rtlpriv, box_reg + idx,
447 					       boxcontent[idx]);
448 			}
449 			break;
450 		case 3:
451 			boxcontent[0] &= ~(BIT(7));
452 			memcpy((u8 *) (boxcontent) + 1,
453 			       p_cmdbuffer, 3);
454 
455 			for (idx = 0; idx < 4; idx++) {
456 				rtl_write_byte(rtlpriv, box_reg + idx,
457 					       boxcontent[idx]);
458 			}
459 			break;
460 		case 4:
461 			boxcontent[0] |= (BIT(7));
462 			memcpy((u8 *) (boxextcontent),
463 			       p_cmdbuffer, 2);
464 			memcpy((u8 *) (boxcontent) + 1,
465 			       p_cmdbuffer + 2, 2);
466 
467 			for (idx = 0; idx < 2; idx++) {
468 				rtl_write_byte(rtlpriv, box_extreg + idx,
469 					       boxextcontent[idx]);
470 			}
471 
472 			for (idx = 0; idx < 4; idx++) {
473 				rtl_write_byte(rtlpriv, box_reg + idx,
474 					       boxcontent[idx]);
475 			}
476 			break;
477 		case 5:
478 			boxcontent[0] |= (BIT(7));
479 			memcpy((u8 *) (boxextcontent),
480 			       p_cmdbuffer, 2);
481 			memcpy((u8 *) (boxcontent) + 1,
482 			       p_cmdbuffer + 2, 3);
483 
484 			for (idx = 0; idx < 2; idx++) {
485 				rtl_write_byte(rtlpriv, box_extreg + idx,
486 					       boxextcontent[idx]);
487 			}
488 
489 			for (idx = 0; idx < 4; idx++) {
490 				rtl_write_byte(rtlpriv, box_reg + idx,
491 					       boxcontent[idx]);
492 			}
493 			break;
494 		default:
495 			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
496 				 ("switch case not process\n"));
497 			break;
498 		}
499 
500 		bwrite_sucess = true;
501 
502 		rtlhal->last_hmeboxnum = boxnum + 1;
503 		if (rtlhal->last_hmeboxnum == 4)
504 			rtlhal->last_hmeboxnum = 0;
505 
506 		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
507 			 ("pHalData->last_hmeboxnum  = %d\n",
508 			  rtlhal->last_hmeboxnum));
509 	}
510 
511 	spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
512 	rtlhal->h2c_setinprogress = false;
513 	spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
514 
515 	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("go out\n"));
516 }
517 
rtl92c_fill_h2c_cmd(struct ieee80211_hw * hw,u8 element_id,u32 cmd_len,u8 * p_cmdbuffer)518 void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
519 			 u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
520 {
521 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
522 	u32 tmp_cmdbuf[2];
523 
524 	if (rtlhal->fw_ready == false) {
525 		RT_ASSERT(false, ("return H2C cmd because of Fw "
526 				  "download fail!!!\n"));
527 		return;
528 	}
529 
530 	memset(tmp_cmdbuf, 0, 8);
531 	memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len);
532 	_rtl92c_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
533 
534 	return;
535 }
536 EXPORT_SYMBOL(rtl92c_fill_h2c_cmd);
537 
rtl92c_firmware_selfreset(struct ieee80211_hw * hw)538 void rtl92c_firmware_selfreset(struct ieee80211_hw *hw)
539 {
540 	u8 u1b_tmp;
541 	u8 delay = 100;
542 	struct rtl_priv *rtlpriv = rtl_priv(hw);
543 
544 	rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
545 	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
546 
547 	while (u1b_tmp & BIT(2)) {
548 		delay--;
549 		if (delay == 0) {
550 			RT_ASSERT(false, ("8051 reset fail.\n"));
551 			break;
552 		}
553 		udelay(50);
554 		u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
555 	}
556 }
557 EXPORT_SYMBOL(rtl92c_firmware_selfreset);
558 
rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw * hw,u8 mode)559 void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
560 {
561 	struct rtl_priv *rtlpriv = rtl_priv(hw);
562 	u8 u1_h2c_set_pwrmode[3] = {0};
563 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
564 
565 	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("FW LPS mode = %d\n", mode));
566 
567 	SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
568 	SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
569 	SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
570 					      ppsc->reg_max_lps_awakeintvl);
571 
572 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
573 		      "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
574 		      u1_h2c_set_pwrmode, 3);
575 	rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
576 
577 }
578 EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd);
579 
_rtl92c_cmd_send_packet(struct ieee80211_hw * hw,struct sk_buff * skb)580 static bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw,
581 				struct sk_buff *skb)
582 {
583 	struct rtl_priv *rtlpriv = rtl_priv(hw);
584 	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
585 	struct rtl8192_tx_ring *ring;
586 	struct rtl_tx_desc *pdesc;
587 	unsigned long flags;
588 	struct sk_buff *pskb = NULL;
589 
590 	ring = &rtlpci->tx_ring[BEACON_QUEUE];
591 
592 	pskb = __skb_dequeue(&ring->queue);
593 	if (pskb)
594 		kfree_skb(pskb);
595 
596 	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
597 
598 	pdesc = &ring->desc[0];
599 
600 	rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
601 
602 	__skb_queue_tail(&ring->queue, skb);
603 
604 	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
605 
606 	rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
607 
608 	return true;
609 }
610 
611 #define BEACON_PG		0 /*->1*/
612 #define PSPOLL_PG		2
613 #define NULL_PG			3
614 #define PROBERSP_PG		4 /*->5*/
615 
616 #define TOTAL_RESERVED_PKT_LEN	768
617 
618 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
619 	/* page 0 beacon */
620 	0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
621 	0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
622 	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
623 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
624 	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
625 	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
626 	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
627 	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
628 	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
629 	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
630 	0x03, 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 	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
634 	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
635 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
636 
637 	/* page 1 beacon */
638 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
639 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
640 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
641 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
642 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
643 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
644 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
645 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
646 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
647 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
648 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
649 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
650 	0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
651 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
652 	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
653 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
654 
655 	/* page 2  ps-poll */
656 	0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
657 	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
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 	0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
669 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
670 	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
671 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
672 
673 	/* page 3  null */
674 	0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
675 	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
676 	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
677 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
678 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
679 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
680 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
681 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
682 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
683 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
684 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
685 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
686 	0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
687 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
688 	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
689 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
690 
691 	/* page 4  probe_resp */
692 	0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
693 	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
694 	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
695 	0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
696 	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
697 	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
698 	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
699 	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
700 	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
701 	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
702 	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
703 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
704 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
705 	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
706 	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
707 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
708 
709 	/* page 5  probe_resp */
710 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
711 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
712 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
713 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
714 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
715 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
716 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
717 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
718 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
719 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
720 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
721 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
722 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
723 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
724 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
725 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
726 };
727 
rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw * hw,bool dl_finished)728 void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
729 {
730 	struct rtl_priv *rtlpriv = rtl_priv(hw);
731 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
732 	struct sk_buff *skb = NULL;
733 
734 	u32 totalpacketlen;
735 	bool rtstatus;
736 	u8 u1RsvdPageLoc[3] = {0};
737 	bool dlok = false;
738 
739 	u8 *beacon;
740 	u8 *pspoll;
741 	u8 *nullfunc;
742 	u8 *probersp;
743 	/*---------------------------------------------------------
744 				(1) beacon
745 	---------------------------------------------------------*/
746 	beacon = &reserved_page_packet[BEACON_PG * 128];
747 	SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
748 	SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
749 
750 	/*-------------------------------------------------------
751 				(2) ps-poll
752 	--------------------------------------------------------*/
753 	pspoll = &reserved_page_packet[PSPOLL_PG * 128];
754 	SET_80211_PS_POLL_AID(pspoll, (mac->assoc_id | 0xc000));
755 	SET_80211_PS_POLL_BSSID(pspoll, mac->bssid);
756 	SET_80211_PS_POLL_TA(pspoll, mac->mac_addr);
757 
758 	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
759 
760 	/*--------------------------------------------------------
761 				(3) null data
762 	---------------------------------------------------------*/
763 	nullfunc = &reserved_page_packet[NULL_PG * 128];
764 	SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
765 	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
766 	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
767 
768 	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
769 
770 	/*---------------------------------------------------------
771 				(4) probe response
772 	----------------------------------------------------------*/
773 	probersp = &reserved_page_packet[PROBERSP_PG * 128];
774 	SET_80211_HDR_ADDRESS1(probersp, mac->bssid);
775 	SET_80211_HDR_ADDRESS2(probersp, mac->mac_addr);
776 	SET_80211_HDR_ADDRESS3(probersp, mac->bssid);
777 
778 	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
779 
780 	totalpacketlen = TOTAL_RESERVED_PKT_LEN;
781 
782 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
783 		      "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
784 		      &reserved_page_packet[0], totalpacketlen);
785 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
786 		      "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
787 		      u1RsvdPageLoc, 3);
788 
789 
790 	skb = dev_alloc_skb(totalpacketlen);
791 	memcpy((u8 *) skb_put(skb, totalpacketlen),
792 	       &reserved_page_packet, totalpacketlen);
793 
794 	rtstatus = _rtl92c_cmd_send_packet(hw, skb);
795 
796 	if (rtstatus)
797 		dlok = true;
798 
799 	if (dlok) {
800 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
801 			 ("Set RSVD page location to Fw.\n"));
802 		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
803 				"H2C_RSVDPAGE:\n",
804 				u1RsvdPageLoc, 3);
805 		rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE,
806 				    sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
807 	} else
808 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
809 			 ("Set RSVD page location to Fw FAIL!!!!!!.\n"));
810 }
811 EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt);
812 
rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw * hw,u8 mstatus)813 void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
814 {
815 	u8 u1_joinbssrpt_parm[1] = {0};
816 
817 	SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
818 
819 	rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
820 }
821 EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd);
822