1 /******************************************************************************
2  *
3  * Copyright(c) 2009-2014  Realtek Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * The full GNU General Public License is included in this distribution in the
15  * file called LICENSE.
16  *
17  * Contact Information:
18  * wlanfae <wlanfae@realtek.com>
19  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
20  * Hsinchu 300, Taiwan.
21  *
22  * Larry Finger <Larry.Finger@lwfinger.net>
23  *
24  *****************************************************************************/
25 
26 #include "../wifi.h"
27 #include "../pci.h"
28 #include "../base.h"
29 #include "../core.h"
30 #include "reg.h"
31 #include "def.h"
32 #include "fw.h"
33 #include "../rtl8723com/fw_common.h"
34 
35 static bool _rtl8723be_check_fw_read_last_h2c(struct ieee80211_hw *hw,
36 					      u8 boxnum)
37 {
38 	struct rtl_priv *rtlpriv = rtl_priv(hw);
39 	u8 val_hmetfr;
40 	bool result = false;
41 
42 	val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
43 	if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
44 		result = true;
45 	return result;
46 }
47 
48 static void _rtl8723be_fill_h2c_command(struct ieee80211_hw *hw, u8 element_id,
49 					u32 cmd_len, u8 *p_cmdbuffer)
50 {
51 	struct rtl_priv *rtlpriv = rtl_priv(hw);
52 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
53 	u8 boxnum;
54 	u16 box_reg = 0, box_extreg = 0;
55 	u8 u1b_tmp;
56 	bool isfw_read = false;
57 	u8 buf_index = 0;
58 	bool bwrite_sucess = false;
59 	u8 wait_h2c_limmit = 100;
60 	u8 wait_writeh2c_limmit = 100;
61 	u8 boxcontent[4], boxextcontent[4];
62 	u32 h2c_waitcounter = 0;
63 	unsigned long flag;
64 	u8 idx;
65 
66 	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
67 
68 	while (true) {
69 		spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
70 		if (rtlhal->h2c_setinprogress) {
71 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
72 				 "H2C set in progress! Wait to set..element_id(%d).\n",
73 				 element_id);
74 
75 			while (rtlhal->h2c_setinprogress) {
76 				spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
77 						       flag);
78 				h2c_waitcounter++;
79 				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
80 					 "Wait 100 us (%d times)...\n",
81 					 h2c_waitcounter);
82 				udelay(100);
83 
84 				if (h2c_waitcounter > 1000)
85 					return;
86 				spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
87 						  flag);
88 			}
89 			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
90 		} else {
91 			rtlhal->h2c_setinprogress = true;
92 			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
93 			break;
94 		}
95 	}
96 
97 	while (!bwrite_sucess) {
98 		wait_writeh2c_limmit--;
99 		if (wait_writeh2c_limmit == 0) {
100 			pr_err("Write H2C fail because no trigger for FW INT!\n");
101 			break;
102 		}
103 
104 		boxnum = rtlhal->last_hmeboxnum;
105 		switch (boxnum) {
106 		case 0:
107 			box_reg = REG_HMEBOX_0;
108 			box_extreg = REG_HMEBOX_EXT_0;
109 			break;
110 		case 1:
111 			box_reg = REG_HMEBOX_1;
112 			box_extreg = REG_HMEBOX_EXT_1;
113 			break;
114 		case 2:
115 			box_reg = REG_HMEBOX_2;
116 			box_extreg = REG_HMEBOX_EXT_2;
117 			break;
118 		case 3:
119 			box_reg = REG_HMEBOX_3;
120 			box_extreg = REG_HMEBOX_EXT_3;
121 			break;
122 		default:
123 			pr_err("switch case %#x not processed\n",
124 			       boxnum);
125 			break;
126 		}
127 
128 		isfw_read = _rtl8723be_check_fw_read_last_h2c(hw, boxnum);
129 		while (!isfw_read) {
130 			wait_h2c_limmit--;
131 			if (wait_h2c_limmit == 0) {
132 				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
133 					 "Waiting too long for FW read clear HMEBox(%d)!\n",
134 					 boxnum);
135 				break;
136 			}
137 
138 			udelay(10);
139 
140 			isfw_read = _rtl8723be_check_fw_read_last_h2c(hw,
141 								boxnum);
142 			u1b_tmp = rtl_read_byte(rtlpriv, 0x130);
143 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
144 				 "Waiting for FW read clear HMEBox(%d)!!! 0x130 = %2x\n",
145 				 boxnum, u1b_tmp);
146 		}
147 
148 		if (!isfw_read) {
149 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
150 				 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
151 				 boxnum);
152 			break;
153 		}
154 
155 		memset(boxcontent, 0, sizeof(boxcontent));
156 		memset(boxextcontent, 0, sizeof(boxextcontent));
157 		boxcontent[0] = element_id;
158 		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
159 			 "Write element_id box_reg(%4x) = %2x\n",
160 			  box_reg, element_id);
161 
162 		switch (cmd_len) {
163 		case 1:
164 		case 2:
165 		case 3:
166 			/*boxcontent[0] &= ~(BIT(7));*/
167 			memcpy((u8 *)(boxcontent) + 1,
168 			       p_cmdbuffer + buf_index, cmd_len);
169 
170 			for (idx = 0; idx < 4; idx++) {
171 				rtl_write_byte(rtlpriv, box_reg + idx,
172 					       boxcontent[idx]);
173 			}
174 			break;
175 		case 4:
176 		case 5:
177 		case 6:
178 		case 7:
179 			/*boxcontent[0] |= (BIT(7));*/
180 			memcpy((u8 *)(boxextcontent),
181 			       p_cmdbuffer + buf_index+3, cmd_len-3);
182 			memcpy((u8 *)(boxcontent) + 1,
183 			       p_cmdbuffer + buf_index, 3);
184 
185 			for (idx = 0; idx < 4; idx++) {
186 				rtl_write_byte(rtlpriv, box_extreg + idx,
187 					       boxextcontent[idx]);
188 			}
189 
190 			for (idx = 0; idx < 4; idx++) {
191 				rtl_write_byte(rtlpriv, box_reg + idx,
192 					       boxcontent[idx]);
193 			}
194 			break;
195 		default:
196 			pr_err("switch case %#x not processed\n",
197 			       cmd_len);
198 			break;
199 		}
200 
201 		bwrite_sucess = true;
202 
203 		rtlhal->last_hmeboxnum = boxnum + 1;
204 		if (rtlhal->last_hmeboxnum == 4)
205 			rtlhal->last_hmeboxnum = 0;
206 
207 		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
208 			 "pHalData->last_hmeboxnum  = %d\n",
209 			  rtlhal->last_hmeboxnum);
210 	}
211 
212 	spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
213 	rtlhal->h2c_setinprogress = false;
214 	spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
215 
216 	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
217 }
218 
219 void rtl8723be_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id,
220 			    u32 cmd_len, u8 *p_cmdbuffer)
221 {
222 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
223 	u32 tmp_cmdbuf[2];
224 
225 	if (!rtlhal->fw_ready) {
226 		WARN_ONCE(true,
227 			  "rtl8723be: error H2C cmd because of Fw download fail!!!\n");
228 		return;
229 	}
230 
231 	memset(tmp_cmdbuf, 0, 8);
232 	memcpy(tmp_cmdbuf, p_cmdbuffer, cmd_len);
233 	_rtl8723be_fill_h2c_command(hw, element_id, cmd_len,
234 				    (u8 *)&tmp_cmdbuf);
235 	return;
236 }
237 
238 void rtl8723be_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
239 {
240 	struct rtl_priv *rtlpriv = rtl_priv(hw);
241 	u8 u1_h2c_set_pwrmode[H2C_PWEMODE_LENGTH] = { 0 };
242 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
243 	u8 rlbm, power_state = 0;
244 	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
245 
246 	SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0));
247 	rlbm = 0;/*YJ,temp,120316. FW now not support RLBM=2.*/
248 	SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, rlbm);
249 	SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
250 					 (rtlpriv->mac80211.p2p) ?
251 					  ppsc->smart_ps : 1);
252 	SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode,
253 					       ppsc->reg_max_lps_awakeintvl);
254 	SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0);
255 	if (mode == FW_PS_ACTIVE_MODE)
256 		power_state |= FW_PWR_STATE_ACTIVE;
257 	else
258 		power_state |= FW_PWR_STATE_RF_OFF;
259 	SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state);
260 
261 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
262 		      "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n",
263 		      u1_h2c_set_pwrmode, H2C_PWEMODE_LENGTH);
264 	rtl8723be_fill_h2c_cmd(hw, H2C_8723B_SETPWRMODE, H2C_PWEMODE_LENGTH,
265 			       u1_h2c_set_pwrmode);
266 }
267 
268 void rtl8723be_set_fw_media_status_rpt_cmd(struct ieee80211_hw *hw, u8 mstatus)
269 {
270 	u8 parm[3] = { 0, 0, 0 };
271 	/* parm[0]: bit0=0-->Disconnect, bit0=1-->Connect
272 	 *          bit1=0-->update Media Status to MACID
273 	 *          bit1=1-->update Media Status from MACID to MACID_End
274 	 * parm[1]: MACID, if this is INFRA_STA, MacID = 0
275 	 * parm[2]: MACID_End
276 	*/
277 	SET_H2CCMD_MSRRPT_PARM_OPMODE(parm, mstatus);
278 	SET_H2CCMD_MSRRPT_PARM_MACID_IND(parm, 0);
279 
280 	rtl8723be_fill_h2c_cmd(hw, H2C_8723B_MSRRPT, 3, parm);
281 }
282 
283 #define BEACON_PG		0 /* ->1 */
284 #define PSPOLL_PG		2
285 #define NULL_PG			3
286 #define PROBERSP_PG		4 /* ->5 */
287 
288 #define TOTAL_RESERVED_PKT_LEN	768
289 
290 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
291 	/* page 0 beacon */
292 	0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
293 	0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
294 	0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x20, 0x00,
295 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
296 	0x64, 0x00, 0x10, 0x04, 0x00, 0x05, 0x54, 0x65,
297 	0x73, 0x74, 0x32, 0x01, 0x08, 0x82, 0x84, 0x0B,
298 	0x16, 0x24, 0x30, 0x48, 0x6C, 0x03, 0x01, 0x06,
299 	0x06, 0x02, 0x00, 0x00, 0x2A, 0x01, 0x02, 0x32,
300 	0x04, 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C,
301 	0x09, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
302 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
303 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
304 	0x00, 0x3D, 0x00, 0xDD, 0x07, 0x00, 0xE0, 0x4C,
305 	0x02, 0x02, 0x00, 0x00, 0xDD, 0x18, 0x00, 0x50,
306 	0xF2, 0x01, 0x01, 0x00, 0x00, 0x50, 0xF2, 0x04,
307 	0x01, 0x00, 0x00, 0x50, 0xF2, 0x04, 0x01, 0x00,
308 
309 	/* page 1 beacon */
310 	0x00, 0x50, 0xF2, 0x02, 0x00, 0x00, 0x00, 0x00,
311 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
312 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
313 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
314 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
317 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
318 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
319 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
320 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
321 	0x10, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
322 	0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00,
323 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
324 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
325 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
326 
327 	/* page 2  ps-poll */
328 	0xA4, 0x10, 0x01, 0xC0, 0xEC, 0x1A, 0x59, 0x0B,
329 	0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
330 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
331 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
332 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
333 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
334 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
335 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
336 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
337 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
338 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
339 	0x18, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
340 	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
341 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
342 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
343 	0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
344 
345 	/* page 3  null */
346 	0x48, 0x01, 0x00, 0x00, 0xEC, 0x1A, 0x59, 0x0B,
347 	0xAD, 0xD4, 0x00, 0xE0, 0x4C, 0x02, 0xB1, 0x78,
348 	0xEC, 0x1A, 0x59, 0x0B, 0xAD, 0xD4, 0x00, 0x00,
349 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
351 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
352 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
353 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
354 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
355 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
356 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
357 	0x72, 0x00, 0x28, 0x8C, 0x00, 0x12, 0x00, 0x00,
358 	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
359 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
360 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
361 	0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
362 
363 	/* page 4  probe_resp */
364 	0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
365 	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
366 	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
367 	0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
368 	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
369 	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
370 	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
371 	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
372 	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
373 	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
374 	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
375 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
376 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
377 	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
378 	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
379 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
380 
381 	/* page 5  probe_resp */
382 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
383 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
384 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
385 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
386 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
387 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
388 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
389 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
390 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
391 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
392 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
393 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
394 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
395 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
396 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
397 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
398 };
399 
400 void rtl8723be_set_fw_rsvdpagepkt(struct ieee80211_hw *hw,
401 				  bool b_dl_finished)
402 {
403 	struct rtl_priv *rtlpriv = rtl_priv(hw);
404 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
405 	struct sk_buff *skb = NULL;
406 
407 	u32 totalpacketlen;
408 	bool rtstatus;
409 	u8 u1rsvdpageloc[5] = { 0 };
410 	bool b_dlok = false;
411 
412 	u8 *beacon;
413 	u8 *p_pspoll;
414 	u8 *nullfunc;
415 	u8 *p_probersp;
416 	/*---------------------------------------------------------
417 	 *			(1) beacon
418 	 *---------------------------------------------------------
419 	 */
420 	beacon = &reserved_page_packet[BEACON_PG * 128];
421 	SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
422 	SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
423 
424 	/*-------------------------------------------------------
425 	 *			(2) ps-poll
426 	 *-------------------------------------------------------
427 	 */
428 	p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
429 	SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
430 	SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
431 	SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
432 
433 	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
434 
435 	/*--------------------------------------------------------
436 	 *			(3) null data
437 	 *--------------------------------------------------------
438 	 */
439 	nullfunc = &reserved_page_packet[NULL_PG * 128];
440 	SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
441 	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
442 	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
443 
444 	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
445 
446 	/*---------------------------------------------------------
447 	 *			(4) probe response
448 	 *---------------------------------------------------------
449 	 */
450 	p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
451 	SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
452 	SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
453 	SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
454 
455 	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
456 
457 	totalpacketlen = TOTAL_RESERVED_PKT_LEN;
458 
459 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
460 		      "rtl8723be_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
461 		      &reserved_page_packet[0], totalpacketlen);
462 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
463 		      "rtl8723be_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
464 		      u1rsvdpageloc, 3);
465 
466 	skb = dev_alloc_skb(totalpacketlen);
467 	memcpy((u8 *)skb_put(skb, totalpacketlen),
468 	       &reserved_page_packet, totalpacketlen);
469 
470 	rtstatus = rtl_cmd_send_packet(hw, skb);
471 
472 	if (rtstatus)
473 		b_dlok = true;
474 
475 	if (b_dlok) {
476 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
477 			 "Set RSVD page location to Fw.\n");
478 		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, "H2C_RSVDPAGE:\n",
479 			      u1rsvdpageloc, 3);
480 		rtl8723be_fill_h2c_cmd(hw, H2C_8723B_RSVDPAGE,
481 				       sizeof(u1rsvdpageloc), u1rsvdpageloc);
482 	} else
483 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
484 			 "Set RSVD page location to Fw FAIL!!!!!!.\n");
485 }
486 
487 /*Should check FW support p2p or not.*/
488 static void rtl8723be_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw,
489 					     u8 ctwindow)
490 {
491 	u8 u1_ctwindow_period[1] = { ctwindow};
492 
493 	rtl8723be_fill_h2c_cmd(hw, H2C_8723B_P2P_PS_CTW_CMD, 1,
494 			       u1_ctwindow_period);
495 }
496 
497 void rtl8723be_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw,
498 				      u8 p2p_ps_state)
499 {
500 	struct rtl_priv *rtlpriv = rtl_priv(hw);
501 	struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
502 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
503 	struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
504 	struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
505 	u8 i;
506 	u16 ctwindow;
507 	u32 start_time, tsf_low;
508 
509 	switch (p2p_ps_state) {
510 	case P2P_PS_DISABLE:
511 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
512 		memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
513 		break;
514 	case P2P_PS_ENABLE:
515 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
516 		/* update CTWindow value. */
517 		if (p2pinfo->ctwindow > 0) {
518 			p2p_ps_offload->ctwindow_en = 1;
519 			ctwindow = p2pinfo->ctwindow;
520 			rtl8723be_set_p2p_ctw_period_cmd(hw, ctwindow);
521 		}
522 		/* hw only support 2 set of NoA */
523 		for (i = 0 ; i < p2pinfo->noa_num ; i++) {
524 			/* To control the register setting
525 			 * for which NOA
526 			 */
527 			rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
528 			if (i == 0)
529 				p2p_ps_offload->noa0_en = 1;
530 			else
531 				p2p_ps_offload->noa1_en = 1;
532 
533 			/* config P2P NoA Descriptor Register */
534 			rtl_write_dword(rtlpriv, 0x5E0,
535 					p2pinfo->noa_duration[i]);
536 			rtl_write_dword(rtlpriv, 0x5E4,
537 					p2pinfo->noa_interval[i]);
538 
539 			/*Get Current TSF value */
540 			tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
541 
542 			start_time = p2pinfo->noa_start_time[i];
543 			if (p2pinfo->noa_count_type[i] != 1) {
544 				while (start_time <= (tsf_low + (50 * 1024))) {
545 					start_time += p2pinfo->noa_interval[i];
546 					if (p2pinfo->noa_count_type[i] != 255)
547 						p2pinfo->noa_count_type[i]--;
548 				}
549 			}
550 			rtl_write_dword(rtlpriv, 0x5E8, start_time);
551 			rtl_write_dword(rtlpriv, 0x5EC,
552 					p2pinfo->noa_count_type[i]);
553 		}
554 
555 		if ((p2pinfo->opp_ps == 1) ||
556 		    (p2pinfo->noa_num > 0)) {
557 			/* rst p2p circuit */
558 			rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
559 
560 			p2p_ps_offload->offload_en = 1;
561 
562 			if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
563 				p2p_ps_offload->role = 1;
564 				p2p_ps_offload->allstasleep = 0;
565 			} else {
566 				p2p_ps_offload->role = 0;
567 			}
568 			p2p_ps_offload->discovery = 0;
569 		}
570 		break;
571 	case P2P_PS_SCAN:
572 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
573 		p2p_ps_offload->discovery = 1;
574 		break;
575 	case P2P_PS_SCAN_DONE:
576 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n");
577 		p2p_ps_offload->discovery = 0;
578 		p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
579 		break;
580 	default:
581 		break;
582 	}
583 
584 	rtl8723be_fill_h2c_cmd(hw, H2C_8723B_P2P_PS_OFFLOAD, 1,
585 			       (u8 *)p2p_ps_offload);
586 }
587 
588 void rtl8723be_c2h_content_parsing(struct ieee80211_hw *hw,
589 				   u8 c2h_cmd_id,
590 				   u8 c2h_cmd_len, u8 *tmp_buf)
591 {
592 	struct rtl_priv *rtlpriv = rtl_priv(hw);
593 
594 	switch (c2h_cmd_id) {
595 	case C2H_8723B_DBG:
596 		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
597 			 "[C2H], C2H_8723BE_DBG!!\n");
598 		break;
599 	case C2H_8723B_TX_REPORT:
600 		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
601 			 "[C2H], C2H_8723BE_TX_REPORT!\n");
602 		break;
603 	case C2H_8723B_BT_INFO:
604 		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
605 			 "[C2H], C2H_8723BE_BT_INFO!!\n");
606 		rtlpriv->btcoexist.btc_ops->btc_btinfo_notify(rtlpriv, tmp_buf,
607 							      c2h_cmd_len);
608 		break;
609 	case C2H_8723B_BT_MP:
610 		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
611 			 "[C2H], C2H_8723BE_BT_MP!!\n");
612 		break;
613 	default:
614 		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
615 			 "[C2H], Unknown packet!! CmdId(%#X)!\n", c2h_cmd_id);
616 		break;
617 	}
618 }
619 
620 void rtl8723be_c2h_packet_handler(struct ieee80211_hw *hw, u8 *buffer, u8 len)
621 {
622 	struct rtl_priv *rtlpriv = rtl_priv(hw);
623 	u8 c2h_cmd_id = 0, c2h_cmd_seq = 0, c2h_cmd_len = 0;
624 	u8 *tmp_buf = NULL;
625 
626 	c2h_cmd_id = buffer[0];
627 	c2h_cmd_seq = buffer[1];
628 	c2h_cmd_len = len - 2;
629 	tmp_buf = buffer + 2;
630 
631 	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
632 		 "[C2H packet], c2hCmdId=0x%x, c2hCmdSeq=0x%x, c2hCmdLen=%d\n",
633 		 c2h_cmd_id, c2h_cmd_seq, c2h_cmd_len);
634 
635 	RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_TRACE,
636 		      "[C2H packet], Content Hex:\n", tmp_buf, c2h_cmd_len);
637 
638 	switch (c2h_cmd_id) {
639 	case C2H_8723B_BT_INFO:
640 	case C2H_8723B_BT_MP:
641 		rtl_c2hcmd_enqueue(hw, c2h_cmd_id, c2h_cmd_len, tmp_buf);
642 		break;
643 
644 	default:
645 		rtl8723be_c2h_content_parsing(hw, c2h_cmd_id, c2h_cmd_len,
646 					      tmp_buf);
647 		break;
648 	}
649 }
650