2 *************************************************************************
4 * 5F., No.36, Taiyuan St., Jhubei City,
8 * (c) Copyright 2002-2007, Ralink Technology, Inc.
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
15 * This program is distributed in the hope that it will be useful, *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18 * GNU General Public License for more details. *
20 * You should have received a copy of the GNU General Public License *
21 * along with this program; if not, write to the *
22 * Free Software Foundation, Inc., *
23 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
25 *************************************************************************
29 All functions in this file must be PCI-depended, or you should out your function
33 #include "../rt_config.h"
35 USHORT RtmpPCI_WriteTxResource(IN PRTMP_ADAPTER pAd,
37 IN BOOLEAN bIsLast, OUT USHORT * FreeNumber)
40 UCHAR *pDMAHeaderBufVA;
41 USHORT TxIdx, RetTxIdx;
44 PRTMP_TX_RING pTxRing;
48 // get Tx Ring Resource
50 pTxRing = &pAd->TxRing[pTxBlk->QueIdx];
51 TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx;
52 pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa;
54 RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa);
56 // copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer
57 if (pTxBlk->TxFrameType == TX_AMSDU_FRAME) {
58 //hwHeaderLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_AMSDU_SUBFRAMEHEAD, 4)+LENGTH_AMSDU_SUBFRAMEHEAD;
60 pTxBlk->MpduHeaderLen - LENGTH_AMSDU_SUBFRAMEHEAD +
61 pTxBlk->HdrPadLen + LENGTH_AMSDU_SUBFRAMEHEAD;
63 //hwHeaderLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4);
64 hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen;
66 NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf,
67 TXINFO_SIZE + TXWI_SIZE + hwHeaderLen);
69 pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket;
70 pTxRing->Cell[TxIdx].pNextNdisPacket = NULL;
73 // build Tx Descriptor
76 pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
77 NdisZeroMemory(pTxD, TXD_SIZE);
79 pTxD->SDPtr0 = BufBasePaLow;
80 pTxD->SDLen0 = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen; // include padding
81 pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);
82 pTxD->SDLen1 = pTxBlk->SrcBufLen;
84 pTxD->LastSec1 = (bIsLast) ? 1 : 0;
86 RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA);
92 INC_RING_INDEX(TxIdx, TX_RING_SIZE);
93 pTxRing->TxCpuIdx = TxIdx;
100 USHORT RtmpPCI_WriteSingleTxResource(IN PRTMP_ADAPTER pAd,
103 OUT USHORT * FreeNumber)
106 UCHAR *pDMAHeaderBufVA;
107 USHORT TxIdx, RetTxIdx;
110 PRTMP_TX_RING pTxRing;
114 // get Tx Ring Resource
116 pTxRing = &pAd->TxRing[pTxBlk->QueIdx];
117 TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx;
118 pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa;
120 RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa);
122 // copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer
123 //hwHeaderLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4);
124 hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen;
126 NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf,
127 TXINFO_SIZE + TXWI_SIZE + hwHeaderLen);
129 pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket;
130 pTxRing->Cell[TxIdx].pNextNdisPacket = NULL;
133 // build Tx Descriptor
135 pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
136 NdisZeroMemory(pTxD, TXD_SIZE);
138 pTxD->SDPtr0 = BufBasePaLow;
139 pTxD->SDLen0 = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen; // include padding
140 pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);;
141 pTxD->SDLen1 = pTxBlk->SrcBufLen;
143 pTxD->LastSec1 = (bIsLast) ? 1 : 0;
145 RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA);
151 INC_RING_INDEX(TxIdx, TX_RING_SIZE);
152 pTxRing->TxCpuIdx = TxIdx;
159 USHORT RtmpPCI_WriteMultiTxResource(IN PRTMP_ADAPTER pAd,
161 IN UCHAR frameNum, OUT USHORT * FreeNumber)
164 UCHAR *pDMAHeaderBufVA;
165 USHORT TxIdx, RetTxIdx;
168 PRTMP_TX_RING pTxRing;
172 bIsLast = ((frameNum == (pTxBlk->TotalFrameNum - 1)) ? 1 : 0);
175 // get Tx Ring Resource
177 pTxRing = &pAd->TxRing[pTxBlk->QueIdx];
178 TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx;
179 pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa;
181 RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa);
184 // copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer
185 if (pTxBlk->TxFrameType == TX_AMSDU_FRAME)
186 //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_AMSDU_SUBFRAMEHEAD, 4)+LENGTH_AMSDU_SUBFRAMEHEAD;
188 pTxBlk->MpduHeaderLen - LENGTH_AMSDU_SUBFRAMEHEAD +
189 pTxBlk->HdrPadLen + LENGTH_AMSDU_SUBFRAMEHEAD;
190 else if (pTxBlk->TxFrameType == TX_RALINK_FRAME)
191 //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen-LENGTH_ARALINK_HEADER_FIELD, 4)+LENGTH_ARALINK_HEADER_FIELD;
193 pTxBlk->MpduHeaderLen -
194 LENGTH_ARALINK_HEADER_FIELD + pTxBlk->HdrPadLen +
195 LENGTH_ARALINK_HEADER_FIELD;
197 //hwHdrLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4);
198 hwHdrLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen;
200 firstDMALen = TXINFO_SIZE + TXWI_SIZE + hwHdrLen;
202 firstDMALen = pTxBlk->MpduHeaderLen;
205 NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, firstDMALen);
207 pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket;
208 pTxRing->Cell[TxIdx].pNextNdisPacket = NULL;
211 // build Tx Descriptor
213 pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
214 NdisZeroMemory(pTxD, TXD_SIZE);
216 pTxD->SDPtr0 = BufBasePaLow;
217 pTxD->SDLen0 = firstDMALen; // include padding
218 pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);;
219 pTxD->SDLen1 = pTxBlk->SrcBufLen;
221 pTxD->LastSec1 = (bIsLast) ? 1 : 0;
223 RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA);
229 INC_RING_INDEX(TxIdx, TX_RING_SIZE);
230 pTxRing->TxCpuIdx = TxIdx;
238 VOID RtmpPCI_FinalWriteTxResource(IN PRTMP_ADAPTER pAd,
240 IN USHORT totalMPDUSize, IN USHORT FirstTxIdx)
244 PRTMP_TX_RING pTxRing;
247 // get Tx Ring Resource
249 pTxRing = &pAd->TxRing[pTxBlk->QueIdx];
250 pTxWI = (PTXWI_STRUC) pTxRing->Cell[FirstTxIdx].DmaBuf.AllocVa;
251 pTxWI->MPDUtotalByteCount = totalMPDUSize;
255 VOID RtmpPCIDataLastTxIdx(IN PRTMP_ADAPTER pAd,
256 IN UCHAR QueIdx, IN USHORT LastTxIdx)
259 PRTMP_TX_RING pTxRing;
262 // get Tx Ring Resource
264 pTxRing = &pAd->TxRing[QueIdx];
267 // build Tx Descriptor
269 pTxD = (PTXD_STRUC) pTxRing->Cell[LastTxIdx].AllocVa;
275 USHORT RtmpPCI_WriteFragTxResource(IN PRTMP_ADAPTER pAd,
277 IN UCHAR fragNum, OUT USHORT * FreeNumber)
279 UCHAR *pDMAHeaderBufVA;
280 USHORT TxIdx, RetTxIdx;
283 PRTMP_TX_RING pTxRing;
288 // Get Tx Ring Resource
290 pTxRing = &pAd->TxRing[pTxBlk->QueIdx];
291 TxIdx = pAd->TxRing[pTxBlk->QueIdx].TxCpuIdx;
292 pDMAHeaderBufVA = (PUCHAR) pTxRing->Cell[TxIdx].DmaBuf.AllocVa;
294 RTMP_GetPhysicalAddressLow(pTxRing->Cell[TxIdx].DmaBuf.AllocPa);
297 // Copy TXINFO + TXWI + WLAN Header + LLC into DMA Header Buffer
299 //hwHeaderLen = ROUND_UP(pTxBlk->MpduHeaderLen, 4);
300 hwHeaderLen = pTxBlk->MpduHeaderLen + pTxBlk->HdrPadLen;
302 firstDMALen = TXINFO_SIZE + TXWI_SIZE + hwHeaderLen;
303 NdisMoveMemory(pDMAHeaderBufVA, pTxBlk->HeaderBuf, firstDMALen);
306 // Build Tx Descriptor
308 pTxD = (PTXD_STRUC) pTxRing->Cell[TxIdx].AllocVa;
309 NdisZeroMemory(pTxD, TXD_SIZE);
311 if (fragNum == pTxBlk->TotalFragNum) {
312 pTxRing->Cell[TxIdx].pNdisPacket = pTxBlk->pPacket;
313 pTxRing->Cell[TxIdx].pNextNdisPacket = NULL;
316 pTxD->SDPtr0 = BufBasePaLow;
317 pTxD->SDLen0 = firstDMALen; // include padding
318 pTxD->SDPtr1 = PCI_MAP_SINGLE(pAd, pTxBlk, 0, 1, PCI_DMA_TODEVICE);
319 pTxD->SDLen1 = pTxBlk->SrcBufLen;
323 RTMPWriteTxDescriptor(pAd, pTxD, FALSE, FIFO_EDCA);
326 pTxBlk->Priv += pTxBlk->SrcBufLen;
331 INC_RING_INDEX(TxIdx, TX_RING_SIZE);
332 pTxRing->TxCpuIdx = TxIdx;
341 Must be run in Interrupt context
342 This function handle PCI specific TxDesc and cpu index update and kick the packet out.
344 int RtmpPCIMgmtKickOut(IN RTMP_ADAPTER * pAd,
346 IN PNDIS_PACKET pPacket,
347 IN PUCHAR pSrcBufVA, IN UINT SrcBufLen)
350 ULONG SwIdx = pAd->MgmtRing.TxCpuIdx;
352 pTxD = (PTXD_STRUC) pAd->MgmtRing.Cell[SwIdx].AllocVa;
354 pAd->MgmtRing.Cell[SwIdx].pNdisPacket = pPacket;
355 pAd->MgmtRing.Cell[SwIdx].pNextNdisPacket = NULL;
357 RTMPWriteTxDescriptor(pAd, pTxD, TRUE, FIFO_MGMT);
363 PCI_MAP_SINGLE(pAd, pSrcBufVA, SrcBufLen, 0, PCI_DMA_TODEVICE);
364 pTxD->SDLen0 = SrcBufLen;
366 //==================================================================
367 /* DBGPRINT_RAW(RT_DEBUG_TRACE, ("MLMEHardTransmit\n"));
368 for (i = 0; i < (TXWI_SIZE+24); i++)
371 DBGPRINT_RAW(RT_DEBUG_TRACE, ("%x:", *(pSrcBufVA+i)));
373 DBGPRINT_RAW(RT_DEBUG_TRACE, (" :: "));
375 DBGPRINT_RAW(RT_DEBUG_TRACE, ("\n "));
377 DBGPRINT_RAW(RT_DEBUG_TRACE, ("\n "));*/
378 //=======================================================================
380 pAd->RalinkCounters.KickTxCount++;
381 pAd->RalinkCounters.OneSecTxDoneCount++;
383 // Increase TX_CTX_IDX, but write to register later.
384 INC_RING_INDEX(pAd->MgmtRing.TxCpuIdx, MGMT_RING_SIZE);
386 RTMP_IO_WRITE32(pAd, TX_MGMTCTX_IDX, pAd->MgmtRing.TxCpuIdx);
392 ========================================================================
395 Check Rx descriptor, return NDIS_STATUS_FAILURE if any error dound
398 pRxD Pointer to the Rx descriptor
401 NDIS_STATUS_SUCCESS No err
402 NDIS_STATUS_FAILURE Error
406 ========================================================================
408 NDIS_STATUS RTMPCheckRxError(IN PRTMP_ADAPTER pAd,
409 IN PHEADER_802_11 pHeader,
410 IN PRXWI_STRUC pRxWI, IN PRT28XX_RXD_STRUC pRxD)
415 // Phy errors & CRC errors
416 if ( /*(pRxD->PhyErr) || */ (pRxD->Crc)) {
417 // Check RSSI for Noise Hist statistic collection.
418 dBm = (INT) (pRxWI->RSSI0) - pAd->BbpRssiToDbmDelta;
420 pAd->StaCfg.RPIDensity[0] += 1;
422 pAd->StaCfg.RPIDensity[1] += 1;
424 pAd->StaCfg.RPIDensity[2] += 1;
426 pAd->StaCfg.RPIDensity[3] += 1;
428 pAd->StaCfg.RPIDensity[4] += 1;
430 pAd->StaCfg.RPIDensity[5] += 1;
432 pAd->StaCfg.RPIDensity[6] += 1;
434 pAd->StaCfg.RPIDensity[7] += 1;
436 return (NDIS_STATUS_FAILURE);
438 // Add Rx size to channel load counter, we should ignore error counts
439 pAd->StaCfg.CLBusyBytes += (pRxD->SDL0 + 14);
441 // Drop ToDs promiscous frame, it is opened due to CCX 2 channel load statistics
442 if (pHeader != NULL) {
443 if (pHeader->FC.ToDs) {
444 return (NDIS_STATUS_FAILURE);
447 // Drop not U2M frames, cant's drop here because we will drop beacon in this case
448 // I am kind of doubting the U2M bit operation
449 // if (pRxD->U2M == 0)
450 // return(NDIS_STATUS_FAILURE);
452 // drop decyption fail frame
453 if (pRxD->CipherErr) {
454 if (pRxD->CipherErr == 2) {
455 DBGPRINT_RAW(RT_DEBUG_TRACE,
456 ("pRxD ERROR: ICV ok but MICErr "));
457 } else if (pRxD->CipherErr == 1) {
458 DBGPRINT_RAW(RT_DEBUG_TRACE, ("pRxD ERROR: ICV Err "));
459 } else if (pRxD->CipherErr == 3)
460 DBGPRINT_RAW(RT_DEBUG_TRACE,
461 ("pRxD ERROR: Key not valid "));
463 if (((pRxD->CipherErr & 1) == 1)
464 && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd))
465 RTMPSendWirelessEvent(pAd, IW_ICV_ERROR_EVENT_FLAG,
466 pAd->MacTab.Content[BSSID_WCID].
469 DBGPRINT_RAW(RT_DEBUG_TRACE,
470 (" %d (len=%d, Mcast=%d, MyBss=%d, Wcid=%d, KeyId=%d)\n",
471 pRxD->CipherErr, pRxD->SDL0,
472 pRxD->Mcast | pRxD->Bcast, pRxD->MyBss,
473 pRxWI->WirelessCliID,
474 // CipherName[pRxD->CipherAlg],
480 if (pRxD->CipherErr == 2) {
481 pWpaKey = &pAd->SharedKey[BSS0][pRxWI->KeyIndex];
482 if (pAd->StaCfg.WpaSupplicantUP)
483 WpaSendMicFailureToWpaSupplicant(pAd,
489 RTMPReportMicError(pAd, pWpaKey);
491 if (((pRxD->CipherErr & 2) == 2)
492 && pAd->CommonCfg.bWirelessEvent && INFRA_ON(pAd))
493 RTMPSendWirelessEvent(pAd,
494 IW_MIC_ERROR_EVENT_FLAG,
496 Content[BSSID_WCID].Addr,
499 DBGPRINT_RAW(RT_DEBUG_ERROR, ("Rx MIC Value error\n"));
503 return (NDIS_STATUS_SUCCESS);
504 /*if ((pRxD->CipherAlg == CIPHER_AES) &&
505 (pHeader->Sequence == pAd->FragFrame.Sequence))
508 // Acceptable since the First FragFrame no CipherErr problem.
510 return(NDIS_STATUS_SUCCESS);
513 return (NDIS_STATUS_FAILURE);
516 return (NDIS_STATUS_SUCCESS);
519 BOOLEAN RTMPFreeTXDUponTxDmaDone(IN PRTMP_ADAPTER pAd, IN UCHAR QueIdx)
521 PRTMP_TX_RING pTxRing;
523 PNDIS_PACKET pPacket;
525 TXD_STRUC TxD, *pOriTxD;
527 BOOLEAN bReschedule = FALSE;
529 ASSERT(QueIdx < NUM_OF_TX_RING);
530 pTxRing = &pAd->TxRing[QueIdx];
532 RTMP_IO_READ32(pAd, TX_DTX_IDX0 + QueIdx * RINGREG_DIFF,
534 while (pTxRing->TxSwFreeIdx != pTxRing->TxDmaIdx) {
535 // RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags);
537 // static rate also need NICUpdateFifoStaCounters() function.
538 //if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_TX_RATE_SWITCH_ENABLED))
539 NICUpdateFifoStaCounters(pAd);
541 /* Note : If (pAd->ate.bQATxStart == TRUE), we will never reach here. */
544 (PTXD_STRUC) (pTxRing->Cell[pTxRing->TxSwFreeIdx].AllocVa);
546 NdisMoveMemory(&TxD, pTxD, sizeof(TXD_STRUC));
553 pTxRing->Cell[pTxRing->TxSwFreeIdx].pNdisPacket;
555 PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1,
558 RELEASE_NDIS_PACKET(pAd, pPacket,
559 NDIS_STATUS_SUCCESS);
561 //Always assign pNdisPacket as NULL after clear
562 pTxRing->Cell[pTxRing->TxSwFreeIdx].pNdisPacket = NULL;
565 pTxRing->Cell[pTxRing->TxSwFreeIdx].pNextNdisPacket;
567 ASSERT(pPacket == NULL);
569 PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1,
572 RELEASE_NDIS_PACKET(pAd, pPacket,
573 NDIS_STATUS_SUCCESS);
575 //Always assign pNextNdisPacket as NULL after clear
576 pTxRing->Cell[pTxRing->TxSwFreeIdx].pNextNdisPacket =
580 pAd->RalinkCounters.TransmittedByteCount +=
581 (pTxD->SDLen1 + pTxD->SDLen0);
582 pAd->RalinkCounters.OneSecDmaDoneCount[QueIdx]++;
583 INC_RING_INDEX(pTxRing->TxSwFreeIdx, TX_RING_SIZE);
584 /* get tx_tdx_idx again */
585 RTMP_IO_READ32(pAd, TX_DTX_IDX0 + QueIdx * RINGREG_DIFF,
587 NdisMoveMemory(pOriTxD, pTxD, sizeof(TXD_STRUC));
589 // RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
597 ========================================================================
600 Process TX Rings DMA Done interrupt, running in DPC level
603 Adapter Pointer to our adapter
608 IRQL = DISPATCH_LEVEL
610 ========================================================================
612 BOOLEAN RTMPHandleTxRingDmaDoneInterrupt(IN PRTMP_ADAPTER pAd,
613 IN INT_SOURCE_CSR_STRUC TxRingBitmap)
616 unsigned long IrqFlags;
617 BOOLEAN bReschedule = FALSE;
619 // Make sure Tx ring resource won't be used by other threads
620 //NdisAcquireSpinLock(&pAd->TxRingLock);
622 RTMP_IRQ_LOCK(&pAd->irq_lock, IrqFlags);
624 if (TxRingBitmap.field.Ac0DmaDone)
625 bReschedule = RTMPFreeTXDUponTxDmaDone(pAd, QID_AC_BE);
627 if (TxRingBitmap.field.Ac3DmaDone)
628 bReschedule |= RTMPFreeTXDUponTxDmaDone(pAd, QID_AC_VO);
630 if (TxRingBitmap.field.Ac2DmaDone)
631 bReschedule |= RTMPFreeTXDUponTxDmaDone(pAd, QID_AC_VI);
633 if (TxRingBitmap.field.Ac1DmaDone)
634 bReschedule |= RTMPFreeTXDUponTxDmaDone(pAd, QID_AC_BK);
636 // Make sure to release Tx ring resource
637 //NdisReleaseSpinLock(&pAd->TxRingLock);
638 RTMP_IRQ_UNLOCK(&pAd->irq_lock, IrqFlags);
640 // Dequeue outgoing frames from TxSwQueue[] and process it
641 RTMPDeQueuePacket(pAd, FALSE, NUM_OF_TX_RING, MAX_TX_PROCESS);
647 ========================================================================
650 Process MGMT ring DMA done interrupt, running in DPC level
653 pAd Pointer to our adapter
658 IRQL = DISPATCH_LEVEL
662 ========================================================================
664 VOID RTMPHandleMgmtRingDmaDoneInterrupt(IN PRTMP_ADAPTER pAd)
667 PNDIS_PACKET pPacket;
670 PRTMP_MGMT_RING pMgmtRing = &pAd->MgmtRing;
672 NdisAcquireSpinLock(&pAd->MgmtRingLock);
674 RTMP_IO_READ32(pAd, TX_MGMTDTX_IDX, &pMgmtRing->TxDmaIdx);
675 while (pMgmtRing->TxSwFreeIdx != pMgmtRing->TxDmaIdx) {
678 (PTXD_STRUC) (pMgmtRing->Cell[pAd->MgmtRing.TxSwFreeIdx].
681 pPacket = pMgmtRing->Cell[pMgmtRing->TxSwFreeIdx].pNdisPacket;
684 PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr0, pTxD->SDLen0,
686 RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS);
688 pMgmtRing->Cell[pMgmtRing->TxSwFreeIdx].pNdisPacket = NULL;
691 pMgmtRing->Cell[pMgmtRing->TxSwFreeIdx].pNextNdisPacket;
693 PCI_UNMAP_SINGLE(pAd, pTxD->SDPtr1, pTxD->SDLen1,
695 RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_SUCCESS);
697 pMgmtRing->Cell[pMgmtRing->TxSwFreeIdx].pNextNdisPacket = NULL;
698 INC_RING_INDEX(pMgmtRing->TxSwFreeIdx, MGMT_RING_SIZE);
701 NdisReleaseSpinLock(&pAd->MgmtRingLock);
706 ========================================================================
710 Adapter Pointer to our adapter. Dequeue all power safe delayed braodcast frames after beacon.
712 IRQL = DISPATCH_LEVEL
714 ========================================================================
716 VOID RTMPHandleTBTTInterrupt(IN PRTMP_ADAPTER pAd)
719 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) {
725 ========================================================================
729 pAd Pointer to our adapter. Rewrite beacon content before next send-out.
731 IRQL = DISPATCH_LEVEL
733 ========================================================================
735 VOID RTMPHandlePreTBTTInterrupt(IN PRTMP_ADAPTER pAd)
738 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE)) {
739 DBGPRINT(RT_DEBUG_TRACE,
740 ("RTMPHandlePreTBTTInterrupt...\n"));
746 VOID RTMPHandleRxCoherentInterrupt(IN PRTMP_ADAPTER pAd)
748 WPDMA_GLO_CFG_STRUC GloCfg;
751 DBGPRINT(RT_DEBUG_TRACE, ("====> pAd is NULL, return.\n"));
755 DBGPRINT(RT_DEBUG_TRACE, ("==> RTMPHandleRxCoherentInterrupt \n"));
757 RTMP_IO_READ32(pAd, WPDMA_GLO_CFG, &GloCfg.word);
759 GloCfg.field.EnTXWriteBackDDONE = 0;
760 GloCfg.field.EnableRxDMA = 0;
761 GloCfg.field.EnableTxDMA = 0;
762 RTMP_IO_WRITE32(pAd, WPDMA_GLO_CFG, GloCfg.word);
764 RTMPRingCleanUp(pAd, QID_AC_BE);
765 RTMPRingCleanUp(pAd, QID_AC_BK);
766 RTMPRingCleanUp(pAd, QID_AC_VI);
767 RTMPRingCleanUp(pAd, QID_AC_VO);
768 RTMPRingCleanUp(pAd, QID_MGMT);
769 RTMPRingCleanUp(pAd, QID_RX);
773 DBGPRINT(RT_DEBUG_TRACE, ("<== RTMPHandleRxCoherentInterrupt \n"));
776 PNDIS_PACKET GetPacketFromRxRing(IN PRTMP_ADAPTER pAd,
777 OUT PRT28XX_RXD_STRUC pSaveRxD,
778 OUT BOOLEAN * pbReschedule,
779 IN OUT UINT32 * pRxPending)
782 PNDIS_PACKET pRxPacket = NULL;
783 PNDIS_PACKET pNewPacket;
785 NDIS_PHYSICAL_ADDRESS AllocPa;
786 BOOLEAN bReschedule = FALSE;
789 RTMP_SEM_LOCK(&pAd->RxRingLock);
791 if (*pRxPending == 0) {
792 // Get how may packets had been received
793 RTMP_IO_READ32(pAd, RX_DRX_IDX, &pAd->RxRing.RxDmaIdx);
795 if (pAd->RxRing.RxSwReadIdx == pAd->RxRing.RxDmaIdx) {
796 // no more rx packets
800 // get rx pending count
801 if (pAd->RxRing.RxDmaIdx > pAd->RxRing.RxSwReadIdx)
803 pAd->RxRing.RxDmaIdx - pAd->RxRing.RxSwReadIdx;
806 pAd->RxRing.RxDmaIdx + RX_RING_SIZE -
807 pAd->RxRing.RxSwReadIdx;
811 pRxCell = &pAd->RxRing.Cell[pAd->RxRing.RxSwReadIdx];
813 // Point to Rx indexed rx ring descriptor
814 pRxD = (PRXD_STRUC) pRxCell->AllocVa;
816 if (pRxD->DDONE == 0) {
818 // DMAIndx had done but DDONE bit not ready
823 // return rx descriptor
824 NdisMoveMemory(pSaveRxD, pRxD, RXD_SIZE);
827 RTMP_AllocateRxPacketBuffer(pAd, RX_BUFFER_AGGRESIZE, FALSE,
831 // unmap the rx buffer
832 PCI_UNMAP_SINGLE(pAd, pRxCell->DmaBuf.AllocPa,
833 pRxCell->DmaBuf.AllocSize, PCI_DMA_FROMDEVICE);
834 pRxPacket = pRxCell->pNdisPacket;
836 pRxCell->DmaBuf.AllocSize = RX_BUFFER_AGGRESIZE;
837 pRxCell->pNdisPacket = (PNDIS_PACKET) pNewPacket;
838 pRxCell->DmaBuf.AllocVa = AllocVa;
839 pRxCell->DmaBuf.AllocPa = AllocPa;
840 /* update SDP0 to new buffer of rx packet */
841 pRxD->SDP0 = AllocPa;
843 //DBGPRINT(RT_DEBUG_TRACE,("No Rx Buffer\n"));
850 // had handled one rx packet
851 *pRxPending = *pRxPending - 1;
853 // update rx descriptor and kick rx
854 INC_RING_INDEX(pAd->RxRing.RxSwReadIdx, RX_RING_SIZE);
856 pAd->RxRing.RxCpuIdx =
857 (pAd->RxRing.RxSwReadIdx ==
858 0) ? (RX_RING_SIZE - 1) : (pAd->RxRing.RxSwReadIdx - 1);
859 RTMP_IO_WRITE32(pAd, RX_CRX_IDX, pAd->RxRing.RxCpuIdx);
862 RTMP_SEM_UNLOCK(&pAd->RxRingLock);
863 *pbReschedule = bReschedule;
867 NDIS_STATUS MlmeHardTransmitTxRing(IN PRTMP_ADAPTER pAd,
868 IN UCHAR QueIdx, IN PNDIS_PACKET pPacket)
870 PACKET_INFO PacketInfo;
874 PHEADER_802_11 pHeader_802_11;
875 BOOLEAN bAckRequired, bInsertTimestamp;
879 ULONG SwIdx = pAd->TxRing[QueIdx].TxCpuIdx;
880 PTXWI_STRUC pFirstTxWI;
882 //HTTRANSMIT_SETTING MlmeTransmit; //Rate for this MGMT frame.
884 MAC_TABLE_ENTRY *pMacEntry = NULL;
886 RTMP_QueryPacketInfo(pPacket, &PacketInfo, &pSrcBufVA, &SrcBufLen);
888 if (pSrcBufVA == NULL) {
889 // The buffer shouldn't be NULL
890 return NDIS_STATUS_FAILURE;
892 // Make sure MGMT ring resource won't be used by other threads
893 //NdisAcquireSpinLock(&pAd->TxRingLock);
895 FreeNum = GET_TXRING_FREENO(pAd, QueIdx);
898 //NdisReleaseSpinLock(&pAd->TxRingLock);
899 return NDIS_STATUS_FAILURE;
902 SwIdx = pAd->TxRing[QueIdx].TxCpuIdx;
904 pTxD = (PTXD_STRUC) pAd->TxRing[QueIdx].Cell[SwIdx].AllocVa;
906 if (pAd->TxRing[QueIdx].Cell[SwIdx].pNdisPacket) {
907 DBGPRINT(RT_DEBUG_OFF, ("MlmeHardTransmit Error\n"));
908 //NdisReleaseSpinLock(&pAd->TxRingLock);
909 return NDIS_STATUS_FAILURE;
913 // outgoing frame always wakeup PHY to prevent frame lost
914 // if (pAd->StaCfg.Psm == PWR_SAVE)
915 if (OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_DOZE))
916 AsicForceWakeup(pAd, TRUE);
918 pFirstTxWI = (PTXWI_STRUC) pSrcBufVA;
920 pHeader_802_11 = (PHEADER_802_11) (pSrcBufVA + TXWI_SIZE);
921 if (pHeader_802_11->Addr1[0] & 0x01) {
922 MlmeRate = pAd->CommonCfg.BasicMlmeRate;
924 MlmeRate = pAd->CommonCfg.MlmeRate;
927 if ((pHeader_802_11->FC.Type == BTYPE_DATA) &&
928 (pHeader_802_11->FC.SubType == SUBTYPE_QOS_NULL)) {
929 pMacEntry = MacTableLookup(pAd, pHeader_802_11->Addr1);
931 // Verify Mlme rate for a / g bands.
932 if ((pAd->LatchRfRegs.Channel > 14) && (MlmeRate < RATE_6)) // 11A band
936 // Should not be hard code to set PwrMgmt to 0 (PWR_ACTIVE)
937 // Snice it's been set to 0 while on MgtMacHeaderInit
938 // By the way this will cause frame to be send on PWR_SAVE failed.
941 // In WMM-UAPSD, mlme frame should be set psm as power saving but probe request frame
942 // Data-Null packets alse pass through MMRequest in RT2860, however, we hope control the psm bit to pass APSD
943 if (pHeader_802_11->FC.Type != BTYPE_DATA) {
944 if ((pHeader_802_11->FC.SubType == SUBTYPE_PROBE_REQ)
945 || !(pAd->CommonCfg.bAPSDCapable
946 && pAd->CommonCfg.APEdcaParm.bAPSDCapable)) {
947 pHeader_802_11->FC.PwrMgmt = PWR_ACTIVE;
949 pHeader_802_11->FC.PwrMgmt =
950 pAd->CommonCfg.bAPSDForcePowerSave;
954 bInsertTimestamp = FALSE;
955 if (pHeader_802_11->FC.Type == BTYPE_CNTL) // must be PS-POLL
957 bAckRequired = FALSE;
958 } else // BTYPE_MGMT or BTYPE_DATA(must be NULL frame)
960 if (pHeader_802_11->Addr1[0] & 0x01) // MULTICAST, BROADCAST
962 bAckRequired = FALSE;
963 pHeader_802_11->Duration = 0;
966 pHeader_802_11->Duration =
967 RTMPCalcDuration(pAd, MlmeRate, 14);
968 if (pHeader_802_11->FC.SubType == SUBTYPE_PROBE_RSP) {
969 bInsertTimestamp = TRUE;
973 pHeader_802_11->Sequence = pAd->Sequence++;
974 if (pAd->Sequence > 0xfff)
976 // Before radar detection done, mgmt frame can not be sent but probe req
977 // Because we need to use probe req to trigger driver to send probe req in passive scan
978 if ((pHeader_802_11->FC.SubType != SUBTYPE_PROBE_REQ)
979 && (pAd->CommonCfg.bIEEE80211H == 1)
980 && (pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE)) {
981 DBGPRINT(RT_DEBUG_ERROR,
982 ("MlmeHardTransmit --> radar detect not in normal mode !!!\n"));
983 //NdisReleaseSpinLock(&pAd->TxRingLock);
984 return (NDIS_STATUS_FAILURE);
987 // fill scatter-and-gather buffer list into TXD. Internally created NDIS PACKET
988 // should always has only one ohysical buffer, and the whole frame size equals
989 // to the first scatter buffer size
992 // Initialize TX Descriptor
993 // For inter-frame gap, the number is for this frame and next frame
994 // For MLME rate, we will fix as 2Mb to match other vendor's implement
995 // pAd->CommonCfg.MlmeTransmit.field.MODE = 1;
997 // management frame doesn't need encryption. so use RESERVED_WCID no matter u are sending to specific wcid or not.
998 // Only beacon use Nseq=TRUE. So here we use Nseq=FALSE.
999 if (pMacEntry == NULL) {
1000 RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE, bInsertTimestamp,
1001 FALSE, bAckRequired, FALSE, 0, RESERVED_WCID,
1002 (SrcBufLen - TXWI_SIZE), PID_MGMT, 0,
1003 (UCHAR) pAd->CommonCfg.MlmeTransmit.field.MCS,
1004 IFS_BACKOFF, FALSE, &pAd->CommonCfg.MlmeTransmit);
1006 RTMPWriteTxWI(pAd, pFirstTxWI, FALSE, FALSE,
1007 bInsertTimestamp, FALSE, bAckRequired, FALSE,
1008 0, pMacEntry->Aid, (SrcBufLen - TXWI_SIZE),
1009 pMacEntry->MaxHTPhyMode.field.MCS, 0,
1010 (UCHAR) pMacEntry->MaxHTPhyMode.field.MCS,
1011 IFS_BACKOFF, FALSE, &pMacEntry->MaxHTPhyMode);
1014 pAd->TxRing[QueIdx].Cell[SwIdx].pNdisPacket = pPacket;
1015 pAd->TxRing[QueIdx].Cell[SwIdx].pNextNdisPacket = NULL;
1016 // pFirstTxWI->MPDUtotalByteCount = SrcBufLen - TXWI_SIZE;
1018 PCI_MAP_SINGLE(pAd, pSrcBufVA, SrcBufLen, 0, PCI_DMA_TODEVICE);
1020 RTMPWriteTxDescriptor(pAd, pTxD, TRUE, FIFO_EDCA);
1023 pTxD->SDLen0 = SrcBufLen;
1025 pTxD->SDPtr0 = SrcBufPA;
1028 pAd->RalinkCounters.KickTxCount++;
1029 pAd->RalinkCounters.OneSecTxDoneCount++;
1031 // Increase TX_CTX_IDX, but write to register later.
1032 INC_RING_INDEX(pAd->TxRing[QueIdx].TxCpuIdx, TX_RING_SIZE);
1034 RTMP_IO_WRITE32(pAd, TX_CTX_IDX0 + QueIdx * 0x10,
1035 pAd->TxRing[QueIdx].TxCpuIdx);
1037 // Make sure to release MGMT ring resource
1038 // NdisReleaseSpinLock(&pAd->TxRingLock);
1040 return NDIS_STATUS_SUCCESS;
1043 NDIS_STATUS MlmeDataHardTransmit(IN PRTMP_ADAPTER pAd,
1044 IN UCHAR QueIdx, IN PNDIS_PACKET pPacket)
1046 if ((pAd->CommonCfg.RadarDetect.RDMode != RD_NORMAL_MODE)
1048 return NDIS_STATUS_FAILURE;
1051 return MlmeHardTransmitTxRing(pAd, QueIdx, pPacket);
1055 ========================================================================
1057 Routine Description:
1058 Calculates the duration which is required to transmit out frames
1059 with given size and specified rate.
1062 pTxD Pointer to transmit descriptor
1063 Ack Setting for Ack requirement bit
1064 Fragment Setting for Fragment bit
1065 RetryMode Setting for retry mode
1066 Ifs Setting for IFS gap
1067 Rate Setting for transmit rate
1068 Service Setting for service
1070 TxPreamble Short or Long preamble when using CCK rates
1071 QueIdx - 0-3, according to 802.11e/d4.4 June/2003
1076 IRQL = PASSIVE_LEVEL
1077 IRQL = DISPATCH_LEVEL
1079 ========================================================================
1081 VOID RTMPWriteTxDescriptor(IN PRTMP_ADAPTER pAd,
1083 IN BOOLEAN bWIV, IN UCHAR QueueSEL)
1086 // Always use Long preamble before verifiation short preamble functionality works well.
1087 // Todo: remove the following line if short preamble functionality works
1089 OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_SHORT_PREAMBLE_INUSED);
1091 pTxD->WIV = (bWIV) ? 1 : 0;
1092 pTxD->QSEL = (QueueSEL);
1093 //RT2860c?? fixed using EDCA queue for test... We doubt Queue1 has problem. 2006-09-26 Jan
1094 //pTxD->QSEL= FIFO_EDCA;