From aa6f5ffbdba45aa8e19e5048648fc6c7b25376d3 Mon Sep 17 00:00:00 2001 From: merge Date: Thu, 22 Jan 2009 13:55:32 +0000 Subject: MERGE-via-pending-tracking-hist-MERGE-via-stable-tracking-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040-1232632141 pending-tracking-hist top was MERGE-via-stable-tracking-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040-1232632141 / fdf777a63bcb59e0dfd78bfe2c6242e01f6d4eb9 ... parent commitmessage: From: merge MERGE-via-stable-tracking-hist-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040 stable-tracking-hist top was MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040 / 90463bfd2d5a3c8b52f6e6d71024a00e052b0ced ... parent commitmessage: From: merge MERGE-via-mokopatches-tracking-hist-fix-stray-endmenu-patch mokopatches-tracking-hist top was fix-stray-endmenu-patch / 3630e0be570de8057e7f8d2fe501ed353cdf34e6 ... parent commitmessage: From: Andy Green fix-stray-endmenu.patch Signed-off-by: Andy Green --- drivers/staging/otus/80211core/ratectrl.c | 874 ++++++++++++++++++++++++++++++ 1 file changed, 874 insertions(+) create mode 100644 drivers/staging/otus/80211core/ratectrl.c (limited to 'drivers/staging/otus/80211core/ratectrl.c') diff --git a/drivers/staging/otus/80211core/ratectrl.c b/drivers/staging/otus/80211core/ratectrl.c new file mode 100644 index 00000000000..a43104cd7f5 --- /dev/null +++ b/drivers/staging/otus/80211core/ratectrl.c @@ -0,0 +1,874 @@ +/* + * Copyright (c) 2007-2008 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "cprecomp.h" +#include "ratectrl.h" + +const u32_t zcRateToPhyCtrl[] = + { + /* 1M, 2M, 5M, 11M , 0 1 2 3*/ + 0x00000, 0x10000, 0x20000, 0x30000, + /* 6M 9M 12M 18M , 4 5 6 7*/ + 0xb0001, 0xf0001, 0xa0001, 0xe0001, + /* 24M 36M 48M 54M , 8 9 10 11*/ + 0x90001, 0xd0001, 0x80001, 0xc0001, + /* MCS0 MCS1 MCS2 MCS3, 12 13 14 15*/ + 0x00002, 0x10002, 0x20002, 0x30002, + /* MCS4 MCS5 MCS6 MCS7, 16 17 18 19*/ + 0x40002, 0x50002, 0x60002, 0x70002, + /* MCS8 MCS9 MCS10 MCS11, 20 21 22 23*/ + 0x80002, 0x90002, 0xa0002, 0xb0002, + /* MCS12 MCS13 MCS14 MCS15, 24 25 26 27*/ + 0xc0002, 0xd0002, 0xe0002, 0xf0002, + /* MCS14SG, MCS15SG MCS7SG , 28 29, 30*/ + 0x800e0002, 0x800f0002, 0x80070002 + }; + + +const u8_t zcHtRateTable[15][4] = + { /*[5G 20MHz] [5G 40MHz] [2.4G 20MHz] [2.4G 40MHz]*/ + { 4, 4, 0, 0}, /*OFDM6M OFDM6M CCK1M CCK1M */ + { 5, 5, 1, 1}, /*OFDM9M OFDM9M CCK2M CCK2M */ + { 13, 12, 2, 2}, /*MCS1 MCS0 CCK5M CCK5M */ + { 14, 13, 3, 3}, /*MCS2 MCS1 CCK11M CCK11M */ + { 15, 14, 13, 12}, /*MCS3 MCS2 MCS1 MCS0 */ + { 16, 15, 14, 13}, /*MCS4 MCS3 MCS2 MCS1 */ + { 23, 16, 15, 14}, /*MCS11 MCS4 MCS3 MCS2 */ + { 24, 23, 16, 15}, /*MCS12 MCS11 MCS4 MCS3 */ + { 25, 24, 23, 16}, /*MCS13 MCS12 MCS11 MCS4 */ + { 26, 25, 24, 23}, /*MCS14 MCS13 MCS12 MCS11 */ + { 27, 26, 25, 24}, /*MCS15 MCS14 MCS13 MCS12 */ + { 0, 27, 26, 25}, /*0 MCS15 MCS14 MCS13 */ + { 0, 29, 27, 26}, /*0 MCS15SG MCS15 MCS14 */ + { 0, 0, 0, 28}, /*0 0 0 MCS14SG*/ + { 0, 0, 0, 29} /*0 0 0 MCS15SG*/ + }; + +const u8_t zcHtOneTxStreamRateTable[15][4] = + { /*[5G 20MHz] [5G 40MHz] [2.4G 20MHz] [2.4G 40MHz]*/ + { 4, 4, 0, 0}, /*OFDM6M OFDM6M CCK1M CCK1M */ + { 5, 5, 1, 1}, /*OFDM9M OFDM9M CCK2M CCK2M */ + { 13, 12, 2, 2}, /*MCS1 MCS0 CCK5M CCK5M */ + { 14, 13, 3, 3}, /*MCS2 MCS1 CCK11M CCK11M */ + { 15, 14, 13, 12}, /*MCS3 MCS2 MCS1 MCS0 */ + { 16, 15, 14, 13}, /*MCS4 MCS3 MCS2 MCS1 */ + { 17, 16, 15, 14}, /*MCS5 MCS4 MCS3 MCS2 */ + { 18, 17, 16, 15}, /*MCS6 MCS5 MCS4 MCS3 */ + { 19, 18, 17, 16}, /*MCS7 MCS6 MCS5 MCS4 */ + { 0, 19, 18, 17}, /*0 MCS7 MCS6 MCS5 */ + { 0, 30, 19, 18}, /*0 MCS7SG MCS7 MCS6 */ + { 0, 0, 0, 19}, /*0 0 0 MCS7 */ + { 0, 0, 0, 30}, /*0 0 0 MCS7SG */ + { 0, 0, 0, 0 }, /*0 0 0 0 */ + { 0, 0, 0, 0 } /*0 0 0 0 */ + }; + +const u16_t zcRate[] = + { + 1, 2, 5, 11, /* 1M, 2M, 5M, 11M , 0 1 2 3*/ + 6, 9, 12, 18, /* 6M 9M 12M 18M , 4 5 6 7*/ + 24, 36, 48, 54, /* 24M 36M 48M 54M , 8 9 10 11*/ + 13, 27, 40, 54, /* MCS0 MCS1 MCS2 MCS3 , 12 13 14 15*/ + 81, 108, 121, 135, /* MCS4 MCS5 MCS6 MCS7 , 16 17 18 19*/ + 27, 54, 81, 108, /* MCS8 MCS9 MCS10 MCS11 , 20 21 22 23*/ + 162, 216, 243, 270, /* MCS12 MCS13 MCS14 MCS15 , 24 25 26 27*/ + 270, 300, 150 /* MCS14SG, MCS15SG, MCS7SG , 28 29 30*/ + }; + +const u16_t PERThreshold[] = + { + 100, 50, 50, 50, /* 1M, 2M, 5M, 11M , 0 1 2 3*/ + 50, 50, 30, 30, /* 6M 9M 12M 18M , 4 5 6 7*/ + 25, 25, 25, 20, /* 24M 36M 48M 54M , 8 9 10 11*/ + 50, 50, 50, 40, /* MCS0 MCS1 MCS2 MCS3 , 12 13 14 15*/ + 30, 30, 30, 30, /* MCS4 MCS5 MCS6 MCS7 , 16 17 18 19*/ + 30, 30, 25, 25, /* MCS8 MCS9 MCS10 MCS11 , 20 21 22 23*/ + 25, 25, 15, 15, /* MCS12 MCS13 MCS14 MCS15 , 24 25 26 27*/ + 15, 15, 10 /* MCS14SG, MCS15SG , 28 29*/ + }; + +const u16_t FailDiff[] = + { + 40, 46, 40, 0, /* 1M, 2M, 5M, 11M , 0 1 2 3*/ + 24, 17, 22, 16, /* 6M 9M 12M 18M , 4 5 6 7*/ + 19, 13, 5, 0, /* 24M 36M 48M 54M , 8 9 10 11*/ + 36, 22, 15, 19, /* MCS0 MCS1 MCS2 MCS3 , 12 13 14 15*/ + 12, 5, 4, 7, /* MCS4 MCS5 MCS6 MCS7 , 16 17 18 19*/ + 0, 0, 0, 0, /* MCS8 MCS9 MCS10 MCS11 , 20 21 22 23*/ + 9, 4, 3, 3, /* MCS12 MCS13 MCS14 MCS15 , 24 25 26 27*/ + 3, 0, 0 /* MCS14SG, MCS15SG , 28 29*/ + }; + + +#ifdef ZM_ENABLE_BA_RATECTRL +u32_t TxMPDU[29]; +u32_t BAFail[29]; +u32_t BAPER[29]; +const u16_t BADiff[] = + { + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 361, 220, 151, 187, + 122, 48, 41, 65, + 0, 0, 0, 0, + 88, 33, 27, 25, + 0 + }; +#endif + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfRateCtrlInitCell */ +/* Initialize rate control cell. */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* type : 0=>11b, 1=>11a/g, 2=>11n, 3=>11n one Tx stream */ +/* gBand : 1=>2.4G, 0=>5G */ +/* */ +/* OUTPUTS */ +/* None */ +/* */ +/* AUTHOR */ +/* Stephen Chen Atheros Communications, INC. 2007.2 */ +/* */ +/************************************************************************/ +void zfRateCtrlInitCell(zdev_t* dev, struct zsRcCell* rcCell, u8_t type, + u8_t gBand, u8_t SG40) +{ + u8_t i; + u8_t maxrate; + zmw_get_wlan_dev(dev); + + if (SG40) SG40 = 1; + + if (gBand != 0) + { + if (type == 1) //11g + { + for (i=0; i<4; i++) //1M 2M 5M 11M + { + rcCell->operationRateSet[i] = (u8_t)i; + } + for (i=4; i<10; i++) //12M 18M 24M 36M 48M 54M + { + rcCell->operationRateSet[i] = 2+i; + } + rcCell->operationRateCount = 10; + rcCell->currentRateIndex = 5; //18M + } + else if (type == 2) //11ng + { + if (wd->wlanMode == ZM_MODE_AP) //AP 11ng 40M + { + for (i=0; i<15; i++) + { + rcCell->operationRateSet[i] = zcHtRateTable[i][3]; + } + if(!SG40) rcCell->operationRateSet[13] = 27; + rcCell->operationRateCount = 14+SG40; + rcCell->currentRateIndex = 10; + } + else //STA + { + if (wd->sta.htCtrlBandwidth == ZM_BANDWIDTH_40MHZ) //11ng 40M + { + for (i=0; i<15; i++) + { + rcCell->operationRateSet[i] = zcHtRateTable[i][3]; + } + if(!SG40) rcCell->operationRateSet[13] = 27; + rcCell->operationRateCount = 14+SG40; + rcCell->currentRateIndex = 10; + } + else //11ng 20M + { + for (i=0; i<13; i++) + { + rcCell->operationRateSet[i] = zcHtRateTable[i][2]; + } + rcCell->operationRateCount = 13; + rcCell->currentRateIndex = 9; + } + } + } + else if (type == 3) //11ng one Tx stream + { + if (wd->sta.htCtrlBandwidth == ZM_BANDWIDTH_40MHZ) //11ng 40M one Tx stream + { + if(SG40 != 0) + { + maxrate = 13; + } + else + { + maxrate = 12; + } + for (i=0; ioperationRateSet[i] = zcHtOneTxStreamRateTable[i][3]; + } + rcCell->operationRateCount = i; + rcCell->currentRateIndex = ((i+1)*3)/4; + } + else //11ng 20M + { + for (i=0; i<11; i++) + { + rcCell->operationRateSet[i] = zcHtOneTxStreamRateTable[i][2]; + } + rcCell->operationRateCount = i; + rcCell->currentRateIndex = ((i+1)*3)/4; + } + } + else //if (type == 0) //11b + { + for (i=0; i<4; i++) + { + rcCell->operationRateSet[i] = (u8_t)i; + } + rcCell->operationRateCount = 4; + rcCell->currentRateIndex = rcCell->operationRateCount-1; + } + } + else + { + if (type == 2) //11na + { + if (wd->wlanMode == ZM_MODE_AP) //AP 11na 40M + { + for (i=0; i<(12+SG40); i++) + { + rcCell->operationRateSet[i] = zcHtRateTable[i][1]; + } + rcCell->operationRateCount = 12+SG40; + rcCell->currentRateIndex = 8; + } + else //STA + { + if (wd->sta.htCtrlBandwidth == ZM_BANDWIDTH_40MHZ) //11na 40M + { + for (i=0; i<(12+SG40); i++) + { + rcCell->operationRateSet[i] = zcHtRateTable[i][1]; + } + rcCell->operationRateCount = 12+SG40; + rcCell->currentRateIndex = 8; + } + else //11na 20M + { + for (i=0; i<11; i++) + { + rcCell->operationRateSet[i] = zcHtRateTable[i][0]; + } + rcCell->operationRateCount = 11; + rcCell->currentRateIndex = 7; + } + } + } + else if (type == 3) //11na one Tx stream + { + if (wd->sta.htCtrlBandwidth == ZM_BANDWIDTH_40MHZ) //11na 40M one Tx stream + { + if(SG40 != 0) + { + maxrate = 11; + } + else + { + maxrate = 10; + } + for (i=0; ioperationRateSet[i] = zcHtOneTxStreamRateTable[i][1]; + } + rcCell->operationRateCount = i; + rcCell->currentRateIndex = ((i+1)*3)/4; + } + else //11ng 20M + { + for (i=0; i<9; i++) + { + rcCell->operationRateSet[i] = zcHtOneTxStreamRateTable[i][0]; + } + rcCell->operationRateCount = i; + rcCell->currentRateIndex = ((i+1)*3)/4; + } + } + else //if (type == 1) //11a + { + for (i=0; i<8; i++) //6M 9M 12M 18M 24M 36M 48M 54M + { + rcCell->operationRateSet[i] = i+4; + } + rcCell->operationRateCount = 8; + rcCell->currentRateIndex = 4; //24M + } + } + + rcCell->flag = 0; + rcCell->txCount = 0; + rcCell->failCount = 0; + rcCell->currentRate = rcCell->operationRateSet[rcCell->currentRateIndex]; + rcCell->lasttxCount = 0; + rcCell->lastTime = wd->tick; + rcCell->probingTime = wd->tick; + for (i=0; iPER[i] = 0; + wd->txMPDU[i] = wd->txFail[i] = 0; + } + wd->probeCount = 0; + wd->probeInterval = 0; +#ifdef ZM_ENABLE_BA_RATECTRL + for (i=0; i<29; i++) { + TxMPDU[i]=0; + BAFail[i]=0; + BAPER[i]=0; + } +#endif + return; +} + + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfRateCtrlGetHigherRate */ +/* Get a higher rate. */ +/* */ +/* INPUTS */ +/* rcCell : rate control cell */ +/* */ +/* OUTPUTS */ +/* rate */ +/* */ +/* AUTHOR */ +/* Stephen Chen Atheros Communications, INC. 2007.2 */ +/* */ +/************************************************************************/ +u8_t zfRateCtrlGetHigherRate(struct zsRcCell* rcCell) +{ + u8_t rateIndex; + + rateIndex = rcCell->currentRateIndex + + (((rcCell->currentRateIndex+1) < rcCell->operationRateCount)?1:0); + return rcCell->operationRateSet[rateIndex]; +} + + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfRateCtrlNextLowerRate */ +/* Get a lower rate. */ +/* */ +/* INPUTS */ +/* rcCell : rate control cell */ +/* */ +/* OUTPUTS */ +/* rate */ +/* */ +/* AUTHOR */ +/* Stephen Chen Atheros Communications, INC. 2007.2 */ +/* */ +/************************************************************************/ +u8_t zfRateCtrlNextLowerRate(zdev_t* dev, struct zsRcCell* rcCell) +{ + zmw_get_wlan_dev(dev); + if (rcCell->currentRateIndex > 0) + { + rcCell->currentRateIndex--; + rcCell->currentRate = rcCell->operationRateSet[rcCell->currentRateIndex]; + } + zm_msg1_tx(ZM_LV_0, "Lower Tx Rate=", rcCell->currentRate); + //DbgPrint("Lower Tx Rate=%d", rcCell->currentRate); + rcCell->failCount = rcCell->txCount = 0; + rcCell->lasttxCount = 0; + rcCell->lastTime = wd->tick; + return rcCell->currentRate; +} + + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfRateCtrlRateDiff */ +/* Rate difference. */ +/* */ +/* INPUTS */ +/* rcCell : rate control cell */ +/* retryRate : retry rate */ +/* */ +/* OUTPUTS */ +/* rate difference */ +/* */ +/* AUTHOR */ +/* Stephen Chen Atheros Communications, INC. 2007.2 */ +/* */ +/************************************************************************/ +u8_t zfRateCtrlRateDiff(struct zsRcCell* rcCell, u8_t retryRate) +{ + u16_t i; + + /* Find retryRate in operationRateSet[] */ + for (i=0; ioperationRateCount; i++) + { + if (retryRate == rcCell->operationRateSet[i]) + { + if (i < rcCell->currentRateIndex) + { + return ((rcCell->currentRateIndex - i)+1)>>1; + } + else if (i == rcCell->currentRateIndex == 0) + { + return 1; + } + else + { + return 0; + } + } + } + /* TODO : retry rate not in operation rate set */ + zm_msg1_tx(ZM_LV_0, "Not in operation rate set:", retryRate); + return 1; + +} + +u32_t zfRateCtrlUDPTP(zdev_t* dev, u16_t Rate, u32_t PER) { + if ((PER < 100) && (Rate > 0) && PER) + return 1168000/(((12304/Rate)+197)*(100+100*PER/(100-PER))); + else + return 0; +} + +u8_t zfRateCtrlFindMaxUDPTP(zdev_t* dev, struct zsRcCell* rcCell) { + u8_t i, maxIndex=0, rateIndex; + u32_t max=0, UDPThroughput; + + zmw_get_wlan_dev(dev); + + rateIndex = zm_agg_min(rcCell->currentRateIndex+3, rcCell->operationRateCount-1); + for (i=rcCell->currentRateIndex; i < rateIndex; i++) { + UDPThroughput = zfRateCtrlUDPTP(dev, zcRate[rcCell->operationRateSet[i]], + wd->PER[rcCell->operationRateSet[i]]); + if (max < UDPThroughput) { + max = UDPThroughput; + maxIndex = i; + } + } + + return rcCell->operationRateSet[maxIndex]; +} +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfRateCtrlGetTxRate */ +/* Get transmission rate. */ +/* */ +/* INPUTS */ +/* dev : device pointer */ +/* rcCell : rate control cell */ +/* probing : rate probing flag */ +/* */ +/* OUTPUTS */ +/* Tx rate */ +/* */ +/* AUTHOR */ +/* Stephen Chen Atheros Communications, INC. 2007.2 */ +/* */ +/************************************************************************/ +u16_t zfRateCtrlGetTxRate(zdev_t* dev, struct zsRcCell* rcCell, u16_t* probing) +{ + u8_t newRate, highRate; + zmw_get_wlan_dev(dev); + + zm_msg1_tx(ZM_LV_3, "txCount=", rcCell->txCount); + zm_msg1_tx(ZM_LV_3, "probingTime=", rcCell->probingTime); + zm_msg1_tx(ZM_LV_3, "tick=", wd->tick); + *probing = 0; + newRate = rcCell->currentRate; + + if (wd->probeCount && (wd->probeCount < wd->success_probing)) + { + if (wd->probeInterval < 50) + { + wd->probeInterval++; + } + else + { + wd->probeInterval++; + if (wd->probeInterval > 52) //probe 51, 52, 53 three packets every 50 packets + { + wd->probeInterval = 0; + } + newRate=zfRateCtrlGetHigherRate(rcCell); + *probing = 1; + wd->probeCount++; + rcCell->probingTime = wd->tick; + } + } + /* Accumulate at least 1000ms and 8 packets or Accumulate over 1K packets */ + else if ((((wd->tick - rcCell->probingTime) > (ZM_RATE_CTRL_PROBING_INTERVAL_MS/ZM_MS_PER_TICK)) + && (rcCell->txCount >= ZM_RATE_CTRL_MIN_PROBING_PACKET)) + || (rcCell->txCount >= 1000)) + { +#ifndef ZM_DISABLE_RATE_CTRL + /* PER = fail/total */ + wd->probeCount = 0; + wd->probeSuccessCount = 0; + if (wd->txMPDU[rcCell->currentRate] != 0) { + wd->PER[rcCell->currentRate] = zm_agg_min(100, + (wd->txFail[rcCell->currentRate]*100)/wd->txMPDU[rcCell->currentRate]); + if (!wd->PER[rcCell->currentRate]) wd->PER[rcCell->currentRate] ++; + } + + /* if PER < threshold, do rate probing, return probing rate */ + if ((wd->PER[rcCell->currentRate] <= (ZM_RATE_PROBING_THRESHOLD+15)) || + ((rcCell->currentRate <= 16) && + ((wd->PER[rcCell->currentRate]/2) <= ZM_RATE_PROBING_THRESHOLD))) + { + if ((newRate=zfRateCtrlGetHigherRate(rcCell)) != rcCell->currentRate) + { + *probing = 1; + wd->probeCount++; + wd->probeInterval = 0; + wd->success_probing = + (rcCell->currentRate <= 16)? (ZM_RATE_SUCCESS_PROBING/2) : ZM_RATE_SUCCESS_PROBING; + //DbgPrint("Start Probing"); + zm_msg1_tx(ZM_LV_0, "Probing Rate=", newRate); + } + } +#endif + + zm_msg0_tx(ZM_LV_1, "Diminish counter"); + rcCell->failCount = rcCell->failCount>>1; + rcCell->txCount = rcCell->txCount>>1; + wd->txFail[rcCell->currentRate] = wd->txFail[rcCell->currentRate] >> 1; + wd->txMPDU[rcCell->currentRate] = wd->txMPDU[rcCell->currentRate] >> 1; + + + if (rcCell->currentRate > 15) { + highRate = zfRateCtrlGetHigherRate(rcCell); + if ((highRate != rcCell->currentRate) && wd->PER[highRate] && + ((wd->PER[rcCell->currentRate] + FailDiff[rcCell->currentRate]) > + wd->PER[highRate])) { + //DbgPrint("PER compare force raise rate to %d", highRate); + wd->probeSuccessCount = wd->probeCount = ZM_RATE_SUCCESS_PROBING; + zfRateCtrlTxSuccessEvent(dev, rcCell, highRate); + } + } + else { + highRate = zfRateCtrlFindMaxUDPTP(dev, rcCell); + if (rcCell->currentRate < highRate) { + //DbgPrint("UDP Throughput compare force raise rate to %d", highRate); + wd->probeSuccessCount = wd->probeCount = ZM_RATE_SUCCESS_PROBING; + zfRateCtrlTxSuccessEvent(dev, rcCell, highRate); + } + } + rcCell->probingTime = wd->tick; + } + + if( (wd->tick > 1000) + && ((wd->tick - rcCell->lastTime) > 3840) ) + { + if (rcCell->lasttxCount < 70) + { + rcCell->failCount = rcCell->failCount>>1; + rcCell->txCount = rcCell->txCount>>1; + wd->txFail[rcCell->currentRate] = wd->txFail[rcCell->currentRate] >> 1; + wd->txMPDU[rcCell->currentRate] = wd->txMPDU[rcCell->currentRate] >> 1; + + rcCell->failCount = (rcCell->failCount < rcCell->txCount)? + rcCell->failCount : rcCell->txCount; + wd->txFail[rcCell->currentRate] = (wd->txFail[rcCell->currentRate] < wd->txMPDU[rcCell->currentRate])? + wd->txFail[rcCell->currentRate] : wd->txMPDU[rcCell->currentRate]; + } + + rcCell->lastTime = wd->tick; + rcCell->lasttxCount = 0; + } + + rcCell->txCount++; + rcCell->lasttxCount++; + wd->txMPDU[rcCell->currentRate]++; + zm_msg1_tx(ZM_LV_1, "Get Tx Rate=", newRate); + return newRate; +} + + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfRateCtrlTxFailEvent */ +/* Tx fail event. Calculate PER and lower Tx rate if under */ +/* PER under threshold. */ +/* */ +/* INPUTS */ +/* rcCell : rate control cell */ +/* retryRate : retry rate */ +/* */ +/* OUTPUTS */ +/* None */ +/* */ +/* AUTHOR */ +/* Stephen Chen Atheros Communications, INC. 2007.2 */ +/* */ +/************************************************************************/ +void zfRateCtrlTxFailEvent(zdev_t* dev, struct zsRcCell* rcCell, u8_t aggRate, u32_t retryRate) +{ + zmw_get_wlan_dev(dev); + + zmw_declare_for_critical_section(); + +#ifndef ZM_DISABLE_RATE_CTRL + //DbgPrint("aggRate=%d, retryRate=%d", aggRate, retryRate); + if (aggRate && (aggRate != rcCell->currentRate)) { + wd->txFail[aggRate] += retryRate; + return; + } + + if (!aggRate) { + retryRate = (zfRateCtrlRateDiff(rcCell, (u8_t)retryRate)+1)>>1; + if (rcCell->currentRate <12) //legacy rate + { + retryRate*=2; + } + } + rcCell->failCount += retryRate; + wd->txFail[rcCell->currentRate] += retryRate; + + //DbgPrint("failCount=%d", rcCell->failCount); + if (rcCell->failCount > ZM_MIN_RATE_FAIL_COUNT) + { + if (wd->txMPDU[rcCell->currentRate] != 0) { + wd->PER[rcCell->currentRate] = zm_agg_min(100, + (wd->txFail[rcCell->currentRate]*100)/wd->txMPDU[rcCell->currentRate]); + if (!wd->PER[rcCell->currentRate]) wd->PER[rcCell->currentRate] ++; + } + //zm_msg1_tx(ZM_LV_1, "PER=", per); + //DbgPrint("PER=%d, txFail=%d, txMPDU=%d", wd->PER[rcCell->currentRate], wd->txFail[rcCell->currentRate], wd->txMPDU[rcCell->currentRate]); + if (wd->PER[rcCell->currentRate] > PERThreshold[rcCell->currentRate]) + { + /* Lower Tx Rate if PER < THRESHOLD */ + zfRateCtrlNextLowerRate(dev, rcCell); + rcCell->flag |= ZM_RC_TRAINED_BIT; + + // Resolve compatibility problem with Marvell + if(rcCell->currentRate == 15) + { + zmw_leave_critical_section(dev); + zfHpSetAggPktNum(dev, 8); + zmw_enter_critical_section(dev); + } + + wd->txFail[rcCell->currentRate] = wd->txFail[rcCell->currentRate] >> 1; + wd->txMPDU[rcCell->currentRate] = wd->txMPDU[rcCell->currentRate] >> 1; + + wd->probeCount = wd->probeSuccessCount = 0; + } + } + +#endif + return; +} + + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfRateCtrlTxSuccessEvent */ +/* Tx success event. Raise Tx rate because rate probing success. */ +/* */ +/* INPUTS */ +/* rcCell : rate control cell */ +/* successRate : success rate */ +/* */ +/* OUTPUTS */ +/* None */ +/* */ +/* AUTHOR */ +/* Stephen Chen Atheros Communications, INC. 2007.2 */ +/* */ +/************************************************************************/ +void zfRateCtrlTxSuccessEvent(zdev_t* dev, struct zsRcCell* rcCell, u8_t successRate) +{ + /* Raise Tx Rate */ + u16_t i, PERProbe; + u16_t pcount; + zmw_get_wlan_dev(dev); + + zmw_declare_for_critical_section(); + + //DbgPrint("Probing successRate=%d", successRate); + /* Find successRate in operationRateSet[] */ + wd->probeSuccessCount++; + if (wd->probeCount < wd->success_probing) + { + return; + } + + pcount = wd->probeCount; + if (pcount != 0) + { + PERProbe = wd->probeSuccessCount * 100 / pcount; + } + else + { + PERProbe = 1; + } + + if (PERProbe < ((rcCell->currentRate < 16)? 80:100)) + { + return; + } + //DbgPrint("wd->probeCount=%d, wd->probeSuccessCount=%d", wd->probeCount, wd->probeSuccessCount); + wd->probeCount = wd->probeSuccessCount = 0; + for (i=0; ioperationRateCount; i++) + { + if (successRate == rcCell->operationRateSet[i]) + { + if (i > rcCell->currentRateIndex) + { + /* Raise current Tx rate */ + zm_msg1_tx(ZM_LV_0, "Raise Tx Rate=", successRate); + //DbgPrint("Raise Tx Rate=%d", successRate); + + // Resolve compatibility problem with Marvell + if((rcCell->currentRate <= 15) && (successRate > 15)) + { + zmw_leave_critical_section(dev); + zfHpSetAggPktNum(dev, 16); + zmw_enter_critical_section(dev); + } + + rcCell->currentRate = successRate; + rcCell->currentRateIndex = (u8_t)i; + rcCell->failCount = rcCell->txCount = 0; + rcCell->lasttxCount = 0; + rcCell->lastTime = wd->tick; + wd->txFail[rcCell->currentRate] = wd->txFail[rcCell->currentRate] >> 1; + wd->txMPDU[rcCell->currentRate] = wd->txMPDU[rcCell->currentRate] >> 1; + } + } + } + + return; +} + + +/************************************************************************/ +/* */ +/* FUNCTION DESCRIPTION zfRateCtrlRxRssiEvent */ +/* Rx RSSI event. Calculate RSSI moving average, accelarate */ +/* rate probing if RSSI variation over threshold. */ +/* */ +/* INPUTS */ +/* rcCell : rate control cell */ +/* successRate : success rate */ +/* */ +/* OUTPUTS */ +/* None */ +/* */ +/* AUTHOR */ +/* Stephen Chen Atheros Communications, INC. 2007.2 */ +/* */ +/************************************************************************/ +void zfRateCtrlRxRssiEvent(struct zsRcCell* rcCell, u16_t rxRssi) +{ + /* if delta(rcCell->rxRssi, rxRssi) > ZM_RATE_CTRL_RSSI_VARIATION */ + if ((rcCell->rxRssi - rxRssi) > ZM_RATE_CTRL_RSSI_VARIATION) + { + /* Accelerate rate probing via decreaing rcCell->probingTime */ + rcCell->probingTime -= ZM_RATE_CTRL_PROBING_INTERVAL_MS/ZM_MS_PER_TICK; + } + + /* Update RSSI moving average */ + rcCell->rxRssi = (((rcCell->rxRssi*7) + rxRssi)+4) >> 3; + return; +} + + +#ifdef ZM_ENABLE_BA_RATECTRL +u8_t HigherRate(u8_t Rate) { + if (Rate < 28) Rate++; //28=MCS15SG, 27=MCS15, 26=MCS14, 25=MCS13 + if (Rate > 28) Rate = 28; + while ((Rate >= 20) && (Rate <= 23)) { + Rate ++; + } + return Rate; +} + +u8_t LowerRate(u8_t Rate) { + if (Rate > 1) Rate--; + while ((Rate >= 20) && (Rate <= 23)) { + Rate --; + } + return Rate; +} + +u8_t RateMapToRateIndex(u8_t Rate, struct zsRcCell* rcCell) { + u8_t i; + for (i=0; ioperationRateCount; i++) { + if (Rate == rcCell->operationRateSet[i]) { + return i; + } + } + return 0; +} + +void zfRateCtrlAggrSta(zdev_t* dev) { + u8_t RateIndex, Rate; + u8_t HRate; + u8_t LRate; + u32_t RateCtrlTxMPDU, RateCtrlBAFail; + zmw_get_wlan_dev(dev); + + RateIndex = wd->sta.oppositeInfo[0].rcCell.currentRateIndex; + Rate = wd->sta.oppositeInfo[0].rcCell.operationRateSet[RateIndex]; + + TxMPDU[Rate] = (TxMPDU[Rate] / 5) + (wd->commTally.RateCtrlTxMPDU * 4 / 5); + BAFail[Rate] = (BAFail[Rate] / 5) + (wd->commTally.RateCtrlBAFail * 4 / 5); + RateCtrlTxMPDU = wd->commTally.RateCtrlTxMPDU; + RateCtrlBAFail = wd->commTally.RateCtrlBAFail; + wd->commTally.RateCtrlTxMPDU = 0; + wd->commTally.RateCtrlBAFail = 0; + if (TxMPDU[Rate] > 0) { + BAPER[Rate] = BAFail[Rate] * 1000 / TxMPDU[Rate]; //PER*1000 + BAPER[Rate] = (BAPER[Rate]>0)? BAPER[Rate]:1; + } + else { + return; + } + + HRate = HigherRate(Rate); + LRate = LowerRate(Rate); + if (BAPER[Rate]>200) { + if ((RateCtrlTxMPDU > 100) && (BAPER[Rate]<300) && (HRate != Rate) && BAPER[HRate] && + (BAPER[HRate] < BAPER[Rate] + BADiff[Rate])) { + Rate = HRate; + //DbgPrint("Rate improved to %d", Rate); + } + else { + Rate = LRate; + //DbgPrint("Rate decreased to %d", Rate); + } + } + else if (BAPER[Rate] && BAPER[Rate]<100) { + if (RateCtrlTxMPDU > 100) { + Rate = HRate; + //DbgPrint("Rate improved to %d", Rate); + } + } + wd->sta.oppositeInfo[0].rcCell.currentRate = Rate; + wd->sta.oppositeInfo[0].rcCell.currentRateIndex = RateMapToRateIndex(Rate, &wd->sta.oppositeInfo[0].rcCell); +} +#endif -- cgit v1.2.3