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