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_common.c (22867B)


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