cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fw.c (21785B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* Copyright(c) 2009-2013  Realtek Corporation.*/
      3
      4#include "../wifi.h"
      5#include "../pci.h"
      6#include "../base.h"
      7#include "../core.h"
      8#include "../efuse.h"
      9#include "reg.h"
     10#include "def.h"
     11#include "fw.h"
     12
     13static void _rtl88e_enable_fw_download(struct ieee80211_hw *hw, bool enable)
     14{
     15	struct rtl_priv *rtlpriv = rtl_priv(hw);
     16	u8 tmp;
     17
     18	if (enable) {
     19		tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
     20		rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04);
     21
     22		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
     23		rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
     24
     25		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
     26		rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
     27	} else {
     28		tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
     29		rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
     30
     31		rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
     32	}
     33}
     34
     35static void _rtl88e_write_fw(struct ieee80211_hw *hw,
     36			     enum version_8188e version, u8 *buffer, u32 size)
     37{
     38	struct rtl_priv *rtlpriv = rtl_priv(hw);
     39	u8 *bufferptr = (u8 *)buffer;
     40	u32 pagenums, remainsize;
     41	u32 page, offset;
     42
     43	rtl_dbg(rtlpriv, COMP_FW, DBG_LOUD, "FW size is %d bytes,\n", size);
     44
     45	rtl_fill_dummy(bufferptr, &size);
     46
     47	pagenums = size / FW_8192C_PAGE_SIZE;
     48	remainsize = size % FW_8192C_PAGE_SIZE;
     49
     50	if (pagenums > 8)
     51		pr_err("Page numbers should not greater then 8\n");
     52
     53	for (page = 0; page < pagenums; page++) {
     54		offset = page * FW_8192C_PAGE_SIZE;
     55		rtl_fw_page_write(hw, page, (bufferptr + offset),
     56				  FW_8192C_PAGE_SIZE);
     57	}
     58
     59	if (remainsize) {
     60		offset = pagenums * FW_8192C_PAGE_SIZE;
     61		page = pagenums;
     62		rtl_fw_page_write(hw, page, (bufferptr + offset), remainsize);
     63	}
     64}
     65
     66static int _rtl88e_fw_free_to_go(struct ieee80211_hw *hw)
     67{
     68	struct rtl_priv *rtlpriv = rtl_priv(hw);
     69	int err = -EIO;
     70	u32 counter = 0;
     71	u32 value32;
     72
     73	do {
     74		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
     75	} while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
     76		 (!(value32 & FWDL_CHKSUM_RPT)));
     77
     78	if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
     79		pr_err("chksum report fail! REG_MCUFWDL:0x%08x .\n",
     80		       value32);
     81		goto exit;
     82	}
     83	value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
     84	value32 |= MCUFWDL_RDY;
     85	value32 &= ~WINTINI_RDY;
     86	rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
     87
     88	rtl88e_firmware_selfreset(hw);
     89	counter = 0;
     90
     91	do {
     92		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
     93		if (value32 & WINTINI_RDY)
     94			return 0;
     95
     96		udelay(FW_8192C_POLLING_DELAY);
     97
     98	} while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
     99
    100	pr_err("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n",
    101	       value32);
    102
    103exit:
    104	return err;
    105}
    106
    107int rtl88e_download_fw(struct ieee80211_hw *hw,
    108		       bool buse_wake_on_wlan_fw)
    109{
    110	struct rtl_priv *rtlpriv = rtl_priv(hw);
    111	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
    112	struct rtlwifi_firmware_header *pfwheader;
    113	u8 *pfwdata;
    114	u32 fwsize;
    115	int err;
    116	enum version_8188e version = rtlhal->version;
    117
    118	if (!rtlhal->pfirmware)
    119		return 1;
    120
    121	pfwheader = (struct rtlwifi_firmware_header *)rtlhal->pfirmware;
    122	rtlhal->fw_version = le16_to_cpu(pfwheader->version);
    123	rtlhal->fw_subversion = pfwheader->subversion;
    124	pfwdata = rtlhal->pfirmware;
    125	fwsize = rtlhal->fwsize;
    126	rtl_dbg(rtlpriv, COMP_FW, DBG_DMESG,
    127		"normal Firmware SIZE %d\n", fwsize);
    128
    129	if (IS_FW_HEADER_EXIST(pfwheader)) {
    130		rtl_dbg(rtlpriv, COMP_FW, DBG_DMESG,
    131			"Firmware Version(%d), Signature(%#x), Size(%d)\n",
    132			pfwheader->version, pfwheader->signature,
    133			(int)sizeof(struct rtlwifi_firmware_header));
    134
    135		pfwdata = pfwdata + sizeof(struct rtlwifi_firmware_header);
    136		fwsize = fwsize - sizeof(struct rtlwifi_firmware_header);
    137	}
    138
    139	if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
    140		rtl_write_byte(rtlpriv, REG_MCUFWDL, 0);
    141		rtl88e_firmware_selfreset(hw);
    142	}
    143	_rtl88e_enable_fw_download(hw, true);
    144	_rtl88e_write_fw(hw, version, pfwdata, fwsize);
    145	_rtl88e_enable_fw_download(hw, false);
    146
    147	err = _rtl88e_fw_free_to_go(hw);
    148	if (err)
    149		pr_err("Firmware is not ready to run!\n");
    150
    151	return 0;
    152}
    153
    154static bool _rtl88e_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
    155{
    156	struct rtl_priv *rtlpriv = rtl_priv(hw);
    157	u8 val_hmetfr;
    158
    159	val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
    160	if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
    161		return true;
    162	return false;
    163}
    164
    165static void _rtl88e_fill_h2c_command(struct ieee80211_hw *hw,
    166				     u8 element_id, u32 cmd_len,
    167				     u8 *cmd_b)
    168{
    169	struct rtl_priv *rtlpriv = rtl_priv(hw);
    170	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
    171	u8 boxnum;
    172	u16 box_reg = 0, box_extreg = 0;
    173	u8 u1b_tmp;
    174	bool isfw_read = false;
    175	u8 buf_index = 0;
    176	bool write_sucess = false;
    177	u8 wait_h2c_limmit = 100;
    178	u8 wait_writeh2c_limit = 100;
    179	u8 boxcontent[4], boxextcontent[4];
    180	u32 h2c_waitcounter = 0;
    181	unsigned long flag;
    182	u8 idx;
    183
    184	rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
    185
    186	while (true) {
    187		spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
    188		if (rtlhal->h2c_setinprogress) {
    189			rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
    190				"H2C set in progress! Wait to set..element_id(%d).\n",
    191				element_id);
    192
    193			while (rtlhal->h2c_setinprogress) {
    194				spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
    195						       flag);
    196				h2c_waitcounter++;
    197				rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
    198					"Wait 100 us (%d times)...\n",
    199					h2c_waitcounter);
    200				udelay(100);
    201
    202				if (h2c_waitcounter > 1000)
    203					return;
    204				spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
    205						  flag);
    206			}
    207			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
    208		} else {
    209			rtlhal->h2c_setinprogress = true;
    210			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
    211			break;
    212		}
    213	}
    214
    215	while (!write_sucess) {
    216		wait_writeh2c_limit--;
    217		if (wait_writeh2c_limit == 0) {
    218			pr_err("Write H2C fail because no trigger for FW INT!\n");
    219			break;
    220		}
    221
    222		boxnum = rtlhal->last_hmeboxnum;
    223		switch (boxnum) {
    224		case 0:
    225			box_reg = REG_HMEBOX_0;
    226			box_extreg = REG_HMEBOX_EXT_0;
    227			break;
    228		case 1:
    229			box_reg = REG_HMEBOX_1;
    230			box_extreg = REG_HMEBOX_EXT_1;
    231			break;
    232		case 2:
    233			box_reg = REG_HMEBOX_2;
    234			box_extreg = REG_HMEBOX_EXT_2;
    235			break;
    236		case 3:
    237			box_reg = REG_HMEBOX_3;
    238			box_extreg = REG_HMEBOX_EXT_3;
    239			break;
    240		default:
    241			rtl_dbg(rtlpriv, COMP_ERR, DBG_LOUD,
    242				"switch case %#x not processed\n", boxnum);
    243			break;
    244		}
    245		isfw_read = _rtl88e_check_fw_read_last_h2c(hw, boxnum);
    246		while (!isfw_read) {
    247			wait_h2c_limmit--;
    248			if (wait_h2c_limmit == 0) {
    249				rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
    250					"Waiting too long for FW read clear HMEBox(%d)!\n",
    251					boxnum);
    252				break;
    253			}
    254
    255			udelay(10);
    256
    257			isfw_read = _rtl88e_check_fw_read_last_h2c(hw, boxnum);
    258			u1b_tmp = rtl_read_byte(rtlpriv, 0x130);
    259			rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
    260				"Waiting for FW read clear HMEBox(%d)!!! 0x130 = %2x\n",
    261				boxnum, u1b_tmp);
    262		}
    263
    264		if (!isfw_read) {
    265			rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
    266				"Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
    267				boxnum);
    268			break;
    269		}
    270
    271		memset(boxcontent, 0, sizeof(boxcontent));
    272		memset(boxextcontent, 0, sizeof(boxextcontent));
    273		boxcontent[0] = element_id;
    274		rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
    275			"Write element_id box_reg(%4x) = %2x\n",
    276			box_reg, element_id);
    277
    278		switch (cmd_len) {
    279		case 1:
    280		case 2:
    281		case 3:
    282			/*boxcontent[0] &= ~(BIT(7));*/
    283			memcpy((u8 *)(boxcontent) + 1,
    284			       cmd_b + buf_index, cmd_len);
    285
    286			for (idx = 0; idx < 4; idx++) {
    287				rtl_write_byte(rtlpriv, box_reg + idx,
    288					       boxcontent[idx]);
    289			}
    290			break;
    291		case 4:
    292		case 5:
    293		case 6:
    294		case 7:
    295			/*boxcontent[0] |= (BIT(7));*/
    296			memcpy((u8 *)(boxextcontent),
    297			       cmd_b + buf_index+3, cmd_len-3);
    298			memcpy((u8 *)(boxcontent) + 1,
    299			       cmd_b + buf_index, 3);
    300
    301			for (idx = 0; idx < 2; idx++) {
    302				rtl_write_byte(rtlpriv, box_extreg + idx,
    303					       boxextcontent[idx]);
    304			}
    305
    306			for (idx = 0; idx < 4; idx++) {
    307				rtl_write_byte(rtlpriv, box_reg + idx,
    308					       boxcontent[idx]);
    309			}
    310			break;
    311		default:
    312			rtl_dbg(rtlpriv, COMP_ERR, DBG_LOUD,
    313				"switch case %#x not processed\n", cmd_len);
    314			break;
    315		}
    316
    317		write_sucess = true;
    318
    319		rtlhal->last_hmeboxnum = boxnum + 1;
    320		if (rtlhal->last_hmeboxnum == 4)
    321			rtlhal->last_hmeboxnum = 0;
    322
    323		rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD,
    324			"pHalData->last_hmeboxnum  = %d\n",
    325			rtlhal->last_hmeboxnum);
    326	}
    327
    328	spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
    329	rtlhal->h2c_setinprogress = false;
    330	spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
    331
    332	rtl_dbg(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
    333}
    334
    335void rtl88e_fill_h2c_cmd(struct ieee80211_hw *hw,
    336			 u8 element_id, u32 cmd_len, u8 *cmdbuffer)
    337{
    338	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
    339	u32 tmp_cmdbuf[2];
    340
    341	if (!rtlhal->fw_ready) {
    342		WARN_ONCE(true,
    343			  "rtl8188ee: error H2C cmd because of Fw download fail!!!\n");
    344		return;
    345	}
    346
    347	memset(tmp_cmdbuf, 0, 8);
    348	memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
    349	_rtl88e_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
    350
    351	return;
    352}
    353
    354void rtl88e_firmware_selfreset(struct ieee80211_hw *hw)
    355{
    356	u8 u1b_tmp;
    357	struct rtl_priv *rtlpriv = rtl_priv(hw);
    358
    359	u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1);
    360	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp & (~BIT(2))));
    361	rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp | BIT(2)));
    362	rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,
    363		"8051Reset88E(): 8051 reset success\n");
    364
    365}
    366
    367void rtl88e_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
    368{
    369	struct rtl_priv *rtlpriv = rtl_priv(hw);
    370	u8 u1_h2c_set_pwrmode[H2C_88E_PWEMODE_LENGTH] = { 0 };
    371	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
    372	u8 rlbm, power_state = 0;
    373	rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
    374
    375	set_h2ccmd_pwrmode_parm_mode(u1_h2c_set_pwrmode, ((mode) ? 1 : 0));
    376	rlbm = 0;/*YJ, temp, 120316. FW now not support RLBM=2.*/
    377	set_h2ccmd_pwrmode_parm_rlbm(u1_h2c_set_pwrmode, rlbm);
    378	set_h2ccmd_pwrmode_parm_smart_ps(u1_h2c_set_pwrmode,
    379		(rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1);
    380	set_h2ccmd_pwrmode_parm_awake_interval(u1_h2c_set_pwrmode,
    381		ppsc->reg_max_lps_awakeintvl);
    382	set_h2ccmd_pwrmode_parm_all_queue_uapsd(u1_h2c_set_pwrmode, 0);
    383	if (mode == FW_PS_ACTIVE_MODE)
    384		power_state |= FW_PWR_STATE_ACTIVE;
    385	else
    386		power_state |= FW_PWR_STATE_RF_OFF;
    387
    388	set_h2ccmd_pwrmode_parm_pwr_state(u1_h2c_set_pwrmode, power_state);
    389
    390	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
    391		      "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n",
    392		      u1_h2c_set_pwrmode, H2C_88E_PWEMODE_LENGTH);
    393	rtl88e_fill_h2c_cmd(hw, H2C_88E_SETPWRMODE,
    394			    H2C_88E_PWEMODE_LENGTH, u1_h2c_set_pwrmode);
    395}
    396
    397void rtl88e_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
    398{
    399	u8 u1_joinbssrpt_parm[1] = { 0 };
    400
    401	SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
    402
    403	rtl88e_fill_h2c_cmd(hw, H2C_88E_JOINBSSRPT, 1, u1_joinbssrpt_parm);
    404}
    405
    406void rtl88e_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw,
    407				   u8 ap_offload_enable)
    408{
    409	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
    410	u8 u1_apoffload_parm[H2C_88E_AP_OFFLOAD_LENGTH] = { 0 };
    411
    412	SET_H2CCMD_AP_OFFLOAD_ON(u1_apoffload_parm, ap_offload_enable);
    413	SET_H2CCMD_AP_OFFLOAD_HIDDEN(u1_apoffload_parm, mac->hiddenssid);
    414	SET_H2CCMD_AP_OFFLOAD_DENYANY(u1_apoffload_parm, 0);
    415
    416	rtl88e_fill_h2c_cmd(hw, H2C_88E_AP_OFFLOAD,
    417			    H2C_88E_AP_OFFLOAD_LENGTH, u1_apoffload_parm);
    418
    419}
    420
    421#define BEACON_PG		0 /* ->1 */
    422#define PSPOLL_PG		2
    423#define NULL_PG			3
    424#define PROBERSP_PG		4 /* ->5 */
    425
    426#define TOTAL_RESERVED_PKT_LEN	768
    427
    428static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
    429	/* page 0 beacon */
    430	0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
    431	0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
    432	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
    433	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    434	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
    435	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
    436	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
    437	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
    438	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
    439	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
    440	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    441	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    442	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    443	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
    444	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    445	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    446
    447	/* page 1 beacon */
    448	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    449	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    450	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    451	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    452	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    453	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    454	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    455	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    456	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    457	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    458	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    459	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    460	0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
    461	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    462	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    463	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    464
    465	/* page 2  ps-poll */
    466	0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
    467	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
    468	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    469	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    470	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    471	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    472	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    473	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    474	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    475	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    476	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    477	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    478	0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
    479	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
    480	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    481	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    482
    483	/* page 3  null */
    484	0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
    485	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
    486	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
    487	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    488	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    489	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    490	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    491	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    492	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    493	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    494	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    495	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    496	0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
    497	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
    498	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    499	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    500
    501	/* page 4  probe_resp */
    502	0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
    503	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
    504	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
    505	0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
    506	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
    507	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
    508	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
    509	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
    510	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
    511	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
    512	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    513	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    514	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    515	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
    516	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    517	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    518
    519	/* page 5  probe_resp */
    520	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    521	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    522	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    523	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    524	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    525	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    526	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    527	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    528	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    529	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    530	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    531	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    532	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    533	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    534	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    535	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    536};
    537
    538void rtl88e_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
    539{
    540	struct rtl_priv *rtlpriv = rtl_priv(hw);
    541	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
    542	struct sk_buff *skb = NULL;
    543	u32 totalpacketlen;
    544	bool rtstatus;
    545	u8 u1rsvdpageloc[5] = { 0 };
    546	bool b_dlok = false;
    547	u8 *beacon;
    548	u8 *p_pspoll;
    549	u8 *nullfunc;
    550	u8 *p_probersp;
    551
    552	/*---------------------------------------------------------
    553	 *			(1) beacon
    554	 *---------------------------------------------------------
    555	 */
    556	beacon = &reserved_page_packet[BEACON_PG * 128];
    557	SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
    558	SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
    559
    560	/*-------------------------------------------------------
    561	 *			(2) ps-poll
    562	 *--------------------------------------------------------
    563	 */
    564	p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
    565	SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
    566	SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
    567	SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
    568
    569	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
    570
    571	/*--------------------------------------------------------
    572	 *			(3) null data
    573	 *---------------------------------------------------------
    574	 */
    575	nullfunc = &reserved_page_packet[NULL_PG * 128];
    576	SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
    577	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
    578	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
    579
    580	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
    581
    582	/*---------------------------------------------------------
    583	 *			(4) probe response
    584	 *----------------------------------------------------------
    585	 */
    586	p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
    587	SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
    588	SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
    589	SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
    590
    591	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
    592
    593	totalpacketlen = TOTAL_RESERVED_PKT_LEN;
    594
    595	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
    596		      "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
    597		      &reserved_page_packet[0], totalpacketlen);
    598	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
    599		      "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
    600		      u1rsvdpageloc, 3);
    601
    602	skb = dev_alloc_skb(totalpacketlen);
    603	if (!skb)
    604		return;
    605	skb_put_data(skb, &reserved_page_packet, totalpacketlen);
    606
    607	rtstatus = rtl_cmd_send_packet(hw, skb);
    608
    609	if (rtstatus)
    610		b_dlok = true;
    611
    612	if (b_dlok) {
    613		rtl_dbg(rtlpriv, COMP_POWER, DBG_LOUD,
    614			"Set RSVD page location to Fw.\n");
    615		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
    616			      "H2C_RSVDPAGE:\n", u1rsvdpageloc, 3);
    617		rtl88e_fill_h2c_cmd(hw, H2C_88E_RSVDPAGE,
    618				    sizeof(u1rsvdpageloc), u1rsvdpageloc);
    619	} else
    620		rtl_dbg(rtlpriv, COMP_ERR, DBG_WARNING,
    621			"Set RSVD page location to Fw FAIL!!!!!!.\n");
    622}
    623
    624/*Should check FW support p2p or not.*/
    625static void rtl88e_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
    626{
    627	u8 u1_ctwindow_period[1] = { ctwindow};
    628
    629	rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
    630
    631}
    632
    633void rtl88e_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
    634{
    635	struct rtl_priv *rtlpriv = rtl_priv(hw);
    636	struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
    637	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
    638	struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
    639	struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
    640	u8	i;
    641	u16	ctwindow;
    642	u32	start_time, tsf_low;
    643
    644	switch (p2p_ps_state) {
    645	case P2P_PS_DISABLE:
    646		rtl_dbg(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
    647		memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
    648		break;
    649	case P2P_PS_ENABLE:
    650		rtl_dbg(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
    651		/* update CTWindow value. */
    652		if (p2pinfo->ctwindow > 0) {
    653			p2p_ps_offload->ctwindow_en = 1;
    654			ctwindow = p2pinfo->ctwindow;
    655			rtl88e_set_p2p_ctw_period_cmd(hw, ctwindow);
    656		}
    657
    658		/* hw only support 2 set of NoA */
    659		for (i = 0 ; i < p2pinfo->noa_num; i++) {
    660			/* To control the register setting for which NOA*/
    661			rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
    662			if (i == 0)
    663				p2p_ps_offload->noa0_en = 1;
    664			else
    665				p2p_ps_offload->noa1_en = 1;
    666
    667			/* config P2P NoA Descriptor Register */
    668			rtl_write_dword(rtlpriv, 0x5E0,
    669					p2pinfo->noa_duration[i]);
    670			rtl_write_dword(rtlpriv, 0x5E4,
    671					p2pinfo->noa_interval[i]);
    672
    673			/*Get Current TSF value */
    674			tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
    675
    676			start_time = p2pinfo->noa_start_time[i];
    677			if (p2pinfo->noa_count_type[i] != 1) {
    678				while (start_time <= (tsf_low+(50*1024))) {
    679					start_time += p2pinfo->noa_interval[i];
    680					if (p2pinfo->noa_count_type[i] != 255)
    681						p2pinfo->noa_count_type[i]--;
    682				}
    683			}
    684			rtl_write_dword(rtlpriv, 0x5E8, start_time);
    685			rtl_write_dword(rtlpriv, 0x5EC,
    686					p2pinfo->noa_count_type[i]);
    687		}
    688
    689		if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
    690			/* rst p2p circuit */
    691			rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
    692
    693			p2p_ps_offload->offload_en = 1;
    694
    695			if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
    696				p2p_ps_offload->role = 1;
    697				p2p_ps_offload->allstasleep = -1;
    698			} else {
    699				p2p_ps_offload->role = 0;
    700			}
    701
    702			p2p_ps_offload->discovery = 0;
    703		}
    704		break;
    705	case P2P_PS_SCAN:
    706		rtl_dbg(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
    707		p2p_ps_offload->discovery = 1;
    708		break;
    709	case P2P_PS_SCAN_DONE:
    710		rtl_dbg(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n");
    711		p2p_ps_offload->discovery = 0;
    712		p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
    713		break;
    714	default:
    715		break;
    716	}
    717
    718	rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_OFFLOAD, 1,
    719			    (u8 *)p2p_ps_offload);
    720
    721}