2 *************************************************************************
4 * 5F., No.36, Taiyuan St., Jhubei City,
8 * (c) Copyright 2002-2007, Ralink Technology, Inc.
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. *
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. *
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. *
25 *************************************************************************
30 #include "../rt_config.h"
34 ========================================================================
37 Allocate DMA memory blocks for send, receive
40 Adapter Pointer to our adapter
51 ========================================================================
53 NDIS_STATUS RTMPAllocTxRxRingMemory(
56 NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
64 PRTMP_TX_RING pTxRing;
67 // PRTMP_REORDERBUF pReorderBuf;
69 DBGPRINT(RT_DEBUG_TRACE, ("--> RTMPAllocTxRxRingMemory\n"));
73 // Allocate all ring descriptors, include TxD, RxD, MgmtD.
74 // Although each size is different, to prevent cacheline and alignment
75 // issue, I intentional set them all to 64 bytes.
77 for (num=0; num<NUM_OF_TX_RING; num++)
84 // Allocate Tx ring descriptor's memory (5 TX rings = 4 ACs + 1 HCCA)
86 pAd->TxDescRing[num].AllocSize = TX_RING_SIZE * TXD_SIZE;
87 RTMP_AllocateTxDescMemory(
90 pAd->TxDescRing[num].AllocSize,
92 &pAd->TxDescRing[num].AllocVa,
93 &pAd->TxDescRing[num].AllocPa);
95 if (pAd->TxDescRing[num].AllocVa == NULL)
97 ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
98 DBGPRINT_ERR(("Failed to allocate a big buffer\n"));
99 Status = NDIS_STATUS_RESOURCES;
103 // Zero init this memory block
104 NdisZeroMemory(pAd->TxDescRing[num].AllocVa, pAd->TxDescRing[num].AllocSize);
106 // Save PA & VA for further operation
107 RingBasePaHigh = RTMP_GetPhysicalAddressHigh(pAd->TxDescRing[num].AllocPa);
108 RingBasePaLow = RTMP_GetPhysicalAddressLow (pAd->TxDescRing[num].AllocPa);
109 RingBaseVa = pAd->TxDescRing[num].AllocVa;
112 // Allocate all 1st TXBuf's memory for this TxRing
114 pAd->TxBufSpace[num].AllocSize = TX_RING_SIZE * TX_DMA_1ST_BUFFER_SIZE;
115 RTMP_AllocateFirstTxBuffer(
118 pAd->TxBufSpace[num].AllocSize,
120 &pAd->TxBufSpace[num].AllocVa,
121 &pAd->TxBufSpace[num].AllocPa);
123 if (pAd->TxBufSpace[num].AllocVa == NULL)
125 ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
126 DBGPRINT_ERR(("Failed to allocate a big buffer\n"));
127 Status = NDIS_STATUS_RESOURCES;
131 // Zero init this memory block
132 NdisZeroMemory(pAd->TxBufSpace[num].AllocVa, pAd->TxBufSpace[num].AllocSize);
134 // Save PA & VA for further operation
135 BufBasePaHigh = RTMP_GetPhysicalAddressHigh(pAd->TxBufSpace[num].AllocPa);
136 BufBasePaLow = RTMP_GetPhysicalAddressLow (pAd->TxBufSpace[num].AllocPa);
137 BufBaseVa = pAd->TxBufSpace[num].AllocVa;
140 // Initialize Tx Ring Descriptor and associated buffer memory
142 pTxRing = &pAd->TxRing[num];
143 for (index = 0; index < TX_RING_SIZE; index++)
145 pTxRing->Cell[index].pNdisPacket = NULL;
146 pTxRing->Cell[index].pNextNdisPacket = NULL;
147 // Init Tx Ring Size, Va, Pa variables
148 pTxRing->Cell[index].AllocSize = TXD_SIZE;
149 pTxRing->Cell[index].AllocVa = RingBaseVa;
150 RTMP_SetPhysicalAddressHigh(pTxRing->Cell[index].AllocPa, RingBasePaHigh);
151 RTMP_SetPhysicalAddressLow (pTxRing->Cell[index].AllocPa, RingBasePaLow);
153 // Setup Tx Buffer size & address. only 802.11 header will store in this space
154 pDmaBuf = &pTxRing->Cell[index].DmaBuf;
155 pDmaBuf->AllocSize = TX_DMA_1ST_BUFFER_SIZE;
156 pDmaBuf->AllocVa = BufBaseVa;
157 RTMP_SetPhysicalAddressHigh(pDmaBuf->AllocPa, BufBasePaHigh);
158 RTMP_SetPhysicalAddressLow(pDmaBuf->AllocPa, BufBasePaLow);
160 // link the pre-allocated TxBuf to TXD
161 pTxD = (PTXD_STRUC) pTxRing->Cell[index].AllocVa;
162 pTxD->SDPtr0 = BufBasePaLow;
163 // advance to next ring descriptor address
165 RingBasePaLow += TXD_SIZE;
166 RingBaseVa = (PUCHAR) RingBaseVa + TXD_SIZE;
168 // advance to next TxBuf address
169 BufBasePaLow += TX_DMA_1ST_BUFFER_SIZE;
170 BufBaseVa = (PUCHAR) BufBaseVa + TX_DMA_1ST_BUFFER_SIZE;
172 DBGPRINT(RT_DEBUG_TRACE, ("TxRing[%d]: total %d entry allocated\n", num, index));
174 if (Status == NDIS_STATUS_RESOURCES)
178 // Allocate MGMT ring descriptor's memory except Tx ring which allocated eariler
180 pAd->MgmtDescRing.AllocSize = MGMT_RING_SIZE * TXD_SIZE;
181 RTMP_AllocateMgmtDescMemory(
183 pAd->MgmtDescRing.AllocSize,
185 &pAd->MgmtDescRing.AllocVa,
186 &pAd->MgmtDescRing.AllocPa);
188 if (pAd->MgmtDescRing.AllocVa == NULL)
190 ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
191 DBGPRINT_ERR(("Failed to allocate a big buffer\n"));
192 Status = NDIS_STATUS_RESOURCES;
196 // Zero init this memory block
197 NdisZeroMemory(pAd->MgmtDescRing.AllocVa, pAd->MgmtDescRing.AllocSize);
199 // Save PA & VA for further operation
200 RingBasePaHigh = RTMP_GetPhysicalAddressHigh(pAd->MgmtDescRing.AllocPa);
201 RingBasePaLow = RTMP_GetPhysicalAddressLow (pAd->MgmtDescRing.AllocPa);
202 RingBaseVa = pAd->MgmtDescRing.AllocVa;
205 // Initialize MGMT Ring and associated buffer memory
207 for (index = 0; index < MGMT_RING_SIZE; index++)
209 pAd->MgmtRing.Cell[index].pNdisPacket = NULL;
210 pAd->MgmtRing.Cell[index].pNextNdisPacket = NULL;
211 // Init MGMT Ring Size, Va, Pa variables
212 pAd->MgmtRing.Cell[index].AllocSize = TXD_SIZE;
213 pAd->MgmtRing.Cell[index].AllocVa = RingBaseVa;
214 RTMP_SetPhysicalAddressHigh(pAd->MgmtRing.Cell[index].AllocPa, RingBasePaHigh);
215 RTMP_SetPhysicalAddressLow (pAd->MgmtRing.Cell[index].AllocPa, RingBasePaLow);
217 // Offset to next ring descriptor address
218 RingBasePaLow += TXD_SIZE;
219 RingBaseVa = (PUCHAR) RingBaseVa + TXD_SIZE;
221 // link the pre-allocated TxBuf to TXD
222 pTxD = (PTXD_STRUC) pAd->MgmtRing.Cell[index].AllocVa;
225 // no pre-allocated buffer required in MgmtRing for scatter-gather case
227 DBGPRINT(RT_DEBUG_TRACE, ("MGMT Ring: total %d entry allocated\n", index));
230 // Allocate RX ring descriptor's memory except Tx ring which allocated eariler
232 pAd->RxDescRing.AllocSize = RX_RING_SIZE * RXD_SIZE;
233 RTMP_AllocateRxDescMemory(
235 pAd->RxDescRing.AllocSize,
237 &pAd->RxDescRing.AllocVa,
238 &pAd->RxDescRing.AllocPa);
240 if (pAd->RxDescRing.AllocVa == NULL)
242 ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
243 DBGPRINT_ERR(("Failed to allocate a big buffer\n"));
244 Status = NDIS_STATUS_RESOURCES;
248 // Zero init this memory block
249 NdisZeroMemory(pAd->RxDescRing.AllocVa, pAd->RxDescRing.AllocSize);
252 DBGPRINT(RT_DEBUG_OFF,
253 ("RX DESC %p size = %ld\n", pAd->RxDescRing.AllocVa, pAd->RxDescRing.AllocSize));
255 // Save PA & VA for further operation
256 RingBasePaHigh = RTMP_GetPhysicalAddressHigh(pAd->RxDescRing.AllocPa);
257 RingBasePaLow = RTMP_GetPhysicalAddressLow (pAd->RxDescRing.AllocPa);
258 RingBaseVa = pAd->RxDescRing.AllocVa;
261 // Initialize Rx Ring and associated buffer memory
263 for (index = 0; index < RX_RING_SIZE; index++)
265 // Init RX Ring Size, Va, Pa variables
266 pAd->RxRing.Cell[index].AllocSize = RXD_SIZE;
267 pAd->RxRing.Cell[index].AllocVa = RingBaseVa;
268 RTMP_SetPhysicalAddressHigh(pAd->RxRing.Cell[index].AllocPa, RingBasePaHigh);
269 RTMP_SetPhysicalAddressLow (pAd->RxRing.Cell[index].AllocPa, RingBasePaLow);
271 //NdisZeroMemory(RingBaseVa, RXD_SIZE);
273 // Offset to next ring descriptor address
274 RingBasePaLow += RXD_SIZE;
275 RingBaseVa = (PUCHAR) RingBaseVa + RXD_SIZE;
277 // Setup Rx associated Buffer size & allocate share memory
278 pDmaBuf = &pAd->RxRing.Cell[index].DmaBuf;
279 pDmaBuf->AllocSize = RX_BUFFER_AGGRESIZE;
280 pPacket = RTMP_AllocateRxPacketBuffer(
287 /* keep allocated rx packet */
288 pAd->RxRing.Cell[index].pNdisPacket = pPacket;
291 if (pDmaBuf->AllocVa == NULL)
293 ErrorValue = ERRLOG_OUT_OF_SHARED_MEMORY;
294 DBGPRINT_ERR(("Failed to allocate RxRing's 1st buffer\n"));
295 Status = NDIS_STATUS_RESOURCES;
299 // Zero init this memory block
300 NdisZeroMemory(pDmaBuf->AllocVa, pDmaBuf->AllocSize);
302 // Write RxD buffer address & allocated buffer length
303 pRxD = (PRXD_STRUC) pAd->RxRing.Cell[index].AllocVa;
304 pRxD->SDP0 = RTMP_GetPhysicalAddressLow(pDmaBuf->AllocPa);
309 DBGPRINT(RT_DEBUG_TRACE, ("Rx Ring: total %d entry allocated\n", index));
314 NdisZeroMemory(&pAd->FragFrame, sizeof(FRAGMENT_FRAME));
315 pAd->FragFrame.pFragPacket = RTMP_AllocateFragPacketBuffer(pAd, RX_BUFFER_NORMSIZE);
317 if (pAd->FragFrame.pFragPacket == NULL)
319 Status = NDIS_STATUS_RESOURCES;
322 if (Status != NDIS_STATUS_SUCCESS)
324 // Log error inforamtion
325 NdisWriteErrorLogEntry(
327 NDIS_ERROR_CODE_OUT_OF_RESOURCES,
332 // Following code segment get from original func:NICInitTxRxRingAndBacklogQueue(), now should integrate it to here.
334 DBGPRINT(RT_DEBUG_TRACE, ("--> NICInitTxRxRingAndBacklogQueue\n"));
338 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);
339 GloCfg.word &= 0xff0;
340 GloCfg.field.EnTXWriteBackDDONE =1;
341 RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word);
344 // Initialize all transmit related software queues
345 for(index = 0; index < NUM_OF_TX_RING; index++)
347 InitializeQueueHeader(&pAd->TxSwQueue[index]);
348 // Init TX rings index pointer
349 pAd->TxRing[index].TxSwFreeIdx = 0;
350 pAd->TxRing[index].TxCpuIdx = 0;
351 //RTMP_IO_WRITE32(pAd, (TX_CTX_IDX0 + i * 0x10) , pAd->TxRing[i].TX_CTX_IDX);
354 // Init RX Ring index pointer
355 pAd->RxRing.RxSwReadIdx = 0;
356 pAd->RxRing.RxCpuIdx = RX_RING_SIZE - 1;
357 //RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RX_CRX_IDX0);
360 // init MGMT ring index pointer
361 pAd->MgmtRing.TxSwFreeIdx = 0;
362 pAd->MgmtRing.TxCpuIdx = 0;
364 pAd->PrivateInfo.TxRingFullCnt = 0;
366 DBGPRINT(RT_DEBUG_TRACE, ("<-- NICInitTxRxRingAndBacklogQueue\n"));
369 DBGPRINT_S(Status, ("<-- RTMPAllocTxRxRingMemory, Status=%x\n", Status));
377 ========================================================================
380 Reset NIC Asics. Call after rest DMA. So reset TX_CTX_IDX to zero.
383 Adapter Pointer to our adapter
389 IRQL = DISPATCH_LEVEL
392 Reset NIC to initial state AS IS system boot up time.
394 ========================================================================
396 VOID RTMPRingCleanUp(
397 IN PRTMP_ADAPTER pAd,
403 PNDIS_PACKET pPacket;
405 PRTMP_TX_RING pTxRing;
406 unsigned long IrqFlags;
407 //UINT32 RxSwReadIdx;
410 DBGPRINT(RT_DEBUG_TRACE,("RTMPRingCleanUp(RingIdx=%d, Pending-NDIS=%ld)\n", RingType, pAd->RalinkCounters.PendingNdisPacketCount));
418 pTxRing = &pAd->TxRing[RingType];
420 RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags);
421 // We have to clean all descriptors in case some error happened with reset
422 for (i=0; i<TX_RING_SIZE; i++) // We have to scan all TX ring
424 pTxD = (PTXD_STRUC) pTxRing->Cell[i].AllocVa;
426 pPacket = (PNDIS_PACKET) pTxRing->Cell[i].pNdisPacket;
427 // release scatter-and-gather NDIS_PACKET
430 RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
431 pTxRing->Cell[i].pNdisPacket = NULL;
434 pPacket = (PNDIS_PACKET) pTxRing->Cell[i].pNextNdisPacket;
435 // release scatter-and-gather NDIS_PACKET
438 RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
439 pTxRing->Cell[i].pNextNdisPacket = NULL;
443 RTMP_IO_READ32(pAd, TX_DTX_IDX0 + RingType * 0x10, &pTxRing->TxDmaIdx);
444 pTxRing->TxSwFreeIdx = pTxRing->TxDmaIdx;
445 pTxRing->TxCpuIdx = pTxRing->TxDmaIdx;
446 RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + RingType * 0x10, pTxRing->TxCpuIdx);
448 RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
450 RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags);
451 while (pAd->TxSwQueue[RingType].Head != NULL)
453 pEntry = RemoveHeadQueue(&pAd->TxSwQueue[RingType]);
454 pPacket = QUEUE_ENTRY_TO_PACKET(pEntry);
455 RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
456 DBGPRINT(RT_DEBUG_TRACE,("Release 1 NDIS packet from s/w backlog queue\n"));
458 RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
462 // We have to clean all descriptors in case some error happened with reset
463 NdisAcquireSpinLock(&pAd->MgmtRingLock);
465 for (i=0; i<MGMT_RING_SIZE; i++)
467 pTxD = (PTXD_STRUC) pAd->MgmtRing.Cell[i].AllocVa;
469 pPacket = (PNDIS_PACKET) pAd->MgmtRing.Cell[i].pNdisPacket;
470 // rlease scatter-and-gather NDIS_PACKET
473 PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0, PCI_DMA_TODEVICE);
474 RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
476 pAd->MgmtRing.Cell[i].pNdisPacket = NULL;
478 pPacket = (PNDIS_PACKET) pAd->MgmtRing.Cell[i].pNextNdisPacket;
479 // release scatter-and-gather NDIS_PACKET
482 PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE);
483 RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
485 pAd->MgmtRing.Cell[i].pNextNdisPacket = NULL;
489 RTMP_IO_READ32(pAd, TX_MGMTDTX_IDX, &pAd->MgmtRing.TxDmaIdx);
490 pAd->MgmtRing.TxSwFreeIdx = pAd->MgmtRing.TxDmaIdx;
491 pAd->MgmtRing.TxCpuIdx = pAd->MgmtRing.TxDmaIdx;
492 RTMP_IO_WRITE32(pAd, TX_MGMTCTX_IDX, pAd->MgmtRing.TxCpuIdx);
494 NdisReleaseSpinLock(&pAd->MgmtRingLock);
495 pAd->RalinkCounters.MgmtRingFullCount = 0;
499 // We have to clean all descriptors in case some error happened with reset
500 NdisAcquireSpinLock(&pAd->RxRingLock);
502 for (i=0; i<RX_RING_SIZE; i++)
504 pRxD = (PRXD_STRUC) pAd->RxRing.Cell[i].AllocVa;
508 RTMP_IO_READ32(pAd, RX_DRX_IDX, &pAd->RxRing.RxDmaIdx);
509 pAd->RxRing.RxSwReadIdx = pAd->RxRing.RxDmaIdx;
510 pAd->RxRing.RxCpuIdx = ((pAd->RxRing.RxDmaIdx == 0) ? (RX_RING_SIZE-1) : (pAd->RxRing.RxDmaIdx-1));
511 RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx);
513 NdisReleaseSpinLock(&pAd->RxRingLock);
522 VOID RTMPFreeTxRxRingMemory(
523 IN PRTMP_ADAPTER pAd)
526 PRTMP_TX_RING pTxRing;
528 PNDIS_PACKET pPacket;
529 unsigned int IrqFlags;
531 //POS_COOKIE pObj =(POS_COOKIE) pAd->OS_Cookie;
533 DBGPRINT(RT_DEBUG_TRACE, ("--> RTMPFreeTxRxRingMemory\n"));
535 // Free TxSwQueue Packet
536 for (index=0; index <NUM_OF_TX_RING; index++)
539 PNDIS_PACKET pPacket;
540 PQUEUE_HEADER pQueue;
542 RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags);
543 pQueue = &pAd->TxSwQueue[index];
546 pEntry = RemoveHeadQueue(pQueue);
547 pPacket = QUEUE_ENTRY_TO_PACKET(pEntry);
548 RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
550 RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
553 // Free Tx Ring Packet
554 for (index=0;index< NUM_OF_TX_RING;index++)
556 pTxRing = &pAd->TxRing[index];
558 for (j=0; j< TX_RING_SIZE; j++)
560 pTxD = (PTXD_STRUC) (pTxRing->Cell[j].AllocVa);
561 pPacket = pTxRing->Cell[j].pNdisPacket;
565 PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0, PCI_DMA_TODEVICE);
566 RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS);
568 //Always assign pNdisPacket as NULL after clear
569 pTxRing->Cell[j].pNdisPacket = NULL;
571 pPacket = pTxRing->Cell[j].pNextNdisPacket;
575 PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1, PCI_DMA_TODEVICE);
576 RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS);
578 //Always assign pNextNdisPacket as NULL after clear
579 pTxRing->Cell[pTxRing->TxSwFreeIdx].pNextNdisPacket = NULL;
584 for (index = RX_RING_SIZE - 1 ; index >= 0; index--)
586 if ((pAd->RxRing.Cell[index].DmaBuf.AllocVa) && (pAd->RxRing.Cell[index].pNdisPacket))
588 PCI_UNMAP_SINGLE(pAd, pAd->RxRing.Cell[index].DmaBuf.AllocPa, pAd->RxRing.Cell[index].DmaBuf.AllocSize, PCI_DMA_FROMDEVICE);
589 RELEASE_NDIS_PACKET(pAd, pAd->RxRing.Cell[index].pNdisPacket, NDIS_STATUS_SUCCESS);
592 NdisZeroMemory(pAd->RxRing.Cell, RX_RING_SIZE * sizeof(RTMP_DMACB));
594 if (pAd->RxDescRing.AllocVa)
596 RTMP_FreeDescMemory(pAd, pAd->RxDescRing.AllocSize, pAd->RxDescRing.AllocVa, pAd->RxDescRing.AllocPa);
598 NdisZeroMemory(&pAd->RxDescRing, sizeof(RTMP_DMABUF));
600 if (pAd->MgmtDescRing.AllocVa)
602 RTMP_FreeDescMemory(pAd, pAd->MgmtDescRing.AllocSize, pAd->MgmtDescRing.AllocVa, pAd->MgmtDescRing.AllocPa);
604 NdisZeroMemory(&pAd->MgmtDescRing, sizeof(RTMP_DMABUF));
606 for (num = 0; num < NUM_OF_TX_RING; num++)
608 if (pAd->TxBufSpace[num].AllocVa)
610 RTMP_FreeFirstTxBuffer(pAd, pAd->TxBufSpace[num].AllocSize, FALSE, pAd->TxBufSpace[num].AllocVa, pAd->TxBufSpace[num].AllocPa);
612 NdisZeroMemory(&pAd->TxBufSpace[num], sizeof(RTMP_DMABUF));
614 if (pAd->TxDescRing[num].AllocVa)
616 RTMP_FreeDescMemory(pAd, pAd->TxDescRing[num].AllocSize, pAd->TxDescRing[num].AllocVa, pAd->TxDescRing[num].AllocPa);
618 NdisZeroMemory(&pAd->TxDescRing[num], sizeof(RTMP_DMABUF));
621 if (pAd->FragFrame.pFragPacket)
622 RELEASE_NDIS_PACKET(pAd, pAd->FragFrame.pFragPacket, NDIS_STATUS_SUCCESS);
624 DBGPRINT(RT_DEBUG_TRACE, ("<-- RTMPFreeTxRxRingMemory\n"));
628 /***************************************************************************
630 * register related procedures.
632 **************************************************************************/
634 ========================================================================
639 *pAd the raxx interface data pointer
645 ========================================================================
647 VOID RT28XXDMADisable(
648 IN RTMP_ADAPTER *pAd)
650 WPDMA_GLO_CFG_STRUC GloCfg;
653 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);
654 GloCfg.word &= 0xff0;
655 GloCfg.field.EnTXWriteBackDDONE =1;
656 RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word);
661 ========================================================================
666 *pAd the raxx interface data pointer
672 ========================================================================
674 VOID RT28XXDMAEnable(
675 IN RTMP_ADAPTER *pAd)
677 WPDMA_GLO_CFG_STRUC GloCfg;
680 RTMP_IO_WRITE32(pAd, MAC_SYS_CTRL, 0x4);
683 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);
684 if ((GloCfg.field.TxDMABusy == 0) && (GloCfg.field.RxDMABusy == 0))
687 DBGPRINT(RT_DEBUG_TRACE, ("==> DMABusy\n"));
694 GloCfg.field.EnTXWriteBackDDONE = 1;
695 GloCfg.field.WPDMABurstSIZE = 2;
696 GloCfg.field.EnableRxDMA = 1;
697 GloCfg.field.EnableTxDMA = 1;
699 DBGPRINT(RT_DEBUG_TRACE, ("<== WRITE DMA offset 0x208 = 0x%x\n", GloCfg.word));
700 RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word);
705 BOOLEAN AsicCheckCommanOk(
706 IN PRTMP_ADAPTER pAd,
709 UINT32 CmdStatus = 0, CID = 0, i;
710 UINT32 ThisCIDMask = 0;
715 RTMP_IO_READ32(pAd, H2M_MAILBOX_CID, &CID);
716 // Find where the command is. Because this is randomly specified by firmware.
717 if ((CID & CID0MASK) == Command)
719 ThisCIDMask = CID0MASK;
722 else if ((((CID & CID1MASK)>>8) & 0xff) == Command)
724 ThisCIDMask = CID1MASK;
727 else if ((((CID & CID2MASK)>>16) & 0xff) == Command)
729 ThisCIDMask = CID2MASK;
732 else if ((((CID & CID3MASK)>>24) & 0xff) == Command)
734 ThisCIDMask = CID3MASK;
742 // Get CommandStatus Value
743 RTMP_IO_READ32(pAd, H2M_MAILBOX_STATUS, &CmdStatus);
745 // This command's status is at the same position as command. So AND command position's bitmask to read status.
748 // If Status is 1, the comamnd is success.
749 if (((CmdStatus & ThisCIDMask) == 0x1) || ((CmdStatus & ThisCIDMask) == 0x100)
750 || ((CmdStatus & ThisCIDMask) == 0x10000) || ((CmdStatus & ThisCIDMask) == 0x1000000))
752 DBGPRINT(RT_DEBUG_TRACE, ("--> AsicCheckCommanOk CID = 0x%x, CmdStatus= 0x%x \n", CID, CmdStatus));
753 RTMP_IO_WRITE32(pAd, H2M_MAILBOX_STATUS, 0xffffffff);
754 RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CID, 0xffffffff);
757 DBGPRINT(RT_DEBUG_TRACE, ("--> AsicCheckCommanFail1 CID = 0x%x, CmdStatus= 0x%x \n", CID, CmdStatus));
761 DBGPRINT(RT_DEBUG_TRACE, ("--> AsicCheckCommanFail2 Timeout Command = %d, CmdStatus= 0x%x \n", Command, CmdStatus));
763 // Clear Command and Status.
764 RTMP_IO_WRITE32(pAd, H2M_MAILBOX_STATUS, 0xffffffff);
765 RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CID, 0xffffffff);
772 ========================================================================
774 Write Beacon buffer to Asic.
777 *pAd the raxx interface data pointer
783 ========================================================================
785 VOID RT28xx_UpdateBeaconToAsic(
786 IN RTMP_ADAPTER *pAd,
791 ULONG CapInfoPos = 0;
792 UCHAR *ptr, *ptr_update, *ptr_capinfo;
794 BOOLEAN bBcnReq = FALSE;
799 DBGPRINT(RT_DEBUG_ERROR, ("%s() : No valid Interface be found.\n", __func__));
803 //if ((pAd->WdsTab.Mode == WDS_BRIDGE_MODE)
804 // || ((pAd->ApCfg.MBSSID[apidx].MSSIDDev == NULL)
805 // || !(pAd->ApCfg.MBSSID[apidx].MSSIDDev->flags & IFF_UP))
807 if (bBcnReq == FALSE)
809 /* when the ra interface is down, do not send its beacon frame */
811 for(i=0; i<TXWI_SIZE; i+=4)
812 RTMP_IO_WRITE32(pAd, pAd->BeaconOffset[bcn_idx] + i, 0x00);
816 ptr = (PUCHAR)&pAd->BeaconTxWI;
817 for (i=0; i<TXWI_SIZE; i+=4) // 16-byte TXWI field
819 UINT32 longptr = *ptr + (*(ptr+1)<<8) + (*(ptr+2)<<16) + (*(ptr+3)<<24);
820 RTMP_IO_WRITE32(pAd, pAd->BeaconOffset[bcn_idx] + i, longptr);
824 // Update CapabilityInfo in Beacon
825 for (i = CapInfoPos; i < (CapInfoPos+2); i++)
827 RTMP_IO_WRITE8(pAd, pAd->BeaconOffset[bcn_idx] + TXWI_SIZE + i, *ptr_capinfo);
831 if (FrameLen > UpdatePos)
833 for (i= UpdatePos; i< (FrameLen); i++)
835 RTMP_IO_WRITE8(pAd, pAd->BeaconOffset[bcn_idx] + TXWI_SIZE + i, *ptr_update);
845 VOID RT28xxPciStaAsicForceWakeup(
846 IN PRTMP_ADAPTER pAd,
849 AUTO_WAKEUP_STRUC AutoWakeupCfg;
851 if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
854 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW))
856 DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
860 OPSTATUS_SET_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
862 RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW);
864 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)
865 &&pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)
867 // Support PCIe Advance Power Save
869 &&(pAd->Mlme.bPsPollTimerRunning == TRUE))
871 pAd->Mlme.bPsPollTimerRunning = FALSE;
872 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
874 DBGPRINT(RT_DEBUG_TRACE, ("=======AsicForceWakeup===bFromTx\n"));
877 AutoWakeupCfg.word = 0;
878 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
880 if (RT28xxPciAsicRadioOn(pAd, DOT11POWERSAVE))
882 #ifdef PCIE_PS_SUPPORT
883 // add by johnli, RF power sequence setup, load RF normal operation-mode setup
884 if ((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) && IS_VERSION_AFTER_F(pAd))
886 RTMP_CHIP_OP *pChipOps = &pAd->chipOps;
888 if (pChipOps->AsicReverseRfFromSleepMode)
889 pChipOps->AsicReverseRfFromSleepMode(pAd);
892 #endif // PCIE_PS_SUPPORT //
895 // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
896 if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
897 && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
900 AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
901 AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
906 AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
907 AsicLockChannel(pAd, pAd->CommonCfg.Channel);
911 #ifdef PCIE_PS_SUPPORT
912 // 3090 MCU Wakeup command needs more time to be stable.
913 // Before stable, don't issue other MCU command to prevent from firmware error.
914 if (((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) && IS_VERSION_AFTER_F(pAd)) && IS_VERSION_AFTER_F(pAd)
915 && (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3)
916 && (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE))
918 DBGPRINT(RT_DEBUG_TRACE, ("<==RT28xxPciStaAsicForceWakeup::Release the MCU Lock(3090)\n"));
919 RTMP_SEM_LOCK(&pAd->McuCmdLock);
920 pAd->brt30xxBanMcuCmd = FALSE;
921 RTMP_SEM_UNLOCK(&pAd->McuCmdLock);
923 #endif // PCIE_PS_SUPPORT //
928 DBGPRINT(RT_DEBUG_TRACE, ("<==RT28xxPciStaAsicForceWakeup::Original PCI Power Saving\n"));
929 AsicSendCommandToMcu(pAd, 0x31, 0xff, 0x00, 0x02);
930 AutoWakeupCfg.word = 0;
931 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
934 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
935 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
936 DBGPRINT(RT_DEBUG_TRACE, ("<=======RT28xxPciStaAsicForceWakeup\n"));
940 VOID RT28xxPciStaAsicSleepThenAutoWakeup(
941 IN PRTMP_ADAPTER pAd,
942 IN USHORT TbttNumToNextWakeUp)
946 if (pAd->StaCfg.bRadio == FALSE)
948 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
951 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)
952 &&pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)
955 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW))
957 DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
958 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
962 NdisGetSystemUpTime(&Now);
963 // If last send NULL fram time is too close to this receiving beacon (within 8ms), don't go to sleep for this DTM.
964 // Because Some AP can't queuing outgoing frames immediately.
965 if (((pAd->Mlme.LastSendNULLpsmTime + 8) >= Now) && (pAd->Mlme.LastSendNULLpsmTime <= Now))
967 DBGPRINT(RT_DEBUG_TRACE, ("Now = %lu, LastSendNULLpsmTime=%lu : RxCountSinceLastNULL = %lu. \n", Now, pAd->Mlme.LastSendNULLpsmTime, pAd->RalinkCounters.RxCountSinceLastNULL));
970 else if ((pAd->RalinkCounters.RxCountSinceLastNULL > 0) && ((pAd->Mlme.LastSendNULLpsmTime + pAd->CommonCfg.BeaconPeriod) >= Now))
972 DBGPRINT(RT_DEBUG_TRACE, ("Now = %lu, LastSendNULLpsmTime=%lu: RxCountSinceLastNULL = %lu > 0 \n", Now, pAd->Mlme.LastSendNULLpsmTime, pAd->RalinkCounters.RxCountSinceLastNULL));
976 brc = RT28xxPciAsicRadioOff(pAd, DOT11POWERSAVE, TbttNumToNextWakeUp);
978 OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE);
982 AUTO_WAKEUP_STRUC AutoWakeupCfg;
983 // we have decided to SLEEP, so at least do it for a BEACON period.
984 if (TbttNumToNextWakeUp == 0)
985 TbttNumToNextWakeUp = 1;
987 //RTMP_IO_WRITE32(pAd, INT_MASK_CSR, AutoWakeupInt);
989 AutoWakeupCfg.word = 0;
990 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
991 AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1;
992 AutoWakeupCfg.field.EnableAutoWakeup = 1;
993 AutoWakeupCfg.field.AutoLeadTime = 5;
994 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
995 AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x00); // send POWER-SAVE command to MCU. Timeout 40us.
996 OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE);
997 DBGPRINT(RT_DEBUG_TRACE, ("<-- %s, TbttNumToNextWakeUp=%d \n", __func__, TbttNumToNextWakeUp));
1002 VOID PsPollWakeExec(
1003 IN PVOID SystemSpecific1,
1004 IN PVOID FunctionContext,
1005 IN PVOID SystemSpecific2,
1006 IN PVOID SystemSpecific3)
1008 RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
1009 unsigned long flags;
1011 DBGPRINT(RT_DEBUG_TRACE,("-->PsPollWakeExec \n"));
1012 RTMP_INT_LOCK(&pAd->irq_lock, flags);
1013 if (pAd->Mlme.bPsPollTimerRunning)
1015 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
1017 pAd->Mlme.bPsPollTimerRunning = FALSE;
1018 RTMP_INT_UNLOCK(&pAd->irq_lock, flags);
1019 #ifdef PCIE_PS_SUPPORT
1020 // For rt30xx power solution 3, Use software timer to wake up in psm. So call
1021 // AsicForceWakeup here instead of handling twakeup interrupt.
1022 if (((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) && IS_VERSION_AFTER_F(pAd))
1023 && (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3)
1024 && (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE))
1026 DBGPRINT(RT_DEBUG_TRACE,("<--PsPollWakeExec::3090 calls AsicForceWakeup(pAd, DOT11POWERSAVE) in advance \n"));
1027 AsicForceWakeup(pAd, DOT11POWERSAVE);
1029 #endif // PCIE_PS_SUPPORT //
1033 IN PVOID SystemSpecific1,
1034 IN PVOID FunctionContext,
1035 IN PVOID SystemSpecific2,
1036 IN PVOID SystemSpecific3)
1038 RTMP_ADAPTER *pAd = (RTMP_ADAPTER *)FunctionContext;
1039 RTMP_CHIP_OP *pChipOps = &pAd->chipOps;
1040 WPDMA_GLO_CFG_STRUC DmaCfg;
1043 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
1045 DBGPRINT(RT_DEBUG_TRACE,("-->RadioOnExec() return on fOP_STATUS_DOZE == TRUE; \n"));
1046 //KH Debug: Add the compile flag "RT2860 and condition
1047 #ifdef RTMP_PCI_SUPPORT
1048 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)
1049 &&pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)
1050 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
1051 #endif // RTMP_PCI_SUPPORT //
1055 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
1057 DBGPRINT(RT_DEBUG_TRACE,("-->RadioOnExec() return on SCAN_IN_PROGRESS; \n"));
1058 #ifdef RTMP_PCI_SUPPORT
1059 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)
1060 &&pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)
1061 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
1062 #endif // RTMP_PCI_SUPPORT //
1065 //KH Debug: need to check. I add the compile flag "CONFIG_STA_SUPPORT" to enclose the following codes.
1066 #ifdef RTMP_PCI_SUPPORT
1067 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)
1068 &&pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)
1070 pAd->Mlme.bPsPollTimerRunning = FALSE;
1071 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
1073 #endif // RTMP_PCI_SUPPORT //
1074 if (pAd->StaCfg.bRadio == TRUE)
1076 pAd->bPCIclkOff = FALSE;
1077 RTMPRingCleanUp(pAd, QID_AC_BK);
1078 RTMPRingCleanUp(pAd, QID_AC_BE);
1079 RTMPRingCleanUp(pAd, QID_AC_VI);
1080 RTMPRingCleanUp(pAd, QID_AC_VO);
1081 RTMPRingCleanUp(pAd, QID_MGMT);
1082 RTMPRingCleanUp(pAd, QID_RX);
1084 // 2. Send wake up command.
1085 AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x02);
1086 // 2-1. wait command ok.
1087 AsicCheckCommanOk(pAd, PowerWakeCID);
1089 // When PCI clock is off, don't want to service interrupt. So when back to clock on, enable interrupt.
1090 //RTMP_IO_WRITE32(pAd, INT_MASK_CSR, (DELAYINTMASK|RxINT));
1091 RTMP_ASIC_INTERRUPT_ENABLE(pAd);
1093 // 3. Enable Tx DMA.
1094 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
1095 DmaCfg.field.EnableTxDMA = 1;
1096 RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, DmaCfg.word);
1098 // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
1099 if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
1100 && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
1102 // Must using 40MHz.
1103 AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
1104 AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
1108 // Must using 20MHz.
1109 AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
1110 AsicLockChannel(pAd, pAd->CommonCfg.Channel);
1113 //KH Debug:The following codes should be enclosed by RT3090 compile flag
1114 if (pChipOps->AsicReverseRfFromSleepMode)
1115 pChipOps->AsicReverseRfFromSleepMode(pAd);
1117 #ifdef PCIE_PS_SUPPORT
1118 // 3090 MCU Wakeup command needs more time to be stable.
1119 // Before stable, don't issue other MCU command to prevent from firmware error.
1120 if ((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) && IS_VERSION_AFTER_F(pAd)
1121 && (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3)
1122 && (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE))
1124 RTMP_SEM_LOCK(&pAd->McuCmdLock);
1125 pAd->brt30xxBanMcuCmd = FALSE;
1126 RTMP_SEM_UNLOCK(&pAd->McuCmdLock);
1128 #endif // PCIE_PS_SUPPORT //
1130 // Clear Radio off flag
1131 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1134 RTMPSetLED(pAd, LED_RADIO_ON);
1136 if (pAd->StaCfg.Psm == PWR_ACTIVE)
1138 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, pAd->StaCfg.BBPR3);
1143 RT28xxPciAsicRadioOff(pAd, GUIRADIO_OFF, 0);
1148 ==========================================================================
1150 This routine sends command to firmware and turn our chip to wake up mode from power save mode.
1151 Both RadioOn and .11 power save function needs to call this routine.
1153 Level = GUIRADIO_OFF : call this function is from Radio Off to Radio On. Need to restore PCI host value.
1154 Level = other value : normal wake up function.
1156 ==========================================================================
1158 BOOLEAN RT28xxPciAsicRadioOn(
1159 IN PRTMP_ADAPTER pAd,
1162 //WPDMA_GLO_CFG_STRUC DmaCfg;
1166 if (pAd->OpMode == OPMODE_AP && Level==DOT11POWERSAVE)
1169 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE))
1171 if (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)
1173 pAd->Mlme.bPsPollTimerRunning = FALSE;
1174 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
1176 if ((pAd->StaCfg.PSControl.field.EnableNewPS == TRUE &&
1177 (Level == GUIRADIO_OFF || Level == GUI_IDLE_POWER_SAVE)) ||
1178 RTMP_TEST_PSFLAG(pAd, fRTMP_PS_SET_PCI_CLK_OFF_COMMAND)) {
1179 // Some chips don't need to delay 6ms, so copy RTMPPCIePowerLinkCtrlRestore
1180 // return condition here.
1182 if (((pAd->MACVersion&0xffff0000) != 0x28600000)
1183 && ((pAd->DeviceID == NIC2860_PCIe_DEVICE_ID)
1184 ||(pAd->DeviceID == NIC2790_PCIe_DEVICE_ID)))
1187 DBGPRINT(RT_DEBUG_TRACE, ("RT28xxPciAsicRadioOn ()\n"));
1188 // 1. Set PCI Link Control in Configuration Space.
1189 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
1190 RTMPusecDelay(6000);
1195 #ifdef PCIE_PS_SUPPORT
1196 if (!(((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) && IS_VERSION_AFTER_F(pAd)
1197 && (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3)
1198 && (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE))))
1199 #endif // PCIE_PS_SUPPORT //
1201 pAd->bPCIclkOff = FALSE;
1202 DBGPRINT(RT_DEBUG_TRACE, ("PSM :309xbPCIclkOff == %d\n", pAd->bPCIclkOff));
1204 // 2. Send wake up command.
1205 AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x02);
1206 pAd->bPCIclkOff = FALSE;
1207 // 2-1. wait command ok.
1208 AsicCheckCommanOk(pAd, PowerWakeCID);
1209 RTMP_ASIC_INTERRUPT_ENABLE(pAd);
1211 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
1212 if (Level == GUI_IDLE_POWER_SAVE)
1214 #ifdef PCIE_PS_SUPPORT
1216 // add by johnli, RF power sequence setup, load RF normal operation-mode setup
1217 if ((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)))
1219 RTMP_CHIP_OP *pChipOps = &pAd->chipOps;
1221 if (pChipOps->AsicReverseRfFromSleepMode)
1222 pChipOps->AsicReverseRfFromSleepMode(pAd);
1223 // 3090 MCU Wakeup command needs more time to be stable.
1224 // Before stable, don't issue other MCU command to prevent from firmware error.
1225 if ((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) && IS_VERSION_AFTER_F(pAd)
1226 && (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3)
1227 && (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE))
1229 RTMP_SEM_LOCK(&pAd->McuCmdLock);
1230 pAd->brt30xxBanMcuCmd = FALSE;
1231 RTMP_SEM_UNLOCK(&pAd->McuCmdLock);
1236 #endif // PCIE_PS_SUPPORT //
1238 // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
1240 if (INFRA_ON(pAd) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
1241 && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
1243 // Must using 40MHz.
1244 AsicSwitchChannel(pAd, pAd->CommonCfg.CentralChannel, FALSE);
1245 AsicLockChannel(pAd, pAd->CommonCfg.CentralChannel);
1249 // Must using 20MHz.
1250 AsicSwitchChannel(pAd, pAd->CommonCfg.Channel, FALSE);
1251 AsicLockChannel(pAd, pAd->CommonCfg.Channel);
1263 ==========================================================================
1265 This routine sends command to firmware and turn our chip to power save mode.
1266 Both RadioOff and .11 power save function needs to call this routine.
1268 Level = GUIRADIO_OFF : GUI Radio Off mode
1269 Level = DOT11POWERSAVE : 802.11 power save mode
1270 Level = RTMP_HALT : When Disable device.
1272 ==========================================================================
1274 BOOLEAN RT28xxPciAsicRadioOff(
1275 IN PRTMP_ADAPTER pAd,
1277 IN USHORT TbttNumToNextWakeUp)
1279 WPDMA_GLO_CFG_STRUC DmaCfg;
1280 UCHAR i, tempBBP_R3 = 0;
1281 BOOLEAN brc = FALSE, Cancelled;
1282 UINT32 TbTTTime = 0;
1283 UINT32 PsPollTime = 0/*, MACValue*/;
1284 ULONG BeaconPeriodTime;
1285 UINT32 RxDmaIdx, RxCpuIdx;
1286 DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> Lv= %d, TxCpuIdx = %d, TxDmaIdx = %d. RxCpuIdx = %d, RxDmaIdx = %d.\n", Level,pAd->TxRing[0].TxCpuIdx, pAd->TxRing[0].TxDmaIdx, pAd->RxRing.RxCpuIdx, pAd->RxRing.RxDmaIdx));
1288 if (pAd->OpMode == OPMODE_AP && Level==DOT11POWERSAVE)
1291 // Check Rx DMA busy status, if more than half is occupied, give up this radio off.
1292 RTMP_IO_READ32(pAd, RX_DRX_IDX , &RxDmaIdx);
1293 RTMP_IO_READ32(pAd, RX_CRX_IDX , &RxCpuIdx);
1294 if ((RxDmaIdx > RxCpuIdx) && ((RxDmaIdx - RxCpuIdx) > RX_RING_SIZE/3))
1296 DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> return1. RxDmaIdx = %d , RxCpuIdx = %d. \n", RxDmaIdx, RxCpuIdx));
1299 else if ((RxCpuIdx >= RxDmaIdx) && ((RxCpuIdx - RxDmaIdx) < RX_RING_SIZE/3))
1301 DBGPRINT(RT_DEBUG_TRACE, ("AsicRadioOff ===> return2. RxCpuIdx = %d. RxDmaIdx = %d , \n", RxCpuIdx, RxDmaIdx));
1305 // Once go into this function, disable tx because don't want too many packets in queue to prevent HW stops.
1306 //pAd->bPCIclkOffDisableTx = TRUE;
1307 RTMP_SET_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
1308 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)
1309 && pAd->OpMode == OPMODE_STA
1310 &&pAd->StaCfg.PSControl.field.EnableNewPS == TRUE
1313 RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
1314 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
1316 if (Level == DOT11POWERSAVE)
1318 RTMP_IO_READ32(pAd, TBTT_TIMER, &TbTTTime);
1319 TbTTTime &= 0x1ffff;
1320 // 00. check if need to do sleep in this DTIM period. If next beacon will arrive within 30ms , ...doesn't necessarily sleep.
1321 // TbTTTime uint = 64us, LEAD_TIME unit = 1024us, PsPollTime unit = 1ms
1322 if (((64*TbTTTime) <((LEAD_TIME*1024) + 40000)) && (TbttNumToNextWakeUp == 0))
1324 DBGPRINT(RT_DEBUG_TRACE, ("TbTTTime = 0x%x , give up this sleep. \n", TbTTTime));
1325 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
1326 //pAd->bPCIclkOffDisableTx = FALSE;
1327 RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
1332 PsPollTime = (64*TbTTTime- LEAD_TIME*1024)/1000;
1333 #ifdef PCIE_PS_SUPPORT
1334 if ((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) && IS_VERSION_AFTER_F(pAd)
1335 && (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3)
1336 && (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE))
1341 #endif // PCIE_PS_SUPPORT //
1344 BeaconPeriodTime = pAd->CommonCfg.BeaconPeriod*102/100;
1345 if (TbttNumToNextWakeUp > 0)
1346 PsPollTime += ((TbttNumToNextWakeUp -1) * BeaconPeriodTime);
1348 pAd->Mlme.bPsPollTimerRunning = TRUE;
1349 RTMPSetTimer(&pAd->Mlme.PsPollTimer, PsPollTime);
1355 DBGPRINT(RT_DEBUG_TRACE, ("RT28xxPciAsicRadioOff::Level!=DOT11POWERSAVE \n"));
1358 pAd->bPCIclkOffDisableTx = FALSE;
1360 RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
1363 if (pAd->Antenna.field.RxPath > 1 && pAd->OpMode == OPMODE_STA)
1365 tempBBP_R3 = (pAd->StaCfg.BBPR3 & 0xE7);
1366 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3, tempBBP_R3);
1369 // In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again.
1370 if ((INFRA_ON(pAd) || pAd->OpMode == OPMODE_AP) && (pAd->CommonCfg.CentralChannel != pAd->CommonCfg.Channel)
1371 && (pAd->MlmeAux.HtCapability.HtCapInfo.ChannelWidth == BW_40))
1373 // Must using 40MHz.
1374 AsicTurnOffRFClk(pAd, pAd->CommonCfg.CentralChannel);
1378 // Must using 20MHz.
1379 AsicTurnOffRFClk(pAd, pAd->CommonCfg.Channel);
1382 if (Level != RTMP_HALT)
1384 // Change Interrupt bitmask.
1385 // When PCI clock is off, don't want to service interrupt.
1386 RTMP_IO_WRITE32(pAd, INT_MASK_CSR, AutoWakeupInt);
1390 RTMP_ASIC_INTERRUPT_DISABLE(pAd);
1394 RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx);
1395 // 2. Send Sleep command
1396 RTMP_IO_WRITE32(pAd, H2M_MAILBOX_STATUS, 0xffffffff);
1397 RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CID, 0xffffffff);
1398 // send POWER-SAVE command to MCU. high-byte = 1 save power as much as possible. high byte = 0 save less power
1399 AsicSendCommandToMcu(pAd, 0x30, PowerSafeCID, 0xff, 0x1);
1400 // 2-1. Wait command success
1401 // Status = 1 : success, Status = 2, already sleep, Status = 3, Maybe MAC is busy so can't finish this task.
1402 brc = AsicCheckCommanOk(pAd, PowerSafeCID);
1404 // 3. After 0x30 command is ok, send radio off command. lowbyte = 0 for power safe.
1405 // If 0x30 command is not ok this time, we can ignore 0x35 command. It will make sure not cause firmware'r problem.
1406 if ((Level == DOT11POWERSAVE) && (brc == TRUE))
1408 AsicSendCommandToMcu(pAd, 0x35, PowerRadioOffCID, 0, 0x00); // lowbyte = 0 means to do power safe, NOT turn off radio.
1409 // 3-1. Wait command success
1410 AsicCheckCommanOk(pAd, PowerRadioOffCID);
1412 else if (brc == TRUE)
1414 AsicSendCommandToMcu(pAd, 0x35, PowerRadioOffCID, 1, 0x00); // lowbyte = 0 means to do power safe, NOT turn off radio.
1415 // 3-1. Wait command success
1416 AsicCheckCommanOk(pAd, PowerRadioOffCID);
1419 // 1. Wait DMA not busy
1423 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &DmaCfg.word);
1424 if ((DmaCfg.field.RxDMABusy == 0) && (DmaCfg.field.TxDMABusy == 0))
1433 pAd->CheckDmaBusyCount++;
1434 DBGPRINT(RT_DEBUG_TRACE, ("DMA Rx keeps busy. return on AsicRadioOff () CheckDmaBusyCount = %d \n", pAd->CheckDmaBusyCount));
1438 pAd->CheckDmaBusyCount = 0;
1441 //KH Debug:My original codes have the follwoing codes, but currecnt codes do not have it.
1442 // Disable for stability. If PCIE Link Control is modified for advance power save, re-covery this code segment.
1443 RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, 0x1280);
1444 //OPSTATUS_SET_FLAG(pAd, fOP_STATUS_CLKSELECT_40MHZ);
1446 #ifdef PCIE_PS_SUPPORT
1447 if ((IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) && IS_VERSION_AFTER_F(pAd)
1448 && (pAd->StaCfg.PSControl.field.rt30xxPowerMode == 3)
1449 && (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE))
1451 DBGPRINT(RT_DEBUG_TRACE, ("RT28xxPciAsicRadioOff::3090 return to skip the following TbttNumToNextWakeUp setting for 279x\n"));
1452 pAd->bPCIclkOff = TRUE;
1453 RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
1454 // For this case, doesn't need to below actions, so return here.
1457 #endif // PCIE_PS_SUPPORT //
1459 if (Level == DOT11POWERSAVE)
1461 AUTO_WAKEUP_STRUC AutoWakeupCfg;
1462 //RTMPSetTimer(&pAd->Mlme.PsPollTimer, 90);
1464 // we have decided to SLEEP, so at least do it for a BEACON period.
1465 if (TbttNumToNextWakeUp == 0)
1466 TbttNumToNextWakeUp = 1;
1468 AutoWakeupCfg.word = 0;
1469 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
1471 // 1. Set auto wake up timer.
1472 AutoWakeupCfg.field.NumofSleepingTbtt = TbttNumToNextWakeUp - 1;
1473 AutoWakeupCfg.field.EnableAutoWakeup = 1;
1474 AutoWakeupCfg.field.AutoLeadTime = LEAD_TIME;
1475 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
1478 // 4-1. If it's to disable our device. Need to restore PCI Configuration Space to its original value.
1479 if (Level == RTMP_HALT && pAd->OpMode == OPMODE_STA)
1481 if ((brc == TRUE) && (i < 50))
1482 RTMPPCIeLinkCtrlSetting(pAd, 1);
1484 // 4. Set PCI configuration Space Link Comtrol fields. Only Radio Off needs to call this function
1485 else if (pAd->OpMode == OPMODE_STA)
1487 if ((brc == TRUE) && (i < 50))
1488 RTMPPCIeLinkCtrlSetting(pAd, 3);
1491 //pAd->bPCIclkOffDisableTx = FALSE;
1492 RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
1499 VOID RT28xxPciMlmeRadioOn(
1500 IN PRTMP_ADAPTER pAd)
1502 if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
1505 DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__));
1507 if ((pAd->OpMode == OPMODE_AP) ||
1508 ((pAd->OpMode == OPMODE_STA)
1509 && (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)
1510 ||pAd->StaCfg.PSControl.field.EnableNewPS == FALSE
1513 RT28xxPciAsicRadioOn(pAd, GUI_IDLE_POWER_SAVE);
1514 //NICResetFromError(pAd);
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);
1524 RTMPEnableRxTx(pAd);
1526 // Clear Radio off flag
1527 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1529 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
1532 RTMPSetLED(pAd, LED_RADIO_ON);
1535 if ((pAd->OpMode == OPMODE_STA) &&
1536 (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE))
1537 &&(pAd->StaCfg.PSControl.field.EnableNewPS == TRUE))
1541 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
1543 pAd->Mlme.bPsPollTimerRunning = FALSE;
1544 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
1545 RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
1546 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 40);
1551 VOID RT28xxPciMlmeRadioOFF(
1552 IN PRTMP_ADAPTER pAd)
1556 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
1559 // Link down first if any association exists
1560 if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_NIC_NOT_EXIST))
1562 if (INFRA_ON(pAd) || ADHOC_ON(pAd))
1564 MLME_DISASSOC_REQ_STRUCT DisReq;
1565 MLME_QUEUE_ELEM *pMsgElem = (MLME_QUEUE_ELEM *) kmalloc(sizeof(MLME_QUEUE_ELEM), MEM_ALLOC_FLAG);
1569 COPY_MAC_ADDR(&DisReq.Addr, pAd->CommonCfg.Bssid);
1570 DisReq.Reason = REASON_DISASSOC_STA_LEAVING;
1572 pMsgElem->Machine = ASSOC_STATE_MACHINE;
1573 pMsgElem->MsgType = MT2_MLME_DISASSOC_REQ;
1574 pMsgElem->MsgLen = sizeof(MLME_DISASSOC_REQ_STRUCT);
1575 NdisMoveMemory(pMsgElem->Msg, &DisReq, sizeof(MLME_DISASSOC_REQ_STRUCT));
1577 MlmeDisassocReqAction(pAd, pMsgElem);
1580 RTMPusecDelay(1000);
1585 DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__));
1587 // Set Radio off flag
1588 RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1592 if (pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)
1594 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS))
1596 RTMPCancelTimer(&pAd->MlmeAux.ScanTimer, &Cancelled);
1597 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_BSS_SCAN_IN_PROGRESS);
1599 // If during power safe mode.
1600 if (pAd->StaCfg.bRadio == TRUE)
1602 DBGPRINT(RT_DEBUG_TRACE,("-->MlmeRadioOff() return on bRadio == TRUE; \n"));
1605 // Always radio on since the NIC needs to set the MCU command (LED_RADIO_OFF).
1607 (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF)))
1609 RT28xxPciAsicRadioOn(pAd, GUI_IDLE_POWER_SAVE);
1611 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE))
1614 pAd->Mlme.bPsPollTimerRunning = FALSE;
1615 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
1616 RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
1620 // Link down first if any association exists
1621 if (INFRA_ON(pAd) || ADHOC_ON(pAd))
1622 LinkDown(pAd, FALSE);
1623 RTMPusecDelay(10000);
1624 //==========================================
1625 // Clean up old bss table
1626 BssTableInit(&pAd->ScanTab);
1629 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE))
1631 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
1637 // Set LED.Move to here for fixing LED bug. This flag must be called after LinkDown
1638 RTMPSetLED(pAd, LED_RADIO_OFF);
1640 //KH Debug:All PCIe devices need to use timer to execute radio off function, or the PCIe&&EnableNewPS needs.
1641 //KH Ans:It is right, because only when the PCIe and EnableNewPs is true, we need to delay the RadioOffTimer
1642 //to avoid the deadlock with PCIe Power saving function.
1643 if (pAd->OpMode == OPMODE_STA&&
1644 OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE)&&
1645 pAd->StaCfg.PSControl.field.EnableNewPS == TRUE)
1647 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
1651 brc=RT28xxPciAsicRadioOff(pAd, GUIRADIO_OFF, 0);
1655 DBGPRINT(RT_DEBUG_ERROR,("%s call RT28xxPciAsicRadioOff fail !!\n", __func__));
1662 #endif // RTMP_MAC_PCI //