1 /******************************************************************************
2  *
3  * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
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  ******************************************************************************/
15 #define _RTL8723A_CMD_C_
16 
17 #include <osdep_service.h>
18 #include <drv_types.h>
19 #include <recv_osdep.h>
20 #include <mlme_osdep.h>
21 #include <rtl8723a_hal.h>
22 #include <usb_ops_linux.h>
23 
24 #define RTL92C_MAX_H2C_BOX_NUMS		4
25 #define RTL92C_MAX_CMD_LEN		5
26 #define MESSAGE_BOX_SIZE		4
27 #define EX_MESSAGE_BOX_SIZE		2
28 
_is_fw_read_cmd_down(struct rtw_adapter * padapter,u8 msgbox_num)29 static u8 _is_fw_read_cmd_down(struct rtw_adapter *padapter, u8 msgbox_num)
30 {
31 	u8 read_down = false;
32 	int	retry_cnts = 100;
33 	u8 valid;
34 
35 	do {
36 		valid = rtl8723au_read8(padapter, REG_HMETFR) & BIT(msgbox_num);
37 		if (0 == valid)
38 			read_down = true;
39 	} while ((!read_down) && (retry_cnts--));
40 
41 	return read_down;
42 }
43 
44 /*****************************************
45 * H2C Msg format :
46 *| 31 - 8		|7		| 6 - 0	|
47 *| h2c_msg	|Ext_bit	|CMD_ID	|
48 *
49 ******************************************/
FillH2CCmd(struct rtw_adapter * padapter,u8 ElementID,u32 CmdLen,u8 * pCmdBuffer)50 int FillH2CCmd(struct rtw_adapter *padapter, u8 ElementID, u32 CmdLen,
51 	       u8 *pCmdBuffer)
52 {
53 	u8 bcmd_down = false;
54 	s32 retry_cnts = 100;
55 	u8 h2c_box_num;
56 	u32 msgbox_addr;
57 	u32 msgbox_ex_addr;
58 	struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
59 	u32 h2c_cmd = 0;
60 	u16 h2c_cmd_ex = 0;
61 	int ret = _FAIL;
62 
63 	padapter = GET_PRIMARY_ADAPTER(padapter);
64 	pHalData = GET_HAL_DATA(padapter);
65 
66 	mutex_lock(&adapter_to_dvobj(padapter)->h2c_fwcmd_mutex);
67 
68 	if (!pCmdBuffer)
69 		goto exit;
70 	if (CmdLen > RTL92C_MAX_CMD_LEN)
71 		goto exit;
72 	if (padapter->bSurpriseRemoved == true)
73 		goto exit;
74 
75 	/* pay attention to if  race condition happened in  H2C cmd setting. */
76 	do {
77 		h2c_box_num = pHalData->LastHMEBoxNum;
78 
79 		if (!_is_fw_read_cmd_down(padapter, h2c_box_num)) {
80 			DBG_8723A(" fw read cmd failed...\n");
81 			goto exit;
82 		}
83 
84 		if (CmdLen <= 3) {
85 			memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, CmdLen);
86 		} else {
87 			memcpy((u8 *)(&h2c_cmd_ex), pCmdBuffer, EX_MESSAGE_BOX_SIZE);
88 			memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer+2, (CmdLen-EX_MESSAGE_BOX_SIZE));
89 			*(u8 *)(&h2c_cmd) |= BIT(7);
90 		}
91 
92 		*(u8 *)(&h2c_cmd) |= ElementID;
93 
94 		if (h2c_cmd & BIT(7)) {
95 			msgbox_ex_addr = REG_HMEBOX_EXT_0 + (h2c_box_num * EX_MESSAGE_BOX_SIZE);
96 			h2c_cmd_ex = le16_to_cpu(h2c_cmd_ex);
97 			rtl8723au_write16(padapter, msgbox_ex_addr, h2c_cmd_ex);
98 		}
99 		msgbox_addr = REG_HMEBOX_0 + (h2c_box_num * MESSAGE_BOX_SIZE);
100 		h2c_cmd = le32_to_cpu(h2c_cmd);
101 		rtl8723au_write32(padapter, msgbox_addr, h2c_cmd);
102 
103 		bcmd_down = true;
104 
105 		pHalData->LastHMEBoxNum = (h2c_box_num+1) % RTL92C_MAX_H2C_BOX_NUMS;
106 
107 	} while ((!bcmd_down) && (retry_cnts--));
108 
109 	ret = _SUCCESS;
110 
111 exit:
112 	mutex_unlock(&adapter_to_dvobj(padapter)->h2c_fwcmd_mutex);
113 	return ret;
114 }
115 
rtl8723a_set_rssi_cmd(struct rtw_adapter * padapter,u8 * param)116 int rtl8723a_set_rssi_cmd(struct rtw_adapter *padapter, u8 *param)
117 {
118 	*((u32 *)param) = cpu_to_le32(*((u32 *)param));
119 
120 	FillH2CCmd(padapter, RSSI_SETTING_EID, 3, param);
121 
122 	return _SUCCESS;
123 }
124 
rtl8723a_set_raid_cmd(struct rtw_adapter * padapter,u32 mask,u8 arg)125 int rtl8723a_set_raid_cmd(struct rtw_adapter *padapter, u32 mask, u8 arg)
126 {
127 	u8 buf[5];
128 
129 	memset(buf, 0, 5);
130 	mask = cpu_to_le32(mask);
131 	memcpy(buf, &mask, 4);
132 	buf[4]  = arg;
133 
134 	FillH2CCmd(padapter, MACID_CONFIG_EID, 5, buf);
135 
136 	return _SUCCESS;
137 }
138 
139 /* bitmap[0:27] = tx_rate_bitmap */
140 /* bitmap[28:31]= Rate Adaptive id */
141 /* arg[0:4] = macid */
142 /* arg[5] = Short GI */
rtl8723a_add_rateatid(struct rtw_adapter * pAdapter,u32 bitmap,u8 arg,u8 rssi_level)143 void rtl8723a_add_rateatid(struct rtw_adapter *pAdapter, u32 bitmap, u8 arg, u8 rssi_level)
144 {
145 	struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter);
146 	u8 macid = arg & 0x1f;
147 	u32 raid = bitmap & 0xf0000000;
148 
149 	bitmap &= 0x0fffffff;
150 	if (rssi_level != DM_RATR_STA_INIT)
151 		bitmap = ODM_Get_Rate_Bitmap23a(pHalData, macid, bitmap,
152 						rssi_level);
153 
154 	bitmap |= raid;
155 
156 	rtl8723a_set_raid_cmd(pAdapter, bitmap, arg);
157 }
158 
rtl8723a_set_FwPwrMode_cmd(struct rtw_adapter * padapter,u8 Mode)159 void rtl8723a_set_FwPwrMode_cmd(struct rtw_adapter *padapter, u8 Mode)
160 {
161 	struct setpwrmode_parm H2CSetPwrMode;
162 	struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
163 	struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
164 
165 	DBG_8723A("%s: Mode =%d SmartPS =%d UAPSD =%d BcnMode = 0x%02x\n", __func__,
166 			Mode, pwrpriv->smart_ps, padapter->registrypriv.uapsd_enable, pwrpriv->bcn_ant_mode);
167 
168 	/*  Forece leave RF low power mode for 1T1R to
169 	    prevent conficting setting in Fw power */
170 	/*  saving sequence. 2010.06.07. Added by tynli.
171 	    Suggested by SD3 yschang. */
172 	if (Mode != PS_MODE_ACTIVE && pHalData->rf_type != RF_2T2R)
173 		ODM_RF_Saving23a(&pHalData->odmpriv, true);
174 
175 	H2CSetPwrMode.Mode = Mode;
176 	H2CSetPwrMode.SmartPS = pwrpriv->smart_ps;
177 	H2CSetPwrMode.AwakeInterval = 1;
178 	H2CSetPwrMode.bAllQueueUAPSD = padapter->registrypriv.uapsd_enable;
179 	H2CSetPwrMode.BcnAntMode = pwrpriv->bcn_ant_mode;
180 
181 	FillH2CCmd(padapter, SET_PWRMODE_EID, sizeof(H2CSetPwrMode), (u8 *)&H2CSetPwrMode);
182 
183 }
184 
185 static void
ConstructBeacon(struct rtw_adapter * padapter,u8 * pframe,u32 * pLength)186 ConstructBeacon(struct rtw_adapter *padapter, u8 *pframe, u32 *pLength)
187 {
188 	struct ieee80211_mgmt *mgmt;
189 	u32 rate_len, pktlen;
190 	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
191 	struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
192 	struct wlan_bssid_ex *cur_network = &pmlmeinfo->network;
193 	u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
194 
195 	/* DBG_8723A("%s\n", __func__); */
196 
197 	mgmt = (struct ieee80211_mgmt *)pframe;
198 
199 	mgmt->frame_control =
200 		cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON);
201 
202 	ether_addr_copy(mgmt->da, bc_addr);
203 	ether_addr_copy(mgmt->sa, myid(&padapter->eeprompriv));
204 	ether_addr_copy(mgmt->bssid, get_my_bssid23a(cur_network));
205 
206 	/* A Beacon frame shouldn't have fragment bits set */
207 	mgmt->seq_ctrl = 0;
208 
209 	/* timestamp will be inserted by hardware */
210 
211 	put_unaligned_le16(cur_network->beacon_interval,
212 			   &mgmt->u.beacon.beacon_int);
213 
214 	put_unaligned_le16(cur_network->capability,
215 			   &mgmt->u.beacon.capab_info);
216 
217 	pframe = mgmt->u.beacon.variable;
218 	pktlen = offsetof(struct ieee80211_mgmt, u.beacon.variable);
219 
220 	if ((pmlmeinfo->state&0x03) == MSR_AP) {
221 		/* DBG_8723A("ie len =%d\n", cur_network->IELength); */
222 		pktlen += cur_network->IELength;
223 		memcpy(pframe, cur_network->IEs, pktlen);
224 
225 		goto _ConstructBeacon;
226 	}
227 
228 	/* below for ad-hoc mode */
229 
230 	/*  SSID */
231 	pframe = rtw_set_ie23a(pframe, WLAN_EID_SSID,
232 			       cur_network->Ssid.ssid_len,
233 			       cur_network->Ssid.ssid, &pktlen);
234 
235 	/*  supported rates... */
236 	rate_len = rtw_get_rateset_len23a(cur_network->SupportedRates);
237 	pframe = rtw_set_ie23a(pframe, WLAN_EID_SUPP_RATES, ((rate_len > 8) ?
238 			       8 : rate_len), cur_network->SupportedRates, &pktlen);
239 
240 	/*  DS parameter set */
241 	pframe = rtw_set_ie23a(pframe, WLAN_EID_DS_PARAMS, 1, (unsigned char *)
242 			       &cur_network->DSConfig, &pktlen);
243 
244 	if ((pmlmeinfo->state&0x03) == MSR_ADHOC) {
245 		u32 ATIMWindow;
246 		/*  IBSS Parameter Set... */
247 		/* ATIMWindow = cur->ATIMWindow; */
248 		ATIMWindow = 0;
249 		pframe = rtw_set_ie23a(pframe, WLAN_EID_IBSS_PARAMS, 2,
250 				       (unsigned char *)&ATIMWindow, &pktlen);
251 	}
252 
253 	/* todo: ERP IE */
254 
255 	/*  EXTERNDED SUPPORTED RATE */
256 	if (rate_len > 8)
257 		pframe = rtw_set_ie23a(pframe, WLAN_EID_EXT_SUPP_RATES,
258 				       (rate_len - 8),
259 				       (cur_network->SupportedRates + 8),
260 				       &pktlen);
261 
262 	/* todo:HT for adhoc */
263 
264 _ConstructBeacon:
265 
266 	if ((pktlen + TXDESC_SIZE) > 512) {
267 		DBG_8723A("beacon frame too large\n");
268 		return;
269 	}
270 
271 	*pLength = pktlen;
272 
273 	/* DBG_8723A("%s bcn_sz =%d\n", __func__, pktlen); */
274 
275 }
276 
ConstructPSPoll(struct rtw_adapter * padapter,u8 * pframe,u32 * pLength)277 static void ConstructPSPoll(struct rtw_adapter *padapter,
278 			    u8 *pframe, u32 *pLength)
279 {
280 	struct ieee80211_hdr *pwlanhdr;
281 	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
282 	struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
283 
284 	pwlanhdr = (struct ieee80211_hdr *)pframe;
285 
286 	/*  Frame control. */
287 	pwlanhdr->frame_control =
288 		cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
289 	pwlanhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
290 
291 	/*  AID. */
292 	pwlanhdr->duration_id = cpu_to_le16(pmlmeinfo->aid | 0xc000);
293 
294 	/*  BSSID. */
295 	memcpy(pwlanhdr->addr1, get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN);
296 
297 	/*  TA. */
298 	memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN);
299 
300 	*pLength = 16;
301 }
302 
303 static void
ConstructNullFunctionData(struct rtw_adapter * padapter,u8 * pframe,u32 * pLength,u8 * StaAddr,u8 bQoS,u8 AC,u8 bEosp,u8 bForcePowerSave)304 ConstructNullFunctionData(struct rtw_adapter *padapter, u8 *pframe,
305 			  u32 *pLength, u8 *StaAddr, u8 bQoS, u8 AC,
306 			  u8 bEosp, u8 bForcePowerSave)
307 {
308 	struct ieee80211_hdr *pwlanhdr;
309 	u32 pktlen;
310 	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
311 	struct wlan_network *cur_network = &pmlmepriv->cur_network;
312 	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
313 	struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
314 
315 	pwlanhdr = (struct ieee80211_hdr *)pframe;
316 
317 	pwlanhdr->frame_control = 0;
318 	pwlanhdr->seq_ctrl = 0;
319 
320 	if (bForcePowerSave)
321 		pwlanhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
322 
323 	switch (cur_network->network.ifmode) {
324 	case NL80211_IFTYPE_P2P_CLIENT:
325 	case NL80211_IFTYPE_STATION:
326 		pwlanhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_TODS);
327 		memcpy(pwlanhdr->addr1,
328 		       get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN);
329 		memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv),
330 		       ETH_ALEN);
331 		memcpy(pwlanhdr->addr3, StaAddr, ETH_ALEN);
332 		break;
333 	case NL80211_IFTYPE_P2P_GO:
334 	case NL80211_IFTYPE_AP:
335 		pwlanhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
336 		memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
337 		memcpy(pwlanhdr->addr2,
338 		       get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN);
339 		memcpy(pwlanhdr->addr3, myid(&padapter->eeprompriv),
340 		       ETH_ALEN);
341 		break;
342 	case NL80211_IFTYPE_ADHOC:
343 	default:
344 		memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
345 		memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN);
346 		memcpy(pwlanhdr->addr3,
347 		       get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN);
348 		break;
349 	}
350 
351 	if (bQoS == true) {
352 		struct ieee80211_qos_hdr *qoshdr;
353 		qoshdr = (struct ieee80211_qos_hdr *)pframe;
354 
355 		qoshdr->frame_control |=
356 			cpu_to_le16(IEEE80211_FTYPE_DATA |
357 				    IEEE80211_STYPE_QOS_NULLFUNC);
358 
359 		qoshdr->qos_ctrl = cpu_to_le16(AC & IEEE80211_QOS_CTL_TID_MASK);
360 		if (bEosp)
361 			qoshdr->qos_ctrl |= cpu_to_le16(IEEE80211_QOS_CTL_EOSP);
362 
363 		pktlen = sizeof(struct ieee80211_qos_hdr);
364 	} else {
365 		pwlanhdr->frame_control |=
366 			cpu_to_le16(IEEE80211_FTYPE_DATA |
367 				    IEEE80211_STYPE_NULLFUNC);
368 
369 		pktlen = sizeof(struct ieee80211_hdr_3addr);
370 	}
371 
372 	*pLength = pktlen;
373 }
374 
ConstructProbeRsp(struct rtw_adapter * padapter,u8 * pframe,u32 * pLength,u8 * StaAddr,bool bHideSSID)375 static void ConstructProbeRsp(struct rtw_adapter *padapter, u8 *pframe,
376 			      u32 *pLength, u8 *StaAddr, bool bHideSSID)
377 {
378 	struct ieee80211_mgmt *mgmt;
379 	u8 *mac, *bssid;
380 	u32 pktlen;
381 	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
382 	struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
383 	struct wlan_bssid_ex *cur_network = &pmlmeinfo->network;
384 
385 	/* DBG_8723A("%s\n", __func__); */
386 
387 	mgmt = (struct ieee80211_mgmt *)pframe;
388 
389 	mac = myid(&padapter->eeprompriv);
390 	bssid = cur_network->MacAddress;
391 
392 	mgmt->frame_control =
393 		cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP);
394 
395 	mgmt->seq_ctrl = 0;
396 
397 	memcpy(mgmt->da, StaAddr, ETH_ALEN);
398 	memcpy(mgmt->sa, mac, ETH_ALEN);
399 	memcpy(mgmt->bssid, bssid, ETH_ALEN);
400 
401 	put_unaligned_le64(cur_network->tsf,
402 			   &mgmt->u.probe_resp.timestamp);
403 	put_unaligned_le16(cur_network->beacon_interval,
404 			   &mgmt->u.probe_resp.beacon_int);
405 	put_unaligned_le16(cur_network->capability,
406 			   &mgmt->u.probe_resp.capab_info);
407 
408 	pktlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
409 
410 	if (cur_network->IELength > MAX_IE_SZ)
411 		return;
412 
413 	memcpy(mgmt->u.probe_resp.variable, cur_network->IEs,
414 	       cur_network->IELength);
415 	pktlen += (cur_network->IELength);
416 
417 	*pLength = pktlen;
418 }
419 
420 /*  */
421 /*  Description: Fill the reserved packets that FW will use to RSVD page. */
422 /*			Now we just send 4 types packet to rsvd page. */
423 /*			(1)Beacon, (2)Ps-poll, (3)Null data, (4)ProbeRsp. */
424 /*	Input: */
425 /*	    bDLFinished - false: At the first time we will send all the packets as a large packet to Hw, */
426 /*						so we need to set the packet length to total lengh. */
427 /*			      true: At the second time, we should send the first packet (default:beacon) */
428 /*						to Hw again and set the lengh in descriptor to the real beacon lengh. */
429 /*  2009.10.15 by tynli. */
SetFwRsvdPagePkt(struct rtw_adapter * padapter,bool bDLFinished)430 static void SetFwRsvdPagePkt(struct rtw_adapter *padapter, bool bDLFinished)
431 {
432 	struct hal_data_8723a *pHalData;
433 	struct xmit_frame *pmgntframe;
434 	struct pkt_attrib *pattrib;
435 	struct xmit_priv *pxmitpriv;
436 	struct mlme_ext_priv *pmlmeext;
437 	struct mlme_ext_info *pmlmeinfo;
438 	u32 BeaconLength = 0, ProbeRspLength = 0, PSPollLength;
439 	u32 NullDataLength, QosNullLength, BTQosNullLength;
440 	u8 *ReservedPagePacket;
441 	u8 PageNum, PageNeed, TxDescLen;
442 	u16 BufIndex;
443 	u32 TotalPacketLen;
444 	struct rsvdpage_loc	RsvdPageLoc;
445 
446 	DBG_8723A("%s\n", __func__);
447 
448 	ReservedPagePacket = kzalloc(1000, GFP_KERNEL);
449 	if (ReservedPagePacket == NULL) {
450 		DBG_8723A("%s: alloc ReservedPagePacket fail!\n", __func__);
451 		return;
452 	}
453 
454 	pHalData = GET_HAL_DATA(padapter);
455 	pxmitpriv = &padapter->xmitpriv;
456 	pmlmeext = &padapter->mlmeextpriv;
457 	pmlmeinfo = &pmlmeext->mlmext_info;
458 
459 	TxDescLen = TXDESC_SIZE;
460 	PageNum = 0;
461 
462 	/* 3 (1) beacon */
463 	BufIndex = TXDESC_OFFSET;
464 	ConstructBeacon(padapter, &ReservedPagePacket[BufIndex], &BeaconLength);
465 
466 	/*  When we count the first page size, we need to reserve description size for the RSVD */
467 	/*  packet, it will be filled in front of the packet in TXPKTBUF. */
468 	PageNeed = (u8)PageNum_128(TxDescLen + BeaconLength);
469 	/*  To reserved 2 pages for beacon buffer. 2010.06.24. */
470 	if (PageNeed == 1)
471 		PageNeed += 1;
472 	PageNum += PageNeed;
473 	pHalData->FwRsvdPageStartOffset = PageNum;
474 
475 	BufIndex += PageNeed*128;
476 
477 	/* 3 (2) ps-poll */
478 	RsvdPageLoc.LocPsPoll = PageNum;
479 	ConstructPSPoll(padapter, &ReservedPagePacket[BufIndex], &PSPollLength);
480 	rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], PSPollLength, true, false);
481 
482 	PageNeed = (u8)PageNum_128(TxDescLen + PSPollLength);
483 	PageNum += PageNeed;
484 
485 	BufIndex += PageNeed*128;
486 
487 	/* 3 (3) null data */
488 	RsvdPageLoc.LocNullData = PageNum;
489 	ConstructNullFunctionData(padapter, &ReservedPagePacket[BufIndex],
490 				  &NullDataLength,
491 				  get_my_bssid23a(&pmlmeinfo->network),
492 				  false, 0, 0, false);
493 	rtl8723a_fill_fake_txdesc(padapter,
494 				  &ReservedPagePacket[BufIndex-TxDescLen],
495 				  NullDataLength, false, false);
496 
497 	PageNeed = (u8)PageNum_128(TxDescLen + NullDataLength);
498 	PageNum += PageNeed;
499 
500 	BufIndex += PageNeed*128;
501 
502 	/* 3 (4) probe response */
503 	RsvdPageLoc.LocProbeRsp = PageNum;
504 	ConstructProbeRsp(
505 		padapter,
506 		&ReservedPagePacket[BufIndex],
507 		&ProbeRspLength,
508 		get_my_bssid23a(&pmlmeinfo->network),
509 		false);
510 	rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], ProbeRspLength, false, false);
511 
512 	PageNeed = (u8)PageNum_128(TxDescLen + ProbeRspLength);
513 	PageNum += PageNeed;
514 
515 	BufIndex += PageNeed*128;
516 
517 	/* 3 (5) Qos null data */
518 	RsvdPageLoc.LocQosNull = PageNum;
519 	ConstructNullFunctionData(
520 		padapter,
521 		&ReservedPagePacket[BufIndex],
522 		&QosNullLength,
523 		get_my_bssid23a(&pmlmeinfo->network),
524 		true, 0, 0, false);
525 	rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], QosNullLength, false, false);
526 
527 	PageNeed = (u8)PageNum_128(TxDescLen + QosNullLength);
528 	PageNum += PageNeed;
529 
530 	BufIndex += PageNeed*128;
531 
532 	/* 3 (6) BT Qos null data */
533 	RsvdPageLoc.LocBTQosNull = PageNum;
534 	ConstructNullFunctionData(
535 		padapter,
536 		&ReservedPagePacket[BufIndex],
537 		&BTQosNullLength,
538 		get_my_bssid23a(&pmlmeinfo->network),
539 		true, 0, 0, false);
540 	rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], BTQosNullLength, false, true);
541 
542 	TotalPacketLen = BufIndex + BTQosNullLength;
543 
544 	pmgntframe = alloc_mgtxmitframe23a(pxmitpriv);
545 	if (pmgntframe == NULL)
546 		goto exit;
547 
548 	/*  update attribute */
549 	pattrib = &pmgntframe->attrib;
550 	update_mgntframe_attrib23a(padapter, pattrib);
551 	pattrib->qsel = 0x10;
552 	pattrib->pktlen = pattrib->last_txcmdsz = TotalPacketLen - TXDESC_OFFSET;
553 	memcpy(pmgntframe->buf_addr, ReservedPagePacket, TotalPacketLen);
554 
555 	rtl8723au_mgnt_xmit(padapter, pmgntframe);
556 
557 	DBG_8723A("%s: Set RSVD page location to Fw\n", __func__);
558 	FillH2CCmd(padapter, RSVD_PAGE_EID, sizeof(RsvdPageLoc), (u8 *)&RsvdPageLoc);
559 
560 exit:
561 	kfree(ReservedPagePacket);
562 }
563 
rtl8723a_set_FwJoinBssReport_cmd(struct rtw_adapter * padapter,u8 mstatus)564 void rtl8723a_set_FwJoinBssReport_cmd(struct rtw_adapter *padapter, u8 mstatus)
565 {
566 	struct joinbssrpt_parm	JoinBssRptParm;
567 	struct hal_data_8723a	*pHalData = GET_HAL_DATA(padapter);
568 	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
569 	struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
570 
571 	DBG_8723A("%s mstatus(%x)\n", __func__, mstatus);
572 
573 	if (mstatus == 1) {
574 		bool bRecover = false;
575 		u8 v8;
576 
577 		/*  We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C. */
578 		/*  Suggested by filen. Added by tynli. */
579 		rtl8723au_write16(padapter, REG_BCN_PSR_RPT,
580 				  0xC000|pmlmeinfo->aid);
581 		/*  Do not set TSF again here or vWiFi beacon DMA INT will not work. */
582 		/* correct_TSF23a(padapter, pmlmeext); */
583 		/*  Hw sequende enable by dedault. 2010.06.23. by tynli. */
584 		/* rtl8723au_write16(padapter, REG_NQOS_SEQ, ((pmlmeext->mgnt_seq+100)&0xFFF)); */
585 		/* rtl8723au_write8(padapter, REG_HWSEQ_CTRL, 0xFF); */
586 
587 		/*  set REG_CR bit 8 */
588 		v8 = rtl8723au_read8(padapter, REG_CR+1);
589 		v8 |= BIT(0); /*  ENSWBCN */
590 		rtl8723au_write8(padapter,  REG_CR+1, v8);
591 
592 		/*  Disable Hw protection for a time which revserd for Hw sending beacon. */
593 		/*  Fix download reserved page packet fail that access collision with the protection time. */
594 		/*  2010.05.11. Added by tynli. */
595 /*			SetBcnCtrlReg23a(padapter, 0, BIT(3)); */
596 /*			SetBcnCtrlReg23a(padapter, BIT(4), 0); */
597 		SetBcnCtrlReg23a(padapter, BIT(4), BIT(3));
598 
599 		/*  Set FWHW_TXQ_CTRL 0x422[6]= 0 to tell Hw the packet is not a real beacon frame. */
600 		if (pHalData->RegFwHwTxQCtrl & BIT(6))
601 			bRecover = true;
602 
603 		/*  To tell Hw the packet is not a real beacon frame. */
604 		/* U1bTmp = rtl8723au_read8(padapter, REG_FWHW_TXQ_CTRL+2); */
605 		rtl8723au_write8(padapter, REG_FWHW_TXQ_CTRL + 2,
606 				 pHalData->RegFwHwTxQCtrl & ~BIT(6));
607 		pHalData->RegFwHwTxQCtrl &= ~BIT(6);
608 		SetFwRsvdPagePkt(padapter, 0);
609 
610 		/*  2010.05.11. Added by tynli. */
611 		SetBcnCtrlReg23a(padapter, BIT(3), BIT(4));
612 
613 		/*  To make sure that if there exists an adapter which would like to send beacon. */
614 		/*  If exists, the origianl value of 0x422[6] will be 1, we should check this to */
615 		/*  prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */
616 		/*  the beacon cannot be sent by HW. */
617 		/*  2010.06.23. Added by tynli. */
618 		if (bRecover) {
619 			rtl8723au_write8(padapter, REG_FWHW_TXQ_CTRL + 2,
620 					 pHalData->RegFwHwTxQCtrl | BIT(6));
621 			pHalData->RegFwHwTxQCtrl |= BIT(6);
622 		}
623 
624 		/*  Clear CR[8] or beacon packet will not be send to TxBuf anymore. */
625 		v8 = rtl8723au_read8(padapter, REG_CR+1);
626 		v8 &= ~BIT(0); /*  ~ENSWBCN */
627 		rtl8723au_write8(padapter, REG_CR+1, v8);
628 	}
629 
630 	JoinBssRptParm.OpMode = mstatus;
631 
632 	FillH2CCmd(padapter, JOINBSS_RPT_EID, sizeof(JoinBssRptParm), (u8 *)&JoinBssRptParm);
633 
634 }
635 
636 #ifdef CONFIG_8723AU_BT_COEXIST
SetFwRsvdPagePkt_BTCoex(struct rtw_adapter * padapter)637 static void SetFwRsvdPagePkt_BTCoex(struct rtw_adapter *padapter)
638 {
639 	struct hal_data_8723a *pHalData;
640 	struct xmit_frame *pmgntframe;
641 	struct pkt_attrib *pattrib;
642 	struct xmit_priv *pxmitpriv;
643 	struct mlme_ext_priv *pmlmeext;
644 	struct mlme_ext_info *pmlmeinfo;
645 	u8 fakemac[6] = {0x00, 0xe0, 0x4c, 0x00, 0x00, 0x00};
646 	u32 NullDataLength, BTQosNullLength;
647 	u8 *ReservedPagePacket;
648 	u8 PageNum, PageNeed, TxDescLen;
649 	u16 BufIndex;
650 	u32 TotalPacketLen;
651 	struct rsvdpage_loc	RsvdPageLoc;
652 
653 	DBG_8723A("+%s\n", __func__);
654 
655 	ReservedPagePacket = kzalloc(1024, GFP_KERNEL);
656 	if (ReservedPagePacket == NULL) {
657 		DBG_8723A("%s: alloc ReservedPagePacket fail!\n", __func__);
658 		return;
659 	}
660 
661 	pHalData = GET_HAL_DATA(padapter);
662 	pxmitpriv = &padapter->xmitpriv;
663 	pmlmeext = &padapter->mlmeextpriv;
664 	pmlmeinfo = &pmlmeext->mlmext_info;
665 
666 	TxDescLen = TXDESC_SIZE;
667 	PageNum = 0;
668 
669 	/* 3 (1) beacon */
670 	BufIndex = TXDESC_OFFSET;
671 	/*  skip Beacon Packet */
672 	PageNeed = 3;
673 
674 	PageNum += PageNeed;
675 	pHalData->FwRsvdPageStartOffset = PageNum;
676 
677 	BufIndex += PageNeed*128;
678 
679 	/* 3 (3) null data */
680 	RsvdPageLoc.LocNullData = PageNum;
681 	ConstructNullFunctionData(
682 		padapter,
683 		&ReservedPagePacket[BufIndex],
684 		&NullDataLength,
685 		fakemac,
686 		false, 0, 0, false);
687 	rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], NullDataLength, false, false);
688 
689 	PageNeed = (u8)PageNum_128(TxDescLen + NullDataLength);
690 	PageNum += PageNeed;
691 
692 	BufIndex += PageNeed*128;
693 
694 	/* 3 (6) BT Qos null data */
695 	RsvdPageLoc.LocBTQosNull = PageNum;
696 	ConstructNullFunctionData(
697 		padapter,
698 		&ReservedPagePacket[BufIndex],
699 		&BTQosNullLength,
700 		fakemac,
701 		true, 0, 0, false);
702 	rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], BTQosNullLength, false, true);
703 
704 	TotalPacketLen = BufIndex + BTQosNullLength;
705 
706 	pmgntframe = alloc_mgtxmitframe23a(pxmitpriv);
707 	if (pmgntframe == NULL)
708 		goto exit;
709 
710 	/*  update attribute */
711 	pattrib = &pmgntframe->attrib;
712 	update_mgntframe_attrib23a(padapter, pattrib);
713 	pattrib->qsel = 0x10;
714 	pattrib->pktlen = pattrib->last_txcmdsz = TotalPacketLen - TXDESC_OFFSET;
715 	memcpy(pmgntframe->buf_addr, ReservedPagePacket, TotalPacketLen);
716 
717 	rtl8723au_mgnt_xmit(padapter, pmgntframe);
718 
719 	DBG_8723A("%s: Set RSVD page location to Fw\n", __func__);
720 	FillH2CCmd(padapter, RSVD_PAGE_EID, sizeof(RsvdPageLoc), (u8 *)&RsvdPageLoc);
721 
722 exit:
723 	kfree(ReservedPagePacket);
724 }
725 
rtl8723a_set_BTCoex_AP_mode_FwRsvdPkt_cmd(struct rtw_adapter * padapter)726 void rtl8723a_set_BTCoex_AP_mode_FwRsvdPkt_cmd(struct rtw_adapter *padapter)
727 {
728 	struct hal_data_8723a *pHalData;
729 	u8 bRecover = false;
730 
731 	DBG_8723A("+%s\n", __func__);
732 
733 	pHalData = GET_HAL_DATA(padapter);
734 
735 	/*  Set FWHW_TXQ_CTRL 0x422[6]= 0 to tell Hw the packet is not a real beacon frame. */
736 	if (pHalData->RegFwHwTxQCtrl & BIT(6))
737 		bRecover = true;
738 
739 	/*  To tell Hw the packet is not a real beacon frame. */
740 	pHalData->RegFwHwTxQCtrl &= ~BIT(6);
741 	rtl8723au_write8(padapter, REG_FWHW_TXQ_CTRL + 2,
742 			 pHalData->RegFwHwTxQCtrl);
743 	SetFwRsvdPagePkt_BTCoex(padapter);
744 
745 	/*  To make sure that if there exists an adapter which would like to send beacon. */
746 	/*  If exists, the origianl value of 0x422[6] will be 1, we should check this to */
747 	/*  prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */
748 	/*  the beacon cannot be sent by HW. */
749 	/*  2010.06.23. Added by tynli. */
750 	if (bRecover) {
751 		pHalData->RegFwHwTxQCtrl |= BIT(6);
752 		rtl8723au_write8(padapter, REG_FWHW_TXQ_CTRL + 2,
753 				 pHalData->RegFwHwTxQCtrl);
754 	}
755 }
756 #endif
757