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 (16246B)


      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 "reg.h"
      8#include "def.h"
      9#include "fw.h"
     10
     11static void _rtl92s_fw_set_rqpn(struct ieee80211_hw *hw)
     12{
     13	struct rtl_priv *rtlpriv = rtl_priv(hw);
     14
     15	rtl_write_dword(rtlpriv, RQPN, 0xffffffff);
     16	rtl_write_dword(rtlpriv, RQPN + 4, 0xffffffff);
     17	rtl_write_byte(rtlpriv, RQPN + 8, 0xff);
     18	rtl_write_byte(rtlpriv, RQPN + 0xB, 0x80);
     19}
     20
     21static bool _rtl92s_firmware_enable_cpu(struct ieee80211_hw *hw)
     22{
     23	struct rtl_priv *rtlpriv = rtl_priv(hw);
     24	u32 ichecktime = 200;
     25	u16 tmpu2b;
     26	u8 tmpu1b, cpustatus = 0;
     27
     28	_rtl92s_fw_set_rqpn(hw);
     29
     30	/* Enable CPU. */
     31	tmpu1b = rtl_read_byte(rtlpriv, SYS_CLKR);
     32	/* AFE source */
     33	rtl_write_byte(rtlpriv, SYS_CLKR, (tmpu1b | SYS_CPU_CLKSEL));
     34
     35	tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN);
     36	rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | FEN_CPUEN));
     37
     38	/* Polling IMEM Ready after CPU has refilled. */
     39	do {
     40		cpustatus = rtl_read_byte(rtlpriv, TCR);
     41		if (cpustatus & IMEM_RDY) {
     42			rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,
     43				"IMEM Ready after CPU has refilled\n");
     44			break;
     45		}
     46
     47		udelay(100);
     48	} while (ichecktime--);
     49
     50	if (!(cpustatus & IMEM_RDY))
     51		return false;
     52
     53	return true;
     54}
     55
     56static enum fw_status _rtl92s_firmware_get_nextstatus(
     57		enum fw_status fw_currentstatus)
     58{
     59	enum fw_status	next_fwstatus = 0;
     60
     61	switch (fw_currentstatus) {
     62	case FW_STATUS_INIT:
     63		next_fwstatus = FW_STATUS_LOAD_IMEM;
     64		break;
     65	case FW_STATUS_LOAD_IMEM:
     66		next_fwstatus = FW_STATUS_LOAD_EMEM;
     67		break;
     68	case FW_STATUS_LOAD_EMEM:
     69		next_fwstatus = FW_STATUS_LOAD_DMEM;
     70		break;
     71	case FW_STATUS_LOAD_DMEM:
     72		next_fwstatus = FW_STATUS_READY;
     73		break;
     74	default:
     75		break;
     76	}
     77
     78	return next_fwstatus;
     79}
     80
     81static u8 _rtl92s_firmware_header_map_rftype(struct ieee80211_hw *hw)
     82{
     83	struct rtl_priv *rtlpriv = rtl_priv(hw);
     84	struct rtl_phy *rtlphy = &(rtlpriv->phy);
     85
     86	switch (rtlphy->rf_type) {
     87	case RF_1T1R:
     88		return 0x11;
     89	case RF_1T2R:
     90		return 0x12;
     91	case RF_2T2R:
     92		return 0x22;
     93	default:
     94		pr_err("Unknown RF type(%x)\n", rtlphy->rf_type);
     95		break;
     96	}
     97	return 0x22;
     98}
     99
    100static void _rtl92s_firmwareheader_priveupdate(struct ieee80211_hw *hw,
    101		struct fw_priv *pfw_priv)
    102{
    103	/* Update RF types for RATR settings. */
    104	pfw_priv->rf_config = _rtl92s_firmware_header_map_rftype(hw);
    105}
    106
    107
    108
    109static bool _rtl92s_cmd_send_packet(struct ieee80211_hw *hw,
    110		struct sk_buff *skb, u8 last)
    111{
    112	struct rtl_priv *rtlpriv = rtl_priv(hw);
    113	struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
    114	struct rtl8192_tx_ring *ring;
    115	struct rtl_tx_desc *pdesc;
    116	unsigned long flags;
    117	u8 idx = 0;
    118
    119	ring = &rtlpci->tx_ring[TXCMD_QUEUE];
    120
    121	spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
    122
    123	idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries;
    124	pdesc = &ring->desc[idx];
    125	rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb);
    126	__skb_queue_tail(&ring->queue, skb);
    127
    128	spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
    129
    130	return true;
    131}
    132
    133static bool _rtl92s_firmware_downloadcode(struct ieee80211_hw *hw,
    134		u8 *code_virtual_address, u32 buffer_len)
    135{
    136	struct rtl_priv *rtlpriv = rtl_priv(hw);
    137	struct sk_buff *skb;
    138	struct rtl_tcb_desc *tcb_desc;
    139	u16 frag_threshold = MAX_FIRMWARE_CODE_SIZE;
    140	u16 frag_length, frag_offset = 0;
    141	u16 extra_descoffset = 0;
    142	u8 last_inipkt = 0;
    143
    144	_rtl92s_fw_set_rqpn(hw);
    145
    146	if (buffer_len >= MAX_FIRMWARE_CODE_SIZE) {
    147		pr_err("Size over FIRMWARE_CODE_SIZE!\n");
    148		return false;
    149	}
    150
    151	extra_descoffset = 0;
    152
    153	do {
    154		if ((buffer_len - frag_offset) > frag_threshold) {
    155			frag_length = frag_threshold + extra_descoffset;
    156		} else {
    157			frag_length = (u16)(buffer_len - frag_offset +
    158					    extra_descoffset);
    159			last_inipkt = 1;
    160		}
    161
    162		/* Allocate skb buffer to contain firmware */
    163		/* info and tx descriptor info. */
    164		skb = dev_alloc_skb(frag_length);
    165		if (!skb)
    166			return false;
    167		skb_reserve(skb, extra_descoffset);
    168		skb_put_data(skb, code_virtual_address + frag_offset,
    169			     (u32)(frag_length - extra_descoffset));
    170
    171		tcb_desc = (struct rtl_tcb_desc *)(skb->cb);
    172		tcb_desc->queue_index = TXCMD_QUEUE;
    173		tcb_desc->cmd_or_init = DESC_PACKET_TYPE_INIT;
    174		tcb_desc->last_inipkt = last_inipkt;
    175
    176		_rtl92s_cmd_send_packet(hw, skb, last_inipkt);
    177
    178		frag_offset += (frag_length - extra_descoffset);
    179
    180	} while (frag_offset < buffer_len);
    181
    182	rtl_write_byte(rtlpriv, TP_POLL, TPPOLL_CQ);
    183
    184	return true ;
    185}
    186
    187static bool _rtl92s_firmware_checkready(struct ieee80211_hw *hw,
    188		u8 loadfw_status)
    189{
    190	struct rtl_priv *rtlpriv = rtl_priv(hw);
    191	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
    192	struct rt_firmware *firmware = (struct rt_firmware *)rtlhal->pfirmware;
    193	u32 tmpu4b;
    194	u8 cpustatus = 0;
    195	short pollingcnt = 1000;
    196	bool rtstatus = true;
    197
    198	rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,
    199		"LoadStaus(%d)\n", loadfw_status);
    200
    201	firmware->fwstatus = (enum fw_status)loadfw_status;
    202
    203	switch (loadfw_status) {
    204	case FW_STATUS_LOAD_IMEM:
    205		/* Polling IMEM code done. */
    206		do {
    207			cpustatus = rtl_read_byte(rtlpriv, TCR);
    208			if (cpustatus & IMEM_CODE_DONE)
    209				break;
    210			udelay(5);
    211		} while (pollingcnt--);
    212
    213		if (!(cpustatus & IMEM_CHK_RPT) || (pollingcnt <= 0)) {
    214			pr_err("FW_STATUS_LOAD_IMEM FAIL CPU, Status=%x\n",
    215			       cpustatus);
    216			goto status_check_fail;
    217		}
    218		break;
    219
    220	case FW_STATUS_LOAD_EMEM:
    221		/* Check Put Code OK and Turn On CPU */
    222		/* Polling EMEM code done. */
    223		do {
    224			cpustatus = rtl_read_byte(rtlpriv, TCR);
    225			if (cpustatus & EMEM_CODE_DONE)
    226				break;
    227			udelay(5);
    228		} while (pollingcnt--);
    229
    230		if (!(cpustatus & EMEM_CHK_RPT) || (pollingcnt <= 0)) {
    231			pr_err("FW_STATUS_LOAD_EMEM FAIL CPU, Status=%x\n",
    232			       cpustatus);
    233			goto status_check_fail;
    234		}
    235
    236		/* Turn On CPU */
    237		rtstatus = _rtl92s_firmware_enable_cpu(hw);
    238		if (!rtstatus) {
    239			pr_err("Enable CPU fail!\n");
    240			goto status_check_fail;
    241		}
    242		break;
    243
    244	case FW_STATUS_LOAD_DMEM:
    245		/* Polling DMEM code done */
    246		do {
    247			cpustatus = rtl_read_byte(rtlpriv, TCR);
    248			if (cpustatus & DMEM_CODE_DONE)
    249				break;
    250			udelay(5);
    251		} while (pollingcnt--);
    252
    253		if (!(cpustatus & DMEM_CODE_DONE) || (pollingcnt <= 0)) {
    254			pr_err("Polling DMEM code done fail ! cpustatus(%#x)\n",
    255			       cpustatus);
    256			goto status_check_fail;
    257		}
    258
    259		rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,
    260			"DMEM code download success, cpustatus(%#x)\n",
    261			cpustatus);
    262
    263		/* Prevent Delay too much and being scheduled out */
    264		/* Polling Load Firmware ready */
    265		pollingcnt = 2000;
    266		do {
    267			cpustatus = rtl_read_byte(rtlpriv, TCR);
    268			if (cpustatus & FWRDY)
    269				break;
    270			udelay(40);
    271		} while (pollingcnt--);
    272
    273		rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,
    274			"Polling Load Firmware ready, cpustatus(%x)\n",
    275			cpustatus);
    276
    277		if (((cpustatus & LOAD_FW_READY) != LOAD_FW_READY) ||
    278		    (pollingcnt <= 0)) {
    279			pr_err("Polling Load Firmware ready fail ! cpustatus(%x)\n",
    280			       cpustatus);
    281			goto status_check_fail;
    282		}
    283
    284		/* If right here, we can set TCR/RCR to desired value  */
    285		/* and config MAC lookback mode to normal mode */
    286		tmpu4b = rtl_read_dword(rtlpriv, TCR);
    287		rtl_write_dword(rtlpriv, TCR, (tmpu4b & (~TCR_ICV)));
    288
    289		tmpu4b = rtl_read_dword(rtlpriv, RCR);
    290		rtl_write_dword(rtlpriv, RCR, (tmpu4b | RCR_APPFCS |
    291				RCR_APP_ICV | RCR_APP_MIC));
    292
    293		rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,
    294			"Current RCR settings(%#x)\n", tmpu4b);
    295
    296		/* Set to normal mode. */
    297		rtl_write_byte(rtlpriv, LBKMD_SEL, LBK_NORMAL);
    298		break;
    299
    300	default:
    301		pr_err("Unknown status check!\n");
    302		rtstatus = false;
    303		break;
    304	}
    305
    306status_check_fail:
    307	rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,
    308		"loadfw_status(%d), rtstatus(%x)\n",
    309		loadfw_status, rtstatus);
    310	return rtstatus;
    311}
    312
    313int rtl92s_download_fw(struct ieee80211_hw *hw)
    314{
    315	struct rtl_priv *rtlpriv = rtl_priv(hw);
    316	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
    317	struct rt_firmware *firmware = NULL;
    318	struct fw_hdr *pfwheader;
    319	struct fw_priv *pfw_priv = NULL;
    320	u8 *puc_mappedfile = NULL;
    321	u32 ul_filelength = 0;
    322	u8 fwhdr_size = RT_8192S_FIRMWARE_HDR_SIZE;
    323	u8 fwstatus = FW_STATUS_INIT;
    324	bool rtstatus = true;
    325
    326	if (rtlpriv->max_fw_size == 0 || !rtlhal->pfirmware)
    327		return 1;
    328
    329	firmware = (struct rt_firmware *)rtlhal->pfirmware;
    330	firmware->fwstatus = FW_STATUS_INIT;
    331
    332	puc_mappedfile = firmware->sz_fw_tmpbuffer;
    333
    334	/* 1. Retrieve FW header. */
    335	firmware->pfwheader = (struct fw_hdr *) puc_mappedfile;
    336	pfwheader = firmware->pfwheader;
    337	firmware->firmwareversion =  byte(pfwheader->version, 0);
    338	firmware->pfwheader->fwpriv.hci_sel = 1;/* pcie */
    339
    340	rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,
    341		"signature:%x, version:%x, size:%x, imemsize:%x, sram size:%x\n",
    342		pfwheader->signature,
    343		pfwheader->version, pfwheader->dmem_size,
    344		pfwheader->img_imem_size, pfwheader->img_sram_size);
    345
    346	/* 2. Retrieve IMEM image. */
    347	if ((pfwheader->img_imem_size == 0) || (pfwheader->img_imem_size >
    348	    sizeof(firmware->fw_imem))) {
    349		pr_err("memory for data image is less than IMEM required\n");
    350		goto fail;
    351	} else {
    352		puc_mappedfile += fwhdr_size;
    353
    354		memcpy(firmware->fw_imem, puc_mappedfile,
    355		       pfwheader->img_imem_size);
    356		firmware->fw_imem_len = pfwheader->img_imem_size;
    357	}
    358
    359	/* 3. Retriecve EMEM image. */
    360	if (pfwheader->img_sram_size > sizeof(firmware->fw_emem)) {
    361		pr_err("memory for data image is less than EMEM required\n");
    362		goto fail;
    363	} else {
    364		puc_mappedfile += firmware->fw_imem_len;
    365
    366		memcpy(firmware->fw_emem, puc_mappedfile,
    367		       pfwheader->img_sram_size);
    368		firmware->fw_emem_len = pfwheader->img_sram_size;
    369	}
    370
    371	/* 4. download fw now */
    372	fwstatus = _rtl92s_firmware_get_nextstatus(firmware->fwstatus);
    373	while (fwstatus != FW_STATUS_READY) {
    374		/* Image buffer redirection. */
    375		switch (fwstatus) {
    376		case FW_STATUS_LOAD_IMEM:
    377			puc_mappedfile = firmware->fw_imem;
    378			ul_filelength = firmware->fw_imem_len;
    379			break;
    380		case FW_STATUS_LOAD_EMEM:
    381			puc_mappedfile = firmware->fw_emem;
    382			ul_filelength = firmware->fw_emem_len;
    383			break;
    384		case FW_STATUS_LOAD_DMEM:
    385			/* Partial update the content of header private. */
    386			pfwheader = firmware->pfwheader;
    387			pfw_priv = &pfwheader->fwpriv;
    388			_rtl92s_firmwareheader_priveupdate(hw, pfw_priv);
    389			puc_mappedfile = (u8 *)(firmware->pfwheader) +
    390					RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE;
    391			ul_filelength = fwhdr_size -
    392					RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE;
    393			break;
    394		default:
    395			pr_err("Unexpected Download step!!\n");
    396			goto fail;
    397		}
    398
    399		/* <2> Download image file */
    400		rtstatus = _rtl92s_firmware_downloadcode(hw, puc_mappedfile,
    401				ul_filelength);
    402
    403		if (!rtstatus) {
    404			pr_err("fail!\n");
    405			goto fail;
    406		}
    407
    408		/* <3> Check whether load FW process is ready */
    409		rtstatus = _rtl92s_firmware_checkready(hw, fwstatus);
    410		if (!rtstatus) {
    411			pr_err("rtl8192se: firmware fail!\n");
    412			goto fail;
    413		}
    414
    415		fwstatus = _rtl92s_firmware_get_nextstatus(firmware->fwstatus);
    416	}
    417
    418	return rtstatus;
    419fail:
    420	return 0;
    421}
    422
    423static u32 _rtl92s_fill_h2c_cmd(struct sk_buff *skb, u32 h2cbufferlen,
    424				u32 cmd_num, u32 *pelement_id, u32 *pcmd_len,
    425				u8 **pcmb_buffer, u8 *cmd_start_seq)
    426{
    427	u32 totallen = 0, len = 0, tx_desclen = 0;
    428	u32 pre_continueoffset = 0;
    429	u8 *ph2c_buffer;
    430	u8 i = 0;
    431
    432	do {
    433		/* 8 - Byte alignment */
    434		len = H2C_TX_CMD_HDR_LEN + N_BYTE_ALIGMENT(pcmd_len[i], 8);
    435
    436		/* Buffer length is not enough */
    437		if (h2cbufferlen < totallen + len + tx_desclen)
    438			break;
    439
    440		/* Clear content */
    441		ph2c_buffer = skb_put(skb, (u32)len);
    442		memset((ph2c_buffer + totallen + tx_desclen), 0, len);
    443
    444		/* CMD len */
    445		le32p_replace_bits((__le32 *)(ph2c_buffer + totallen +
    446					      tx_desclen), pcmd_len[i],
    447				   GENMASK(15, 0));
    448
    449		/* CMD ID */
    450		le32p_replace_bits((__le32 *)(ph2c_buffer + totallen +
    451					      tx_desclen), pelement_id[i],
    452				   GENMASK(23, 16));
    453
    454		/* CMD Sequence */
    455		*cmd_start_seq = *cmd_start_seq % 0x80;
    456		le32p_replace_bits((__le32 *)(ph2c_buffer + totallen +
    457					      tx_desclen), *cmd_start_seq,
    458				   GENMASK(30, 24));
    459		++*cmd_start_seq;
    460
    461		/* Copy memory */
    462		memcpy((ph2c_buffer + totallen + tx_desclen +
    463			H2C_TX_CMD_HDR_LEN), pcmb_buffer[i], pcmd_len[i]);
    464
    465		/* CMD continue */
    466		/* set the continue in prevoius cmd. */
    467		if (i < cmd_num - 1)
    468			le32p_replace_bits((__le32 *)(ph2c_buffer +
    469						      pre_continueoffset),
    470					   1, BIT(31));
    471
    472		pre_continueoffset = totallen;
    473
    474		totallen += len;
    475	} while (++i < cmd_num);
    476
    477	return totallen;
    478}
    479
    480static u32 _rtl92s_get_h2c_cmdlen(u32 h2cbufferlen, u32 cmd_num, u32 *pcmd_len)
    481{
    482	u32 totallen = 0, len = 0, tx_desclen = 0;
    483	u8 i = 0;
    484
    485	do {
    486		/* 8 - Byte alignment */
    487		len = H2C_TX_CMD_HDR_LEN + N_BYTE_ALIGMENT(pcmd_len[i], 8);
    488
    489		/* Buffer length is not enough */
    490		if (h2cbufferlen < totallen + len + tx_desclen)
    491			break;
    492
    493		totallen += len;
    494	} while (++i < cmd_num);
    495
    496	return totallen + tx_desclen;
    497}
    498
    499static bool _rtl92s_firmware_set_h2c_cmd(struct ieee80211_hw *hw, u8 h2c_cmd,
    500					 u8 *pcmd_buffer)
    501{
    502	struct rtl_priv *rtlpriv = rtl_priv(hw);
    503	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
    504	struct rtl_tcb_desc *cb_desc;
    505	struct sk_buff *skb;
    506	u32	element_id = 0;
    507	u32	cmd_len = 0;
    508	u32	len;
    509
    510	switch (h2c_cmd) {
    511	case FW_H2C_SETPWRMODE:
    512		element_id = H2C_SETPWRMODE_CMD ;
    513		cmd_len = sizeof(struct h2c_set_pwrmode_parm);
    514		break;
    515	case FW_H2C_JOINBSSRPT:
    516		element_id = H2C_JOINBSSRPT_CMD;
    517		cmd_len = sizeof(struct h2c_joinbss_rpt_parm);
    518		break;
    519	case FW_H2C_WOWLAN_UPDATE_GTK:
    520		element_id = H2C_WOWLAN_UPDATE_GTK_CMD;
    521		cmd_len = sizeof(struct h2c_wpa_two_way_parm);
    522		break;
    523	case FW_H2C_WOWLAN_UPDATE_IV:
    524		element_id = H2C_WOWLAN_UPDATE_IV_CMD;
    525		cmd_len = sizeof(unsigned long long);
    526		break;
    527	case FW_H2C_WOWLAN_OFFLOAD:
    528		element_id = H2C_WOWLAN_FW_OFFLOAD;
    529		cmd_len = sizeof(u8);
    530		break;
    531	default:
    532		break;
    533	}
    534
    535	len = _rtl92s_get_h2c_cmdlen(MAX_TRANSMIT_BUFFER_SIZE, 1, &cmd_len);
    536	skb = dev_alloc_skb(len);
    537	if (!skb)
    538		return false;
    539	cb_desc = (struct rtl_tcb_desc *)(skb->cb);
    540	cb_desc->queue_index = TXCMD_QUEUE;
    541	cb_desc->cmd_or_init = DESC_PACKET_TYPE_NORMAL;
    542	cb_desc->last_inipkt = false;
    543
    544	_rtl92s_fill_h2c_cmd(skb, MAX_TRANSMIT_BUFFER_SIZE, 1, &element_id,
    545			&cmd_len, &pcmd_buffer,	&rtlhal->h2c_txcmd_seq);
    546	_rtl92s_cmd_send_packet(hw, skb, false);
    547	rtlpriv->cfg->ops->tx_polling(hw, TXCMD_QUEUE);
    548
    549	return true;
    550}
    551
    552void rtl92s_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
    553{
    554	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
    555	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
    556	struct h2c_set_pwrmode_parm	pwrmode;
    557	u16 max_wakeup_period = 0;
    558
    559	pwrmode.mode = mode;
    560	pwrmode.flag_low_traffic_en = 0;
    561	pwrmode.flag_lpnav_en = 0;
    562	pwrmode.flag_rf_low_snr_en = 0;
    563	pwrmode.flag_dps_en = 0;
    564	pwrmode.bcn_rx_en = 0;
    565	pwrmode.bcn_to = 0;
    566	le16p_replace_bits((__le16 *)(((u8 *)(&pwrmode) + 8)),
    567			   mac->vif->bss_conf.beacon_int, GENMASK(15, 0));
    568	pwrmode.app_itv = 0;
    569	pwrmode.awake_bcn_itvl = ppsc->reg_max_lps_awakeintvl;
    570	pwrmode.smart_ps = 1;
    571	pwrmode.bcn_pass_period = 10;
    572
    573	/* Set beacon pass count */
    574	if (pwrmode.mode == FW_PS_MIN_MODE)
    575		max_wakeup_period = mac->vif->bss_conf.beacon_int;
    576	else if (pwrmode.mode == FW_PS_MAX_MODE)
    577		max_wakeup_period = mac->vif->bss_conf.beacon_int *
    578			mac->vif->bss_conf.dtim_period;
    579
    580	if (max_wakeup_period >= 500)
    581		pwrmode.bcn_pass_cnt = 1;
    582	else if ((max_wakeup_period >= 300) && (max_wakeup_period < 500))
    583		pwrmode.bcn_pass_cnt = 2;
    584	else if ((max_wakeup_period >= 200) && (max_wakeup_period < 300))
    585		pwrmode.bcn_pass_cnt = 3;
    586	else if ((max_wakeup_period >= 20) && (max_wakeup_period < 200))
    587		pwrmode.bcn_pass_cnt = 5;
    588	else
    589		pwrmode.bcn_pass_cnt = 1;
    590
    591	_rtl92s_firmware_set_h2c_cmd(hw, FW_H2C_SETPWRMODE, (u8 *)&pwrmode);
    592
    593}
    594
    595void rtl92s_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw,
    596		u8 mstatus, u8 ps_qosinfo)
    597{
    598	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
    599	struct h2c_joinbss_rpt_parm joinbss_rpt;
    600
    601	joinbss_rpt.opmode = mstatus;
    602	joinbss_rpt.ps_qos_info = ps_qosinfo;
    603	joinbss_rpt.bssid[0] = mac->bssid[0];
    604	joinbss_rpt.bssid[1] = mac->bssid[1];
    605	joinbss_rpt.bssid[2] = mac->bssid[2];
    606	joinbss_rpt.bssid[3] = mac->bssid[3];
    607	joinbss_rpt.bssid[4] = mac->bssid[4];
    608	joinbss_rpt.bssid[5] = mac->bssid[5];
    609	le16p_replace_bits((__le16 *)(((u8 *)(&joinbss_rpt) + 8)),
    610			   mac->vif->bss_conf.beacon_int, GENMASK(15, 0));
    611	le16p_replace_bits((__le16 *)(((u8 *)(&joinbss_rpt) + 10)),
    612			   mac->assoc_id, GENMASK(15, 0));
    613
    614	_rtl92s_firmware_set_h2c_cmd(hw, FW_H2C_JOINBSSRPT, (u8 *)&joinbss_rpt);
    615}
    616