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