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