]>
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 | ||
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 | 51 | int 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 | 403 | void 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 | 536 | void 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 | ======================================================================== | |
658 | Routine Description: | |
659 | Disable DMA. | |
660 | ||
661 | Arguments: | |
662 | *pAd the raxx interface data pointer | |
663 | ||
664 | Return Value: | |
665 | None | |
666 | ||
667 | Note: | |
668 | ======================================================================== | |
669 | */ | |
62eb734b | 670 | void 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 | ======================================================================== | |
682 | Routine Description: | |
683 | Enable DMA. | |
684 | ||
685 | Arguments: | |
686 | *pAd the raxx interface data pointer | |
687 | ||
688 | Return Value: | |
689 | None | |
690 | ||
691 | Note: | |
692 | ======================================================================== | |
693 | */ | |
62eb734b | 694 | void 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 | 724 | BOOLEAN 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 | ======================================================================== | |
785 | Routine Description: | |
786 | Write Beacon buffer to Asic. | |
787 | ||
788 | Arguments: | |
789 | *pAd the raxx interface data pointer | |
790 | ||
791 | Return Value: | |
792 | None | |
793 | ||
794 | Note: | |
795 | ======================================================================== | |
796 | */ | |
62eb734b | 797 | void 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 | 856 | void 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 | 952 | void 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 |
1019 | void 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 |
1047 | void 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 | 1167 | BOOLEAN 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 | 1289 | BOOLEAN 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 | 1500 | void 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 | 1549 | void 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 // */ |