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