• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/staging/rt2860/common/
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#ifdef RTMP_MAC_PCI
29#include	"../rt_config.h"
30
31/*
32	========================================================================
33
34	Routine Description:
35		Allocate DMA memory blocks for send, receive
36
37	Arguments:
38		Adapter		Pointer to our adapter
39
40	Return Value:
41		NDIS_STATUS_SUCCESS
42		NDIS_STATUS_FAILURE
43		NDIS_STATUS_RESOURCES
44
45	IRQL = PASSIVE_LEVEL
46
47	Note:
48
49	========================================================================
50*/
51int RTMPAllocTxRxRingMemory(struct rt_rtmp_adapter *pAd)
52{
53	int Status = NDIS_STATUS_SUCCESS;
54	unsigned long RingBasePaHigh;
55	unsigned long RingBasePaLow;
56	void *RingBaseVa;
57	int index, num;
58	struct rt_txd * pTxD;
59	struct rt_rxd * pRxD;
60	unsigned long ErrorValue = 0;
61	struct rt_rtmp_tx_ring *pTxRing;
62	struct rt_rtmp_dmabuf *pDmaBuf;
63	void *pPacket;
64/*      PRTMP_REORDERBUF        pReorderBuf; */
65
66	DBGPRINT(RT_DEBUG_TRACE, ("--> RTMPAllocTxRxRingMemory\n"));
67	do {
68		/* */
69		/* Allocate all ring descriptors, include TxD, RxD, MgmtD. */
70		/* Although each size is different, to prevent cacheline and alignment */
71		/* issue, I intentional set them all to 64 bytes. */
72		/* */
73		for (num = 0; num < NUM_OF_TX_RING; num++) {
74			unsigned long BufBasePaHigh;
75			unsigned long BufBasePaLow;
76			void *BufBaseVa;
77
78			/* */
79			/* Allocate Tx ring descriptor's memory (5 TX rings = 4 ACs + 1 HCCA) */
80			/* */
81			pAd->TxDescRing[num].AllocSize =
82			    TX_RING_SIZE * TXD_SIZE;
83			RTMP_AllocateTxDescMemory(pAd, num,
84						  pAd->TxDescRing[num].
85						  AllocSize, FALSE,
86						  &pAd->TxDescRing[num].AllocVa,
87						  &pAd->TxDescRing[num].
88						  AllocPa);
89
90			if (pAd->TxDescRing[num].AllocVa == NULL) {
91				ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
92				DBGPRINT_ERR(("Failed to allocate a big buffer\n"));
93				Status = NDIS_STATUS_RESOURCES;
94				break;
95			}
96			/* Zero init this memory block */
97			NdisZeroMemory(pAd->TxDescRing[num].AllocVa,
98				       pAd->TxDescRing[num].AllocSize);
99
100			/* Save PA & VA for further operation */
101			RingBasePaHigh =
102			    RTMP_GetPhysicalAddressHigh(pAd->TxDescRing[num].
103							AllocPa);
104			RingBasePaLow =
105			    RTMP_GetPhysicalAddressLow(pAd->TxDescRing[num].
106						       AllocPa);
107			RingBaseVa = pAd->TxDescRing[num].AllocVa;
108
109			/* */
110			/* Allocate all 1st TXBuf's memory for this TxRing */
111			/* */
112			pAd->TxBufSpace[num].AllocSize =
113			    TX_RING_SIZE * TX_DMA_1ST_BUFFER_SIZE;
114			RTMP_AllocateFirstTxBuffer(pAd, num,
115						   pAd->TxBufSpace[num].
116						   AllocSize, FALSE,
117						   &pAd->TxBufSpace[num].
118						   AllocVa,
119						   &pAd->TxBufSpace[num].
120						   AllocPa);
121
122			if (pAd->TxBufSpace[num].AllocVa == NULL) {
123				ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
124				DBGPRINT_ERR(("Failed to allocate a big buffer\n"));
125				Status = NDIS_STATUS_RESOURCES;
126				break;
127			}
128			/* Zero init this memory block */
129			NdisZeroMemory(pAd->TxBufSpace[num].AllocVa,
130				       pAd->TxBufSpace[num].AllocSize);
131
132			/* Save PA & VA for further operation */
133			BufBasePaHigh =
134			    RTMP_GetPhysicalAddressHigh(pAd->TxBufSpace[num].
135							AllocPa);
136			BufBasePaLow =
137			    RTMP_GetPhysicalAddressLow(pAd->TxBufSpace[num].
138						       AllocPa);
139			BufBaseVa = pAd->TxBufSpace[num].AllocVa;
140
141			/* */
142			/* Initialize Tx Ring Descriptor and associated buffer memory */
143			/* */
144			pTxRing = &pAd->TxRing[num];
145			for (index = 0; index < TX_RING_SIZE; index++) {
146				pTxRing->Cell[index].pNdisPacket = NULL;
147				pTxRing->Cell[index].pNextNdisPacket = NULL;
148				/* Init Tx Ring Size, Va, Pa variables */
149				pTxRing->Cell[index].AllocSize = TXD_SIZE;
150				pTxRing->Cell[index].AllocVa = RingBaseVa;
151				RTMP_SetPhysicalAddressHigh(pTxRing->
152							    Cell[index].AllocPa,
153							    RingBasePaHigh);
154				RTMP_SetPhysicalAddressLow(pTxRing->Cell[index].
155							   AllocPa,
156							   RingBasePaLow);
157
158				/* Setup Tx Buffer size & address. only 802.11 header will store in this space */
159				pDmaBuf = &pTxRing->Cell[index].DmaBuf;
160				pDmaBuf->AllocSize = TX_DMA_1ST_BUFFER_SIZE;
161				pDmaBuf->AllocVa = BufBaseVa;
162				RTMP_SetPhysicalAddressHigh(pDmaBuf->AllocPa,
163							    BufBasePaHigh);
164				RTMP_SetPhysicalAddressLow(pDmaBuf->AllocPa,
165							   BufBasePaLow);
166
167				/* link the pre-allocated TxBuf to TXD */
168				pTxD =
169				    (struct rt_txd *) pTxRing->Cell[index].AllocVa;
170				pTxD->SDPtr0 = BufBasePaLow;
171				/* advance to next ring descriptor address */
172				pTxD->DMADONE = 1;
173				RingBasePaLow += TXD_SIZE;
174				RingBaseVa = (u8 *)RingBaseVa + TXD_SIZE;
175
176				/* advance to next TxBuf address */
177				BufBasePaLow += TX_DMA_1ST_BUFFER_SIZE;
178				BufBaseVa =
179				    (u8 *)BufBaseVa + TX_DMA_1ST_BUFFER_SIZE;
180			}
181			DBGPRINT(RT_DEBUG_TRACE,
182				 ("TxRing[%d]: total %d entry allocated\n", num,
183				  index));
184		}
185		if (Status == NDIS_STATUS_RESOURCES)
186			break;
187
188		/* */
189		/* Allocate MGMT ring descriptor's memory except Tx ring which allocated eariler */
190		/* */
191		pAd->MgmtDescRing.AllocSize = MGMT_RING_SIZE * TXD_SIZE;
192		RTMP_AllocateMgmtDescMemory(pAd,
193					    pAd->MgmtDescRing.AllocSize,
194					    FALSE,
195					    &pAd->MgmtDescRing.AllocVa,
196					    &pAd->MgmtDescRing.AllocPa);
197
198		if (pAd->MgmtDescRing.AllocVa == NULL) {
199			ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
200			DBGPRINT_ERR(("Failed to allocate a big buffer\n"));
201			Status = NDIS_STATUS_RESOURCES;
202			break;
203		}
204		/* Zero init this memory block */
205		NdisZeroMemory(pAd->MgmtDescRing.AllocVa,
206			       pAd->MgmtDescRing.AllocSize);
207
208		/* Save PA & VA for further operation */
209		RingBasePaHigh =
210		    RTMP_GetPhysicalAddressHigh(pAd->MgmtDescRing.AllocPa);
211		RingBasePaLow =
212		    RTMP_GetPhysicalAddressLow(pAd->MgmtDescRing.AllocPa);
213		RingBaseVa = pAd->MgmtDescRing.AllocVa;
214
215		/* */
216		/* Initialize MGMT Ring and associated buffer memory */
217		/* */
218		for (index = 0; index < MGMT_RING_SIZE; index++) {
219			pAd->MgmtRing.Cell[index].pNdisPacket = NULL;
220			pAd->MgmtRing.Cell[index].pNextNdisPacket = NULL;
221			/* Init MGMT Ring Size, Va, Pa variables */
222			pAd->MgmtRing.Cell[index].AllocSize = TXD_SIZE;
223			pAd->MgmtRing.Cell[index].AllocVa = RingBaseVa;
224			RTMP_SetPhysicalAddressHigh(pAd->MgmtRing.Cell[index].
225						    AllocPa, RingBasePaHigh);
226			RTMP_SetPhysicalAddressLow(pAd->MgmtRing.Cell[index].
227						   AllocPa, RingBasePaLow);
228
229			/* Offset to next ring descriptor address */
230			RingBasePaLow += TXD_SIZE;
231			RingBaseVa = (u8 *)RingBaseVa + TXD_SIZE;
232
233			/* link the pre-allocated TxBuf to TXD */
234			pTxD = (struct rt_txd *) pAd->MgmtRing.Cell[index].AllocVa;
235			pTxD->DMADONE = 1;
236
237			/* no pre-allocated buffer required in MgmtRing for scatter-gather case */
238		}
239		DBGPRINT(RT_DEBUG_TRACE,
240			 ("MGMT Ring: total %d entry allocated\n", index));
241
242		/* */
243		/* Allocate RX ring descriptor's memory except Tx ring which allocated eariler */
244		/* */
245		pAd->RxDescRing.AllocSize = RX_RING_SIZE * RXD_SIZE;
246		RTMP_AllocateRxDescMemory(pAd,
247					  pAd->RxDescRing.AllocSize,
248					  FALSE,
249					  &pAd->RxDescRing.AllocVa,
250					  &pAd->RxDescRing.AllocPa);
251
252		if (pAd->RxDescRing.AllocVa == NULL) {
253			ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
254			DBGPRINT_ERR(("Failed to allocate a big buffer\n"));
255			Status = NDIS_STATUS_RESOURCES;
256			break;
257		}
258		/* Zero init this memory block */
259		NdisZeroMemory(pAd->RxDescRing.AllocVa,
260			       pAd->RxDescRing.AllocSize);
261
262		DBGPRINT(RT_DEBUG_OFF,
263			 ("RX DESC %p  size = %ld\n", pAd->RxDescRing.AllocVa,
264			  pAd->RxDescRing.AllocSize));
265
266		/* Save PA & VA for further operation */
267		RingBasePaHigh =
268		    RTMP_GetPhysicalAddressHigh(pAd->RxDescRing.AllocPa);
269		RingBasePaLow =
270		    RTMP_GetPhysicalAddressLow(pAd->RxDescRing.AllocPa);
271		RingBaseVa = pAd->RxDescRing.AllocVa;
272
273		/* */
274		/* Initialize Rx Ring and associated buffer memory */
275		/* */
276		for (index = 0; index < RX_RING_SIZE; index++) {
277			/* Init RX Ring Size, Va, Pa variables */
278			pAd->RxRing.Cell[index].AllocSize = RXD_SIZE;
279			pAd->RxRing.Cell[index].AllocVa = RingBaseVa;
280			RTMP_SetPhysicalAddressHigh(pAd->RxRing.Cell[index].
281						    AllocPa, RingBasePaHigh);
282			RTMP_SetPhysicalAddressLow(pAd->RxRing.Cell[index].
283						   AllocPa, RingBasePaLow);
284
285			/*NdisZeroMemory(RingBaseVa, RXD_SIZE); */
286
287			/* Offset to next ring descriptor address */
288			RingBasePaLow += RXD_SIZE;
289			RingBaseVa = (u8 *)RingBaseVa + RXD_SIZE;
290
291			/* Setup Rx associated Buffer size & allocate share memory */
292			pDmaBuf = &pAd->RxRing.Cell[index].DmaBuf;
293			pDmaBuf->AllocSize = RX_BUFFER_AGGRESIZE;
294			pPacket = RTMP_AllocateRxPacketBuffer(pAd,
295							      pDmaBuf->
296							      AllocSize, FALSE,
297							      &pDmaBuf->AllocVa,
298							      &pDmaBuf->
299							      AllocPa);
300
301			/* keep allocated rx packet */
302			pAd->RxRing.Cell[index].pNdisPacket = pPacket;
303
304			/* Error handling */
305			if (pDmaBuf->AllocVa == NULL) {
306				ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
307				DBGPRINT_ERR(("Failed to allocate RxRing's 1st buffer\n"));
308				Status = NDIS_STATUS_RESOURCES;
309				break;
310			}
311			/* Zero init this memory block */
312			NdisZeroMemory(pDmaBuf->AllocVa, pDmaBuf->AllocSize);
313
314			/* Write RxD buffer address & allocated buffer length */
315			pRxD = (struct rt_rxd *) pAd->RxRing.Cell[index].AllocVa;
316			pRxD->SDP0 =
317			    RTMP_GetPhysicalAddressLow(pDmaBuf->AllocPa);
318			pRxD->DDONE = 0;
319
320		}
321
322		DBGPRINT(RT_DEBUG_TRACE,
323			 ("Rx Ring: total %d entry allocated\n", index));
324
325	} while (FALSE);
326
327	NdisZeroMemory(&pAd->FragFrame, sizeof(struct rt_fragment_frame));
328	pAd->FragFrame.pFragPacket =
329	    RTMP_AllocateFragPacketBuffer(pAd, RX_BUFFER_NORMSIZE);
330
331	if (pAd->FragFrame.pFragPacket == NULL) {
332		Status = NDIS_STATUS_RESOURCES;
333	}
334
335	if (Status != NDIS_STATUS_SUCCESS) {
336		/* Log error inforamtion */
337		NdisWriteErrorLogEntry(pAd->AdapterHandle,
338				       NDIS_ERROR_CODE_OUT_OF_RESOURCES,
339				       1, ErrorValue);
340	}
341	/* Following code segment get from original func:NICInitTxRxRingAndBacklogQueue(), now should integrate it to here. */
342	{
343		DBGPRINT(RT_DEBUG_TRACE,
344			 ("--> NICInitTxRxRingAndBacklogQueue\n"));
345
346/*
347		// Disable DMA.
348		RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);
349		GloCfg.word &= 0xff0;
350		GloCfg.field.EnTXWriteBackDDONE =1;
351		RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word);
352*/
353
354		/* Initialize all transmit related software queues */
355		for (index = 0; index < NUM_OF_TX_RING; index++) {
356			InitializeQueueHeader(&pAd->TxSwQueue[index]);
357			/* Init TX rings index pointer */
358			pAd->TxRing[index].TxSwFreeIdx = 0;
359			pAd->TxRing[index].TxCpuIdx = 0;
360			/*RTMP_IO_WRITE32(pAd, (TX_CTX_IDX0 + i * 0x10) ,  pAd->TxRing[i].TX_CTX_IDX); */
361		}
362
363		/* Init RX Ring index pointer */
364		pAd->RxRing.RxSwReadIdx = 0;
365		pAd->RxRing.RxCpuIdx = RX_RING_SIZE - 1;
366		/*RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RX_CRX_IDX0); */
367
368		/* init MGMT ring index pointer */
369		pAd->MgmtRing.TxSwFreeIdx = 0;
370		pAd->MgmtRing.TxCpuIdx = 0;
371
372		pAd->PrivateInfo.TxRingFullCnt = 0;
373
374		DBGPRINT(RT_DEBUG_TRACE,
375			 ("<-- NICInitTxRxRingAndBacklogQueue\n"));
376	}
377
378	DBGPRINT_S(Status,
379		   ("<-- RTMPAllocTxRxRingMemory, Status=%x\n", Status));
380	return Status;
381}
382
383/*
384	========================================================================
385
386	Routine Description:
387		Reset NIC Asics. Call after rest DMA. So reset TX_CTX_IDX to zero.
388
389	Arguments:
390		Adapter						Pointer to our adapter
391
392	Return Value:
393		None
394
395	IRQL = PASSIVE_LEVEL
396	IRQL = DISPATCH_LEVEL
397
398	Note:
399		Reset NIC to initial state AS IS system boot up time.
400
401	========================================================================
402*/
403void RTMPRingCleanUp(struct rt_rtmp_adapter *pAd, u8 RingType)
404{
405	struct rt_txd * pTxD;
406	struct rt_rxd * pRxD;
407	struct rt_queue_entry *pEntry;
408	void *pPacket;
409	int i;
410	struct rt_rtmp_tx_ring *pTxRing;
411	unsigned long IrqFlags;
412	/*u32                        RxSwReadIdx; */
413
414	DBGPRINT(RT_DEBUG_TRACE,
415		 ("RTMPRingCleanUp(RingIdx=%d, Pending-NDIS=%ld)\n", RingType,
416		  pAd->RalinkCounters.PendingNdisPacketCount));
417	switch (RingType) {
418	case QID_AC_BK:
419	case QID_AC_BE:
420	case QID_AC_VI:
421	case QID_AC_VO:
422
423		pTxRing = &pAd->TxRing[RingType];
424
425		RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags);
426		/* We have to clean all descriptors in case some error happened with reset */
427		for (i = 0; i < TX_RING_SIZE; i++)	/* We have to scan all TX ring */
428		{
429			pTxD = (struct rt_txd *) pTxRing->Cell[i].AllocVa;
430
431			pPacket = (void *)pTxRing->Cell[i].pNdisPacket;
432			/* release scatter-and-gather char */
433			if (pPacket) {
434				RELEASE_NDIS_PACKET(pAd, pPacket,
435						    NDIS_STATUS_FAILURE);
436				pTxRing->Cell[i].pNdisPacket = NULL;
437			}
438
439			pPacket =
440			    (void *)pTxRing->Cell[i].pNextNdisPacket;
441			/* release scatter-and-gather char */
442			if (pPacket) {
443				RELEASE_NDIS_PACKET(pAd, pPacket,
444						    NDIS_STATUS_FAILURE);
445				pTxRing->Cell[i].pNextNdisPacket = NULL;
446			}
447		}
448
449		RTMP_IO_READ32(pAd, TX_DTX_IDX0 + RingType * 0x10,
450			       &pTxRing->TxDmaIdx);
451		pTxRing->TxSwFreeIdx = pTxRing->TxDmaIdx;
452		pTxRing->TxCpuIdx = pTxRing->TxDmaIdx;
453		RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + RingType * 0x10,
454				pTxRing->TxCpuIdx);
455
456		RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
457
458		RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags);
459		while (pAd->TxSwQueue[RingType].Head != NULL) {
460			pEntry = RemoveHeadQueue(&pAd->TxSwQueue[RingType]);
461			pPacket = QUEUE_ENTRY_TO_PACKET(pEntry);
462			RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
463			DBGPRINT(RT_DEBUG_TRACE,
464				 ("Release 1 NDIS packet from s/w backlog queue\n"));
465		}
466		RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
467		break;
468
469	case QID_MGMT:
470		/* We have to clean all descriptors in case some error happened with reset */
471		NdisAcquireSpinLock(&pAd->MgmtRingLock);
472
473		for (i = 0; i < MGMT_RING_SIZE; i++) {
474			pTxD = (struct rt_txd *) pAd->MgmtRing.Cell[i].AllocVa;
475
476			pPacket =
477			    (void *)pAd->MgmtRing.Cell[i].pNdisPacket;
478			/* rlease scatter-and-gather char */
479			if (pPacket) {
480				PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0,
481						 pTxD->SDLen0,
482						 PCI_DMA_TODEVICE);
483				RELEASE_NDIS_PACKET(pAd, pPacket,
484						    NDIS_STATUS_FAILURE);
485			}
486			pAd->MgmtRing.Cell[i].pNdisPacket = NULL;
487
488			pPacket =
489			    (void *)pAd->MgmtRing.Cell[i].
490			    pNextNdisPacket;
491			/* release scatter-and-gather char */
492			if (pPacket) {
493				PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1,
494						 pTxD->SDLen1,
495						 PCI_DMA_TODEVICE);
496				RELEASE_NDIS_PACKET(pAd, pPacket,
497						    NDIS_STATUS_FAILURE);
498			}
499			pAd->MgmtRing.Cell[i].pNextNdisPacket = NULL;
500
501		}
502
503		RTMP_IO_READ32(pAd, TX_MGMTDTX_IDX, &pAd->MgmtRing.TxDmaIdx);
504		pAd->MgmtRing.TxSwFreeIdx = pAd->MgmtRing.TxDmaIdx;
505		pAd->MgmtRing.TxCpuIdx = pAd->MgmtRing.TxDmaIdx;
506		RTMP_IO_WRITE32(pAd, TX_MGMTCTX_IDX, pAd->MgmtRing.TxCpuIdx);
507
508		NdisReleaseSpinLock(&pAd->MgmtRingLock);
509		pAd->RalinkCounters.MgmtRingFullCount = 0;
510		break;
511
512	case QID_RX:
513		/* We have to clean all descriptors in case some error happened with reset */
514		NdisAcquireSpinLock(&pAd->RxRingLock);
515
516		for (i = 0; i < RX_RING_SIZE; i++) {
517			pRxD = (struct rt_rxd *) pAd->RxRing.Cell[i].AllocVa;
518			pRxD->DDONE = 0;
519		}
520
521		RTMP_IO_READ32(pAd, RX_DRX_IDX, &pAd->RxRing.RxDmaIdx);
522		pAd->RxRing.RxSwReadIdx = pAd->RxRing.RxDmaIdx;
523		pAd->RxRing.RxCpuIdx =
524		    ((pAd->RxRing.RxDmaIdx ==
525		      0) ? (RX_RING_SIZE - 1) : (pAd->RxRing.RxDmaIdx - 1));
526		RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx);
527
528		NdisReleaseSpinLock(&pAd->RxRingLock);
529		break;
530
531	default:
532		break;
533	}
534}
535
536void RTMPFreeTxRxRingMemory(struct rt_rtmp_adapter *pAd)
537{
538	int index, num, j;
539	struct rt_rtmp_tx_ring *pTxRing;
540	struct rt_txd * pTxD;
541	void *pPacket;
542	unsigned int IrqFlags;
543
544	/*struct os_cookie *pObj =(struct os_cookie *)pAd->OS_Cookie; */
545
546	DBGPRINT(RT_DEBUG_TRACE, ("--> RTMPFreeTxRxRingMemory\n"));
547
548	/* Free TxSwQueue Packet */
549	for (index = 0; index < NUM_OF_TX_RING; index++) {
550		struct rt_queue_entry *pEntry;
551		void *pPacket;
552		struct rt_queue_header *pQueue;
553
554		RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags);
555		pQueue = &pAd->TxSwQueue[index];
556		while (pQueue->Head) {
557			pEntry = RemoveHeadQueue(pQueue);
558			pPacket = QUEUE_ENTRY_TO_PACKET(pEntry);
559			RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
560		}
561		RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
562	}
563
564	/* Free Tx Ring Packet */
565	for (index = 0; index < NUM_OF_TX_RING; index++) {
566		pTxRing = &pAd->TxRing[index];
567
568		for (j = 0; j < TX_RING_SIZE; j++) {
569			pTxD = (struct rt_txd *) (pTxRing->Cell[j].AllocVa);
570			pPacket = pTxRing->Cell[j].pNdisPacket;
571
572			if (pPacket) {
573				PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0,
574						 pTxD->SDLen0,
575						 PCI_DMA_TODEVICE);
576				RELEASE_NDIS_PACKET(pAd, pPacket,
577						    NDIS_STATUS_SUCCESS);
578			}
579			/*Always assign pNdisPacket as NULL after clear */
580			pTxRing->Cell[j].pNdisPacket = NULL;
581
582			pPacket = pTxRing->Cell[j].pNextNdisPacket;
583
584			if (pPacket) {
585				PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1,
586						 pTxD->SDLen1,
587						 PCI_DMA_TODEVICE);
588				RELEASE_NDIS_PACKET(pAd, pPacket,
589						    NDIS_STATUS_SUCCESS);
590			}
591			/*Always assign pNextNdisPacket as NULL after clear */
592			pTxRing->Cell[pTxRing->TxSwFreeIdx].pNextNdisPacket =
593			    NULL;
594
595		}
596	}
597
598	for (index = RX_RING_SIZE - 1; index >= 0; index--) {
599		if ((pAd->RxRing.Cell[index].DmaBuf.AllocVa)
600		    && (pAd->RxRing.Cell[index].pNdisPacket)) {
601			PCI_UNMAP_SINGLE(pAd,
602					 pAd->RxRing.Cell[index].DmaBuf.AllocPa,
603					 pAd->RxRing.Cell[index].DmaBuf.
604					 AllocSize, PCI_DMA_FROMDEVICE);
605			RELEASE_NDIS_PACKET(pAd,
606					    pAd->RxRing.Cell[index].pNdisPacket,
607					    NDIS_STATUS_SUCCESS);
608		}
609	}
610	NdisZeroMemory(pAd->RxRing.Cell, RX_RING_SIZE * sizeof(struct rt_rtmp_dmacb));
611
612	if (pAd->RxDescRing.AllocVa) {
613		RTMP_FreeDescMemory(pAd, pAd->RxDescRing.AllocSize,
614				    pAd->RxDescRing.AllocVa,
615				    pAd->RxDescRing.AllocPa);
616	}
617	NdisZeroMemory(&pAd->RxDescRing, sizeof(struct rt_rtmp_dmabuf));
618
619	if (pAd->MgmtDescRing.AllocVa) {
620		RTMP_FreeDescMemory(pAd, pAd->MgmtDescRing.AllocSize,
621				    pAd->MgmtDescRing.AllocVa,
622				    pAd->MgmtDescRing.AllocPa);
623	}
624	NdisZeroMemory(&pAd->MgmtDescRing, sizeof(struct rt_rtmp_dmabuf));
625
626	for (num = 0; num < NUM_OF_TX_RING; num++) {
627		if (pAd->TxBufSpace[num].AllocVa) {
628			RTMP_FreeFirstTxBuffer(pAd,
629					       pAd->TxBufSpace[num].AllocSize,
630					       FALSE,
631					       pAd->TxBufSpace[num].AllocVa,
632					       pAd->TxBufSpace[num].AllocPa);
633		}
634		NdisZeroMemory(&pAd->TxBufSpace[num], sizeof(struct rt_rtmp_dmabuf));
635
636		if (pAd->TxDescRing[num].AllocVa) {
637			RTMP_FreeDescMemory(pAd, pAd->TxDescRing[num].AllocSize,
638					    pAd->TxDescRing[num].AllocVa,
639					    pAd->TxDescRing[num].AllocPa);
640		}
641		NdisZeroMemory(&pAd->TxDescRing[num], sizeof(struct rt_rtmp_dmabuf));
642	}
643
644	if (pAd->FragFrame.pFragPacket)
645		RELEASE_NDIS_PACKET(pAd, pAd->FragFrame.pFragPacket,
646				    NDIS_STATUS_SUCCESS);
647
648	DBGPRINT(RT_DEBUG_TRACE, ("<-- RTMPFreeTxRxRingMemory\n"));
649}
650
651/***************************************************************************
652  *
653  *	register related procedures.
654  *
655  **************************************************************************/
656/*
657========================================================================
658Routine Description:
659    Disable DMA.
660
661Arguments:
662	*pAd				the raxx interface data pointer
663
664Return Value:
665	None
666
667Note:
668========================================================================
669*/
670void RT28XXDMADisable(struct rt_rtmp_adapter *pAd)
671{
672	WPDMA_GLO_CFG_STRUC GloCfg;
673
674	RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);
675	GloCfg.word &= 0xff0;
676	GloCfg.field.EnTXWriteBackDDONE = 1;
677	RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word);
678}
679
680/*
681========================================================================
682Routine Description:
683    Enable DMA.
684
685Arguments:
686	*pAd				the raxx interface data pointer
687
688Return Value:
689	None
690
691Note:
692========================================================================
693*/
694void RT28XXDMAEnable(struct rt_rtmp_adapter *pAd)
695{
696	WPDMA_GLO_CFG_STRUC GloCfg;
697	int i = 0;
698
699	RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x4);
700	do {
701		RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);
702		if ((GloCfg.field.TxDMABusy == 0)
703		    && (GloCfg.field.RxDMABusy == 0))
704			break;
705
706		DBGPRINT(RT_DEBUG_TRACE, ("==>  DMABusy\n"));
707		RTMPusecDelay(1000);
708		i++;
709	} while (i < 200);
710
711	RTMPusecDelay(50);
712
713	GloCfg.field.EnTXWriteBackDDONE = 1;
714	GloCfg.field.WPDMABurstSIZE = 2;
715	GloCfg.field.EnableRxDMA = 1;
716	GloCfg.field.EnableTxDMA = 1;
717
718	DBGPRINT(RT_DEBUG_TRACE,
719		 ("<== WRITE DMA offset 0x208 = 0x%x\n", GloCfg.word));
720	RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word);
721
722}
723
724BOOLEAN AsicCheckCommanOk(struct rt_rtmp_adapter *pAd, u8 Command)
725{
726	u32 CmdStatus = 0, CID = 0, i;
727	u32 ThisCIDMask = 0;
728
729	i = 0;
730	do {
731		RTMP_IO_READ32(pAd, H2M_MAILBOX_CID, &CID);
732		/* Find where the command is. Because this is randomly specified by firmware. */
733		if ((CID & CID0MASK) == Command) {
734			ThisCIDMask = CID0MASK;
735			break;
736		} else if ((((CID & CID1MASK) >> 8) & 0xff) == Command) {
737			ThisCIDMask = CID1MASK;
738			break;
739		} else if ((((CID & CID2MASK) >> 16) & 0xff) == Command) {
740			ThisCIDMask = CID2MASK;
741			break;
742		} else if ((((CID & CID3MASK) >> 24) & 0xff) == Command) {
743			ThisCIDMask = CID3MASK;
744			break;
745		}
746
747		RTMPusecDelay(100);
748		i++;
749	} while (i < 200);
750
751	/* Get CommandStatus Value */
752	RTMP_IO_READ32(pAd, H2M_MAILBOX_STATUS, &CmdStatus);
753
754	/* This command's status is at the same position as command. So AND command position's bitmask to read status. */
755	if (i < 200) {
756		/* If Status is 1, the comamnd is success. */
757		if (((CmdStatus & ThisCIDMask) == 0x1)
758		    || ((CmdStatus & ThisCIDMask) == 0x100)
759		    || ((CmdStatus & ThisCIDMask) == 0x10000)
760		    || ((CmdStatus & ThisCIDMask) == 0x1000000)) {
761			DBGPRINT(RT_DEBUG_TRACE,
762				 ("--> AsicCheckCommanOk CID = 0x%x, CmdStatus= 0x%x \n",
763				  CID, CmdStatus));
764			RTMP_IO_WRITE32(pAd, H2M_MAILBOX_STATUS, 0xffffffff);
765			RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CID, 0xffffffff);
766			return TRUE;
767		}
768		DBGPRINT(RT_DEBUG_TRACE,
769			 ("--> AsicCheckCommanFail1 CID = 0x%x, CmdStatus= 0x%x \n",
770			  CID, CmdStatus));
771	} else {
772		DBGPRINT(RT_DEBUG_TRACE,
773			 ("--> AsicCheckCommanFail2 Timeout Command = %d, CmdStatus= 0x%x \n",
774			  Command, CmdStatus));
775	}
776	/* Clear Command and Status. */
777	RTMP_IO_WRITE32(pAd, H2M_MAILBOX_STATUS, 0xffffffff);
778	RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CID, 0xffffffff);
779
780	return FALSE;
781}
782
783/*
784========================================================================
785Routine Description:
786    Write Beacon buffer to Asic.
787
788Arguments:
789	*pAd				the raxx interface data pointer
790
791Return Value:
792	None
793
794Note:
795========================================================================
796*/
797void RT28xx_UpdateBeaconToAsic(struct rt_rtmp_adapter *pAd,
798			       int apidx,
799			       unsigned long FrameLen, unsigned long UpdatePos)
800{
801	unsigned long CapInfoPos = 0;
802	u8 *ptr, *ptr_update, *ptr_capinfo;
803	u32 i;
804	BOOLEAN bBcnReq = FALSE;
805	u8 bcn_idx = 0;
806
807	{
808		DBGPRINT(RT_DEBUG_ERROR,
809			 ("%s() : No valid Interface be found.\n", __func__));
810		return;
811	}
812
813	/*if ((pAd->WdsTab.Mode == WDS_BRIDGE_MODE) */
814	/*      || ((pAd->ApCfg.MBSSID[apidx].MSSIDDev == NULL) */
815	/*              || !(pAd->ApCfg.MBSSID[apidx].MSSIDDev->flags & IFF_UP)) */
816	/*      ) */
817	if (bBcnReq == FALSE) {
818		/* when the ra interface is down, do not send its beacon frame */
819		/* clear all zero */
820		for (i = 0; i < TXWI_SIZE; i += 4)
821			RTMP_IO_WRITE32(pAd, pAd->BeaconOffset[bcn_idx] + i,
822					0x00);
823	} else {
824		ptr = (u8 *)& pAd->BeaconTxWI;
825		for (i = 0; i < TXWI_SIZE; i += 4)	/* 16-byte TXWI field */
826		{
827			u32 longptr =
828			    *ptr + (*(ptr + 1) << 8) + (*(ptr + 2) << 16) +
829			    (*(ptr + 3) << 24);
830			RTMP_IO_WRITE32(pAd, pAd->BeaconOffset[bcn_idx] + i,
831					longptr);
832			ptr += 4;
833		}
834
835		/* Update CapabilityInfo in Beacon */
836		for (i = CapInfoPos; i < (CapInfoPos + 2); i++) {
837			RTMP_IO_WRITE8(pAd,
838				       pAd->BeaconOffset[bcn_idx] + TXWI_SIZE +
839				       i, *ptr_capinfo);
840			ptr_capinfo++;
841		}
842
843		if (FrameLen > UpdatePos) {
844			for (i = UpdatePos; i < (FrameLen); i++) {
845				RTMP_IO_WRITE8(pAd,
846					       pAd->BeaconOffset[bcn_idx] +
847					       TXWI_SIZE + i, *ptr_update);
848				ptr_update++;
849			}
850		}
851
852	}
853
854}
855
856void RT28xxPciStaAsicForceWakeup(struct rt_rtmp_adapter *pAd, IN BOOLEAN bFromTx)
857{
858	AUTO_WAKEUP_STRUC AutoWakeupCfg;
859
860	if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
861		return;
862
863	if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW)) {
864		DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
865		return;
866	}
867
868	OPSTATUS_SET_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
869
870	RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW);
871
872	if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)
873	    && pAd->StaCfg.PSControl.field.EnableNewPS == TRUE) {
874		/* Support PCIe Advance Power Save */
875		if (bFromTx == TRUE && (pAd->Mlme.bPsPollTimerRunning == TRUE)) {
876			pAd->Mlme.bPsPollTimerRunning = FALSE;
877			RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
878			RTMPusecDelay(3000);
879			DBGPRINT(RT_DEBUG_TRACE,
880				 ("=======AsicForceWakeup===bFromTx\n"));
881		}
882
883		AutoWakeupCfg.word = 0;
884		RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
885
886		if (RT28xxPciAsicRadioOn(pAd, DOT11POWERSAVE)) {
887#ifdef PCIE_PS_SUPPORT
888			/* add by johnli, RF power sequence setup, load RF normal operation-mode setup */
889			if ((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd))
890			    && IS_VERSION_AFTER_F(pAd)) {
891				struct rt_rtmp_chip_op *pChipOps = &pAd->chipOps;
892
893				if (pChipOps->AsicReverseRfFromSleepMode)
894					pChipOps->
895					    AsicReverseRfFromSleepMode(pAd);
896			} else
897#endif /* PCIE_PS_SUPPORT // */
898			{
899				/* end johnli */
900				/* In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again. */
901				if (INFRA_ON(pAd)
902				    && (pAd->CommonCfg.CentralChannel !=
903					pAd->CommonCfg.Channel)
904				    && (pAd->MlmeAux.HtCapability.HtCapInfo.
905					ChannelWidth == BW_40)) {
906					/* Must using 40MHz. */
907					AsicSwitchChannel(pAd,
908							  pAd->CommonCfg.
909							  CentralChannel,
910							  FALSE);
911					AsicLockChannel(pAd,
912							pAd->CommonCfg.
913							CentralChannel);
914				} else {
915					/* Must using 20MHz. */
916					AsicSwitchChannel(pAd,
917							  pAd->CommonCfg.
918							  Channel, FALSE);
919					AsicLockChannel(pAd,
920							pAd->CommonCfg.Channel);
921				}
922			}
923		}
924#ifdef PCIE_PS_SUPPORT
925		/* 3090 MCU Wakeup command needs more time to be stable. */
926		/* Before stable, don't issue other MCU command to prevent from firmware error. */
927		if (((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd))
928		     && IS_VERSION_AFTER_F(pAd)) && IS_VERSION_AFTER_F(pAd)
929		    && (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3)
930		    && (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)) {
931			DBGPRINT(RT_DEBUG_TRACE,
932				 ("<==RT28xxPciStaAsicForceWakeup::Release the MCU Lock(3090)\n"));
933			RTMP_SEM_LOCK(&pAd->McuCmdLock);
934			pAd->brt30xxBanMcuCmd = FALSE;
935			RTMP_SEM_UNLOCK(&pAd->McuCmdLock);
936		}
937#endif /* PCIE_PS_SUPPORT // */
938	} else {
939		/* PCI, 2860-PCIe */
940		DBGPRINT(RT_DEBUG_TRACE,
941			 ("<==RT28xxPciStaAsicForceWakeup::Original PCI Power Saving\n"));
942		AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x02);
943		AutoWakeupCfg.word = 0;
944		RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
945	}
946
947	OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
948	OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
949	DBGPRINT(RT_DEBUG_TRACE, ("<=======RT28xxPciStaAsicForceWakeup\n"));
950}
951
952void RT28xxPciStaAsicSleepThenAutoWakeup(struct rt_rtmp_adapter *pAd,
953					 u16 TbttNumToNextWakeUp)
954{
955	BOOLEAN brc;
956
957	if (pAd->StaCfg.bRadio == FALSE) {
958		OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
959		return;
960	}
961	if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)
962	    && pAd->StaCfg.PSControl.field.EnableNewPS == TRUE) {
963		unsigned long Now = 0;
964		if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW)) {
965			DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
966			OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
967			return;
968		}
969
970		NdisGetSystemUpTime(&Now);
971		/* If last send NULL fram time is too close to this receiving beacon (within 8ms), don't go to sleep for this DTM. */
972		/* Because Some AP can't queuing outgoing frames immediately. */
973		if (((pAd->Mlme.LastSendNULLpsmTime + 8) >= Now)
974		    && (pAd->Mlme.LastSendNULLpsmTime <= Now)) {
975			DBGPRINT(RT_DEBUG_TRACE,
976				 ("Now = %lu, LastSendNULLpsmTime=%lu :  RxCountSinceLastNULL = %lu. \n",
977				  Now, pAd->Mlme.LastSendNULLpsmTime,
978				  pAd->RalinkCounters.RxCountSinceLastNULL));
979			return;
980		} else if ((pAd->RalinkCounters.RxCountSinceLastNULL > 0)
981			   &&
982			   ((pAd->Mlme.LastSendNULLpsmTime +
983			     pAd->CommonCfg.BeaconPeriod) >= Now)) {
984			DBGPRINT(RT_DEBUG_TRACE,
985				 ("Now = %lu, LastSendNULLpsmTime=%lu: RxCountSinceLastNULL = %lu > 0 \n",
986				  Now, pAd->Mlme.LastSendNULLpsmTime,
987				  pAd->RalinkCounters.RxCountSinceLastNULL));
988			return;
989		}
990
991		brc =
992		    RT28xxPciAsicRadioOff(pAd, DOT11POWERSAVE,
993					  TbttNumToNextWakeUp);
994		if (brc == TRUE)
995			OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE);
996	} else {
997		AUTO_WAKEUP_STRUC AutoWakeupCfg;
998		/* we have decided to SLEEP, so at least do it for a BEACON period. */
999		if (TbttNumToNextWakeUp == 0)
1000			TbttNumToNextWakeUp = 1;
1001
1002		/*RTMP_IO_WRITE32(pAd, INT_MASK_CSR, AutoWakeupInt); */
1003
1004		AutoWakeupCfg.word = 0;
1005		RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
1006		AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1;
1007		AutoWakeupCfg.field.EnableAutoWakeup = 1;
1008		AutoWakeupCfg.field.AutoLeadTime = 5;
1009		RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
1010		AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x00);	/* send POWER-SAVE command to MCU. Timeout 40us. */
1011		OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE);
1012		DBGPRINT(RT_DEBUG_TRACE,
1013			 ("<-- %s, TbttNumToNextWakeUp=%d \n", __func__,
1014			  TbttNumToNextWakeUp));
1015	}
1016
1017}
1018
1019void PsPollWakeExec(void *SystemSpecific1,
1020		    void *FunctionContext,
1021		    void *SystemSpecific2, void *SystemSpecific3)
1022{
1023	struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)FunctionContext;
1024	unsigned long flags;
1025
1026	DBGPRINT(RT_DEBUG_TRACE, ("-->PsPollWakeExec \n"));
1027	RTMP_INT_LOCK(&pAd->irq_lock, flags);
1028	if (pAd->Mlme.bPsPollTimerRunning) {
1029		RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
1030	}
1031	pAd->Mlme.bPsPollTimerRunning = FALSE;
1032	RTMP_INT_UNLOCK(&pAd->irq_lock, flags);
1033#ifdef PCIE_PS_SUPPORT
1034	/* For rt30xx power solution 3, Use software timer to wake up in psm. So call */
1035	/* AsicForceWakeup here instead of handling twakeup interrupt. */
1036	if (((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd))
1037	     && IS_VERSION_AFTER_F(pAd))
1038	    && (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3)
1039	    && (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)) {
1040		DBGPRINT(RT_DEBUG_TRACE,
1041			 ("<--PsPollWakeExec::3090 calls AsicForceWakeup(pAd, DOT11POWERSAVE) in advance \n"));
1042		AsicForceWakeup(pAd, DOT11POWERSAVE);
1043	}
1044#endif /* PCIE_PS_SUPPORT // */
1045}
1046
1047void RadioOnExec(void *SystemSpecific1,
1048		 void *FunctionContext,
1049		 void *SystemSpecific2, void *SystemSpecific3)
1050{
1051	struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)FunctionContext;
1052	struct rt_rtmp_chip_op *pChipOps = &pAd->chipOps;
1053	WPDMA_GLO_CFG_STRUC DmaCfg;
1054	BOOLEAN Cancelled;
1055
1056	if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) {
1057		DBGPRINT(RT_DEBUG_TRACE,
1058			 ("-->RadioOnExec() return on fOP_STATUS_DOZE == TRUE; \n"));
1059/*KH Debug: Add the compile flag "RT2860 and condition */
1060#ifdef RTMP_PCI_SUPPORT
1061		if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)
1062		    && pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)
1063			RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
1064#endif /* RTMP_PCI_SUPPORT // */
1065		return;
1066	}
1067
1068	if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) {
1069		DBGPRINT(RT_DEBUG_TRACE,
1070			 ("-->RadioOnExec() return on SCAN_IN_PROGRESS; \n"));
1071#ifdef RTMP_PCI_SUPPORT
1072		if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)
1073		    && pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)
1074			RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
1075#endif /* RTMP_PCI_SUPPORT // */
1076		return;
1077	}
1078/*KH Debug: need to check. I add the compile flag "CONFIG_STA_SUPPORT" to enclose the following codes. */
1079#ifdef RTMP_PCI_SUPPORT
1080	if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)
1081	    && pAd->StaCfg.PSControl.field.EnableNewPS == TRUE) {
1082		pAd->Mlme.bPsPollTimerRunning = FALSE;
1083		RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
1084	}
1085#endif /* RTMP_PCI_SUPPORT // */
1086	if (pAd->StaCfg.bRadio == TRUE) {
1087		pAd->bPCIclkOff = FALSE;
1088		RTMPRingCleanUp(pAd, QID_AC_BK);
1089		RTMPRingCleanUp(pAd, QID_AC_BE);
1090		RTMPRingCleanUp(pAd, QID_AC_VI);
1091		RTMPRingCleanUp(pAd, QID_AC_VO);
1092		RTMPRingCleanUp(pAd, QID_MGMT);
1093		RTMPRingCleanUp(pAd, QID_RX);
1094
1095		/* 2. Send wake up command. */
1096		AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x02);
1097		/* 2-1. wait command ok. */
1098		AsicCheckCommanOk(pAd, PowerWakeCID);
1099
1100		/* When PCI clock is off, don't want to service interrupt. So when back to clock on, enable interrupt. */
1101		/*RTMP_IO_WRITE32(pAd, INT_MASK_CSR, (DELAYINTMASK|RxINT)); */
1102		RTMP_ASIC_INTERRUPT_ENABLE(pAd);
1103
1104		/* 3. Enable Tx DMA. */
1105		RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
1106		DmaCfg.field.EnableTxDMA = 1;
1107		RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
1108
1109		/* In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again. */
1110		if (INFRA_ON(pAd)
1111		    && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
1112		    && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth ==
1113			BW_40)) {
1114			/* Must using 40MHz. */
1115			AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel,
1116					  FALSE);
1117			AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
1118		} else {
1119			/* Must using 20MHz. */
1120			AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
1121			AsicLockChannel(pAd, pAd->CommonCfg.Channel);
1122		}
1123
1124/*KH Debug:The following codes should be enclosed by RT3090 compile flag */
1125		if (pChipOps->AsicReverseRfFromSleepMode)
1126			pChipOps->AsicReverseRfFromSleepMode(pAd);
1127
1128#ifdef PCIE_PS_SUPPORT
1129/* 3090 MCU Wakeup command needs more time to be stable. */
1130/* Before stable, don't issue other MCU command to prevent from firmware error. */
1131		if ((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd))
1132		    && IS_VERSION_AFTER_F(pAd)
1133		    && (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3)
1134		    && (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)) {
1135			RTMP_SEM_LOCK(&pAd->McuCmdLock);
1136			pAd->brt30xxBanMcuCmd = FALSE;
1137			RTMP_SEM_UNLOCK(&pAd->McuCmdLock);
1138		}
1139#endif /* PCIE_PS_SUPPORT // */
1140
1141		/* Clear Radio off flag */
1142		RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1143
1144		/* Set LED */
1145		RTMPSetLED(pAd, LED_RADIO_ON);
1146
1147		if (pAd->StaCfg.Psm == PWR_ACTIVE) {
1148			RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3,
1149						     pAd->StaCfg.BBPR3);
1150		}
1151	} else {
1152		RT28xxPciAsicRadioOff(pAd, GUIRADIO_OFF, 0);
1153	}
1154}
1155
1156/*
1157	==========================================================================
1158	Description:
1159		This routine sends command to firmware and turn our chip to wake up mode from power save mode.
1160		Both RadioOn and .11 power save function needs to call this routine.
1161	Input:
1162		Level = GUIRADIO_OFF : call this function is from Radio Off to Radio On.  Need to restore PCI host value.
1163		Level = other value : normal wake up function.
1164
1165	==========================================================================
1166 */
1167BOOLEAN RT28xxPciAsicRadioOn(struct rt_rtmp_adapter *pAd, u8 Level)
1168{
1169	/*WPDMA_GLO_CFG_STRUC       DmaCfg; */
1170	BOOLEAN Cancelled;
1171	/*u32                        MACValue; */
1172
1173	if (pAd->OpMode == OPMODE_AP && Level == DOT11POWERSAVE)
1174		return FALSE;
1175
1176	if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)) {
1177		if (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE) {
1178			pAd->Mlme.bPsPollTimerRunning = FALSE;
1179			RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
1180		}
1181		if ((pAd->StaCfg.PSControl.field.EnableNewPS == TRUE &&
1182		     (Level == GUIRADIO_OFF || Level == GUI_IDLE_POWER_SAVE)) ||
1183		    RTMP_TEST_PSFLAG(pAd, fRTMP_PS_SET_PCI_CLK_OFF_COMMAND)) {
1184			/* Some chips don't need to delay 6ms, so copy RTMPPCIePowerLinkCtrlRestore */
1185			/* return condition here. */
1186			/*
1187			   if (((pAd->MACVersion&0xffff0000) != 0x28600000)
1188			   && ((pAd->DeviceID == NIC2860_PCIe_DEVICE_ID)
1189			   ||(pAd->DeviceID == NIC2790_PCIe_DEVICE_ID)))
1190			 */
1191			{
1192				DBGPRINT(RT_DEBUG_TRACE,
1193					 ("RT28xxPciAsicRadioOn ()\n"));
1194				/* 1. Set PCI Link Control in Configuration Space. */
1195				RTMPPCIeLinkCtrlValueRestore(pAd,
1196							     RESTORE_WAKEUP);
1197				RTMPusecDelay(6000);
1198			}
1199		}
1200	}
1201#ifdef PCIE_PS_SUPPORT
1202	if (!
1203	    (((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd))
1204	      && IS_VERSION_AFTER_F(pAd)
1205	      && (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3)
1206	      && (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE))))
1207#endif /* PCIE_PS_SUPPORT // */
1208	{
1209		pAd->bPCIclkOff = FALSE;
1210		DBGPRINT(RT_DEBUG_TRACE,
1211			 ("PSM :309xbPCIclkOff == %d\n", pAd->bPCIclkOff));
1212	}
1213	/* 2. Send wake up command. */
1214	AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x02);
1215	pAd->bPCIclkOff = FALSE;
1216	/* 2-1. wait command ok. */
1217	AsicCheckCommanOk(pAd, PowerWakeCID);
1218	RTMP_ASIC_INTERRUPT_ENABLE(pAd);
1219
1220	RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
1221	if (Level == GUI_IDLE_POWER_SAVE) {
1222#ifdef  PCIE_PS_SUPPORT
1223
1224		/* add by johnli, RF power sequence setup, load RF normal operation-mode setup */
1225		if ((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd))) {
1226			struct rt_rtmp_chip_op *pChipOps = &pAd->chipOps;
1227
1228			if (pChipOps->AsicReverseRfFromSleepMode)
1229				pChipOps->AsicReverseRfFromSleepMode(pAd);
1230			/* 3090 MCU Wakeup command needs more time to be stable. */
1231			/* Before stable, don't issue other MCU command to prevent from firmware error. */
1232			if ((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd))
1233			    && IS_VERSION_AFTER_F(pAd)
1234			    && (pAd->StaCfg.PSControl.field.rt30xxPowerMode ==
1235				3)
1236			    && (pAd->StaCfg.PSControl.field.EnableNewPS ==
1237				TRUE)) {
1238				RTMP_SEM_LOCK(&pAd->McuCmdLock);
1239				pAd->brt30xxBanMcuCmd = FALSE;
1240				RTMP_SEM_UNLOCK(&pAd->McuCmdLock);
1241			}
1242		} else
1243			/* end johnli */
1244#endif /* PCIE_PS_SUPPORT // */
1245		{
1246			/* In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again. */
1247			{
1248				if (INFRA_ON(pAd)
1249				    && (pAd->CommonCfg.CentralChannel !=
1250					pAd->CommonCfg.Channel)
1251				    && (pAd->MlmeAux.HtCapability.HtCapInfo.
1252					ChannelWidth == BW_40)) {
1253					/* Must using 40MHz. */
1254					AsicSwitchChannel(pAd,
1255							  pAd->CommonCfg.
1256							  CentralChannel,
1257							  FALSE);
1258					AsicLockChannel(pAd,
1259							pAd->CommonCfg.
1260							CentralChannel);
1261				} else {
1262					/* Must using 20MHz. */
1263					AsicSwitchChannel(pAd,
1264							  pAd->CommonCfg.
1265							  Channel, FALSE);
1266					AsicLockChannel(pAd,
1267							pAd->CommonCfg.Channel);
1268				}
1269			}
1270
1271		}
1272	}
1273	return TRUE;
1274
1275}
1276
1277/*
1278	==========================================================================
1279	Description:
1280		This routine sends command to firmware and turn our chip to power save mode.
1281		Both RadioOff and .11 power save function needs to call this routine.
1282	Input:
1283		Level = GUIRADIO_OFF  : GUI Radio Off mode
1284		Level = DOT11POWERSAVE  : 802.11 power save mode
1285		Level = RTMP_HALT  : When Disable device.
1286
1287	==========================================================================
1288 */
1289BOOLEAN RT28xxPciAsicRadioOff(struct rt_rtmp_adapter *pAd,
1290			      u8 Level, u16 TbttNumToNextWakeUp)
1291{
1292	WPDMA_GLO_CFG_STRUC DmaCfg;
1293	u8 i, tempBBP_R3 = 0;
1294	BOOLEAN brc = FALSE, Cancelled;
1295	u32 TbTTTime = 0;
1296	u32 PsPollTime = 0 /*, MACValue */ ;
1297	unsigned long BeaconPeriodTime;
1298	u32 RxDmaIdx, RxCpuIdx;
1299	DBGPRINT(RT_DEBUG_TRACE,
1300		 ("AsicRadioOff ===> Lv= %d, TxCpuIdx = %d, TxDmaIdx = %d. RxCpuIdx = %d, RxDmaIdx = %d.\n",
1301		  Level, pAd->TxRing[0].TxCpuIdx, pAd->TxRing[0].TxDmaIdx,
1302		  pAd->RxRing.RxCpuIdx, pAd->RxRing.RxDmaIdx));
1303
1304	if (pAd->OpMode == OPMODE_AP && Level == DOT11POWERSAVE)
1305		return FALSE;
1306
1307	/* Check Rx DMA busy status, if more than half is occupied, give up this radio off. */
1308	RTMP_IO_READ32(pAd, RX_DRX_IDX, &RxDmaIdx);
1309	RTMP_IO_READ32(pAd, RX_CRX_IDX, &RxCpuIdx);
1310	if ((RxDmaIdx > RxCpuIdx) && ((RxDmaIdx - RxCpuIdx) > RX_RING_SIZE / 3)) {
1311		DBGPRINT(RT_DEBUG_TRACE,
1312			 ("AsicRadioOff ===> return1. RxDmaIdx = %d ,  RxCpuIdx = %d. \n",
1313			  RxDmaIdx, RxCpuIdx));
1314		return FALSE;
1315	} else if ((RxCpuIdx >= RxDmaIdx)
1316		   && ((RxCpuIdx - RxDmaIdx) < RX_RING_SIZE / 3)) {
1317		DBGPRINT(RT_DEBUG_TRACE,
1318			 ("AsicRadioOff ===> return2.  RxCpuIdx = %d. RxDmaIdx = %d ,  \n",
1319			  RxCpuIdx, RxDmaIdx));
1320		return FALSE;
1321	}
1322	/* Once go into this function, disable tx because don't want too many packets in queue to prevent HW stops. */
1323	/*pAd->bPCIclkOffDisableTx = TRUE; */
1324	RTMP_SET_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
1325	if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)
1326	    && pAd->OpMode == OPMODE_STA
1327	    && pAd->StaCfg.PSControl.field.EnableNewPS == TRUE) {
1328		RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
1329		RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
1330
1331		if (Level == DOT11POWERSAVE) {
1332			RTMP_IO_READ32(pAd, TBTT_TIMER, &TbTTTime);
1333			TbTTTime &= 0x1ffff;
1334			/* 00. check if need to do sleep in this DTIM period.   If next beacon will arrive within 30ms , ...doesn't necessarily sleep. */
1335			/* TbTTTime uint = 64us, LEAD_TIME unit = 1024us, PsPollTime unit = 1ms */
1336			if (((64 * TbTTTime) < ((LEAD_TIME * 1024) + 40000))
1337			    && (TbttNumToNextWakeUp == 0)) {
1338				DBGPRINT(RT_DEBUG_TRACE,
1339					 ("TbTTTime = 0x%x , give up this sleep. \n",
1340					  TbTTTime));
1341				OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
1342				/*pAd->bPCIclkOffDisableTx = FALSE; */
1343				RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
1344				return FALSE;
1345			} else {
1346				PsPollTime =
1347				    (64 * TbTTTime - LEAD_TIME * 1024) / 1000;
1348#ifdef PCIE_PS_SUPPORT
1349				if ((IS_RT3090(pAd) || IS_RT3572(pAd)
1350				     || IS_RT3390(pAd))
1351				    && IS_VERSION_AFTER_F(pAd)
1352				    && (pAd->StaCfg.PSControl.field.
1353					rt30xxPowerMode == 3)
1354				    && (pAd->StaCfg.PSControl.field.
1355					EnableNewPS == TRUE)) {
1356					PsPollTime -= 5;
1357				} else
1358#endif /* PCIE_PS_SUPPORT // */
1359					PsPollTime -= 3;
1360
1361				BeaconPeriodTime =
1362				    pAd->CommonCfg.BeaconPeriod * 102 / 100;
1363				if (TbttNumToNextWakeUp > 0)
1364					PsPollTime +=
1365					    ((TbttNumToNextWakeUp -
1366					      1) * BeaconPeriodTime);
1367
1368				pAd->Mlme.bPsPollTimerRunning = TRUE;
1369				RTMPSetTimer(&pAd->Mlme.PsPollTimer,
1370					     PsPollTime);
1371			}
1372		}
1373	} else {
1374		DBGPRINT(RT_DEBUG_TRACE,
1375			 ("RT28xxPciAsicRadioOff::Level!=DOT11POWERSAVE \n"));
1376	}
1377
1378	pAd->bPCIclkOffDisableTx = FALSE;
1379
1380	RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
1381
1382	/* Set to 1R. */
1383	if (pAd->Antenna.field.RxPath > 1 && pAd->OpMode == OPMODE_STA) {
1384		tempBBP_R3 = (pAd->StaCfg.BBPR3 & 0xE7);
1385		RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, tempBBP_R3);
1386	}
1387	/* In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again. */
1388	if ((INFRA_ON(pAd) || pAd->OpMode == OPMODE_AP)
1389	    && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
1390	    && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40)) {
1391		/* Must using 40MHz. */
1392		AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel);
1393	} else {
1394		/* Must using 20MHz. */
1395		AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel);
1396	}
1397
1398	if (Level != RTMP_HALT) {
1399		/* Change Interrupt bitmask. */
1400		/* When PCI clock is off, don't want to service interrupt. */
1401		RTMP_IO_WRITE32(pAd, INT_MASK_CSR, AutoWakeupInt);
1402	} else {
1403		RTMP_ASIC_INTERRUPT_DISABLE(pAd);
1404	}
1405
1406	RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx);
1407	/*  2. Send Sleep command */
1408	RTMP_IO_WRITE32(pAd, H2M_MAILBOX_STATUS, 0xffffffff);
1409	RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CID, 0xffffffff);
1410	/* send POWER-SAVE command to MCU. high-byte = 1 save power as much as possible. high byte = 0 save less power */
1411	AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x1);
1412	/*  2-1. Wait command success */
1413	/* Status = 1 : success, Status = 2, already sleep, Status = 3, Maybe MAC is busy so can't finish this task. */
1414	brc = AsicCheckCommanOk(pAd, PowerSafeCID);
1415
1416	/*  3. After 0x30 command is ok, send radio off command. lowbyte = 0 for power safe. */
1417	/* If 0x30 command is not ok this time, we can ignore 0x35 command. It will make sure not cause firmware'r problem. */
1418	if ((Level == DOT11POWERSAVE) && (brc == TRUE)) {
1419		AsicSendCommandToMcu(pAd, 0x35, PowerRadioOffCID, 0, 0x00);	/* lowbyte = 0 means to do power safe, NOT turn off radio. */
1420		/*  3-1. Wait command success */
1421		AsicCheckCommanOk(pAd, PowerRadioOffCID);
1422	} else if (brc == TRUE) {
1423		AsicSendCommandToMcu(pAd, 0x35, PowerRadioOffCID, 1, 0x00);	/* lowbyte = 0 means to do power safe, NOT turn off radio. */
1424		/*  3-1. Wait command success */
1425		AsicCheckCommanOk(pAd, PowerRadioOffCID);
1426	}
1427	/* 1. Wait DMA not busy */
1428	i = 0;
1429	do {
1430		RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
1431		if ((DmaCfg.field.RxDMABusy == 0)
1432		    && (DmaCfg.field.TxDMABusy == 0))
1433			break;
1434		RTMPusecDelay(20);
1435		i++;
1436	} while (i < 50);
1437
1438	/*
1439	   if (i >= 50)
1440	   {
1441	   pAd->CheckDmaBusyCount++;
1442	   DBGPRINT(RT_DEBUG_TRACE, ("DMA Rx keeps busy.  return on AsicRadioOff () CheckDmaBusyCount = %d \n", pAd->CheckDmaBusyCount));
1443	   }
1444	   else
1445	   {
1446	   pAd->CheckDmaBusyCount = 0;
1447	   }
1448	 */
1449/*KH Debug:My original codes have the follwoing codes, but currecnt codes do not have it. */
1450/* Disable for stability. If PCIE Link Control is modified for advance power save, re-covery this code segment. */
1451	RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, 0x1280);
1452/*OPSTATUS_SET_FLAG(pAd, fOP_STATUS_CLKSELECT_40MHZ); */
1453
1454#ifdef PCIE_PS_SUPPORT
1455	if ((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd))
1456	    && IS_VERSION_AFTER_F(pAd)
1457	    && (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3)
1458	    && (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)) {
1459		DBGPRINT(RT_DEBUG_TRACE,
1460			 ("RT28xxPciAsicRadioOff::3090 return to skip the following TbttNumToNextWakeUp setting for 279x\n"));
1461		pAd->bPCIclkOff = TRUE;
1462		RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
1463		/* For this case, doesn't need to below actions, so return here. */
1464		return brc;
1465	}
1466#endif /* PCIE_PS_SUPPORT // */
1467
1468	if (Level == DOT11POWERSAVE) {
1469		AUTO_WAKEUP_STRUC AutoWakeupCfg;
1470		/*RTMPSetTimer(&pAd->Mlme.PsPollTimer, 90); */
1471
1472		/* we have decided to SLEEP, so at least do it for a BEACON period. */
1473		if (TbttNumToNextWakeUp == 0)
1474			TbttNumToNextWakeUp = 1;
1475
1476		AutoWakeupCfg.word = 0;
1477		RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
1478
1479		/* 1. Set auto wake up timer. */
1480		AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1;
1481		AutoWakeupCfg.field.EnableAutoWakeup = 1;
1482		AutoWakeupCfg.field.AutoLeadTime = LEAD_TIME;
1483		RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
1484	}
1485	/*  4-1. If it's to disable our device. Need to restore PCI Configuration Space to its original value. */
1486	if (Level == RTMP_HALT && pAd->OpMode == OPMODE_STA) {
1487		if ((brc == TRUE) && (i < 50))
1488			RTMPPCIeLinkCtrlSetting(pAd, 1);
1489	}
1490	/*  4. Set PCI configuration Space Link Comtrol fields.  Only Radio Off needs to call this function */
1491	else if (pAd->OpMode == OPMODE_STA) {
1492		if ((brc == TRUE) && (i < 50))
1493			RTMPPCIeLinkCtrlSetting(pAd, 3);
1494	}
1495	/*pAd->bPCIclkOffDisableTx = FALSE; */
1496	RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
1497	return TRUE;
1498}
1499
1500void RT28xxPciMlmeRadioOn(struct rt_rtmp_adapter *pAd)
1501{
1502	if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
1503		return;
1504
1505	DBGPRINT(RT_DEBUG_TRACE, ("%s===>\n", __func__));
1506
1507	if ((pAd->OpMode == OPMODE_AP) || ((pAd->OpMode == OPMODE_STA)
1508					   &&
1509					   (!OPSTATUS_TEST_FLAG
1510					    (pAd, fOP_STATUS_PCIE_DEVICE)
1511					    || pAd->StaCfg.PSControl.field.
1512					    EnableNewPS == FALSE))) {
1513		RT28xxPciAsicRadioOn(pAd, GUI_IDLE_POWER_SAVE);
1514		/*NICResetFromError(pAd); */
1515
1516		RTMPRingCleanUp(pAd, QID_AC_BK);
1517		RTMPRingCleanUp(pAd, QID_AC_BE);
1518		RTMPRingCleanUp(pAd, QID_AC_VI);
1519		RTMPRingCleanUp(pAd, QID_AC_VO);
1520		RTMPRingCleanUp(pAd, QID_MGMT);
1521		RTMPRingCleanUp(pAd, QID_RX);
1522
1523		/* Enable Tx/Rx */
1524		RTMPEnableRxTx(pAd);
1525
1526		/* Clear Radio off flag */
1527		RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1528
1529		RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
1530
1531		/* Set LED */
1532		RTMPSetLED(pAd, LED_RADIO_ON);
1533	}
1534
1535	if ((pAd->OpMode == OPMODE_STA) &&
1536	    (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE))
1537	    && (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)) {
1538		BOOLEAN Cancelled;
1539
1540		RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
1541
1542		pAd->Mlme.bPsPollTimerRunning = FALSE;
1543		RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
1544		RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
1545		RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 40);
1546	}
1547}
1548
1549void RT28xxPciMlmeRadioOFF(struct rt_rtmp_adapter *pAd)
1550{
1551	BOOLEAN brc = TRUE;
1552
1553	if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
1554		return;
1555
1556	/* Link down first if any association exists */
1557	if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST)) {
1558		if (INFRA_ON(pAd) || ADHOC_ON(pAd)) {
1559			struct rt_mlme_disassoc_req DisReq;
1560			struct rt_mlme_queue_elem *pMsgElem =
1561			    kmalloc(sizeof(struct rt_mlme_queue_elem),
1562							MEM_ALLOC_FLAG);
1563
1564			if (pMsgElem) {
1565				COPY_MAC_ADDR(&DisReq.Addr,
1566					      pAd->CommonCfg.Bssid);
1567				DisReq.Reason = REASON_DISASSOC_STA_LEAVING;
1568
1569				pMsgElem->Machine = ASSOC_STATE_MACHINE;
1570				pMsgElem->MsgType = MT2_MLME_DISASSOC_REQ;
1571				pMsgElem->MsgLen =
1572				    sizeof(struct rt_mlme_disassoc_req);
1573				NdisMoveMemory(pMsgElem->Msg, &DisReq,
1574					       sizeof
1575					       (struct rt_mlme_disassoc_req));
1576
1577				MlmeDisassocReqAction(pAd, pMsgElem);
1578				kfree(pMsgElem);
1579
1580				RTMPusecDelay(1000);
1581			}
1582		}
1583	}
1584
1585	DBGPRINT(RT_DEBUG_TRACE, ("%s===>\n", __func__));
1586
1587	/* Set Radio off flag */
1588	RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1589
1590	{
1591		BOOLEAN Cancelled;
1592		if (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE) {
1593			if (RTMP_TEST_FLAG
1594			    (pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS)) {
1595				RTMPCancelTimer(&pAd->MlmeAux.ScanTimer,
1596						&Cancelled);
1597				RTMP_CLEAR_FLAG(pAd,
1598						fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS);
1599			}
1600			/* If during power safe mode. */
1601			if (pAd->StaCfg.bRadio == TRUE) {
1602				DBGPRINT(RT_DEBUG_TRACE,
1603					 ("-->MlmeRadioOff() return on bRadio == TRUE; \n"));
1604				return;
1605			}
1606			/* Always radio on since the NIC needs to set the MCU command (LED_RADIO_OFF). */
1607			if (IDLE_ON(pAd) &&
1608			    (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF)))
1609			{
1610				RT28xxPciAsicRadioOn(pAd, GUI_IDLE_POWER_SAVE);
1611			}
1612			if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)) {
1613				BOOLEAN Cancelled;
1614				pAd->Mlme.bPsPollTimerRunning = FALSE;
1615				RTMPCancelTimer(&pAd->Mlme.PsPollTimer,
1616						&Cancelled);
1617				RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer,
1618						&Cancelled);
1619			}
1620		}
1621		/* Link down first if any association exists */
1622		if (INFRA_ON(pAd) || ADHOC_ON(pAd))
1623			LinkDown(pAd, FALSE);
1624		RTMPusecDelay(10000);
1625		/*========================================== */
1626		/* Clean up old bss table */
1627		BssTableInit(&pAd->ScanTab);
1628
1629		/*
1630		   if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE))
1631		   {
1632		   RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
1633		   return;
1634		   }
1635		 */
1636	}
1637
1638	/* Set LED.Move to here for fixing LED bug. This flag must be called after LinkDown */
1639	RTMPSetLED(pAd, LED_RADIO_OFF);
1640
1641/*KH Debug:All PCIe devices need to use timer to execute radio off function, or the PCIe&&EnableNewPS needs. */
1642/*KH Ans:It is right, because only when the PCIe and EnableNewPs is true, we need to delay the RadioOffTimer */
1643/*to avoid the deadlock with PCIe Power saving function. */
1644	if (pAd->OpMode == OPMODE_STA &&
1645	    OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE) &&
1646	    pAd->StaCfg.PSControl.field.EnableNewPS == TRUE) {
1647		RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
1648	} else {
1649		brc = RT28xxPciAsicRadioOff(pAd, GUIRADIO_OFF, 0);
1650
1651		if (brc == FALSE) {
1652			DBGPRINT(RT_DEBUG_ERROR,
1653				 ("%s call RT28xxPciAsicRadioOff fail!\n",
1654				  __func__));
1655		}
1656	}
1657/*
1658*/
1659}
1660
1661#endif /* RTMP_MAC_PCI // */
1662