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