blob: fd97f312bbe865d9e8b16d80f6fed38be50d523b [file] [log] [blame]
/******************************************************************************
*
* This file is provided under a dual license. When you use or
* distribute this software, you may choose to be licensed under
* version 2 of the GNU General Public License ("GPLv2 License")
* or BSD License.
*
* GPLv2 License
*
* Copyright(C) 2016 MediaTek Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See http://www.gnu.org/licenses/gpl-2.0.html for more details.
*
* BSD LICENSE
*
* Copyright(C) 2016 MediaTek Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
/*
** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/mgmt/rate.c#1
*/
/*! \file "rate.c"
* \brief This file contains the transmission rate handling routines.
*
* This file contains the transmission rate handling routines for setting up
* ACK/CTS Rate, Highest Tx Rate, Lowest Tx Rate, Initial Tx Rate and do
* conversion between Rate Set and Data Rates.
*/
/*******************************************************************************
* C O M P I L E R F L A G S
********************************************************************************
*/
/*******************************************************************************
* E X T E R N A L R E F E R E N C E S
********************************************************************************
*/
#include "precomp.h"
/*******************************************************************************
* C O N S T A N T S
********************************************************************************
*/
/* The list of valid data rates. */
const UINT_8 aucDataRate[] = {
RATE_1M, /* RATE_1M_INDEX = 0 */
RATE_2M, /* RATE_2M_INDEX */
RATE_5_5M, /* RATE_5_5M_INDEX */
RATE_11M, /* RATE_11M_INDEX */
RATE_22M, /* RATE_22M_INDEX */
RATE_33M, /* RATE_33M_INDEX */
RATE_6M, /* RATE_6M_INDEX */
RATE_9M, /* RATE_9M_INDEX */
RATE_12M, /* RATE_12M_INDEX */
RATE_18M, /* RATE_18M_INDEX */
RATE_24M, /* RATE_24M_INDEX */
RATE_36M, /* RATE_36M_INDEX */
RATE_48M, /* RATE_48M_INDEX */
RATE_54M, /* RATE_54M_INDEX */
RATE_VHT_PHY, /* RATE_VHT_PHY_INDEX */
RATE_HT_PHY /* RATE_HT_PHY_INDEX */
};
static const UINT_8 aucDefaultAckCtsRateIndex[RATE_NUM_SW] = {
RATE_1M_SW_INDEX, /* RATE_1M_SW_INDEX = 0 */
RATE_2M_SW_INDEX, /* RATE_2M_SW_INDEX */
RATE_5_5M_SW_INDEX, /* RATE_5_5M_SW_INDEX */
RATE_11M_SW_INDEX, /* RATE_11M_SW_INDEX */
RATE_1M_SW_INDEX, /* RATE_22M_SW_INDEX - Not supported */
RATE_1M_SW_INDEX, /* RATE_33M_SW_INDEX - Not supported */
RATE_6M_SW_INDEX, /* RATE_6M_SW_INDEX */
RATE_6M_SW_INDEX, /* RATE_9M_SW_INDEX */
RATE_12M_SW_INDEX, /* RATE_12M_SW_INDEX */
RATE_12M_SW_INDEX, /* RATE_18M_SW_INDEX */
RATE_24M_SW_INDEX, /* RATE_24M_SW_INDEX */
RATE_24M_SW_INDEX, /* RATE_36M_SW_INDEX */
RATE_24M_SW_INDEX, /* RATE_48M_SW_INDEX */
RATE_24M_SW_INDEX /* RATE_54M_SW_INDEX */
};
const BOOLEAN afgIsOFDMRate[RATE_NUM_SW] = {
FALSE, /* RATE_1M_INDEX = 0 */
FALSE, /* RATE_2M_INDEX */
FALSE, /* RATE_5_5M_INDEX */
FALSE, /* RATE_11M_INDEX */
FALSE, /* RATE_22M_INDEX - Not supported */
FALSE, /* RATE_33M_INDEX - Not supported */
TRUE, /* RATE_6M_INDEX */
TRUE, /* RATE_9M_INDEX */
TRUE, /* RATE_12M_INDEX */
TRUE, /* RATE_18M_INDEX */
TRUE, /* RATE_24M_INDEX */
TRUE, /* RATE_36M_INDEX */
TRUE, /* RATE_48M_INDEX */
TRUE /* RATE_54M_INDEX */
};
/*******************************************************************************
* D A T A T Y P E S
********************************************************************************
*/
/*******************************************************************************
* P U B L I C D A T A
********************************************************************************
*/
/*******************************************************************************
* P R I V A T E D A T A
********************************************************************************
*/
/*******************************************************************************
* M A C R O S
********************************************************************************
*/
/*******************************************************************************
* F U N C T I O N D E C L A R A T I O N S
********************************************************************************
*/
/*******************************************************************************
* F U N C T I O N S
********************************************************************************
*/
/*----------------------------------------------------------------------------*/
/*!
* @brief Convert the given Supported Rate & Extended Supported Rate IE to the
* Operational Rate Set and Basic Rate Set, and also check if any Basic
* Rate Code is unknown by driver.
*
* @param[in] prIeSupportedRate Pointer to the Supported Rate IE
* @param[in] prIeExtSupportedRate Pointer to the Ext Supported Rate IE
* @param[out] pu2OperationalRateSet Pointer to the Operational Rate Set
* @param[out] pu2BSSBasicRateSet Pointer to the Basic Rate Set
* @param[out] pfgIsUnknownBSSBasicRate Pointer to a Flag to indicate that Basic
* Rate Set has unknown Rate Code
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
VOID
rateGetRateSetFromIEs(IN P_IE_SUPPORTED_RATE_T prIeSupportedRate,
IN P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate,
OUT PUINT_16 pu2OperationalRateSet,
OUT PUINT_16 pu2BSSBasicRateSet, OUT PBOOLEAN pfgIsUnknownBSSBasicRate)
{
UINT_16 u2OperationalRateSet = 0;
UINT_16 u2BSSBasicRateSet = 0;
BOOLEAN fgIsUnknownBSSBasicRate = FALSE;
UINT_8 ucRate;
UINT_32 i, j;
ASSERT(pu2OperationalRateSet);
ASSERT(pu2BSSBasicRateSet);
ASSERT(pfgIsUnknownBSSBasicRate);
if (prIeSupportedRate) {
/* NOTE(Kevin): Buffalo WHR-G54S's supported rate set IE exceed 8.
* IE_LEN(pucIE) == 12, "1(B), 2(B), 5.5(B), 6(B), 9(B), 11(B),
* 12(B), 18(B), 24(B), 36(B), 48(B), 54(B)"
*/
/* ASSERT(prIeSupportedRate->ucLength <= ELEM_MAX_LEN_SUP_RATES); */
ASSERT(prIeSupportedRate->ucLength <= RATE_NUM_SW);
for (i = 0; i < prIeSupportedRate->ucLength; i++) {
ucRate = prIeSupportedRate->aucSupportedRates[i] & RATE_MASK;
/* Search all valid data rates */
for (j = 0; j < sizeof(aucDataRate) / sizeof(UINT_8); j++) {
if (ucRate == aucDataRate[j]) {
u2OperationalRateSet |= BIT(j);
if (prIeSupportedRate->aucSupportedRates[i] & RATE_BASIC_BIT)
u2BSSBasicRateSet |= BIT(j);
break;
}
}
if ((j == sizeof(aucDataRate) / sizeof(UINT_8)) &&
(prIeSupportedRate->aucSupportedRates[i] & RATE_BASIC_BIT)) {
fgIsUnknownBSSBasicRate = TRUE; /* A data rate not list in the aucDataRate[] */
}
}
}
if (prIeExtSupportedRate) {
/* ASSERT(prIeExtSupportedRate->ucLength <= ELEM_MAX_LEN_EXTENDED_SUP_RATES); */
for (i = 0; i < prIeExtSupportedRate->ucLength; i++) {
ucRate = prIeExtSupportedRate->aucExtSupportedRates[i] & RATE_MASK;
/* Search all valid data rates */
for (j = 0; j < sizeof(aucDataRate) / sizeof(UINT_8); j++) {
if (ucRate == aucDataRate[j]) {
u2OperationalRateSet |= BIT(j);
if (prIeExtSupportedRate->aucExtSupportedRates[i] & RATE_BASIC_BIT)
u2BSSBasicRateSet |= BIT(j);
break;
}
}
if ((j == sizeof(aucDataRate) / sizeof(UINT_8)) &&
(prIeExtSupportedRate->aucExtSupportedRates[i] & RATE_BASIC_BIT)) {
fgIsUnknownBSSBasicRate = TRUE; /* A data rate not list in the aucDataRate[] */
}
}
}
*pu2OperationalRateSet = u2OperationalRateSet;
*pu2BSSBasicRateSet = u2BSSBasicRateSet;
*pfgIsUnknownBSSBasicRate = fgIsUnknownBSSBasicRate;
return;
} /* end of rateGetRateSetFromIEs() */
/*----------------------------------------------------------------------------*/
/*!
* @brief Convert the given Operational Rate Set & Basic Rate Set to the Rate Code
* Format for used in (Ext)Supportec Rate IE.
*
* @param[in] u2OperationalRateSet Operational Rate Set
* @param[in] u2BSSBasicRateSet Basic Rate Set
* @param[out] pucDataRates Pointer to the Data Rate Buffer
* @param[out] pucDataRatesLen Pointer to the Data Rate Buffer Length
*
* @return (none)
*/
/*----------------------------------------------------------------------------*/
VOID
rateGetDataRatesFromRateSet(IN UINT_16 u2OperationalRateSet,
IN UINT_16 u2BSSBasicRateSet, OUT PUINT_8 pucDataRates, OUT PUINT_8 pucDataRatesLen)
{
UINT_32 i, j;
ASSERT(pucDataRates);
ASSERT(pucDataRatesLen);
ASSERT(u2BSSBasicRateSet == (u2OperationalRateSet & u2BSSBasicRateSet));
for (i = RATE_1M_SW_INDEX, j = 0; i < RATE_NUM_SW; i++) {
if (u2OperationalRateSet & BIT(i)) {
*(pucDataRates + j) = aucDataRate[i];
if (u2BSSBasicRateSet & BIT(i))
*(pucDataRates + j) |= RATE_BASIC_BIT;
j++;
}
}
*pucDataRatesLen = (UINT_8) j;
return;
} /* end of rateGetDataRatesFromRateSet() */
/*----------------------------------------------------------------------------*/
/*!
* \brief Get the highest rate from given Rate Set.
*
* \param[in] u2RateSet Rate Set
* \param[out] pucHighestRateIndex Pointer to buffer of the Highest Rate Index
*
* \retval TRUE Highest Rate Index was found
* \retval FALSE Highest Rate Index was not found
*/
/*----------------------------------------------------------------------------*/
BOOLEAN rateGetHighestRateIndexFromRateSet(IN UINT_16 u2RateSet, OUT PUINT_8 pucHighestRateIndex)
{
INT_32 i;
ASSERT(pucHighestRateIndex);
for (i = RATE_54M_SW_INDEX; i >= RATE_1M_SW_INDEX; i--) {
if (u2RateSet & BIT(i)) {
*pucHighestRateIndex = (UINT_8) i;
return TRUE;
}
}
return FALSE;
} /* end of rateGetHighestRateIndexFromRateSet() */
/*----------------------------------------------------------------------------*/
/*!
* \brief Get the lowest rate from given Rate Set.
*
* \param[in] u2RateSet Rate Set
* \param[out] pucLowestRateIndex Pointer to buffer of the Lowest Rate Index
*
* \retval TRUE Lowest Rate Index was found
* \retval FALSE Lowest Rate Index was not found
*/
/*----------------------------------------------------------------------------*/
BOOLEAN rateGetLowestRateIndexFromRateSet(IN UINT_16 u2RateSet, OUT PUINT_8 pucLowestRateIndex)
{
UINT_32 i;
ASSERT(pucLowestRateIndex);
for (i = RATE_1M_SW_INDEX; i <= RATE_54M_SW_INDEX; i++) {
if (u2RateSet & BIT(i)) {
*pucLowestRateIndex = (UINT_8) i;
return TRUE;
}
}
return FALSE;
} /* end of rateGetLowestRateIndexFromRateSet() */
#if 0 /* NOTE(Kevin): For reference */
/*----------------------------------------------------------------------------*/
/*!
* \brief Convert the given Data Rates to the Rate Set.
*
* \param[in] pucDataRates Pointer to the Data Rates
* \param[in] ucDataRatesLen Length of given Data Rates
* \param[out] pu2RateSet Pointer to the Rate Set
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
VOID rateGetRateSetFromDataRates(IN PUINT_8 pucDataRates, IN UINT_8 ucDataRatesLen, OUT PUINT_16 pu2RateSet)
{
UINT_16 u2RateSet = 0;
UINT_8 ucRate;
UINT_32 i, j;
ASSERT(pucDataRates);
ASSERT(pu2RateSet);
if (pucDataRates) {
for (i = 0; i < ucDataRatesLen; i++) {
ucRate = pucDataRates[i] & RATE_MASK;
/* Search all valid data rates */
for (j = 0; j < sizeof(aucDataRate) / sizeof(UINT_8); j++) {
if (ucRate == aucDataRate[j]) {
u2RateSet |= BIT(j);
break;
}
}
}
}
*pu2RateSet = u2RateSet;
return;
} /* end of rateGetRateSetFromDataRates() */
/*----------------------------------------------------------------------------*/
/*!
* \brief Parse the Operational Rate Set and Basic Rate Set to get the corresponding
* ACK/CTS(Respnose) TX Rates.
*
* \param[in] u2OperationalRateSet Operational Rate Set
* \param[in] u2BSSBasicRateSet Basic Rate Set
* \param[out] aucAckCtsRateIndex Pointer to the Ack/Cts Data Rate Buffer
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
VOID
rateSetAckCtsDataRatesFromRateSet(IN UINT_16 u2OperationalRateSet,
IN UINT_16 u2BSSBasicRateSet, IN OUT UINT_8 aucAckCtsRateIndex[])
{
INT_32 i, j;
ASSERT(aucAckCtsRateIndex);
ASSERT(u2BSSBasicRateSet == (u2OperationalRateSet & u2BSSBasicRateSet));
/* Setup default ACK/CTS response rate */
kalMemCopy(aucAckCtsRateIndex, (PVOID) aucDefaultAckCtsRateIndex, sizeof(aucDefaultAckCtsRateIndex));
for (i = RATE_54M_INDEX; i >= RATE_1M_INDEX; i--) {
if (u2OperationalRateSet & BIT(i)) {
for (j = i; j >= RATE_1M_INDEX; j--) {
if (u2BSSBasicRateSet & BIT(j)) {
/* Reply ACK Frame at the same Modulation Scheme. */
if ((afgIsOFDMRate[i] && afgIsOFDMRate[j]) ||
(!afgIsOFDMRate[i] && !afgIsOFDMRate[j]))
aucAckCtsRateIndex[i] = (UINT_8) j;
break;
}
}
/* NOTE(Kevin 2008/03/25): Following code is used for those AP which has
* NULL BasicRateSet.
* e.g. If input Operational Rate Set = [18M 12M 9M], Basic Rate Set = NULL.
* Originally we'll get Ack Rate for [18M 12M 9M] is [12M 12M "6M"].
* Now we'll get Ack Rate for [18M 12M 9M] is [12M 12M 9M],
* The Ack Rate for Tx Rates which are not list in Operational Rate Set is still
* use highest mandatory rate as default.
*/
if (j < RATE_1M_INDEX) { /* The ACK/CTS rate was not found in BasicRateSet */
if (!(BIT(aucAckCtsRateIndex[i]) & u2OperationalRateSet))
aucAckCtsRateIndex[i] = (UINT_8) i;
}
}
}
return;
} /* end of rateSetAckCtsDataRatesFromRateSet() */
/*----------------------------------------------------------------------------*/
/*!
* \brief Get the proper initial rate from Rate Set according to given RCPI value
*
* \param[in] u2RateSet Rate Set
* \param[in] rRcpi RCPI value from AP or Peer STA
* \param[out] pucInitialRateIndex Pointer to buffer of the initial Rate Index
*
* \retval TRUE Initial Rate Index was found
* \retval FALSE Initial Rate Index was not found
*/
/*----------------------------------------------------------------------------*/
BOOLEAN rateGetBestInitialRateIndex(IN UINT_16 u2RateSet, IN RCPI rRcpi, OUT PUINT_8 pucInitialRateIndex)
{
UINT_16 u2InitRateSet;
INT_32 i;
ASSERT(pucInitialRateIndex);
DBGLOG(MGT, TRACE, "rRcpi = %d\n", rRcpi);
if (rRcpi >= RCPI_100) { /* Best Signal */
u2InitRateSet = INITIAL_RATE_SET(RCPI_100);
} else if (rRcpi >= RCPI_80) { /* Better Signal */
u2InitRateSet = INITIAL_RATE_SET(RCPI_80);
} else if (rRcpi >= RCPI_60) { /* Good Signal */
u2InitRateSet = INITIAL_RATE_SET(RCPI_60);
} else { /* Worse Signal */
/* NOTE(Kevin): If return FALSE, we should assign the BSS Basic Rate Index
* (prBssInfo->ucBasicRateIndex) to the initial rate. It was determined in
* function - bssUpdateTxRateForControlFrame().
*/
return FALSE;
}
u2RateSet &= u2InitRateSet;
for (i = RATE_54M_INDEX; i >= RATE_1M_INDEX; i--) {
if (u2RateSet & BIT(i)) {
*pucInitialRateIndex = (UINT_8) i;
return TRUE;
}
}
return FALSE;
} /* end of rateGetBestInitialRateIndex() */
#endif