RT-AC56 3.0.0.4.374.37 core
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / drivers / staging / rt2860 / common / cmm_mac_pci.c
blobe26ba494287789b341af54c9d97714b2b9f88881
1 /*
2 *************************************************************************
3 * Ralink Tech Inc.
4 * 5F., No.36, Taiyuan St., Jhubei City,
5 * Hsinchu County 302,
6 * Taiwan, R.O.C.
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. *
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 *************************************************************************
28 #ifdef RTMP_MAC_PCI
29 #include "../rt_config.h"
32 ========================================================================
34 Routine Description:
35 Allocate DMA memory blocks for send, receive
37 Arguments:
38 Adapter Pointer to our adapter
40 Return Value:
41 NDIS_STATUS_SUCCESS
42 NDIS_STATUS_FAILURE
43 NDIS_STATUS_RESOURCES
45 IRQL = PASSIVE_LEVEL
47 Note:
49 ========================================================================
51 int RTMPAllocTxRxRingMemory(struct rt_rtmp_adapter *pAd)
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; */
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;
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);
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;
96 /* Zero init this memory block */
97 NdisZeroMemory(pAd->TxDescRing[num].AllocVa,
98 pAd->TxDescRing[num].AllocSize);
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;
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);
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;
128 /* Zero init this memory block */
129 NdisZeroMemory(pAd->TxBufSpace[num].AllocVa,
130 pAd->TxBufSpace[num].AllocSize);
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;
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);
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);
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;
176 /* advance to next TxBuf address */
177 BufBasePaLow += TX_DMA_1ST_BUFFER_SIZE;
178 BufBaseVa =
179 (u8 *)BufBaseVa + TX_DMA_1ST_BUFFER_SIZE;
181 DBGPRINT(RT_DEBUG_TRACE,
182 ("TxRing[%d]: total %d entry allocated\n", num,
183 index));
185 if (Status == NDIS_STATUS_RESOURCES)
186 break;
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);
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;
204 /* Zero init this memory block */
205 NdisZeroMemory(pAd->MgmtDescRing.AllocVa,
206 pAd->MgmtDescRing.AllocSize);
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;
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);
229 /* Offset to next ring descriptor address */
230 RingBasePaLow += TXD_SIZE;
231 RingBaseVa = (u8 *)RingBaseVa + TXD_SIZE;
233 /* link the pre-allocated TxBuf to TXD */
234 pTxD = (struct rt_txd *) pAd->MgmtRing.Cell[index].AllocVa;
235 pTxD->DMADONE = 1;
237 /* no pre-allocated buffer required in MgmtRing for scatter-gather case */
239 DBGPRINT(RT_DEBUG_TRACE,
240 ("MGMT Ring: total %d entry allocated\n", index));
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);
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;
258 /* Zero init this memory block */
259 NdisZeroMemory(pAd->RxDescRing.AllocVa,
260 pAd->RxDescRing.AllocSize);
262 DBGPRINT(RT_DEBUG_OFF,
263 ("RX DESC %p size = %ld\n", pAd->RxDescRing.AllocVa,
264 pAd->RxDescRing.AllocSize));
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;
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);
285 /*NdisZeroMemory(RingBaseVa, RXD_SIZE); */
287 /* Offset to next ring descriptor address */
288 RingBasePaLow += RXD_SIZE;
289 RingBaseVa = (u8 *)RingBaseVa + RXD_SIZE;
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);
301 /* keep allocated rx packet */
302 pAd->RxRing.Cell[index].pNdisPacket = pPacket;
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;
311 /* Zero init this memory block */
312 NdisZeroMemory(pDmaBuf->AllocVa, pDmaBuf->AllocSize);
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;
322 DBGPRINT(RT_DEBUG_TRACE,
323 ("Rx Ring: total %d entry allocated\n", index));
325 } while (FALSE);
327 NdisZeroMemory(&pAd->FragFrame, sizeof(struct rt_fragment_frame));
328 pAd->FragFrame.pFragPacket =
329 RTMP_AllocateFragPacketBuffer(pAd, RX_BUFFER_NORMSIZE);
331 if (pAd->FragFrame.pFragPacket == NULL) {
332 Status = NDIS_STATUS_RESOURCES;
335 if (Status != NDIS_STATUS_SUCCESS) {
336 /* Log error inforamtion */
337 NdisWriteErrorLogEntry(pAd->AdapterHandle,
338 NDIS_ERROR_CODE_OUT_OF_RESOURCES,
339 1, ErrorValue);
341 /* Following code segment get from original func:NICInitTxRxRingAndBacklogQueue(), now should integrate it to here. */
343 DBGPRINT(RT_DEBUG_TRACE,
344 ("--> NICInitTxRxRingAndBacklogQueue\n"));
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);
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); */
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); */
368 /* init MGMT ring index pointer */
369 pAd->MgmtRing.TxSwFreeIdx = 0;
370 pAd->MgmtRing.TxCpuIdx = 0;
372 pAd->PrivateInfo.TxRingFullCnt = 0;
374 DBGPRINT(RT_DEBUG_TRACE,
375 ("<-- NICInitTxRxRingAndBacklogQueue\n"));
378 DBGPRINT_S(Status,
379 ("<-- RTMPAllocTxRxRingMemory, Status=%x\n", Status));
380 return Status;
384 ========================================================================
386 Routine Description:
387 Reset NIC Asics. Call after rest DMA. So reset TX_CTX_IDX to zero.
389 Arguments:
390 Adapter Pointer to our adapter
392 Return Value:
393 None
395 IRQL = PASSIVE_LEVEL
396 IRQL = DISPATCH_LEVEL
398 Note:
399 Reset NIC to initial state AS IS system boot up time.
401 ========================================================================
403 void RTMPRingCleanUp(struct rt_rtmp_adapter *pAd, u8 RingType)
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; */
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:
423 pTxRing = &pAd->TxRing[RingType];
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 */
429 pTxD = (struct rt_txd *) pTxRing->Cell[i].AllocVa;
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;
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;
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);
456 RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
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"));
466 RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
467 break;
469 case QID_MGMT:
470 /* We have to clean all descriptors in case some error happened with reset */
471 NdisAcquireSpinLock(&pAd->MgmtRingLock);
473 for (i = 0; i < MGMT_RING_SIZE; i++) {
474 pTxD = (struct rt_txd *) pAd->MgmtRing.Cell[i].AllocVa;
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);
486 pAd->MgmtRing.Cell[i].pNdisPacket = NULL;
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);
499 pAd->MgmtRing.Cell[i].pNextNdisPacket = NULL;
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);
508 NdisReleaseSpinLock(&pAd->MgmtRingLock);
509 pAd->RalinkCounters.MgmtRingFullCount = 0;
510 break;
512 case QID_RX:
513 /* We have to clean all descriptors in case some error happened with reset */
514 NdisAcquireSpinLock(&pAd->RxRingLock);
516 for (i = 0; i < RX_RING_SIZE; i++) {
517 pRxD = (struct rt_rxd *) pAd->RxRing.Cell[i].AllocVa;
518 pRxD->DDONE = 0;
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);
528 NdisReleaseSpinLock(&pAd->RxRingLock);
529 break;
531 default:
532 break;
536 void RTMPFreeTxRxRingMemory(struct rt_rtmp_adapter *pAd)
538 int index, num, j;
539 struct rt_rtmp_tx_ring *pTxRing;
540 struct rt_txd * pTxD;
541 void *pPacket;
542 unsigned int IrqFlags;
544 /*struct os_cookie *pObj =(struct os_cookie *)pAd->OS_Cookie; */
546 DBGPRINT(RT_DEBUG_TRACE, ("--> RTMPFreeTxRxRingMemory\n"));
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;
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);
561 RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
564 /* Free Tx Ring Packet */
565 for (index = 0; index < NUM_OF_TX_RING; index++) {
566 pTxRing = &pAd->TxRing[index];
568 for (j = 0; j < TX_RING_SIZE; j++) {
569 pTxD = (struct rt_txd *) (pTxRing->Cell[j].AllocVa);
570 pPacket = pTxRing->Cell[j].pNdisPacket;
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);
579 /*Always assign pNdisPacket as NULL after clear */
580 pTxRing->Cell[j].pNdisPacket = NULL;
582 pPacket = pTxRing->Cell[j].pNextNdisPacket;
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);
591 /*Always assign pNextNdisPacket as NULL after clear */
592 pTxRing->Cell[pTxRing->TxSwFreeIdx].pNextNdisPacket =
593 NULL;
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);
610 NdisZeroMemory(pAd->RxRing.Cell, RX_RING_SIZE * sizeof(struct rt_rtmp_dmacb));
612 if (pAd->RxDescRing.AllocVa) {
613 RTMP_FreeDescMemory(pAd, pAd->RxDescRing.AllocSize,
614 pAd->RxDescRing.AllocVa,
615 pAd->RxDescRing.AllocPa);
617 NdisZeroMemory(&pAd->RxDescRing, sizeof(struct rt_rtmp_dmabuf));
619 if (pAd->MgmtDescRing.AllocVa) {
620 RTMP_FreeDescMemory(pAd, pAd->MgmtDescRing.AllocSize,
621 pAd->MgmtDescRing.AllocVa,
622 pAd->MgmtDescRing.AllocPa);
624 NdisZeroMemory(&pAd->MgmtDescRing, sizeof(struct rt_rtmp_dmabuf));
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);
634 NdisZeroMemory(&pAd->TxBufSpace[num], sizeof(struct rt_rtmp_dmabuf));
636 if (pAd->TxDescRing[num].AllocVa) {
637 RTMP_FreeDescMemory(pAd, pAd->TxDescRing[num].AllocSize,
638 pAd->TxDescRing[num].AllocVa,
639 pAd->TxDescRing[num].AllocPa);
641 NdisZeroMemory(&pAd->TxDescRing[num], sizeof(struct rt_rtmp_dmabuf));
644 if (pAd->FragFrame.pFragPacket)
645 RELEASE_NDIS_PACKET(pAd, pAd->FragFrame.pFragPacket,
646 NDIS_STATUS_SUCCESS);
648 DBGPRINT(RT_DEBUG_TRACE, ("<-- RTMPFreeTxRxRingMemory\n"));
651 /***************************************************************************
653 * register related procedures.
655 **************************************************************************/
657 ========================================================================
658 Routine Description:
659 Disable DMA.
661 Arguments:
662 *pAd the raxx interface data pointer
664 Return Value:
665 None
667 Note:
668 ========================================================================
670 void RT28XXDMADisable(struct rt_rtmp_adapter *pAd)
672 WPDMA_GLO_CFG_STRUC GloCfg;
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);
681 ========================================================================
682 Routine Description:
683 Enable DMA.
685 Arguments:
686 *pAd the raxx interface data pointer
688 Return Value:
689 None
691 Note:
692 ========================================================================
694 void RT28XXDMAEnable(struct rt_rtmp_adapter *pAd)
696 WPDMA_GLO_CFG_STRUC GloCfg;
697 int i = 0;
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;
706 DBGPRINT(RT_DEBUG_TRACE, ("==> DMABusy\n"));
707 RTMPusecDelay(1000);
708 i++;
709 } while (i < 200);
711 RTMPusecDelay(50);
713 GloCfg.field.EnTXWriteBackDDONE = 1;
714 GloCfg.field.WPDMABurstSIZE = 2;
715 GloCfg.field.EnableRxDMA = 1;
716 GloCfg.field.EnableTxDMA = 1;
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);
724 BOOLEAN AsicCheckCommanOk(struct rt_rtmp_adapter *pAd, u8 Command)
726 u32 CmdStatus = 0, CID = 0, i;
727 u32 ThisCIDMask = 0;
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;
747 RTMPusecDelay(100);
748 i++;
749 } while (i < 200);
751 /* Get CommandStatus Value */
752 RTMP_IO_READ32(pAd, H2M_MAILBOX_STATUS, &CmdStatus);
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;
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));
776 /* Clear Command and Status. */
777 RTMP_IO_WRITE32(pAd, H2M_MAILBOX_STATUS, 0xffffffff);
778 RTMP_IO_WRITE32(pAd, H2M_MAILBOX_CID, 0xffffffff);
780 return FALSE;
784 ========================================================================
785 Routine Description:
786 Write Beacon buffer to Asic.
788 Arguments:
789 *pAd the raxx interface data pointer
791 Return Value:
792 None
794 Note:
795 ========================================================================
797 void RT28xx_UpdateBeaconToAsic(struct rt_rtmp_adapter *pAd,
798 int apidx,
799 unsigned long FrameLen, unsigned long UpdatePos)
801 unsigned long CapInfoPos = 0;
802 u8 *ptr, *ptr_update, *ptr_capinfo;
803 u32 i;
804 BOOLEAN bBcnReq = FALSE;
805 u8 bcn_idx = 0;
808 DBGPRINT(RT_DEBUG_ERROR,
809 ("%s() : No valid Interface be found.\n", __func__));
810 return;
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 */
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;
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++;
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++;
856 void RT28xxPciStaAsicForceWakeup(struct rt_rtmp_adapter *pAd, IN BOOLEAN bFromTx)
858 AUTO_WAKEUP_STRUC AutoWakeupCfg;
860 if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
861 return;
863 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_WAKEUP_NOW)) {
864 DBGPRINT(RT_DEBUG_TRACE, ("waking up now!\n"));
865 return;
868 OPSTATUS_SET_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
870 RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_GO_TO_SLEEP_NOW);
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"));
883 AutoWakeupCfg.word = 0;
884 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
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;
893 if (pChipOps->AsicReverseRfFromSleepMode)
894 pChipOps->
895 AsicReverseRfFromSleepMode(pAd);
896 } else
897 #endif /* PCIE_PS_SUPPORT // */
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);
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);
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);
947 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
948 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_WAKEUP_NOW);
949 DBGPRINT(RT_DEBUG_TRACE, ("<=======RT28xxPciStaAsicForceWakeup\n"));
952 void RT28xxPciStaAsicSleepThenAutoWakeup(struct rt_rtmp_adapter *pAd,
953 u16 TbttNumToNextWakeUp)
955 BOOLEAN brc;
957 if (pAd->StaCfg.bRadio == FALSE) {
958 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_DOZE);
959 return;
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;
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)
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;
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;
1002 /*RTMP_IO_WRITE32(pAd, INT_MASK_CSR, AutoWakeupInt); */
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));
1019 void PsPollWakeExec(void *SystemSpecific1,
1020 void *FunctionContext,
1021 void *SystemSpecific2, void *SystemSpecific3)
1023 struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)FunctionContext;
1024 unsigned long flags;
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);
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);
1044 #endif /* PCIE_PS_SUPPORT // */
1047 void RadioOnExec(void *SystemSpecific1,
1048 void *FunctionContext,
1049 void *SystemSpecific2, void *SystemSpecific3)
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;
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;
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;
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);
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);
1095 /* 2. Send wake up command. */
1096 AsicSendCommandToMcu(pAd, 0x31, PowerWakeCID, 0x00, 0x02);
1097 /* 2-1. wait command ok. */
1098 AsicCheckCommanOk(pAd, PowerWakeCID);
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);
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);
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);
1124 /*KH Debug:The following codes should be enclosed by RT3090 compile flag */
1125 if (pChipOps->AsicReverseRfFromSleepMode)
1126 pChipOps->AsicReverseRfFromSleepMode(pAd);
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);
1139 #endif /* PCIE_PS_SUPPORT // */
1141 /* Clear Radio off flag */
1142 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
1144 /* Set LED */
1145 RTMPSetLED(pAd, LED_RADIO_ON);
1147 if (pAd->StaCfg.Psm == PWR_ACTIVE) {
1148 RTMP_BBP_IO_WRITE8_BY_REG_ID(pAd, BBP_R3,
1149 pAd->StaCfg.BBPR3);
1151 } else {
1152 RT28xxPciAsicRadioOff(pAd, GUIRADIO_OFF, 0);
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.
1165 ==========================================================================
1167 BOOLEAN RT28xxPciAsicRadioOn(struct rt_rtmp_adapter *pAd, u8 Level)
1169 /*WPDMA_GLO_CFG_STRUC DmaCfg; */
1170 BOOLEAN Cancelled;
1171 /*u32 MACValue; */
1173 if (pAd->OpMode == OPMODE_AP && Level == DOT11POWERSAVE)
1174 return FALSE;
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);
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. */
1187 if (((pAd->MACVersion&0xffff0000) != 0x28600000)
1188 && ((pAd->DeviceID == NIC2860_PCIe_DEVICE_ID)
1189 ||(pAd->DeviceID == NIC2790_PCIe_DEVICE_ID)))
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);
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 // */
1209 pAd->bPCIclkOff = FALSE;
1210 DBGPRINT(RT_DEBUG_TRACE,
1211 ("PSM :309xbPCIclkOff == %d\n", pAd->bPCIclkOff));
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);
1220 RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
1221 if (Level == GUI_IDLE_POWER_SAVE) {
1222 #ifdef PCIE_PS_SUPPORT
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;
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 ==
1236 && (pAd->StaCfg.PSControl.field.EnableNewPS ==
1237 TRUE)) {
1238 RTMP_SEM_LOCK(&pAd->McuCmdLock);
1239 pAd->brt30xxBanMcuCmd = FALSE;
1240 RTMP_SEM_UNLOCK(&pAd->McuCmdLock);
1242 } else
1243 /* end johnli */
1244 #endif /* PCIE_PS_SUPPORT // */
1246 /* In Radio Off, we turn off RF clk, So now need to call ASICSwitchChannel again. */
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);
1273 return TRUE;
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.
1287 ==========================================================================
1289 BOOLEAN RT28xxPciAsicRadioOff(struct rt_rtmp_adapter *pAd,
1290 u8 Level, u16 TbttNumToNextWakeUp)
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));
1304 if (pAd->OpMode == OPMODE_AP && Level == DOT11POWERSAVE)
1305 return FALSE;
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;
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);
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;
1361 BeaconPeriodTime =
1362 pAd->CommonCfg.BeaconPeriod * 102 / 100;
1363 if (TbttNumToNextWakeUp > 0)
1364 PsPollTime +=
1365 ((TbttNumToNextWakeUp -
1366 1) * BeaconPeriodTime);
1368 pAd->Mlme.bPsPollTimerRunning = TRUE;
1369 RTMPSetTimer(&pAd->Mlme.PsPollTimer,
1370 PsPollTime);
1373 } else {
1374 DBGPRINT(RT_DEBUG_TRACE,
1375 ("RT28xxPciAsicRadioOff::Level!=DOT11POWERSAVE \n"));
1378 pAd->bPCIclkOffDisableTx = FALSE;
1380 RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_IDLE_RADIO_OFF);
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);
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);
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);
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);
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);
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);
1439 if (i >= 50)
1441 pAd->CheckDmaBusyCount++;
1442 DBGPRINT(RT_DEBUG_TRACE, ("DMA Rx keeps busy. return on AsicRadioOff () CheckDmaBusyCount = %d \n", pAd->CheckDmaBusyCount));
1444 else
1446 pAd->CheckDmaBusyCount = 0;
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); */
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;
1466 #endif /* PCIE_PS_SUPPORT // */
1468 if (Level == DOT11POWERSAVE) {
1469 AUTO_WAKEUP_STRUC AutoWakeupCfg;
1470 /*RTMPSetTimer(&pAd->Mlme.PsPollTimer, 90); */
1472 /* we have decided to SLEEP, so at least do it for a BEACON period. */
1473 if (TbttNumToNextWakeUp == 0)
1474 TbttNumToNextWakeUp = 1;
1476 AutoWakeupCfg.word = 0;
1477 RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
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);
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);
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);
1495 /*pAd->bPCIclkOffDisableTx = FALSE; */
1496 RTMP_CLEAR_PSFLAG(pAd, fRTMP_PS_DISABLE_TX);
1497 return TRUE;
1500 void RT28xxPciMlmeRadioOn(struct rt_rtmp_adapter *pAd)
1502 if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
1503 return;
1505 DBGPRINT(RT_DEBUG_TRACE, ("%s===>\n", __func__));
1507 if ((pAd->OpMode == OPMODE_AP) || ((pAd->OpMode == OPMODE_STA)
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); */
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);
1523 /* Enable Tx/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);
1531 /* Set LED */
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)) {
1538 BOOLEAN Cancelled;
1540 RTMPPCIeLinkCtrlValueRestore(pAd, RESTORE_WAKEUP);
1542 pAd->Mlme.bPsPollTimerRunning = FALSE;
1543 RTMPCancelTimer(&pAd->Mlme.PsPollTimer, &Cancelled);
1544 RTMPCancelTimer(&pAd->Mlme.RadioOnOffTimer, &Cancelled);
1545 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 40);
1549 void RT28xxPciMlmeRadioOFF(struct rt_rtmp_adapter *pAd)
1551 BOOLEAN brc = TRUE;
1553 if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
1554 return;
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);
1564 if (pMsgElem) {
1565 COPY_MAC_ADDR(&DisReq.Addr,
1566 pAd->CommonCfg.Bssid);
1567 DisReq.Reason = REASON_DISASSOC_STA_LEAVING;
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));
1577 MlmeDisassocReqAction(pAd, pMsgElem);
1578 kfree(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);
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);
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;
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)))
1610 RT28xxPciAsicRadioOn(pAd, GUI_IDLE_POWER_SAVE);
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);
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);
1630 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE))
1632 RTMPSetTimer(&pAd->Mlme.RadioOnOffTimer, 10);
1633 return;
1638 /* Set LED.Move to here for fixing LED bug. This flag must be called after LinkDown */
1639 RTMPSetLED(pAd, LED_RADIO_OFF);
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);
1651 if (brc == FALSE) {
1652 DBGPRINT(RT_DEBUG_ERROR,
1653 ("%s call RT28xxPciAsicRadioOff fail!\n",
1654 __func__));
1661 #endif /* RTMP_MAC_PCI // */