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