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