• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *************************************************************************
3  * Ralink Tech Inc.
4  * 5F., No.36, Taiyuan St., Jhubei City,
5  * Hsinchu County 302,
6  * Taiwan, R.O.C.
7  *
8  * (c) Copyright 2002-2007, Ralink Technology, Inc.
9  *
10  * This program is free software; you can redistribute it and/or modify  *
11  * it under the terms of the GNU General Public License as published by  *
12  * the Free Software Foundation; either version 2 of the License, or     *
13  * (at your option) any later version.                                   *
14  *                                                                       *
15  * This program is distributed in the hope that it will be useful,       *
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
18  * GNU General Public License for more details.                          *
19  *                                                                       *
20  * You should have received a copy of the GNU General Public License     *
21  * along with this program; if not, write to the                         *
22  * Free Software Foundation, Inc.,                                       *
23  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
24  *                                                                       *
25  *************************************************************************
26 */
27 
28 /*
29    All functions in this file must be PCI-depended, or you should out your function
30 	in other files.
31 
32 */
33 #include "../rt_config.h"
34 
35 extern RTMP_RF_REGS RF2850RegTable[];
36 extern UCHAR	NUM_OF_2850_CHNL;
37 
RtmpPCI_WriteTxResource(IN PRTMP_ADAPTER pAd,IN TX_BLK * pTxBlk,IN BOOLEAN bIsLast,OUT USHORT * FreeNumber)38 USHORT RtmpPCI_WriteTxResource(
39 	IN	PRTMP_ADAPTER	pAd,
40 	IN	TX_BLK			*pTxBlk,
41 	IN	BOOLEAN			bIsLast,
42 	OUT	USHORT			*FreeNumber)
43 {
44 
45 	UCHAR			*pDMAHeaderBufVA;
46 	USHORT			TxIdx, RetTxIdx;
47 	PTXD_STRUC		pTxD;
48 	UINT32			BufBasePaLow;
49 	PRTMP_TX_RING	pTxRing;
50 	USHORT			hwHeaderLen;
51 
52 	//
53 	// get Tx Ring Resource
54 	//
55 	pTxRing = &pAd->TxRing[pTxBlk->QueIdx];
56 	TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx;
57 	pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa;
58 	BufBasePaLow = RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa);
59 
60 	// copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer
61 	if (pTxBlk->TxFrameType == TX_AMSDU_FRAME)
62 	{
63 		hwHeaderLen = pTxBlk->MpduHeaderLen - LENGTH_AMSDU_SUBFRAMEHEAD + pTxBlk->HdrPadLen + LENGTH_AMSDU_SUBFRAMEHEAD;
64 	}
65 	else
66 	{
67 		hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen;
68 	}
69 	NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHeaderLen);
70 
71 	pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket;
72 	pTxRing->Cell[TxIdx].pNextNdisPacket = NULL;
73 
74 	//
75 	// build Tx Descriptor
76 	//
77 
78 	pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
79 	NdisZeroMemory(pTxD, TXD_SIZE);
80 
81 	pTxD->SDPtr0 = BufBasePaLow;
82 	pTxD->SDLen0 = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen; // include padding
83 	pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);;
84 	pTxD->SDLen1 = pTxBlk->SrcBufLen;
85 	pTxD->LastSec0 = 0;
86 	pTxD->LastSec1 = (bIsLast) ? 1 : 0;
87 
88 	RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA);
89 
90 	RetTxIdx = TxIdx;
91 	//
92 	// Update Tx index
93 	//
94 	INC_RING_INDEX(TxIdx, TX_RING_SIZE);
95 	pTxRing->TxCpuIdx = TxIdx;
96 
97 	*FreeNumber -= 1;
98 
99 	return RetTxIdx;
100 }
101 
102 
RtmpPCI_WriteSingleTxResource(IN PRTMP_ADAPTER pAd,IN TX_BLK * pTxBlk,IN BOOLEAN bIsLast,OUT USHORT * FreeNumber)103 USHORT RtmpPCI_WriteSingleTxResource(
104 	IN	PRTMP_ADAPTER	pAd,
105 	IN	TX_BLK			*pTxBlk,
106 	IN	BOOLEAN			bIsLast,
107 	OUT	USHORT			*FreeNumber)
108 {
109 
110 	UCHAR			*pDMAHeaderBufVA;
111 	USHORT			TxIdx, RetTxIdx;
112 	PTXD_STRUC		pTxD;
113 #ifdef RT_BIG_ENDIAN
114     PTXD_STRUC      pDestTxD;
115     TXD_STRUC       TxD;
116 #endif
117 	UINT32			BufBasePaLow;
118 	PRTMP_TX_RING	pTxRing;
119 	USHORT			hwHeaderLen;
120 
121 	//
122 	// get Tx Ring Resource
123 	//
124 	pTxRing = &pAd->TxRing[pTxBlk->QueIdx];
125 	TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx;
126 	pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa;
127 	BufBasePaLow = RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa);
128 
129 	// copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer
130 	hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen;
131 
132 	NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, TXINFO_SIZE + TXWI_SIZE + hwHeaderLen);
133 
134 	pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket;
135 	pTxRing->Cell[TxIdx].pNextNdisPacket = NULL;
136 
137 	//
138 	// build Tx Descriptor
139 	//
140 #ifndef RT_BIG_ENDIAN
141 	pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
142 #else
143 	pDestTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
144 	TxD = *pDestTxD;
145 	pTxD = &TxD;
146 #endif
147 	NdisZeroMemory(pTxD, TXD_SIZE);
148 
149 	pTxD->SDPtr0 = BufBasePaLow;
150 	pTxD->SDLen0 = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen; // include padding
151 	pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);;
152 	pTxD->SDLen1 = pTxBlk->SrcBufLen;
153 	pTxD->LastSec0 = 0;
154 	pTxD->LastSec1 = (bIsLast) ? 1 : 0;
155 
156 	RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA);
157 #ifdef RT_BIG_ENDIAN
158 	RTMPWIEndianChange((PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE), TYPE_TXWI);
159 	RTMPFrameEndianChange(pAd, (PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE);
160 	RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD);
161     WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD);
162 #endif // RT_BIG_ENDIAN //
163 
164 	RetTxIdx = TxIdx;
165 	//
166 	// Update Tx index
167 	//
168 	INC_RING_INDEX(TxIdx, TX_RING_SIZE);
169 	pTxRing->TxCpuIdx = TxIdx;
170 
171 	*FreeNumber -= 1;
172 
173 	return RetTxIdx;
174 }
175 
176 
RtmpPCI_WriteMultiTxResource(IN PRTMP_ADAPTER pAd,IN TX_BLK * pTxBlk,IN UCHAR frameNum,OUT USHORT * FreeNumber)177 USHORT RtmpPCI_WriteMultiTxResource(
178 	IN	PRTMP_ADAPTER	pAd,
179 	IN	TX_BLK			*pTxBlk,
180 	IN	UCHAR			frameNum,
181 	OUT	USHORT			*FreeNumber)
182 {
183 	BOOLEAN bIsLast;
184 	UCHAR			*pDMAHeaderBufVA;
185 	USHORT			TxIdx, RetTxIdx;
186 	PTXD_STRUC		pTxD;
187 #ifdef RT_BIG_ENDIAN
188     PTXD_STRUC      pDestTxD;
189     TXD_STRUC       TxD;
190 #endif
191 	UINT32			BufBasePaLow;
192 	PRTMP_TX_RING	pTxRing;
193 	USHORT			hwHdrLen;
194 	UINT32			firstDMALen;
195 
196 	bIsLast = ((frameNum == (pTxBlk->TotalFrameNum - 1)) ? 1 : 0);
197 
198 	//
199 	// get Tx Ring Resource
200 	//
201 	pTxRing = &pAd->TxRing[pTxBlk->QueIdx];
202 	TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx;
203 	pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa;
204 	BufBasePaLow = RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa);
205 
206 	if (frameNum == 0)
207 	{
208 		// copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer
209 		if (pTxBlk->TxFrameType == TX_AMSDU_FRAME)
210 			//hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_AMSDU_SUBFRAMEHEAD, 4)+LENGTH_AMSDU_SUBFRAMEHEAD;
211 			hwHdrLen = pTxBlk->MpduHeaderLen - LENGTH_AMSDU_SUBFRAMEHEAD + pTxBlk->HdrPadLen + LENGTH_AMSDU_SUBFRAMEHEAD;
212 		else if (pTxBlk->TxFrameType == TX_RALINK_FRAME)
213 			//hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_ARALINK_HEADER_FIELD, 4)+LENGTH_ARALINK_HEADER_FIELD;
214 			hwHdrLen = pTxBlk->MpduHeaderLen - LENGTH_ARALINK_HEADER_FIELD + pTxBlk->HdrPadLen + LENGTH_ARALINK_HEADER_FIELD;
215 		else
216 			//hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4);
217 			hwHdrLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen;
218 
219 		firstDMALen = TXINFO_SIZE + TXWI_SIZE + hwHdrLen;
220 	}
221 	else
222 	{
223 		firstDMALen = pTxBlk->MpduHeaderLen;
224 	}
225 
226 	NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, firstDMALen);
227 
228 	pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket;
229 	pTxRing->Cell[TxIdx].pNextNdisPacket = NULL;
230 
231 	//
232 	// build Tx Descriptor
233 	//
234 #ifndef RT_BIG_ENDIAN
235 	pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
236 #else
237 	pDestTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
238 	TxD = *pDestTxD;
239 	pTxD = &TxD;
240 #endif
241 	NdisZeroMemory(pTxD, TXD_SIZE);
242 
243 	pTxD->SDPtr0 = BufBasePaLow;
244 	pTxD->SDLen0 = firstDMALen; // include padding
245 	pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);;
246 	pTxD->SDLen1 = pTxBlk->SrcBufLen;
247 	pTxD->LastSec0 = 0;
248 	pTxD->LastSec1 = (bIsLast) ? 1 : 0;
249 
250 	RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA);
251 
252 #ifdef RT_BIG_ENDIAN
253 	if (frameNum == 0)
254 		RTMPFrameEndianChange(pAd, (PUCHAR)(pDMAHeaderBufVA+ TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE);
255 
256 	if (frameNum != 0)
257 		RTMPWIEndianChange((PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE), TYPE_TXWI);
258 
259 	RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD);
260 	WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD);
261 #endif // RT_BIG_ENDIAN //
262 
263 	RetTxIdx = TxIdx;
264 	//
265 	// Update Tx index
266 	//
267 	INC_RING_INDEX(TxIdx, TX_RING_SIZE);
268 	pTxRing->TxCpuIdx = TxIdx;
269 
270 	*FreeNumber -= 1;
271 
272 	return RetTxIdx;
273 
274 }
275 
276 
RtmpPCI_FinalWriteTxResource(IN PRTMP_ADAPTER pAd,IN TX_BLK * pTxBlk,IN USHORT totalMPDUSize,IN USHORT FirstTxIdx)277 VOID RtmpPCI_FinalWriteTxResource(
278 	IN	PRTMP_ADAPTER	pAd,
279 	IN	TX_BLK			*pTxBlk,
280 	IN	USHORT			totalMPDUSize,
281 	IN	USHORT			FirstTxIdx)
282 {
283 
284 	PTXWI_STRUC		pTxWI;
285 	PRTMP_TX_RING	pTxRing;
286 
287 	//
288 	// get Tx Ring Resource
289 	//
290 	pTxRing = &pAd->TxRing[pTxBlk->QueIdx];
291 	pTxWI = (PTXWI_STRUC) pTxRing->Cell[FirstTxIdx].DmaBuf.AllocVa;
292 	pTxWI->MPDUtotalByteCount = totalMPDUSize;
293 #ifdef RT_BIG_ENDIAN
294 	RTMPWIEndianChange((PUCHAR)pTxWI, TYPE_TXWI);
295 #endif // RT_BIG_ENDIAN //
296 
297 }
298 
299 
RtmpPCIDataLastTxIdx(IN PRTMP_ADAPTER pAd,IN UCHAR QueIdx,IN USHORT LastTxIdx)300 VOID RtmpPCIDataLastTxIdx(
301 	IN	PRTMP_ADAPTER	pAd,
302 	IN	UCHAR			QueIdx,
303 	IN	USHORT			LastTxIdx)
304 {
305 	PTXD_STRUC		pTxD;
306 #ifdef RT_BIG_ENDIAN
307     PTXD_STRUC      pDestTxD;
308     TXD_STRUC       TxD;
309 #endif
310 	PRTMP_TX_RING	pTxRing;
311 
312 	//
313 	// get Tx Ring Resource
314 	//
315 	pTxRing = &pAd->TxRing[QueIdx];
316 
317 	//
318 	// build Tx Descriptor
319 	//
320 #ifndef RT_BIG_ENDIAN
321 	pTxD = (PTXD_STRUC) pTxRing->Cell[LastTxIdx].AllocVa;
322 #else
323 	pDestTxD = (PTXD_STRUC) pTxRing->Cell[LastTxIdx].AllocVa;
324 	TxD = *pDestTxD;
325 	pTxD = &TxD;
326 #endif
327 
328 	pTxD->LastSec1 = 1;
329 
330 #ifdef RT_BIG_ENDIAN
331 	RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD);
332     WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD);
333 #endif // RT_BIG_ENDIAN //
334 
335 }
336 
337 
RtmpPCI_WriteFragTxResource(IN PRTMP_ADAPTER pAd,IN TX_BLK * pTxBlk,IN UCHAR fragNum,OUT USHORT * FreeNumber)338 USHORT	RtmpPCI_WriteFragTxResource(
339 	IN	PRTMP_ADAPTER	pAd,
340 	IN	TX_BLK			*pTxBlk,
341 	IN	UCHAR			fragNum,
342 	OUT	USHORT			*FreeNumber)
343 {
344 	UCHAR			*pDMAHeaderBufVA;
345 	USHORT			TxIdx, RetTxIdx;
346 	PTXD_STRUC		pTxD;
347 #ifdef RT_BIG_ENDIAN
348     PTXD_STRUC      pDestTxD;
349     TXD_STRUC       TxD;
350 #endif
351 	UINT32			BufBasePaLow;
352 	PRTMP_TX_RING	pTxRing;
353 	USHORT			hwHeaderLen;
354 	UINT32			firstDMALen;
355 
356 	//
357 	// Get Tx Ring Resource
358 	//
359 	pTxRing = &pAd->TxRing[pTxBlk->QueIdx];
360 	TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx;
361 	pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa;
362 	BufBasePaLow = RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa);
363 
364 	//
365 	// Copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer
366 	//
367 	hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen;
368 
369 	firstDMALen = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen;
370 	NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, firstDMALen);
371 
372 
373 	//
374 	// Build Tx Descriptor
375 	//
376 #ifndef RT_BIG_ENDIAN
377 	pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
378 #else
379 	pDestTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
380 	TxD = *pDestTxD;
381 	pTxD = &TxD;
382 #endif
383 	NdisZeroMemory(pTxD, TXD_SIZE);
384 
385 	if (fragNum == pTxBlk->TotalFragNum)
386 	{
387 		pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket;
388 		pTxRing->Cell[TxIdx].pNextNdisPacket = NULL;
389 	}
390 
391 	pTxD->SDPtr0 = BufBasePaLow;
392 	pTxD->SDLen0 = firstDMALen; // include padding
393 	pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);
394 	pTxD->SDLen1 = pTxBlk->SrcBufLen;
395 	pTxD->LastSec0 = 0;
396 	pTxD->LastSec1 = 1;
397 
398 	RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA);
399 
400 #ifdef RT_BIG_ENDIAN
401 	RTMPWIEndianChange((PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE), TYPE_TXWI);
402 	RTMPFrameEndianChange(pAd, (PUCHAR)(pDMAHeaderBufVA + TXINFO_SIZE + TXWI_SIZE), DIR_WRITE, FALSE);
403 	RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD);
404     WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD);
405 #endif // RT_BIG_ENDIAN //
406 
407 	RetTxIdx = TxIdx;
408 	pTxBlk->Priv += pTxBlk->SrcBufLen;
409 
410 	//
411 	// Update Tx index
412 	//
413 	INC_RING_INDEX(TxIdx, TX_RING_SIZE);
414 	pTxRing->TxCpuIdx = TxIdx;
415 
416 	*FreeNumber -= 1;
417 
418 	return RetTxIdx;
419 
420 }
421 
422 /*
423 	Must be run in Interrupt context
424 	This function handle PCI specific TxDesc and cpu index update and kick the packet out.
425  */
RtmpPCIMgmtKickOut(IN RTMP_ADAPTER * pAd,IN UCHAR QueIdx,IN PNDIS_PACKET pPacket,IN PUCHAR pSrcBufVA,IN UINT SrcBufLen)426 int RtmpPCIMgmtKickOut(
427 	IN RTMP_ADAPTER 	*pAd,
428 	IN UCHAR 			QueIdx,
429 	IN PNDIS_PACKET		pPacket,
430 	IN PUCHAR			pSrcBufVA,
431 	IN UINT 			SrcBufLen)
432 {
433 	PTXD_STRUC		pTxD;
434 #ifdef RT_BIG_ENDIAN
435     PTXD_STRUC      pDestTxD;
436     TXD_STRUC       TxD;
437 #endif
438 	ULONG			SwIdx = pAd->MgmtRing.TxCpuIdx;
439 
440 #ifdef RT_BIG_ENDIAN
441     pDestTxD  = (PTXD_STRUC)pAd->MgmtRing.Cell[SwIdx].AllocVa;
442     TxD = *pDestTxD;
443     pTxD = &TxD;
444     RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD);
445 #else
446 	pTxD  = (PTXD_STRUC) pAd->MgmtRing.Cell[SwIdx].AllocVa;
447 #endif
448 
449 	pAd->MgmtRing.Cell[SwIdx].pNdisPacket = pPacket;
450 	pAd->MgmtRing.Cell[SwIdx].pNextNdisPacket = NULL;
451 
452 	RTMPWriteTxDescriptor(pAd, pTxD, TRUE, FIFO_MGMT);
453 	pTxD->LastSec0 = 1;
454 	pTxD->LastSec1 = 1;
455 	pTxD->DMADONE = 0;
456 	pTxD->SDLen1 = 0;
457 	pTxD->SDPtr0 = PCI_MAP_SINGLE(pAd, pSrcBufVA, SrcBufLen, 0, PCI_DMA_TODEVICE);;
458 	pTxD->SDLen0 = SrcBufLen;
459 
460 #ifdef RT_BIG_ENDIAN
461 	RTMPDescriptorEndianChange((PUCHAR)pTxD, TYPE_TXD);
462     WriteBackToDescriptor((PUCHAR)pDestTxD, (PUCHAR)pTxD, FALSE, TYPE_TXD);
463 #endif
464 
465 	pAd->RalinkCounters.KickTxCount++;
466 	pAd->RalinkCounters.OneSecTxDoneCount++;
467 
468 	// Increase TX_CTX_IDX, but write to register later.
469 	INC_RING_INDEX(pAd->MgmtRing.TxCpuIdx, MGMT_RING_SIZE);
470 
471 	RTMP_IO_WRITE32(pAd, TX_MGMTCTX_IDX,  pAd->MgmtRing.TxCpuIdx);
472 
473 	return 0;
474 }
475 
476 
477 #ifdef CONFIG_STA_SUPPORT
478 /*
479 	========================================================================
480 
481 	Routine Description:
482 		Check Rx descriptor, return NDIS_STATUS_FAILURE if any error dound
483 
484 	Arguments:
485 		pRxD		Pointer to the Rx descriptor
486 
487 	Return Value:
488 		NDIS_STATUS_SUCCESS 	No err
489 		NDIS_STATUS_FAILURE 	Error
490 
491 	Note:
492 
493 	========================================================================
494 */
RTMPCheckRxError(IN PRTMP_ADAPTER pAd,IN PHEADER_802_11 pHeader,IN PRXWI_STRUC pRxWI,IN PRT28XX_RXD_STRUC pRxD)495 NDIS_STATUS RTMPCheckRxError(
496 	IN	PRTMP_ADAPTER		pAd,
497 	IN	PHEADER_802_11		pHeader,
498 	IN	PRXWI_STRUC 		pRxWI,
499 	IN  PRT28XX_RXD_STRUC 	pRxD)
500 {
501 	PCIPHER_KEY pWpaKey;
502 	INT dBm;
503 
504 	// Phy errors & CRC errors
505 	if (/*(pRxD->PhyErr) ||*/ (pRxD->Crc))
506 	{
507 		// Check RSSI for Noise Hist statistic collection.
508 		dBm = (INT) (pRxWI->RSSI0) - pAd->BbpRssiToDbmDelta;
509 		if (dBm <= -87)
510 			pAd->StaCfg.RPIDensity[0] += 1;
511 		else if (dBm <= -82)
512 			pAd->StaCfg.RPIDensity[1] += 1;
513 		else if (dBm <= -77)
514 			pAd->StaCfg.RPIDensity[2] += 1;
515 		else if (dBm <= -72)
516 			pAd->StaCfg.RPIDensity[3] += 1;
517 		else if (dBm <= -67)
518 			pAd->StaCfg.RPIDensity[4] += 1;
519 		else if (dBm <= -62)
520 			pAd->StaCfg.RPIDensity[5] += 1;
521 		else if (dBm <= -57)
522 			pAd->StaCfg.RPIDensity[6] += 1;
523 		else if (dBm > -57)
524 			pAd->StaCfg.RPIDensity[7] += 1;
525 
526 		return(NDIS_STATUS_FAILURE);
527 	}
528 
529 	// Add Rx size to channel load counter, we should ignore error counts
530 	pAd->StaCfg.CLBusyBytes += (pRxD->SDL0 + 14);
531 
532 	// Drop ToDs promiscous frame, it is opened due to CCX 2 channel load statistics
533 	if (pHeader != NULL)
534 	{
535 		if (pHeader->FC.ToDs)
536 		{
537 			return(NDIS_STATUS_FAILURE);
538 		}
539 	}
540 
541 	// Drop not U2M frames, cant's drop here because we will drop beacon in this case
542 	// I am kind of doubting the U2M bit operation
543 	// if (pRxD->U2M == 0)
544 	//	return(NDIS_STATUS_FAILURE);
545 
546 	// drop decyption fail frame
547 	if (pRxD->CipherErr)
548 	{
549 		if (pRxD->CipherErr == 2)
550 			{DBGPRINT_RAW(RT_DEBUG_TRACE,("pRxD ERROR: ICV ok but MICErr "));}
551 		else if (pRxD->CipherErr == 1)
552 			{DBGPRINT_RAW(RT_DEBUG_TRACE,("pRxD ERROR: ICV Err "));}
553 		else if (pRxD->CipherErr == 3)
554 			DBGPRINT_RAW(RT_DEBUG_TRACE,("pRxD ERROR: Key not valid "));
555 
556         if (((pRxD->CipherErr & 1) == 1) && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd))
557             RTMPSendWirelessEvent(pAd, IW_ICV_ERROR_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
558 
559 		DBGPRINT_RAW(RT_DEBUG_TRACE,(" %d (len=%d, Mcast=%d, MyBss=%d, Wcid=%d, KeyId=%d)\n",
560 			pRxD->CipherErr,
561 			pRxD->SDL0,
562 			pRxD->Mcast | pRxD->Bcast,
563 			pRxD->MyBss,
564 			pRxWI->WirelessCliID,
565 			pRxWI->KeyIndex));
566 
567 		//
568 		// MIC Error
569 		//
570 		if (pRxD->CipherErr == 2)
571 		{
572 			pWpaKey = &pAd->SharedKey[BSS0][pRxWI->KeyIndex];
573 #ifdef WPA_SUPPLICANT_SUPPORT
574             if (pAd->StaCfg.WpaSupplicantUP)
575                 WpaSendMicFailureToWpaSupplicant(pAd,
576                                    (pWpaKey->Type == PAIRWISEKEY) ? TRUE:FALSE);
577             else
578 #endif // WPA_SUPPLICANT_SUPPORT //
579 			    RTMPReportMicError(pAd, pWpaKey);
580 
581             if (((pRxD->CipherErr & 2) == 2) && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd))
582                 RTMPSendWirelessEvent(pAd, IW_MIC_ERROR_EVENT_FLAG, pAd->MacTab.Content[BSSID_WCID].Addr, BSS0, 0);
583 
584 			DBGPRINT_RAW(RT_DEBUG_ERROR,("Rx MIC Value error\n"));
585 		}
586 
587 		if (pHeader == NULL)
588 			return(NDIS_STATUS_SUCCESS);
589 
590 		return(NDIS_STATUS_FAILURE);
591 	}
592 
593 	return(NDIS_STATUS_SUCCESS);
594 }
595 
596 /*
597 	==========================================================================
598 	Description:
599 		This routine sends command to firmware and turn our chip to power save mode.
600 		Both RadioOff and .11 power save function needs to call this routine.
601 	Input:
602 		Level = GUIRADIO_OFF  : GUI Radio Off mode
603 		Level = DOT11POWERSAVE  : 802.11 power save mode
604 		Level = RTMP_HALT  : When Disable device.
605 
606 	==========================================================================
607  */
RT28xxPciAsicRadioOff(IN PRTMP_ADAPTER pAd,IN UCHAR Level,IN USHORT TbttNumToNextWakeUp)608 VOID RT28xxPciAsicRadioOff(
609 	IN PRTMP_ADAPTER    pAd,
610 	IN UCHAR            Level,
611 	IN USHORT           TbttNumToNextWakeUp)
612 {
613 	WPDMA_GLO_CFG_STRUC	DmaCfg;
614 	UCHAR		i, tempBBP_R3 = 0;
615 	BOOLEAN		brc = FALSE, Cancelled;
616     UINT32		TbTTTime = 0;
617 	UINT32		PsPollTime = 0, MACValue;
618     ULONG		BeaconPeriodTime;
619     UINT32		RxDmaIdx, RxCpuIdx;
620 	DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> TxCpuIdx = %d, TxDmaIdx = %d. RxCpuIdx = %d, RxDmaIdx = %d.\n", pAd->TxRing[0].TxCpuIdx, pAd->TxRing[0].TxDmaIdx, pAd->RxRing.RxCpuIdx, pAd->RxRing.RxDmaIdx));
621 
622     // Check Rx DMA busy status, if more than half is occupied, give up this radio off.
623 	RTMP_IO_READ32(pAd, RX_DRX_IDX , &RxDmaIdx);
624 	RTMP_IO_READ32(pAd, RX_CRX_IDX , &RxCpuIdx);
625 	if ((RxDmaIdx > RxCpuIdx) && ((RxDmaIdx - RxCpuIdx) > RX_RING_SIZE/3))
626 	{
627 		DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> return1. RxDmaIdx = %d ,  RxCpuIdx = %d. \n", RxDmaIdx, RxCpuIdx));
628 		return;
629 	}
630 	else if ((RxCpuIdx >= RxDmaIdx) && ((RxCpuIdx - RxDmaIdx) < RX_RING_SIZE/3))
631 	{
632 		DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> return2.  RxCpuIdx = %d. RxDmaIdx = %d ,  \n", RxCpuIdx, RxDmaIdx));
633 		return;
634 	}
635 
636     // Once go into this function, disable tx because don't want too many packets in queue to prevent HW stops.
637 	pAd->bPCIclkOffDisableTx = TRUE;
638 
639 	if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
640 	{
641 	    RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer,	&Cancelled);
642 	    RTMPCancelTimer(&pAd->Mlme.PsPollTimer,	&Cancelled);
643 
644 	    if (Level == DOT11POWERSAVE)
645 		{
646 			RTMP_IO_READ32(pAd, TBTT_TIMER, &TbTTTime);
647 			TbTTTime &= 0x1ffff;
648 			// 00. check if need to do sleep in this DTIM period.   If next beacon will arrive within 30ms , ...doesn't necessarily sleep.
649 			// TbTTTime uint = 64us, LEAD_TIME unit = 1024us, PsPollTime unit = 1ms
650 	        if  (((64*TbTTTime) <((LEAD_TIME*1024) + 40000)) && (TbttNumToNextWakeUp == 0))
651 			{
652 				DBGPRINT(RT_DEBUG_TRACE, ("TbTTTime = 0x%x , give up this sleep. \n", TbTTTime));
653 	            OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
654 	            pAd->bPCIclkOffDisableTx = FALSE;
655 				return;
656 			}
657 			else
658 			{
659 				PsPollTime = (64*TbTTTime- LEAD_TIME*1024)/1000;
660 				PsPollTime -= 3;
661 
662 	            BeaconPeriodTime = pAd->CommonCfg.BeaconPeriod*102/100;
663 				if (TbttNumToNextWakeUp > 0)
664 					PsPollTime += ((TbttNumToNextWakeUp -1) * BeaconPeriodTime);
665 
666 	            pAd->Mlme.bPsPollTimerRunning = TRUE;
667 				RTMPSetTimer(&pAd->Mlme.PsPollTimer, PsPollTime);
668 			}
669 		}
670 	}
671 
672     // 0. Disable Tx DMA.
673 	RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
674 	DmaCfg.field.EnableTxDMA = 0;
675 	RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
676 
677 	// 1. Wait DMA not busy
678 	i = 0;
679 	do
680 	{
681 		RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
682 		if ((DmaCfg.field.TxDMABusy == 0) && (DmaCfg.field.RxDMABusy == 0))
683 			break;
684 		RTMPusecDelay(20);
685 		i++;
686 	}while(i < 50);
687 
688 	if (i >= 50)
689 	{
690 		DBGPRINT(RT_DEBUG_TRACE, ("DMA keeps busy.  return on RT28xxPciAsicRadioOff ()\n"));
691 		pAd->bPCIclkOffDisableTx = FALSE;
692 		RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
693 		DmaCfg.field.EnableTxDMA = 1;
694 		RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
695 		return;
696 	}
697 
698     RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
699 
700     // Set to 1R.
701     tempBBP_R3 = (pAd->StaCfg.BBPR3 & 0xE7);
702 	RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, tempBBP_R3);
703 
704 	// In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
705 	if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
706 		&& (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
707 	{
708 		// Must using 40MHz.
709 		AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel);
710 	}
711 	else
712 	{
713 		// Must using 20MHz.
714 		AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel);
715 	}
716 
717     // When PCI clock is off, don't want to service interrupt.
718 	RTMP_IO_WRITE32(pAd, INT_MASK_CSR, AutoWakeupInt);
719 
720     RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx);
721 	// Disable MAC Rx
722 	RTMP_IO_READ32(pAd, MAC_SYS_CTRL , &MACValue);
723 	MACValue &= 0xf7;
724 	RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL , MACValue);
725 
726 	//  2. Send Sleep command
727 	RTMP_IO_WRITE32(pAd, H2M_MAILBOX_STATUS, 0xffffffff);
728 	RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CID, 0xffffffff);
729 	AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x00);   // send POWER-SAVE command to MCU. Timeout unit:40us.
730 	//  2-1. Wait command success
731 	// Status = 1 : success, Status = 2, already sleep, Status = 3, Maybe MAC is busy so can't finish this task.
732 	brc = AsicCheckCommanOk(pAd, PowerSafeCID);
733 
734     if (brc == FALSE)
735     {
736         // try again
737     	AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x00);   // send POWER-SAVE command to MCU. Timeout unit:40us.
738     	//RTMPusecDelay(200);
739     	brc = AsicCheckCommanOk(pAd, PowerSafeCID);
740     }
741 
742 	//  3. After 0x30 command is ok, send radio off command. lowbyte = 0 for power safe.
743 	// If 0x30 command is not ok this time, we can ignore 0x35 command. It will make sure not cause firmware'r problem.
744 	if ((Level == DOT11POWERSAVE) && (brc == TRUE))
745 	{
746 		AsicSendCommandToMcu(pAd, 0x35, PowerRadioOffCID, 0, 0x00);	// lowbyte = 0 means to do power safe, NOT turn off radio.
747 	 	//  3-1. Wait command success
748 	 	AsicCheckCommanOk(pAd, PowerRadioOffCID);
749 	}
750 	else if (brc == TRUE)
751 	{
752 		AsicSendCommandToMcu(pAd, 0x35, PowerRadioOffCID, 1, 0x00);	// lowbyte = 0 means to do power safe, NOT turn off radio.
753 	 	//  3-1. Wait command success
754 	 	AsicCheckCommanOk(pAd, PowerRadioOffCID);
755 	}
756 
757     // Wait DMA not busy
758 	i = 0;
759 	do
760 	{
761 		RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
762 		if (DmaCfg.field.RxDMABusy == 0)
763 			break;
764 		RTMPusecDelay(20);
765 		i++;
766 	}while(i < 50);
767 
768 	if (i >= 50)
769 	{
770 		DBGPRINT(RT_DEBUG_TRACE, ("DMA Rx keeps busy.  on RT28xxPciAsicRadioOff ()\n"));
771 	}
772 	// disable DMA Rx.
773 	{
774 		RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
775 		DmaCfg.field.EnableRxDMA = 0;
776 		RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
777 	}
778 
779 	if (Level == DOT11POWERSAVE)
780 	{
781 		AUTO_WAKEUP_STRUC	AutoWakeupCfg;
782 		//RTMPSetTimer(&pAd->Mlme.PsPollTimer, 90);
783 
784 		// we have decided to SLEEP, so at least do it for a BEACON period.
785 		if (TbttNumToNextWakeUp == 0)
786 			TbttNumToNextWakeUp = 1;
787 
788 		AutoWakeupCfg.word = 0;
789 		RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
790 
791 		// 1. Set auto wake up timer.
792 		AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1;
793 		AutoWakeupCfg.field.EnableAutoWakeup = 1;
794 		AutoWakeupCfg.field.AutoLeadTime = LEAD_TIME;
795 		RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
796 	}
797 
798 	//  4-1. If it's to disable our device. Need to restore PCI Configuration Space to its original value.
799 	if (Level == RTMP_HALT)
800 	{
801 		if ((brc == TRUE) && (i < 50))
802 			RTMPPCIeLinkCtrlSetting(pAd, 1);
803 	}
804 	//  4. Set PCI configuration Space Link Comtrol fields.  Only Radio Off needs to call this function
805 	else
806 	{
807 		if ((brc == TRUE) && (i < 50))
808 			RTMPPCIeLinkCtrlSetting(pAd, 3);
809 	}
810 
811     pAd->bPCIclkOffDisableTx = FALSE;
812 }
813 
814 
815 /*
816 	==========================================================================
817 	Description:
818 		This routine sends command to firmware and turn our chip to wake up mode from power save mode.
819 		Both RadioOn and .11 power save function needs to call this routine.
820 	Input:
821 		Level = GUIRADIO_OFF : call this function is from Radio Off to Radio On.  Need to restore PCI host value.
822 		Level = other value : normal wake up function.
823 
824 	==========================================================================
825  */
RT28xxPciAsicRadioOn(IN PRTMP_ADAPTER pAd,IN UCHAR Level)826 BOOLEAN RT28xxPciAsicRadioOn(
827 	IN PRTMP_ADAPTER pAd,
828 	IN UCHAR     Level)
829 {
830     WPDMA_GLO_CFG_STRUC	DmaCfg;
831 	BOOLEAN				Cancelled, brv = TRUE;
832     UINT32			    MACValue;
833 
834 	if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
835 	{
836 	    pAd->Mlme.bPsPollTimerRunning = FALSE;
837 		RTMPCancelTimer(&pAd->Mlme.PsPollTimer,	&Cancelled);
838 		if ((Level == GUIRADIO_OFF) || (Level == GUI_IDLE_POWER_SAVE))
839 		{
840 			DBGPRINT(RT_DEBUG_TRACE, ("RT28xxPciAsicRadioOn ()\n"));
841 			// 1. Set PCI Link Control in Configuration Space.
842 			RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
843 			RTMPusecDelay(6000);
844 		}
845 	}
846 
847     pAd->bPCIclkOff = FALSE;
848 
849 	// 2. Send wake up command.
850 	AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x00);
851 
852 	// 2-1. wait command ok.
853 	brv = AsicCheckCommanOk(pAd, PowerWakeCID);
854     if (brv)
855     {
856     	//RTMP_IO_WRITE32(pAd, INT_MASK_CSR, (DELAYINTMASK|RxINT));
857     	NICEnableInterrupt(pAd);
858 
859     	// 3. Enable Tx DMA.
860     	RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
861     	DmaCfg.field.EnableTxDMA = 1;
862         DmaCfg.field.EnableRxDMA = 1;
863     	RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
864 
865         // Eable MAC Rx
866     	RTMP_IO_READ32(pAd, MAC_SYS_CTRL , &MACValue);
867     	MACValue |= 0x8;
868     	RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL , MACValue);
869 
870     	RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
871     	if (Level == GUI_IDLE_POWER_SAVE)
872     	{
873     		// In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
874     		if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
875     			&& (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
876     		{
877     			// Must using 40MHz.
878     			AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
879     			AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
880     		}
881     		else
882     		{
883     			// Must using 20MHz.
884     			AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
885     			AsicLockChannel(pAd, pAd->CommonCfg.Channel);
886     		}
887     	}
888         return TRUE;
889     }
890     else
891         return FALSE;
892 }
893 
RT28xxPciStaAsicForceWakeup(IN PRTMP_ADAPTER pAd,IN BOOLEAN bFromTx)894 VOID RT28xxPciStaAsicForceWakeup(
895 	IN PRTMP_ADAPTER pAd,
896 	IN BOOLEAN       bFromTx)
897 {
898     AUTO_WAKEUP_STRUC	AutoWakeupCfg;
899 
900     if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
901         return;
902 
903     if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW))
904     {
905         DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
906         return;
907     }
908 
909     OPSTATUS_SET_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
910 
911     if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
912     {
913         // Support PCIe Advance Power Save
914     	if (bFromTx == TRUE)
915     	{
916             pAd->Mlme.bPsPollTimerRunning = FALSE;
917     		RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
918     		RTMPusecDelay(3000);
919             DBGPRINT(RT_DEBUG_TRACE, ("=======AsicForceWakeup===bFromTx\n"));
920     	}
921 
922 		AutoWakeupCfg.word = 0;
923 		RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
924 
925         if (RT28xxPciAsicRadioOn(pAd, DOT11POWERSAVE))
926         {
927             // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
928         	if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
929         		&& (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
930         	{
931         		// Must using 40MHz.
932         		AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
933         		AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
934         	}
935         	else
936         	{
937         		// Must using 20MHz.
938         		AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
939         		AsicLockChannel(pAd, pAd->CommonCfg.Channel);
940         	}
941         }
942     }
943     else
944     {
945         // PCI, 2860-PCIe
946         AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x00);
947 		AutoWakeupCfg.word = 0;
948 		RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
949     }
950 
951     OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
952     OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
953     DBGPRINT(RT_DEBUG_TRACE, ("<=======RT28xxPciStaAsicForceWakeup\n"));
954 }
955 
RT28xxPciStaAsicSleepThenAutoWakeup(IN PRTMP_ADAPTER pAd,IN USHORT TbttNumToNextWakeUp)956 VOID RT28xxPciStaAsicSleepThenAutoWakeup(
957 	IN PRTMP_ADAPTER pAd,
958 	IN USHORT TbttNumToNextWakeUp)
959 {
960     if (pAd->StaCfg.bRadio == FALSE)
961 	{
962 		OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
963 		return;
964 	}
965     if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
966     {
967     	ULONG	Now = 0;
968         if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW))
969         {
970             DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
971             OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
972             return;
973         }
974 
975 		NdisGetSystemUpTime(&Now);
976 		// If last send NULL fram time is too close to this receiving beacon (within 8ms), don't go to sleep for this DTM.
977 		// Because Some AP can't queuing outgoing frames immediately.
978 		if (((pAd->Mlme.LastSendNULLpsmTime + 8) >= Now) && (pAd->Mlme.LastSendNULLpsmTime <= Now))
979 		{
980 			DBGPRINT(RT_DEBUG_TRACE, ("Now = %lu, LastSendNULLpsmTime=%lu :  RxCountSinceLastNULL = %lu. \n", Now, pAd->Mlme.LastSendNULLpsmTime, pAd->RalinkCounters.RxCountSinceLastNULL));
981 			return;
982 		}
983 		else if ((pAd->RalinkCounters.RxCountSinceLastNULL > 0) && ((pAd->Mlme.LastSendNULLpsmTime + pAd->CommonCfg.BeaconPeriod) >= Now))
984 		{
985 			DBGPRINT(RT_DEBUG_TRACE, ("Now = %lu, LastSendNULLpsmTime=%lu: RxCountSinceLastNULL = %lu > 0 \n", Now, pAd->Mlme.LastSendNULLpsmTime,  pAd->RalinkCounters.RxCountSinceLastNULL));
986 			return;
987 		}
988 
989         RT28xxPciAsicRadioOff(pAd, DOT11POWERSAVE, TbttNumToNextWakeUp);
990     }
991     else
992     {
993         AUTO_WAKEUP_STRUC	AutoWakeupCfg;
994         // we have decided to SLEEP, so at least do it for a BEACON period.
995         if (TbttNumToNextWakeUp == 0)
996             TbttNumToNextWakeUp = 1;
997 
998         AutoWakeupCfg.word = 0;
999         RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
1000         AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1;
1001         AutoWakeupCfg.field.EnableAutoWakeup = 1;
1002         AutoWakeupCfg.field.AutoLeadTime = 5;
1003         RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
1004         AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x00);   // send POWER-SAVE command to MCU. Timeout 40us.
1005         DBGPRINT(RT_DEBUG_TRACE, ("<-- %s, TbttNumToNextWakeUp=%d \n", __func__, TbttNumToNextWakeUp));
1006     }
1007     OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE);
1008 }
1009 
PsPollWakeExec(IN PVOID SystemSpecific1,IN PVOID FunctionContext,IN PVOID SystemSpecific2,IN PVOID SystemSpecific3)1010 VOID PsPollWakeExec(
1011 	IN PVOID SystemSpecific1,
1012 	IN PVOID FunctionContext,
1013 	IN PVOID SystemSpecific2,
1014 	IN PVOID SystemSpecific3)
1015 {
1016 	RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
1017 	unsigned long flags;
1018 
1019     DBGPRINT(RT_DEBUG_TRACE,("-->PsPollWakeExec \n"));
1020 	RTMP_INT_LOCK(&pAd->irq_lock, flags);
1021     if (pAd->Mlme.bPsPollTimerRunning)
1022     {
1023 	    RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
1024     }
1025     pAd->Mlme.bPsPollTimerRunning = FALSE;
1026 	RTMP_INT_UNLOCK(&pAd->irq_lock, flags);
1027 }
1028 
RadioOnExec(IN PVOID SystemSpecific1,IN PVOID FunctionContext,IN PVOID SystemSpecific2,IN PVOID SystemSpecific3)1029 VOID  RadioOnExec(
1030 	IN PVOID SystemSpecific1,
1031 	IN PVOID FunctionContext,
1032 	IN PVOID SystemSpecific2,
1033 	IN PVOID SystemSpecific3)
1034 {
1035 	RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
1036 	WPDMA_GLO_CFG_STRUC	DmaCfg;
1037 	BOOLEAN				Cancelled;
1038 
1039 	if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
1040 	{
1041 		DBGPRINT(RT_DEBUG_TRACE,("-->RadioOnExec() return on fOP_STATUS_DOZE == TRUE; \n"));
1042 		RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
1043 		return;
1044 	}
1045 
1046 	if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
1047 	{
1048 		DBGPRINT(RT_DEBUG_TRACE,("-->RadioOnExec() return on SCAN_IN_PROGRESS; \n"));
1049 		RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
1050 		return;
1051 	}
1052     pAd->Mlme.bPsPollTimerRunning = FALSE;
1053 	RTMPCancelTimer(&pAd->Mlme.PsPollTimer,	&Cancelled);
1054 	if (pAd->StaCfg.bRadio == TRUE)
1055 	{
1056 		pAd->bPCIclkOff = FALSE;
1057         RTMPRingCleanUp(pAd, QID_AC_BK);
1058 		RTMPRingCleanUp(pAd, QID_AC_BE);
1059 		RTMPRingCleanUp(pAd, QID_AC_VI);
1060 		RTMPRingCleanUp(pAd, QID_AC_VO);
1061 		RTMPRingCleanUp(pAd, QID_HCCA);
1062 		RTMPRingCleanUp(pAd, QID_MGMT);
1063 		RTMPRingCleanUp(pAd, QID_RX);
1064 
1065 		// 2. Send wake up command.
1066 		AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x02);
1067 		// 2-1. wait command ok.
1068 		AsicCheckCommanOk(pAd, PowerWakeCID);
1069 
1070 		// When PCI clock is off, don't want to service interrupt. So when back to clock on, enable interrupt.
1071 		NICEnableInterrupt(pAd);
1072 
1073 		// 3. Enable Tx DMA.
1074 		RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
1075 		DmaCfg.field.EnableTxDMA = 1;
1076 		RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
1077 
1078 		// In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
1079 		if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
1080 			&& (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
1081 		{
1082 			// Must using 40MHz.
1083 			AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
1084 			AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
1085 		}
1086 		else
1087 		{
1088 			// Must using 20MHz.
1089 			AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
1090 			AsicLockChannel(pAd, pAd->CommonCfg.Channel);
1091 		}
1092 
1093 		// Clear Radio off flag
1094 		RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1095 
1096 		// Set LED
1097 		RTMPSetLED(pAd, LED_RADIO_ON);
1098 
1099         if (pAd->StaCfg.Psm == PWR_ACTIVE)
1100         {
1101     		RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, pAd->StaCfg.BBPR3);
1102         }
1103 	}
1104 	else
1105 	{
1106 		RT28xxPciAsicRadioOff(pAd, GUIRADIO_OFF, 0);
1107 	}
1108 }
1109 
1110 #endif // CONFIG_STA_SUPPORT //
1111 
RT28xxPciMlmeRadioOn(IN PRTMP_ADAPTER pAd)1112 VOID RT28xxPciMlmeRadioOn(
1113 	IN PRTMP_ADAPTER pAd)
1114 {
1115     if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
1116    		return;
1117 
1118     DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__));
1119 
1120     if ((pAd->OpMode == OPMODE_AP) ||
1121         ((pAd->OpMode == OPMODE_STA) && (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))))
1122     {
1123     	NICResetFromError(pAd);
1124 
1125     	RTMPRingCleanUp(pAd, QID_AC_BK);
1126     	RTMPRingCleanUp(pAd, QID_AC_BE);
1127     	RTMPRingCleanUp(pAd, QID_AC_VI);
1128     	RTMPRingCleanUp(pAd, QID_AC_VO);
1129     	RTMPRingCleanUp(pAd, QID_HCCA);
1130     	RTMPRingCleanUp(pAd, QID_MGMT);
1131     	RTMPRingCleanUp(pAd, QID_RX);
1132 
1133     	// Enable Tx/Rx
1134     	RTMPEnableRxTx(pAd);
1135 
1136     	// Clear Radio off flag
1137     	RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1138 
1139 	    // Set LED
1140 	    RTMPSetLED(pAd, LED_RADIO_ON);
1141     }
1142 
1143 #ifdef CONFIG_STA_SUPPORT
1144     if ((pAd->OpMode == OPMODE_STA) &&
1145         (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE)))
1146     {
1147         BOOLEAN		Cancelled;
1148 
1149     	RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
1150 
1151         pAd->Mlme.bPsPollTimerRunning = FALSE;
1152     	RTMPCancelTimer(&pAd->Mlme.PsPollTimer,	&Cancelled);
1153     	RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer,	&Cancelled);
1154     	RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
1155     }
1156 #endif // CONFIG_STA_SUPPORT //
1157 }
1158 
RT28xxPciMlmeRadioOFF(IN PRTMP_ADAPTER pAd)1159 VOID RT28xxPciMlmeRadioOFF(
1160 	IN PRTMP_ADAPTER pAd)
1161 {
1162     WPDMA_GLO_CFG_STRUC	GloCfg;
1163 	UINT32	i;
1164 
1165     if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
1166     	return;
1167 
1168     DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__));
1169 
1170 	// Set LED
1171 	RTMPSetLED(pAd, LED_RADIO_OFF);
1172 	// Set Radio off flag
1173 	RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1174 
1175 #ifdef CONFIG_STA_SUPPORT
1176 	IF_DEV_CONFIG_OPMODE_ON_STA(pAd)
1177     {
1178     	BOOLEAN		Cancelled;
1179     	if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
1180     	{
1181 			RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled);
1182 			RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS);
1183     	}
1184 
1185 		if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
1186         {
1187             BOOLEAN Cancelled;
1188             pAd->Mlme.bPsPollTimerRunning = FALSE;
1189             RTMPCancelTimer(&pAd->Mlme.PsPollTimer,	&Cancelled);
1190 	        RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer,	&Cancelled);
1191         }
1192 
1193         // Link down first if any association exists
1194         if (INFRA_ON(pAd) || ADHOC_ON(pAd))
1195             LinkDown(pAd, FALSE);
1196         RTMPusecDelay(10000);
1197         //==========================================
1198         // Clean up old bss table
1199         BssTableInit(&pAd->ScanTab);
1200     }
1201 #endif // CONFIG_STA_SUPPORT //
1202 
1203 	// Disable Tx/Rx DMA
1204 	RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);	   // disable DMA
1205 	GloCfg.field.EnableTxDMA = 0;
1206 	GloCfg.field.EnableRxDMA = 0;
1207 	RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word);	   // abort all TX rings
1208 
1209 
1210 	// MAC_SYS_CTRL => value = 0x0 => 40mA
1211 	RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0);
1212 
1213 	// PWR_PIN_CFG => value = 0x0 => 40mA
1214 	RTMP_IO_WRITE32(pAd, PWR_PIN_CFG, 0);
1215 
1216 	// TX_PIN_CFG => value = 0x0 => 20mA
1217 	RTMP_IO_WRITE32(pAd, TX_PIN_CFG, 0);
1218 
1219 	if (pAd->CommonCfg.BBPCurrentBW == BW_40)
1220 	{
1221 		// Must using 40MHz.
1222 		AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel);
1223 	}
1224 	else
1225 	{
1226 		// Must using 20MHz.
1227 		AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel);
1228 	}
1229 
1230 	// Waiting for DMA idle
1231 	i = 0;
1232 	do
1233 	{
1234 		RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);
1235 		if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0))
1236 			break;
1237 
1238 		RTMPusecDelay(1000);
1239 	}while (i++ < 100);
1240 }
1241