Merge branch 'for-linus' of git://neil.brown.name/md
[sfrench/cifs-2.6.git] / drivers / staging / rt2860 / common / cmm_mac_pci.c
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 */
51 int 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 */
403 void 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
536 void 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 ========================================================================
658 Routine Description:
659     Disable DMA.
660
661 Arguments:
662         *pAd                            the raxx interface data pointer
663
664 Return Value:
665         None
666
667 Note:
668 ========================================================================
669 */
670 void 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 ========================================================================
682 Routine Description:
683     Enable DMA.
684
685 Arguments:
686         *pAd                            the raxx interface data pointer
687
688 Return Value:
689         None
690
691 Note:
692 ========================================================================
693 */
694 void 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
724 BOOLEAN 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 ========================================================================
785 Routine Description:
786     Write Beacon buffer to Asic.
787
788 Arguments:
789         *pAd                            the raxx interface data pointer
790
791 Return Value:
792         None
793
794 Note:
795 ========================================================================
796 */
797 void 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
856 void 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
952 void 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
1019 void 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
1047 void 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  */
1167 BOOLEAN 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  */
1289 BOOLEAN 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
1500 void 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
1549 void 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 // */