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