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
38static 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
44static 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
66static 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
92static 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
104static 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
118static 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
149static 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
173void 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
194static 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
242int 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	}
340exit:
341	err = _rtl92d_fw_init(hw);
342	return err;
343}
344
345static 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
357static 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
532void 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
543static bool _rtl92d_cmd_send_packet(struct ieee80211_hw *hw,
544				    struct sk_buff *skb)
545{
546	struct rtl_priv *rtlpriv = rtl_priv(hw);
547	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
548	struct rtl8192_tx_ring *ring;
549	struct rtl_tx_desc *pdesc;
550	u8 idx = 0;
551	unsigned long flags;
552	struct sk_buff *pskb;
553
554	ring = &rtlpci->tx_ring[BEACON_QUEUE];
555	pskb = __skb_dequeue(&ring->queue);
556	kfree_skb(pskb);
557	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
558	pdesc = &ring->desc[idx];
559	/* discard output from call below */
560	rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN);
561	rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
562	__skb_queue_tail(&ring->queue, skb);
563	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
564	rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
565	return true;
566}
567
568#define BEACON_PG		0	/*->1 */
569#define PSPOLL_PG		2
570#define NULL_PG			3
571#define PROBERSP_PG		4	/*->5 */
572#define TOTAL_RESERVED_PKT_LEN	768
573
574static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
575	/* page 0 beacon */
576	0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
577	0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
578	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
579	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
580	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
581	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
582	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
583	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
584	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
585	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
586	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
587	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
588	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
589	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
590	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
591	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
592
593	/* page 1 beacon */
594	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
595	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
596	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
597	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
598	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
599	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
600	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
601	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
602	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
603	0x00, 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	0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
607	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
608	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
609	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
610
611	/* page 2  ps-poll */
612	0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
613	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
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	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
624	0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
625	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
626	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
627	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
628
629	/* page 3  null */
630	0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
631	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
632	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 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	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
642	0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
643	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
644	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
645	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
646
647	/* page 4  probe_resp */
648	0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
649	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
650	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
651	0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
652	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
653	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
654	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
655	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
656	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
657	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
658	0x03, 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	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
662	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
663	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
664
665	/* page 5  probe_resp */
666	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
667	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
668	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
669	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
670	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
671	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
672	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
673	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
674	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
675	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
676	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
677	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
678	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};
683
684void rtl92d_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
685{
686	struct rtl_priv *rtlpriv = rtl_priv(hw);
687	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
688	struct sk_buff *skb = NULL;
689	u32 totalpacketlen;
690	bool rtstatus;
691	u8 u1RsvdPageLoc[3] = { 0 };
692	bool dlok = false;
693	u8 *beacon;
694	u8 *p_pspoll;
695	u8 *nullfunc;
696	u8 *p_probersp;
697	/*---------------------------------------------------------
698						(1) beacon
699	---------------------------------------------------------*/
700	beacon = &reserved_page_packet[BEACON_PG * 128];
701	SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
702	SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
703	/*-------------------------------------------------------
704						(2) ps-poll
705	--------------------------------------------------------*/
706	p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
707	SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
708	SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
709	SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
710	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
711	/*--------------------------------------------------------
712						(3) null data
713	---------------------------------------------------------*/
714	nullfunc = &reserved_page_packet[NULL_PG * 128];
715	SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
716	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
717	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
718	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
719	/*---------------------------------------------------------
720						(4) probe response
721	----------------------------------------------------------*/
722	p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
723	SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
724	SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
725	SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
726	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
727	totalpacketlen = TOTAL_RESERVED_PKT_LEN;
728	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
729		      "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL",
730		      &reserved_page_packet[0], totalpacketlen);
731	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
732		      "rtl92d_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL",
733		      u1RsvdPageLoc, 3);
734	skb = dev_alloc_skb(totalpacketlen);
735	if (!skb) {
736		dlok = false;
737	} else {
738		memcpy((u8 *) skb_put(skb, totalpacketlen),
739			&reserved_page_packet, totalpacketlen);
740		rtstatus = _rtl92d_cmd_send_packet(hw, skb);
741
742		if (rtstatus)
743			dlok = true;
744	}
745	if (dlok) {
746		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
747			 "Set RSVD page location to Fw\n");
748		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
749			      "H2C_RSVDPAGE", u1RsvdPageLoc, 3);
750		rtl92d_fill_h2c_cmd(hw, H2C_RSVDPAGE,
751			sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
752	} else
753		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
754			 "Set RSVD page location to Fw FAIL!!!!!!\n");
755}
756
757void rtl92d_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
758{
759	u8 u1_joinbssrpt_parm[1] = {0};
760
761	SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
762	rtl92d_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
763}
764