[go: nahoru, domu]

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
29static 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******************************************/
50int 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
111exit:
112	mutex_unlock(&adapter_to_dvobj(padapter)->h2c_fwcmd_mutex);
113	return ret;
114}
115
116int 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
127int 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 */
146void 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
176void 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
204static void
205ConstructBeacon(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
296static 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
322static void
323ConstructNullFunctionData(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
394static 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. */
449static 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
579exit:
580	kfree(ReservedPagePacket);
581}
582
583void 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
656static 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
741exit:
742	kfree(ReservedPagePacket);
743}
744
745void 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