Linux Audio

Check our new training course

Loading...
  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
 39static 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
 74static 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
102static 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
137static 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
150static 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
166static 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 = (u8 *) 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
207static 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
252int 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 = (u8 *) 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}
293EXPORT_SYMBOL(rtl92c_download_fw);
294
295static 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
309static 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_sucess = 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_sucess) {
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_sucess = 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
512void 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}
523EXPORT_SYMBOL(rtl92c_fill_h2c_cmd);
524
525void 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}
544EXPORT_SYMBOL(rtl92c_firmware_selfreset);
545
546void 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, 1);
556	SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
557					      ppsc->reg_max_lps_awakeintvl);
558
559	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
560		      "rtl92c_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode",
561		      u1_h2c_set_pwrmode, 3);
562	rtl92c_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
563
564}
565EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd);
566
567static bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw,
568				struct sk_buff *skb)
569{
570	struct rtl_priv *rtlpriv = rtl_priv(hw);
571	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
572	struct rtl8192_tx_ring *ring;
573	struct rtl_tx_desc *pdesc;
574	unsigned long flags;
575	struct sk_buff *pskb = NULL;
576
577	ring = &rtlpci->tx_ring[BEACON_QUEUE];
578
579	pskb = __skb_dequeue(&ring->queue);
580	if (pskb)
581		kfree_skb(pskb);
582
583	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
584
585	pdesc = &ring->desc[0];
586
587	rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
588
589	__skb_queue_tail(&ring->queue, skb);
590
591	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
592
593	rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
594
595	return true;
596}
597
598#define BEACON_PG		0 /*->1*/
599#define PSPOLL_PG		2
600#define NULL_PG			3
601#define PROBERSP_PG		4 /*->5*/
602
603#define TOTAL_RESERVED_PKT_LEN	768
604
605static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
606	/* page 0 beacon */
607	0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
608	0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
609	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
610	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
611	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
612	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
613	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
614	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
615	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
616	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
617	0x03, 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	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
621	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
622	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
623
624	/* page 1 beacon */
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	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
637	0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
638	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
639	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
640	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
641
642	/* page 2  ps-poll */
643	0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
644	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
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	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
655	0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
656	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
657	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
658	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
659
660	/* page 3  null */
661	0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
662	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
663	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 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	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
673	0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
674	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
675	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
676	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
677
678	/* page 4  probe_resp */
679	0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
680	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
681	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
682	0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
683	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
684	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
685	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
686	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
687	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
688	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
689	0x03, 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	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
693	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
694	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
695
696	/* page 5  probe_resp */
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	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
713};
714
715void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
716{
717	struct rtl_priv *rtlpriv = rtl_priv(hw);
718	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
719	struct sk_buff *skb = NULL;
720
721	u32 totalpacketlen;
722	bool rtstatus;
723	u8 u1RsvdPageLoc[3] = {0};
724	bool dlok = false;
725
726	u8 *beacon;
727	u8 *pspoll;
728	u8 *nullfunc;
729	u8 *probersp;
730	/*---------------------------------------------------------
731				(1) beacon
732	---------------------------------------------------------*/
733	beacon = &reserved_page_packet[BEACON_PG * 128];
734	SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
735	SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
736
737	/*-------------------------------------------------------
738				(2) ps-poll
739	--------------------------------------------------------*/
740	pspoll = &reserved_page_packet[PSPOLL_PG * 128];
741	SET_80211_PS_POLL_AID(pspoll, (mac->assoc_id | 0xc000));
742	SET_80211_PS_POLL_BSSID(pspoll, mac->bssid);
743	SET_80211_PS_POLL_TA(pspoll, mac->mac_addr);
744
745	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
746
747	/*--------------------------------------------------------
748				(3) null data
749	---------------------------------------------------------*/
750	nullfunc = &reserved_page_packet[NULL_PG * 128];
751	SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
752	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
753	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
754
755	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
756
757	/*---------------------------------------------------------
758				(4) probe response
759	----------------------------------------------------------*/
760	probersp = &reserved_page_packet[PROBERSP_PG * 128];
761	SET_80211_HDR_ADDRESS1(probersp, mac->bssid);
762	SET_80211_HDR_ADDRESS2(probersp, mac->mac_addr);
763	SET_80211_HDR_ADDRESS3(probersp, mac->bssid);
764
765	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
766
767	totalpacketlen = TOTAL_RESERVED_PKT_LEN;
768
769	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
770		      "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL",
771		      &reserved_page_packet[0], totalpacketlen);
772	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
773		      "rtl92c_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL",
774		      u1RsvdPageLoc, 3);
775
776
777	skb = dev_alloc_skb(totalpacketlen);
778	if (!skb)
779		return;
780	kmemleak_not_leak(skb);
781
782	memcpy((u8 *) skb_put(skb, totalpacketlen),
783	       &reserved_page_packet, totalpacketlen);
784
785	rtstatus = _rtl92c_cmd_send_packet(hw, skb);
786
787	if (rtstatus)
788		dlok = true;
789
790	if (dlok) {
791		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
792			 "Set RSVD page location to Fw\n");
793		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
794			      "H2C_RSVDPAGE", u1RsvdPageLoc, 3);
795		rtl92c_fill_h2c_cmd(hw, H2C_RSVDPAGE,
796				    sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
797	} else
798		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
799			 "Set RSVD page location to Fw FAIL!!!!!!\n");
800}
801EXPORT_SYMBOL(rtl92c_set_fw_rsvdpagepkt);
802
803void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
804{
805	u8 u1_joinbssrpt_parm[1] = {0};
806
807	SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
808
809	rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
810}
811EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd);