1 /******************************************************************************
2  *
3  * Copyright(c) 2009-2012  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 _rtl8723e_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, val_mcutst_1;
40 	bool result = false;
41 
42 	val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
43 	val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum));
44 
45 	if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0)
46 		result = true;
47 	return result;
48 }
49 
50 static void _rtl8723e_fill_h2c_command(struct ieee80211_hw *hw, u8 element_id,
51 				       u32 cmd_len, u8 *cmdbuffer)
52 {
53 	struct rtl_priv *rtlpriv = rtl_priv(hw);
54 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
55 	u8 boxnum;
56 	u16 box_reg = 0, box_extreg = 0;
57 	u8 u1b_tmp;
58 	bool isfw_read = false;
59 	u8 buf_index = 0;
60 	bool bwrite_sucess = false;
61 	u8 wait_h2c_limmit = 100;
62 	u8 wait_writeh2c_limmit = 100;
63 	u8 boxcontent[4], boxextcontent[2];
64 	u32 h2c_waitcounter = 0;
65 	unsigned long flag;
66 	u8 idx;
67 
68 	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
69 
70 	while (true) {
71 		spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
72 		if (rtlhal->h2c_setinprogress) {
73 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
74 				 "H2C set in progress! Wait to set..element_id(%d).\n",
75 				 element_id);
76 
77 			while (rtlhal->h2c_setinprogress) {
78 				spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
79 						       flag);
80 				h2c_waitcounter++;
81 				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
82 					 "Wait 100 us (%d times)...\n",
83 					  h2c_waitcounter);
84 				udelay(100);
85 
86 				if (h2c_waitcounter > 1000)
87 					return;
88 				spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
89 						  flag);
90 			}
91 			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
92 		} else {
93 			rtlhal->h2c_setinprogress = true;
94 			spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
95 			break;
96 		}
97 	}
98 
99 	while (!bwrite_sucess) {
100 		wait_writeh2c_limmit--;
101 		if (wait_writeh2c_limmit == 0) {
102 			pr_err("Write H2C fail because no trigger for FW INT!\n");
103 			break;
104 		}
105 
106 		boxnum = rtlhal->last_hmeboxnum;
107 		switch (boxnum) {
108 		case 0:
109 			box_reg = REG_HMEBOX_0;
110 			box_extreg = REG_HMEBOX_EXT_0;
111 			break;
112 		case 1:
113 			box_reg = REG_HMEBOX_1;
114 			box_extreg = REG_HMEBOX_EXT_1;
115 			break;
116 		case 2:
117 			box_reg = REG_HMEBOX_2;
118 			box_extreg = REG_HMEBOX_EXT_2;
119 			break;
120 		case 3:
121 			box_reg = REG_HMEBOX_3;
122 			box_extreg = REG_HMEBOX_EXT_3;
123 			break;
124 		default:
125 			pr_err("switch case %#x not processed\n",
126 			       boxnum);
127 			break;
128 		}
129 
130 		isfw_read = _rtl8723e_check_fw_read_last_h2c(hw, boxnum);
131 		while (!isfw_read) {
132 
133 			wait_h2c_limmit--;
134 			if (wait_h2c_limmit == 0) {
135 				RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
136 					 "Waiting too long for FW read clear HMEBox(%d)!\n",
137 					 boxnum);
138 				break;
139 			}
140 
141 			udelay(10);
142 
143 			isfw_read = _rtl8723e_check_fw_read_last_h2c(hw,
144 								boxnum);
145 			u1b_tmp = rtl_read_byte(rtlpriv, 0x1BF);
146 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
147 				 "Waiting for FW read clear HMEBox(%d)!!! 0x1BF = %2x\n",
148 				 boxnum, u1b_tmp);
149 		}
150 
151 		if (!isfw_read) {
152 			RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
153 				 "Write H2C register BOX[%d] fail!!!!! Fw do not read.\n",
154 				 boxnum);
155 			break;
156 		}
157 
158 		memset(boxcontent, 0, sizeof(boxcontent));
159 		memset(boxextcontent, 0, sizeof(boxextcontent));
160 		boxcontent[0] = element_id;
161 		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
162 			 "Write element_id box_reg(%4x) = %2x\n",
163 			  box_reg, element_id);
164 
165 		switch (cmd_len) {
166 		case 1:
167 			boxcontent[0] &= ~(BIT(7));
168 			memcpy((u8 *)(boxcontent) + 1,
169 			       cmdbuffer + buf_index, 1);
170 
171 			for (idx = 0; idx < 4; idx++) {
172 				rtl_write_byte(rtlpriv, box_reg + idx,
173 					       boxcontent[idx]);
174 			}
175 			break;
176 		case 2:
177 			boxcontent[0] &= ~(BIT(7));
178 			memcpy((u8 *)(boxcontent) + 1,
179 			       cmdbuffer + buf_index, 2);
180 
181 			for (idx = 0; idx < 4; idx++) {
182 				rtl_write_byte(rtlpriv, box_reg + idx,
183 					       boxcontent[idx]);
184 			}
185 			break;
186 		case 3:
187 			boxcontent[0] &= ~(BIT(7));
188 			memcpy((u8 *)(boxcontent) + 1,
189 			       cmdbuffer + buf_index, 3);
190 
191 			for (idx = 0; idx < 4; idx++) {
192 				rtl_write_byte(rtlpriv, box_reg + idx,
193 					       boxcontent[idx]);
194 			}
195 			break;
196 		case 4:
197 			boxcontent[0] |= (BIT(7));
198 			memcpy((u8 *)(boxextcontent),
199 			       cmdbuffer + buf_index, 2);
200 			memcpy((u8 *)(boxcontent) + 1,
201 			       cmdbuffer + buf_index + 2, 2);
202 
203 			for (idx = 0; idx < 2; idx++) {
204 				rtl_write_byte(rtlpriv, box_extreg + idx,
205 					       boxextcontent[idx]);
206 			}
207 
208 			for (idx = 0; idx < 4; idx++) {
209 				rtl_write_byte(rtlpriv, box_reg + idx,
210 					       boxcontent[idx]);
211 			}
212 			break;
213 		case 5:
214 			boxcontent[0] |= (BIT(7));
215 			memcpy((u8 *)(boxextcontent),
216 			       cmdbuffer + buf_index, 2);
217 			memcpy((u8 *)(boxcontent) + 1,
218 			       cmdbuffer + buf_index + 2, 3);
219 
220 			for (idx = 0; idx < 2; idx++) {
221 				rtl_write_byte(rtlpriv, box_extreg + idx,
222 					       boxextcontent[idx]);
223 			}
224 
225 			for (idx = 0; idx < 4; idx++) {
226 				rtl_write_byte(rtlpriv, box_reg + idx,
227 					       boxcontent[idx]);
228 			}
229 			break;
230 		default:
231 			pr_err("switch case %#x not processed\n",
232 			       cmd_len);
233 			break;
234 		}
235 
236 		bwrite_sucess = true;
237 
238 		rtlhal->last_hmeboxnum = boxnum + 1;
239 		if (rtlhal->last_hmeboxnum == 4)
240 			rtlhal->last_hmeboxnum = 0;
241 
242 		RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
243 			 "pHalData->last_hmeboxnum  = %d\n",
244 			  rtlhal->last_hmeboxnum);
245 	}
246 
247 	spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
248 	rtlhal->h2c_setinprogress = false;
249 	spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
250 
251 	RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
252 }
253 
254 void rtl8723e_fill_h2c_cmd(struct ieee80211_hw *hw,
255 			   u8 element_id, u32 cmd_len, u8 *cmdbuffer)
256 {
257 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
258 	u32 tmp_cmdbuf[2];
259 
260 	if (!rtlhal->fw_ready) {
261 		WARN_ONCE(true,
262 			  "rtl8723ae: error H2C cmd because of Fw download fail!!!\n");
263 		return;
264 	}
265 	memset(tmp_cmdbuf, 0, 8);
266 	memcpy(tmp_cmdbuf, cmdbuffer, cmd_len);
267 	_rtl8723e_fill_h2c_command(hw, element_id, cmd_len,
268 				   (u8 *)&tmp_cmdbuf);
269 }
270 
271 void rtl8723e_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
272 {
273 	struct rtl_priv *rtlpriv = rtl_priv(hw);
274 	u8 u1_h2c_set_pwrmode[3] = { 0 };
275 	struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
276 
277 	RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
278 
279 	SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
280 	SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
281 		(rtlpriv->mac80211.p2p) ? ppsc->smart_ps : 1);
282 	SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
283 					      ppsc->reg_max_lps_awakeintvl);
284 
285 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
286 		      "rtl8723e_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
287 		      u1_h2c_set_pwrmode, 3);
288 	rtl8723e_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
289 }
290 
291 #define BEACON_PG		0 /* ->1 */
292 #define PSPOLL_PG		2
293 #define NULL_PG			3
294 #define PROBERSP_PG		4 /* ->5 */
295 
296 #define TOTAL_RESERVED_PKT_LEN	768
297 
298 static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
299 	/* page 0 beacon */
300 	0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
301 	0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
302 	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
303 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
304 	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
305 	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
306 	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
307 	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
308 	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
309 	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
310 	0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
312 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
313 	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
314 	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316 
317 	/* page 1 beacon */
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 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
327 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
328 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
329 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
330 	0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
331 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
332 	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
333 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
334 
335 	/* page 2  ps-poll */
336 	0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
337 	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
338 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
339 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
340 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
341 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
342 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
343 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
344 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
345 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
346 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
347 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
348 	0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
349 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
350 	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
351 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
352 
353 	/* page 3  null */
354 	0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
355 	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
356 	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
357 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
358 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
359 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
360 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
361 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
362 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
363 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
364 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
365 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
366 	0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
367 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
368 	0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
369 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
370 
371 	/* page 4  probe_resp */
372 	0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
373 	0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
374 	0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
375 	0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
376 	0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
377 	0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
378 	0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
379 	0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
380 	0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
381 	0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
382 	0x03, 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 	0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
386 	0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
387 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
388 
389 	/* page 5  probe_resp */
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 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
399 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
400 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
401 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
402 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
403 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
404 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
405 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
406 };
407 
408 void rtl8723e_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
409 {
410 	struct rtl_priv *rtlpriv = rtl_priv(hw);
411 	struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
412 	struct sk_buff *skb = NULL;
413 	u32 totalpacketlen;
414 	bool rtstatus;
415 	u8 u1rsvdpageloc[3] = { 0 };
416 	bool b_dlok = false;
417 	u8 *beacon;
418 	u8 *p_pspoll;
419 	u8 *nullfunc;
420 	u8 *p_probersp;
421 
422 	/*---------------------------------------------------------
423 	 *			(1) beacon
424 	 *---------------------------------------------------------
425 	 */
426 	beacon = &reserved_page_packet[BEACON_PG * 128];
427 	SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
428 	SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
429 
430 	/*-------------------------------------------------------
431 	 *			(2) ps-poll
432 	 *--------------------------------------------------------
433 	 */
434 	p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
435 	SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
436 	SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
437 	SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
438 
439 	SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1rsvdpageloc, PSPOLL_PG);
440 
441 	/*--------------------------------------------------------
442 	 *			(3) null data
443 	 *---------------------------------------------------------
444 	 */
445 	nullfunc = &reserved_page_packet[NULL_PG * 128];
446 	SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
447 	SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
448 	SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
449 
450 	SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1rsvdpageloc, NULL_PG);
451 
452 	/*---------------------------------------------------------
453 	 *			(4) probe response
454 	 *----------------------------------------------------------
455 	 */
456 	p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
457 	SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
458 	SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
459 	SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
460 
461 	SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1rsvdpageloc, PROBERSP_PG);
462 
463 	totalpacketlen = TOTAL_RESERVED_PKT_LEN;
464 
465 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
466 		      "rtl8723e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
467 		      &reserved_page_packet[0], totalpacketlen);
468 	RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
469 		      "rtl8723e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
470 		      u1rsvdpageloc, 3);
471 
472 	skb = dev_alloc_skb(totalpacketlen);
473 	skb_put_data(skb, &reserved_page_packet, totalpacketlen);
474 
475 	rtstatus = rtl_cmd_send_packet(hw, skb);
476 
477 	if (rtstatus)
478 		b_dlok = true;
479 
480 	if (b_dlok) {
481 		RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
482 			 "Set RSVD page location to Fw.\n");
483 		RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
484 			      "H2C_RSVDPAGE:\n",
485 			      u1rsvdpageloc, 3);
486 		rtl8723e_fill_h2c_cmd(hw, H2C_RSVDPAGE,
487 				      sizeof(u1rsvdpageloc), u1rsvdpageloc);
488 	} else
489 		RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
490 			 "Set RSVD page location to Fw FAIL!!!!!!.\n");
491 }
492 
493 void rtl8723e_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
494 {
495 	u8 u1_joinbssrpt_parm[1] = { 0 };
496 
497 	SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
498 
499 	rtl8723e_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
500 }
501 
502 static void rtl8723e_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw,
503 					    u8 ctwindow)
504 {
505 	u8 u1_ctwindow_period[1] = { ctwindow};
506 
507 	rtl8723e_fill_h2c_cmd(hw, H2C_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
508 
509 }
510 
511 void rtl8723e_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
512 {
513 	struct rtl_priv *rtlpriv = rtl_priv(hw);
514 	struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
515 	struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
516 	struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
517 	struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
518 	u8	i;
519 	u16	ctwindow;
520 	u32	start_time, tsf_low;
521 
522 	switch (p2p_ps_state) {
523 	case P2P_PS_DISABLE:
524 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
525 		memset(p2p_ps_offload, 0, sizeof(*p2p_ps_offload));
526 		break;
527 	case P2P_PS_ENABLE:
528 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
529 		/* update CTWindow value. */
530 		if (p2pinfo->ctwindow > 0) {
531 			p2p_ps_offload->ctwindow_en = 1;
532 			ctwindow = p2pinfo->ctwindow;
533 			rtl8723e_set_p2p_ctw_period_cmd(hw, ctwindow);
534 		}
535 
536 		/* hw only support 2 set of NoA */
537 		for (i = 0 ; i < p2pinfo->noa_num ; i++) {
538 			/* To control the register setting for which NOA*/
539 			rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
540 			if (i == 0)
541 				p2p_ps_offload->noa0_en = 1;
542 			else
543 				p2p_ps_offload->noa1_en = 1;
544 
545 			/* config P2P NoA Descriptor Register */
546 			rtl_write_dword(rtlpriv, 0x5E0,
547 					p2pinfo->noa_duration[i]);
548 			rtl_write_dword(rtlpriv, 0x5E4,
549 					p2pinfo->noa_interval[i]);
550 
551 			/*Get Current TSF value */
552 			tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
553 
554 			start_time = p2pinfo->noa_start_time[i];
555 			if (p2pinfo->noa_count_type[i] != 1) {
556 				while (start_time <=
557 					(tsf_low+(50*1024))) {
558 					start_time +=
559 						p2pinfo->noa_interval[i];
560 					if (p2pinfo->noa_count_type[i] != 255)
561 						p2pinfo->noa_count_type[i]--;
562 				}
563 			}
564 			rtl_write_dword(rtlpriv, 0x5E8, start_time);
565 			rtl_write_dword(rtlpriv, 0x5EC,
566 				p2pinfo->noa_count_type[i]);
567 
568 		}
569 
570 		if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
571 			/* rst p2p circuit */
572 			rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
573 
574 			p2p_ps_offload->offload_en = 1;
575 
576 			if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
577 				p2p_ps_offload->role = 1;
578 				p2p_ps_offload->allstasleep = 0;
579 			} else {
580 				p2p_ps_offload->role = 0;
581 			}
582 
583 			p2p_ps_offload->discovery = 0;
584 		}
585 		break;
586 	case P2P_PS_SCAN:
587 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
588 		p2p_ps_offload->discovery = 1;
589 		break;
590 	case P2P_PS_SCAN_DONE:
591 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n");
592 		p2p_ps_offload->discovery = 0;
593 		p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
594 		break;
595 	default:
596 		break;
597 	}
598 
599 	rtl8723e_fill_h2c_cmd(hw, H2C_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload);
600 
601 }
602