Files
Linux_Drivers/osdrv/extdrv/wireless/mediatek/mt7603/common/ps.c
forum_service 213c880673 add driver of tp、wiegand-gpio and wireless
Change-Id: Ie3c11d9d85cf1a05042f5690ac711856fe8b1ad7
2023-12-22 09:56:05 +08:00

376 lines
11 KiB
C

/****************************************************************************
* Ralink Tech Inc.
* Taiwan, R.O.C.
*
* (c) Copyright 2010, Ralink Technology, Inc.
*
* All rights reserved. Ralink's source code is an unpublished work and the
* use of a copyright notice does not imply otherwise. This source code
* contains confidential trade secret material of Ralink Tech. Any attemp
* or participation in deciphering, decoding, reverse engineering or in any
* way altering the source code is stricitly prohibited, unless the prior
* written consent of Ralink Technology, Inc. is obtained.
***************************************************************************/
/****************************************************************************
Abstract:
All related POWER SAVE function body.
***************************************************************************/
#include "rt_config.h"
/*
========================================================================
Routine Description:
This routine is used to do insert packet into power-saveing queue.
Arguments:
pAd: Pointer to our adapter
pPacket: Pointer to send packet
pMacEntry: portint to entry of MacTab. the pMacEntry store attribute of client (STA).
QueIdx: Priority queue idex.
Return Value:
NDIS_STATUS_SUCCESS:If succes to queue the packet into TxSwQ.
NDIS_STATUS_FAILURE: If failed to do en-queue.
========================================================================
*/
NDIS_STATUS RtmpInsertPsQueue(
RTMP_ADAPTER *pAd,
PNDIS_PACKET pPacket,
MAC_TABLE_ENTRY *pMacEntry,
UCHAR QueIdx)
{
ULONG IrqFlags = 0;
#ifdef UAPSD_SUPPORT
UINT32 ac_id;
#endif
STA_TR_ENTRY *tr_entry = &pAd->MacTab.tr_entry[pMacEntry->wcid];;
#ifdef UAPSD_SUPPORT
/* put the U-APSD packet to its U-APSD queue by AC ID */
ac_id = QueIdx - QID_AC_BE; /* should be >= 0 */
tr_entry = &pAd->MacTab.tr_entry[pMacEntry->wcid];
if (UAPSD_MR_IS_UAPSD_AC(pMacEntry, ac_id))
{
UAPSD_PacketEnqueue(pAd, pMacEntry, pPacket, ac_id, FALSE);
#if defined(DOT11Z_TDLS_SUPPORT)
TDLS_UAPSDP_TrafficIndSend(pAd, pMacEntry->Addr);
#endif /* defined(DOT11Z_TDLS_SUPPORT) */
#ifdef CFG_TDLS_SUPPORT
cfg_tdls_send_PeerTrafficIndication(pAd,pMacEntry->Addr);
#endif /* CFG_TDLS_SUPPORT */
}
else
#endif /* UAPSD_SUPPORT */
{
if (tr_entry->ps_queue.Number >= MAX_PACKETS_IN_PS_QUEUE)
{
#ifdef RELEASE_EXCLUDE
DBGPRINT(RT_DEBUG_INFO, ("UCAST PSQ full, drop it!\n"));
#endif /* RELEASE_EXCLUDE */
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
return NDIS_STATUS_FAILURE;
}
else
{
DBGPRINT(RT_DEBUG_TRACE, ("legacy ps> queue a packet!\n"));
RTMP_IRQ_LOCK(&pAd->irq_lock /*&tr_entry->ps_queue_lock*/, IrqFlags);
InsertTailQueue(&tr_entry->ps_queue, PACKET_TO_QUEUE_ENTRY(pPacket));
RTMP_IRQ_UNLOCK(&pAd->irq_lock /*&tr_entry->ps_queue_lock*/, IrqFlags);
}
}
#ifdef CONFIG_AP_SUPPORT
/* mark corresponding TIM bit in outgoing BEACON frame */
#ifdef UAPSD_SUPPORT
if (UAPSD_MR_IS_NOT_TIM_BIT_NEEDED_HANDLED(pMacEntry, QueIdx))
{
/* 1. the station is UAPSD station;
2. one of AC is non-UAPSD (legacy) AC;
3. the destinated AC of the packet is UAPSD AC. */
/* So we can not set TIM bit due to one of AC is legacy AC */
}
else
#endif /* UAPSD_SUPPORT */
{
WLAN_MR_TIM_BIT_SET(pAd, pMacEntry->func_tb_idx, pMacEntry->Aid);
#ifdef RELEASE_EXCLUDE
DBGPRINT(RT_DEBUG_INFO,
("STA (AID=%d) in PSM, move to PSQ, Psqueue #=%d\n",
pMacEntry->Aid, tr_entry->ps_queue.Number));
#endif /* RELEASE_EXCLUDE */
}
#endif /* CONFIG_AP_SUPPORT */
return NDIS_STATUS_SUCCESS;
}
/*
==========================================================================
Description:
This routine is used to clean up a specified power-saving queue. It's
used whenever a wireless client is deleted.
==========================================================================
*/
VOID RtmpCleanupPsQueue(RTMP_ADAPTER *pAd, QUEUE_HEADER *pQueue)
{
QUEUE_ENTRY *pQEntry;
PNDIS_PACKET pPacket;
DBGPRINT(RT_DEBUG_TRACE, ("RtmpCleanupPsQueue (0x%08lx)...\n", (ULONG)pQueue));
while (pQueue->Head)
{
DBGPRINT(RT_DEBUG_TRACE,
("RtmpCleanupPsQueue %d...\n",pQueue->Number));
pQEntry = RemoveHeadQueue(pQueue);
/*pPacket = CONTAINING_RECORD(pEntry, NDIS_PACKET, MiniportReservedEx); */
pPacket = QUEUE_ENTRY_TO_PACKET(pQEntry);
RELEASE_NDIS_PACKET(pAd, pPacket, NDIS_STATUS_FAILURE);
DBGPRINT(RT_DEBUG_TRACE, ("RtmpCleanupPsQueue pkt = %lx...\n", (ULONG)pPacket));
}
}
/*
========================================================================
Description:
This routine frees all packets in PSQ that's destined to a specific DA.
BCAST/MCAST in DTIMCount=0 case is also handled here, just like a PS-POLL
is received from a WSTA which has MAC address FF:FF:FF:FF:FF:FF
========================================================================
*/
VOID RtmpHandleRxPsPoll(RTMP_ADAPTER *pAd, UCHAR *pAddr, USHORT wcid, BOOLEAN isActive)
{
MAC_TABLE_ENTRY *pMacEntry;
STA_TR_ENTRY *tr_entry = NULL;
ASSERT(wcid < MAX_LEN_OF_MAC_TABLE);
pMacEntry = &pAd->MacTab.Content[wcid];
tr_entry = &pAd->MacTab.tr_entry[wcid];
if (!RTMPEqualMemory(pMacEntry->Addr, pAddr, MAC_ADDR_LEN))
{
DBGPRINT(RT_DEBUG_WARN | DBG_FUNC_PS,("%s(%d) PS-POLL (MAC addr not match) from %02x:%02x:%02x:%02x:%02x:%02x. Why???\n",
__FUNCTION__, __LINE__, PRINT_MAC(pAddr)));
return;
}
#ifdef UAPSD_SUPPORT00
if (UAPSD_MR_IS_ALL_AC_UAPSD(isActive, pMacEntry))
{
/*
IEEE802.11e spec.
11.2.1.7 Receive operation for STAs in PS mode during the CP
When a non-AP QSTA that is using U-APSD and has all ACs
delivery-enabled detects that the bit corresponding to its AID
is set in the TIM, the non-AP QSTA shall issue a trigger frame
or a PS-Poll frame to retrieve the buffered MSDU or management
frames.
WMM Spec. v1.1a 070601
3.6.2 U-APSD STA Operation
3.6.2.3 In case one or more ACs are not
delivery-enabled ACs, the WMM STA may retrieve MSDUs and
MMPDUs belonging to those ACs by sending PS-Polls to the WMM AP.
In case all ACs are delivery enabled ACs, WMM STA should only
use trigger frames to retrieve MSDUs and MMPDUs belonging to
those ACs, and it should not send PS-Poll frames.
Different definitions in IEEE802.11e and WMM spec.
But we follow the WiFi WMM Spec.
*/
DBGPRINT(RT_DEBUG_TRACE, ("All AC are UAPSD, can not use PS-Poll\n"));
return; /* all AC are U-APSD, can not use PS-Poll */
}
#endif /* UAPSD_SUPPORT */
/* Reset ContinueTxFailCnt */
pMacEntry->ContinueTxFailCnt = 0;
pAd->MacTab.tr_entry[pMacEntry->wcid].ContinueTxFailCnt = 0;
if (isActive == FALSE)
{
if (tr_entry->PsDeQWaitCnt == 0) {
tr_entry->PsDeQWaitCnt = 1;
} else {
DBGPRINT(RT_DEBUG_TRACE,
("%s(): : packet not send by HW then ignore other PS-Poll Aid[%d]!\n",
__FUNCTION__, pMacEntry->Aid));
return;
}
}
else
tr_entry->PsDeQWaitCnt = 0;
#ifdef CONFIG_AP_SUPPORT
#ifdef MT_MAC
if (pAd->chipCap.hif_type == HIF_MT)
{
MtHandleRxPsPoll(pAd, pAddr, wcid, isActive);
}
#endif /* MT_MAC */
#if defined(RTMP_MAC) || defined(RLT_MAC)
if ((pAd->chipCap.hif_type == HIF_RTMP)
|| (pAd->chipCap.hif_type == HIF_RLT))
{
RalHandleRxPsPoll(pAd, pAddr, wcid, isActive);
}
#endif /* RTMP_MAC || RLT_MAC */
#endif /* CONFIG_AP_SUPPORT */
}
/*
==========================================================================
Description:
Update the station current power save mode. Calling this routine also
prove the specified client is still alive. Otherwise AP will age-out
this client once IdleCount exceeds a threshold.
==========================================================================
*/
BOOLEAN RtmpPsIndicate(RTMP_ADAPTER *pAd, UCHAR *pAddr, UCHAR wcid, UCHAR Psm)
{
#ifdef MT_MAC
if (pAd->chipCap.hif_type == HIF_MT)
{
return MtPsIndicate(pAd, pAddr, wcid, Psm);
}
#endif /* MT_MAC */
#if defined(RTMP_MAC) || defined(RLT_MAC)
if ((pAd->chipCap.hif_type == HIF_RTMP)
|| (pAd->chipCap.hif_type == HIF_RLT))
{
return RalPsIndicate(pAd, pAddr, wcid, Psm);
}
#endif /* RTMP_MAC || RLT_MAC */
return FALSE;
}
#ifdef CONFIG_STA_SUPPORT
/*
========================================================================
Routine Description:
Check if PM of any packet is set.
Arguments:
pAd Pointer to our adapter
Return Value:
TRUE can set
FALSE can not set
Note:
========================================================================
*/
BOOLEAN RtmpPktPmBitCheck(RTMP_ADAPTER *pAd)
{
BOOLEAN FlgCanPmBitSet = TRUE;
#ifdef DOT11Z_TDLS_SUPPORT
/* check TDLS condition */
if (pAd->StaCfg.TdlsInfo.TdlsFlgIsKeepingActiveCountDown == TRUE)
FlgCanPmBitSet = FALSE;
#endif /* DOT11Z_TDLS_SUPPORT */
if (FlgCanPmBitSet == TRUE)
return (pAd->StaCfg.PwrMgmt.Psm == PWR_SAVE);
return FALSE;
}
VOID RtmpPsActiveExtendCheck(RTMP_ADAPTER *pAd)
{
/* count down the TDLS active counter */
#ifdef DOT11Z_TDLS_SUPPORT
if (pAd->StaCfg.TdlsInfo.TdlsPowerSaveActiveCountDown > 0)
{
pAd->StaCfg.TdlsInfo.TdlsPowerSaveActiveCountDown --;
if (pAd->StaCfg.TdlsInfo.TdlsPowerSaveActiveCountDown == 0)
{
/* recover our power save state */
TDLS_RECOVER_POWER_SAVE(pAd);
DBGPRINT(RT_DEBUG_TRACE, ("TDLS PS> Recover PS mode!\n"));
}
}
#endif /* DOT11Z_TDLS_SUPPORT */
}
VOID RtmpPsModeChange(RTMP_ADAPTER *pAd, UINT32 PsMode)
{
if (pAd->StaCfg.BssType == BSS_INFRA)
{
/* reset ps mode */
if (PsMode == Ndis802_11PowerModeMAX_PSP)
{
// do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange()
// to exclude certain situations.
// MlmeSetPsm(pAd, PWR_SAVE);
OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM);
if (pAd->StaCfg.bWindowsACCAMEnable == FALSE)
pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeMAX_PSP;
pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeMAX_PSP;
pAd->StaCfg.DefaultListenCount = 5;
}
else if (PsMode == Ndis802_11PowerModeFast_PSP)
{
// do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange()
// to exclude certain situations.
OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM);
if (pAd->StaCfg.bWindowsACCAMEnable == FALSE)
pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeFast_PSP;
pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeFast_PSP;
pAd->StaCfg.DefaultListenCount = 3;
}
else if (PsMode == Ndis802_11PowerModeLegacy_PSP)
{
// do NOT turn on PSM bit here, wait until MlmeCheckForPsmChange()
// to exclude certain situations.
OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM);
if (pAd->StaCfg.bWindowsACCAMEnable == FALSE)
pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeLegacy_PSP;
pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeLegacy_PSP;
#if defined(DOT11Z_TDLS_SUPPORT) || defined(CFG_TDLS_SUPPORT)
pAd->StaCfg.DefaultListenCount = 1;
#else
pAd->StaCfg.DefaultListenCount = 3;
#endif // defined(DOT11Z_TDLS_SUPPORT) || defined(CFG_TDLS_SUPPORT) //
}
else
{ //Default Ndis802_11PowerModeCAM
// clear PSM bit immediately
RTMP_SET_PSM_BIT(pAd, PWR_ACTIVE);
OPSTATUS_SET_FLAG(pAd, fOP_STATUS_RECEIVE_DTIM);
if (pAd->StaCfg.bWindowsACCAMEnable == FALSE)
pAd->StaCfg.WindowsPowerMode = Ndis802_11PowerModeCAM;
pAd->StaCfg.WindowsBatteryPowerMode = Ndis802_11PowerModeCAM;
}
/* change ps mode */
RTMPSendNullFrame(pAd, pAd->CommonCfg.TxRate, TRUE, FALSE);
DBGPRINT(RT_DEBUG_TRACE, ("PSMode=%ld\n", pAd->StaCfg.WindowsPowerMode));
}
}
#endif /* CONFIG_STA_SUPPORT */