2008-08-04 00:16:41 -07:00
/*
* Copyright ( c ) 2004 Video54 Technologies , Inc .
* Copyright ( c ) 2004 - 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 "core.h"
static struct ath_rate_table ar5416_11na_ratetable = {
42 ,
2008-11-18 09:07:53 +05:30
{ 0 } ,
2008-08-04 00:16:41 -07:00
{
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 6000 , /* 6 Mb */
2008-08-04 00:16:41 -07:00
5400 , 0x0b , 0x00 , 12 ,
0 , 2 , 1 , 0 , 0 , 0 , 0 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 9000 , /* 9 Mb */
2008-08-04 00:16:41 -07:00
7800 , 0x0f , 0x00 , 18 ,
0 , 3 , 1 , 1 , 1 , 1 , 1 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 12000 , /* 12 Mb */
2008-08-04 00:16:41 -07:00
10000 , 0x0a , 0x00 , 24 ,
2 , 4 , 2 , 2 , 2 , 2 , 2 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 18000 , /* 18 Mb */
2008-08-04 00:16:41 -07:00
13900 , 0x0e , 0x00 , 36 ,
2 , 6 , 2 , 3 , 3 , 3 , 3 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 24000 , /* 24 Mb */
2008-08-04 00:16:41 -07:00
17300 , 0x09 , 0x00 , 48 ,
4 , 10 , 3 , 4 , 4 , 4 , 4 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 36000 , /* 36 Mb */
2008-08-04 00:16:41 -07:00
23000 , 0x0d , 0x00 , 72 ,
4 , 14 , 3 , 5 , 5 , 5 , 5 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 48000 , /* 48 Mb */
2008-08-04 00:16:41 -07:00
27400 , 0x08 , 0x00 , 96 ,
4 , 20 , 3 , 6 , 6 , 6 , 6 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 54000 , /* 54 Mb */
2008-08-04 00:16:41 -07:00
29300 , 0x0c , 0x00 , 108 ,
4 , 23 , 3 , 7 , 7 , 7 , 7 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID_20 , VALID_20 , WLAN_RC_PHY_HT_20_SS , 6500 , /* 6.5 Mb */
2008-08-04 00:16:41 -07:00
6400 , 0x80 , 0x00 , 0 ,
0 , 2 , 3 , 8 , 24 , 8 , 24 , 3216 } ,
2008-11-18 09:08:13 +05:30
{ VALID_20 , VALID_20 , WLAN_RC_PHY_HT_20_SS , 13000 , /* 13 Mb */
2008-08-04 00:16:41 -07:00
12700 , 0x81 , 0x00 , 1 ,
2 , 4 , 3 , 9 , 25 , 9 , 25 , 6434 } ,
2008-11-18 09:08:13 +05:30
{ VALID_20 , VALID_20 , WLAN_RC_PHY_HT_20_SS , 19500 , /* 19.5 Mb */
2008-08-04 00:16:41 -07:00
18800 , 0x82 , 0x00 , 2 ,
2 , 6 , 3 , 10 , 26 , 10 , 26 , 9650 } ,
2008-11-18 09:08:13 +05:30
{ VALID_20 , VALID_20 , WLAN_RC_PHY_HT_20_SS , 26000 , /* 26 Mb */
2008-08-04 00:16:41 -07:00
25000 , 0x83 , 0x00 , 3 ,
4 , 10 , 3 , 11 , 27 , 11 , 27 , 12868 } ,
2008-11-18 09:08:13 +05:30
{ VALID_20 , VALID_20 , WLAN_RC_PHY_HT_20_SS , 39000 , /* 39 Mb */
2008-08-04 00:16:41 -07:00
36700 , 0x84 , 0x00 , 4 ,
4 , 14 , 3 , 12 , 28 , 12 , 28 , 19304 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , VALID_20 , WLAN_RC_PHY_HT_20_SS , 52000 , /* 52 Mb */
2008-08-04 00:16:41 -07:00
48100 , 0x85 , 0x00 , 5 ,
4 , 20 , 3 , 13 , 29 , 13 , 29 , 25740 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , VALID_20 , WLAN_RC_PHY_HT_20_SS , 58500 , /* 58.5 Mb */
2008-08-04 00:16:41 -07:00
53500 , 0x86 , 0x00 , 6 ,
4 , 23 , 3 , 14 , 30 , 14 , 30 , 28956 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , VALID_20 , WLAN_RC_PHY_HT_20_SS , 65000 , /* 65 Mb */
2008-08-04 00:16:41 -07:00
59000 , 0x87 , 0x00 , 7 ,
4 , 25 , 3 , 15 , 31 , 15 , 32 , 32180 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , INVALID , WLAN_RC_PHY_HT_20_DS , 13000 , /* 13 Mb */
2008-08-04 00:16:41 -07:00
12700 , 0x88 , 0x00 ,
8 , 0 , 2 , 3 , 16 , 33 , 16 , 33 , 6430 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , INVALID , WLAN_RC_PHY_HT_20_DS , 26000 , /* 26 Mb */
2008-08-04 00:16:41 -07:00
24800 , 0x89 , 0x00 , 9 ,
2 , 4 , 3 , 17 , 34 , 17 , 34 , 12860 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , INVALID , WLAN_RC_PHY_HT_20_DS , 39000 , /* 39 Mb */
2008-08-04 00:16:41 -07:00
36600 , 0x8a , 0x00 , 10 ,
2 , 6 , 3 , 18 , 35 , 18 , 35 , 19300 } ,
2008-11-18 09:08:13 +05:30
{ VALID_20 , INVALID , WLAN_RC_PHY_HT_20_DS , 52000 , /* 52 Mb */
2008-08-04 00:16:41 -07:00
48100 , 0x8b , 0x00 , 11 ,
4 , 10 , 3 , 19 , 36 , 19 , 36 , 25736 } ,
2008-11-18 09:08:13 +05:30
{ VALID_20 , INVALID , WLAN_RC_PHY_HT_20_DS , 78000 , /* 78 Mb */
2008-08-04 00:16:41 -07:00
69500 , 0x8c , 0x00 , 12 ,
4 , 14 , 3 , 20 , 37 , 20 , 37 , 38600 } ,
2008-11-18 09:08:13 +05:30
{ VALID_20 , INVALID , WLAN_RC_PHY_HT_20_DS , 104000 , /* 104 Mb */
2008-08-04 00:16:41 -07:00
89500 , 0x8d , 0x00 , 13 ,
4 , 20 , 3 , 21 , 38 , 21 , 38 , 51472 } ,
2008-11-18 09:08:13 +05:30
{ VALID_20 , INVALID , WLAN_RC_PHY_HT_20_DS , 117000 , /* 117 Mb */
2008-08-04 00:16:41 -07:00
98900 , 0x8e , 0x00 , 14 ,
4 , 23 , 3 , 22 , 39 , 22 , 39 , 57890 } ,
2008-11-18 09:08:13 +05:30
{ VALID_20 , INVALID , WLAN_RC_PHY_HT_20_DS , 130000 , /* 130 Mb */
2008-08-04 00:16:41 -07:00
108300 , 0x8f , 0x00 , 15 ,
4 , 25 , 3 , 23 , 40 , 23 , 41 , 64320 } ,
2008-11-18 09:08:13 +05:30
{ VALID_40 , VALID_40 , WLAN_RC_PHY_HT_40_SS , 13500 , /* 13.5 Mb */
2008-08-04 00:16:41 -07:00
13200 , 0x80 , 0x00 , 0 ,
0 , 2 , 3 , 8 , 24 , 24 , 24 , 6684 } ,
2008-11-18 09:08:13 +05:30
{ VALID_40 , VALID_40 , WLAN_RC_PHY_HT_40_SS , 27500 , /* 27.0 Mb */
2008-08-04 00:16:41 -07:00
25900 , 0x81 , 0x00 , 1 ,
2 , 4 , 3 , 9 , 25 , 25 , 25 , 13368 } ,
2008-11-18 09:08:13 +05:30
{ VALID_40 , VALID_40 , WLAN_RC_PHY_HT_40_SS , 40500 , /* 40.5 Mb */
2008-08-04 00:16:41 -07:00
38600 , 0x82 , 0x00 , 2 ,
2 , 6 , 3 , 10 , 26 , 26 , 26 , 20052 } ,
2008-11-18 09:08:13 +05:30
{ VALID_40 , VALID_40 , WLAN_RC_PHY_HT_40_SS , 54000 , /* 54 Mb */
2008-08-04 00:16:41 -07:00
49800 , 0x83 , 0x00 , 3 ,
4 , 10 , 3 , 11 , 27 , 27 , 27 , 26738 } ,
2008-11-18 09:08:13 +05:30
{ VALID_40 , VALID_40 , WLAN_RC_PHY_HT_40_SS , 81500 , /* 81 Mb */
2008-08-04 00:16:41 -07:00
72200 , 0x84 , 0x00 , 4 ,
4 , 14 , 3 , 12 , 28 , 28 , 28 , 40104 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , VALID_40 , WLAN_RC_PHY_HT_40_SS , 108000 , /* 108 Mb */
2008-08-04 00:16:41 -07:00
92900 , 0x85 , 0x00 , 5 ,
4 , 20 , 3 , 13 , 29 , 29 , 29 , 53476 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , VALID_40 , WLAN_RC_PHY_HT_40_SS , 121500 , /* 121.5 Mb */
2008-08-04 00:16:41 -07:00
102700 , 0x86 , 0x00 , 6 ,
4 , 23 , 3 , 14 , 30 , 30 , 30 , 60156 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , VALID_40 , WLAN_RC_PHY_HT_40_SS , 135000 , /* 135 Mb */
2008-08-04 00:16:41 -07:00
112000 , 0x87 , 0x00 , 7 ,
4 , 25 , 3 , 15 , 31 , 32 , 32 , 66840 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , VALID_40 , WLAN_RC_PHY_HT_40_SS_HGI , 150000 , /* 150 Mb */
2008-08-04 00:16:41 -07:00
122000 , 0x87 , 0x00 , 7 ,
4 , 25 , 3 , 15 , 31 , 32 , 32 , 74200 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , INVALID , WLAN_RC_PHY_HT_40_DS , 27000 , /* 27 Mb */
2008-08-04 00:16:41 -07:00
25800 , 0x88 , 0x00 , 8 ,
0 , 2 , 3 , 16 , 33 , 33 , 33 , 13360 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , INVALID , WLAN_RC_PHY_HT_40_DS , 54000 , /* 54 Mb */
2008-08-04 00:16:41 -07:00
49800 , 0x89 , 0x00 , 9 ,
2 , 4 , 3 , 17 , 34 , 34 , 34 , 26720 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , INVALID , WLAN_RC_PHY_HT_40_DS , 81000 , /* 81 Mb */
2008-08-04 00:16:41 -07:00
71900 , 0x8a , 0x00 , 10 ,
2 , 6 , 3 , 18 , 35 , 35 , 35 , 40080 } ,
2008-11-18 09:08:13 +05:30
{ VALID_40 , INVALID , WLAN_RC_PHY_HT_40_DS , 108000 , /* 108 Mb */
2008-08-04 00:16:41 -07:00
92500 , 0x8b , 0x00 , 11 ,
4 , 10 , 3 , 19 , 36 , 36 , 36 , 53440 } ,
2008-11-18 09:08:13 +05:30
{ VALID_40 , INVALID , WLAN_RC_PHY_HT_40_DS , 162000 , /* 162 Mb */
2008-08-04 00:16:41 -07:00
130300 , 0x8c , 0x00 , 12 ,
4 , 14 , 3 , 20 , 37 , 37 , 37 , 80160 } ,
2008-11-18 09:08:13 +05:30
{ VALID_40 , INVALID , WLAN_RC_PHY_HT_40_DS , 216000 , /* 216 Mb */
2008-08-04 00:16:41 -07:00
162800 , 0x8d , 0x00 , 13 ,
4 , 20 , 3 , 21 , 38 , 38 , 38 , 106880 } ,
2008-11-18 09:08:13 +05:30
{ VALID_40 , INVALID , WLAN_RC_PHY_HT_40_DS , 243000 , /* 243 Mb */
2008-08-04 00:16:41 -07:00
178200 , 0x8e , 0x00 , 14 ,
4 , 23 , 3 , 22 , 39 , 39 , 39 , 120240 } ,
2008-11-18 09:08:13 +05:30
{ VALID_40 , INVALID , WLAN_RC_PHY_HT_40_DS , 270000 , /* 270 Mb */
2008-08-04 00:16:41 -07:00
192100 , 0x8f , 0x00 , 15 ,
4 , 25 , 3 , 23 , 40 , 41 , 41 , 133600 } ,
2008-11-18 09:08:13 +05:30
{ VALID_40 , INVALID , WLAN_RC_PHY_HT_40_DS_HGI , 300000 , /* 300 Mb */
2008-08-04 00:16:41 -07:00
207000 , 0x8f , 0x00 , 15 ,
4 , 25 , 3 , 23 , 40 , 41 , 41 , 148400 } ,
} ,
50 , /* probe interval */
50 , /* rssi reduce interval */
WLAN_RC_HT_FLAG , /* Phy rates allowed initially */
} ;
/* 4ms frame limit not used for NG mode. The values filled
* for HT are the 64 K max aggregate limit */
static struct ath_rate_table ar5416_11ng_ratetable = {
46 ,
2008-11-18 09:07:53 +05:30
{ 0 } ,
2008-08-04 00:16:41 -07:00
{
2008-11-18 09:08:13 +05:30
{ VALID_ALL , VALID_ALL , WLAN_RC_PHY_CCK , 1000 , /* 1 Mb */
2008-08-04 00:16:41 -07:00
900 , 0x1b , 0x00 , 2 ,
0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID_ALL , VALID_ALL , WLAN_RC_PHY_CCK , 2000 , /* 2 Mb */
2008-08-04 00:16:41 -07:00
1900 , 0x1a , 0x04 , 4 ,
1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID_ALL , VALID_ALL , WLAN_RC_PHY_CCK , 5500 , /* 5.5 Mb */
2008-08-04 00:16:41 -07:00
4900 , 0x19 , 0x04 , 11 ,
2 , 2 , 2 , 2 , 2 , 2 , 2 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID_ALL , VALID_ALL , WLAN_RC_PHY_CCK , 11000 , /* 11 Mb */
2008-08-04 00:16:41 -07:00
8100 , 0x18 , 0x04 , 22 ,
3 , 3 , 2 , 3 , 3 , 3 , 3 , 0 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , INVALID , WLAN_RC_PHY_OFDM , 6000 , /* 6 Mb */
2008-08-04 00:16:41 -07:00
5400 , 0x0b , 0x00 , 12 ,
4 , 2 , 1 , 4 , 4 , 4 , 4 , 0 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , INVALID , WLAN_RC_PHY_OFDM , 9000 , /* 9 Mb */
2008-08-04 00:16:41 -07:00
7800 , 0x0f , 0x00 , 18 ,
4 , 3 , 1 , 5 , 5 , 5 , 5 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 12000 , /* 12 Mb */
2008-08-04 00:16:41 -07:00
10100 , 0x0a , 0x00 , 24 ,
6 , 4 , 1 , 6 , 6 , 6 , 6 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 18000 , /* 18 Mb */
2008-08-04 00:16:41 -07:00
14100 , 0x0e , 0x00 , 36 ,
6 , 6 , 2 , 7 , 7 , 7 , 7 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 24000 , /* 24 Mb */
2008-08-04 00:16:41 -07:00
17700 , 0x09 , 0x00 , 48 ,
8 , 10 , 3 , 8 , 8 , 8 , 8 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 36000 , /* 36 Mb */
2008-08-04 00:16:41 -07:00
23700 , 0x0d , 0x00 , 72 ,
8 , 14 , 3 , 9 , 9 , 9 , 9 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 48000 , /* 48 Mb */
2008-08-04 00:16:41 -07:00
27400 , 0x08 , 0x00 , 96 ,
8 , 20 , 3 , 10 , 10 , 10 , 10 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 54000 , /* 54 Mb */
2008-08-04 00:16:41 -07:00
30900 , 0x0c , 0x00 , 108 ,
8 , 23 , 3 , 11 , 11 , 11 , 11 , 0 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , INVALID , WLAN_RC_PHY_HT_20_SS , 6500 , /* 6.5 Mb */
2008-08-04 00:16:41 -07:00
6400 , 0x80 , 0x00 , 0 ,
4 , 2 , 3 , 12 , 28 , 12 , 28 , 3216 } ,
2008-11-18 09:08:13 +05:30
{ VALID_20 , VALID_20 , WLAN_RC_PHY_HT_20_SS , 13000 , /* 13 Mb */
2008-08-04 00:16:41 -07:00
12700 , 0x81 , 0x00 , 1 ,
6 , 4 , 3 , 13 , 29 , 13 , 29 , 6434 } ,
2008-11-18 09:08:13 +05:30
{ VALID_20 , VALID_20 , WLAN_RC_PHY_HT_20_SS , 19500 , /* 19.5 Mb */
2008-08-04 00:16:41 -07:00
18800 , 0x82 , 0x00 , 2 ,
6 , 6 , 3 , 14 , 30 , 14 , 30 , 9650 } ,
2008-11-18 09:08:13 +05:30
{ VALID_20 , VALID_20 , WLAN_RC_PHY_HT_20_SS , 26000 , /* 26 Mb */
2008-08-04 00:16:41 -07:00
25000 , 0x83 , 0x00 , 3 ,
8 , 10 , 3 , 15 , 31 , 15 , 31 , 12868 } ,
2008-11-18 09:08:13 +05:30
{ VALID_20 , VALID_20 , WLAN_RC_PHY_HT_20_SS , 39000 , /* 39 Mb */
2008-08-04 00:16:41 -07:00
36700 , 0x84 , 0x00 , 4 ,
8 , 14 , 3 , 16 , 32 , 16 , 32 , 19304 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , VALID_20 , WLAN_RC_PHY_HT_20_SS , 52000 , /* 52 Mb */
2008-08-04 00:16:41 -07:00
48100 , 0x85 , 0x00 , 5 ,
8 , 20 , 3 , 17 , 33 , 17 , 33 , 25740 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , VALID_20 , WLAN_RC_PHY_HT_20_SS , 58500 , /* 58.5 Mb */
2008-08-04 00:16:41 -07:00
53500 , 0x86 , 0x00 , 6 ,
8 , 23 , 3 , 18 , 34 , 18 , 34 , 28956 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , VALID_20 , WLAN_RC_PHY_HT_20_SS , 65000 , /* 65 Mb */
2008-08-04 00:16:41 -07:00
59000 , 0x87 , 0x00 , 7 ,
8 , 25 , 3 , 19 , 35 , 19 , 36 , 32180 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , INVALID , WLAN_RC_PHY_HT_20_DS , 13000 , /* 13 Mb */
2008-08-04 00:16:41 -07:00
12700 , 0x88 , 0x00 , 8 ,
4 , 2 , 3 , 20 , 37 , 20 , 37 , 6430 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , INVALID , WLAN_RC_PHY_HT_20_DS , 26000 , /* 26 Mb */
2008-08-04 00:16:41 -07:00
24800 , 0x89 , 0x00 , 9 ,
6 , 4 , 3 , 21 , 38 , 21 , 38 , 12860 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , INVALID , WLAN_RC_PHY_HT_20_DS , 39000 , /* 39 Mb */
2008-08-04 00:16:41 -07:00
36600 , 0x8a , 0x00 , 10 ,
6 , 6 , 3 , 22 , 39 , 22 , 39 , 19300 } ,
2008-11-18 09:08:13 +05:30
{ VALID_20 , INVALID , WLAN_RC_PHY_HT_20_DS , 52000 , /* 52 Mb */
2008-08-04 00:16:41 -07:00
48100 , 0x8b , 0x00 , 11 ,
8 , 10 , 3 , 23 , 40 , 23 , 40 , 25736 } ,
2008-11-18 09:08:13 +05:30
{ VALID_20 , INVALID , WLAN_RC_PHY_HT_20_DS , 78000 , /* 78 Mb */
2008-08-04 00:16:41 -07:00
69500 , 0x8c , 0x00 , 12 ,
8 , 14 , 3 , 24 , 41 , 24 , 41 , 38600 } ,
2008-11-18 09:08:13 +05:30
{ VALID_20 , INVALID , WLAN_RC_PHY_HT_20_DS , 104000 , /* 104 Mb */
2008-08-04 00:16:41 -07:00
89500 , 0x8d , 0x00 , 13 ,
8 , 20 , 3 , 25 , 42 , 25 , 42 , 51472 } ,
2008-11-18 09:08:13 +05:30
{ VALID_20 , INVALID , WLAN_RC_PHY_HT_20_DS , 117000 , /* 117 Mb */
2008-08-04 00:16:41 -07:00
98900 , 0x8e , 0x00 , 14 ,
8 , 23 , 3 , 26 , 43 , 26 , 44 , 57890 } ,
2008-11-18 09:08:13 +05:30
{ VALID_20 , INVALID , WLAN_RC_PHY_HT_20_DS , 130000 , /* 130 Mb */
2008-08-04 00:16:41 -07:00
108300 , 0x8f , 0x00 , 15 ,
8 , 25 , 3 , 27 , 44 , 27 , 45 , 64320 } ,
2008-11-18 09:08:13 +05:30
{ VALID_40 , VALID_40 , WLAN_RC_PHY_HT_40_SS , 13500 , /* 13.5 Mb */
2008-08-04 00:16:41 -07:00
13200 , 0x80 , 0x00 , 0 ,
8 , 2 , 3 , 12 , 28 , 28 , 28 , 6684 } ,
2008-11-18 09:08:13 +05:30
{ VALID_40 , VALID_40 , WLAN_RC_PHY_HT_40_SS , 27500 , /* 27.0 Mb */
2008-08-04 00:16:41 -07:00
25900 , 0x81 , 0x00 , 1 ,
8 , 4 , 3 , 13 , 29 , 29 , 29 , 13368 } ,
2008-11-18 09:08:13 +05:30
{ VALID_40 , VALID_40 , WLAN_RC_PHY_HT_40_SS , 40500 , /* 40.5 Mb */
2008-08-04 00:16:41 -07:00
38600 , 0x82 , 0x00 , 2 ,
8 , 6 , 3 , 14 , 30 , 30 , 30 , 20052 } ,
2008-11-18 09:08:13 +05:30
{ VALID_40 , VALID_40 , WLAN_RC_PHY_HT_40_SS , 54000 , /* 54 Mb */
2008-08-04 00:16:41 -07:00
49800 , 0x83 , 0x00 , 3 ,
8 , 10 , 3 , 15 , 31 , 31 , 31 , 26738 } ,
2008-11-18 09:08:13 +05:30
{ VALID_40 , VALID_40 , WLAN_RC_PHY_HT_40_SS , 81500 , /* 81 Mb */
2008-08-04 00:16:41 -07:00
72200 , 0x84 , 0x00 , 4 ,
8 , 14 , 3 , 16 , 32 , 32 , 32 , 40104 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , VALID_40 , WLAN_RC_PHY_HT_40_SS , 108000 , /* 108 Mb */
2008-08-04 00:16:41 -07:00
92900 , 0x85 , 0x00 , 5 ,
8 , 20 , 3 , 17 , 33 , 33 , 33 , 53476 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , VALID_40 , WLAN_RC_PHY_HT_40_SS , 121500 , /* 121.5 Mb */
2008-08-04 00:16:41 -07:00
102700 , 0x86 , 0x00 , 6 ,
8 , 23 , 3 , 18 , 34 , 34 , 34 , 60156 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , VALID_40 , WLAN_RC_PHY_HT_40_SS , 135000 , /* 135 Mb */
2008-08-04 00:16:41 -07:00
112000 , 0x87 , 0x00 , 7 ,
8 , 23 , 3 , 19 , 35 , 36 , 36 , 66840 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , VALID_40 , WLAN_RC_PHY_HT_40_SS_HGI , 150000 , /* 150 Mb */
2008-08-04 00:16:41 -07:00
122000 , 0x87 , 0x00 , 7 ,
8 , 25 , 3 , 19 , 35 , 36 , 36 , 74200 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , INVALID , WLAN_RC_PHY_HT_40_DS , 27000 , /* 27 Mb */
2008-08-04 00:16:41 -07:00
25800 , 0x88 , 0x00 , 8 ,
8 , 2 , 3 , 20 , 37 , 37 , 37 , 13360 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , INVALID , WLAN_RC_PHY_HT_40_DS , 54000 , /* 54 Mb */
2008-08-04 00:16:41 -07:00
49800 , 0x89 , 0x00 , 9 ,
8 , 4 , 3 , 21 , 38 , 38 , 38 , 26720 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , INVALID , WLAN_RC_PHY_HT_40_DS , 81000 , /* 81 Mb */
2008-08-04 00:16:41 -07:00
71900 , 0x8a , 0x00 , 10 ,
8 , 6 , 3 , 22 , 39 , 39 , 39 , 40080 } ,
2008-11-18 09:08:13 +05:30
{ VALID_40 , INVALID , WLAN_RC_PHY_HT_40_DS , 108000 , /* 108 Mb */
2008-08-04 00:16:41 -07:00
92500 , 0x8b , 0x00 , 11 ,
8 , 10 , 3 , 23 , 40 , 40 , 40 , 53440 } ,
2008-11-18 09:08:13 +05:30
{ VALID_40 , INVALID , WLAN_RC_PHY_HT_40_DS , 162000 , /* 162 Mb */
2008-08-04 00:16:41 -07:00
130300 , 0x8c , 0x00 , 12 ,
8 , 14 , 3 , 24 , 41 , 41 , 41 , 80160 } ,
2008-11-18 09:08:13 +05:30
{ VALID_40 , INVALID , WLAN_RC_PHY_HT_40_DS , 216000 , /* 216 Mb */
2008-08-04 00:16:41 -07:00
162800 , 0x8d , 0x00 , 13 ,
8 , 20 , 3 , 25 , 42 , 42 , 42 , 106880 } ,
2008-11-18 09:08:13 +05:30
{ VALID_40 , INVALID , WLAN_RC_PHY_HT_40_DS , 243000 , /* 243 Mb */
2008-08-04 00:16:41 -07:00
178200 , 0x8e , 0x00 , 14 ,
8 , 23 , 3 , 26 , 43 , 43 , 43 , 120240 } ,
2008-11-18 09:08:13 +05:30
{ VALID_40 , INVALID , WLAN_RC_PHY_HT_40_DS , 270000 , /* 270 Mb */
2008-08-04 00:16:41 -07:00
192100 , 0x8f , 0x00 , 15 ,
8 , 23 , 3 , 27 , 44 , 45 , 45 , 133600 } ,
2008-11-18 09:08:13 +05:30
{ VALID_40 , INVALID , WLAN_RC_PHY_HT_40_DS_HGI , 300000 , /* 300 Mb */
2008-08-04 00:16:41 -07:00
207000 , 0x8f , 0x00 , 15 ,
8 , 25 , 3 , 27 , 44 , 45 , 45 , 148400 } ,
} ,
50 , /* probe interval */
50 , /* rssi reduce interval */
WLAN_RC_HT_FLAG , /* Phy rates allowed initially */
} ;
static struct ath_rate_table ar5416_11a_ratetable = {
8 ,
2008-11-18 09:07:53 +05:30
{ 0 } ,
2008-08-04 00:16:41 -07:00
{
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 6000 , /* 6 Mb */
2008-08-04 00:16:41 -07:00
5400 , 0x0b , 0x00 , ( 0x80 | 12 ) ,
0 , 2 , 1 , 0 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 9000 , /* 9 Mb */
2008-08-04 00:16:41 -07:00
7800 , 0x0f , 0x00 , 18 ,
0 , 3 , 1 , 1 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 12000 , /* 12 Mb */
2008-08-04 00:16:41 -07:00
10000 , 0x0a , 0x00 , ( 0x80 | 24 ) ,
2 , 4 , 2 , 2 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 18000 , /* 18 Mb */
2008-08-04 00:16:41 -07:00
13900 , 0x0e , 0x00 , 36 ,
2 , 6 , 2 , 3 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 24000 , /* 24 Mb */
2008-08-04 00:16:41 -07:00
17300 , 0x09 , 0x00 , ( 0x80 | 48 ) ,
4 , 10 , 3 , 4 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 36000 , /* 36 Mb */
2008-08-04 00:16:41 -07:00
23000 , 0x0d , 0x00 , 72 ,
4 , 14 , 3 , 5 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 48000 , /* 48 Mb */
2008-08-04 00:16:41 -07:00
27400 , 0x08 , 0x00 , 96 ,
4 , 19 , 3 , 6 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 54000 , /* 54 Mb */
2008-08-04 00:16:41 -07:00
29300 , 0x0c , 0x00 , 108 ,
4 , 23 , 3 , 7 , 0 } ,
} ,
50 , /* probe interval */
50 , /* rssi reduce interval */
0 , /* Phy rates allowed initially */
} ;
static struct ath_rate_table ar5416_11g_ratetable = {
12 ,
2008-11-18 09:07:53 +05:30
{ 0 } ,
2008-08-04 00:16:41 -07:00
{
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_CCK , 1000 , /* 1 Mb */
2008-08-04 00:16:41 -07:00
900 , 0x1b , 0x00 , 2 ,
0 , 0 , 1 , 0 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_CCK , 2000 , /* 2 Mb */
2008-08-04 00:16:41 -07:00
1900 , 0x1a , 0x04 , 4 ,
1 , 1 , 1 , 1 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_CCK , 5500 , /* 5.5 Mb */
2008-08-04 00:16:41 -07:00
4900 , 0x19 , 0x04 , 11 ,
2 , 2 , 2 , 2 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_CCK , 11000 , /* 11 Mb */
2008-08-04 00:16:41 -07:00
8100 , 0x18 , 0x04 , 22 ,
3 , 3 , 2 , 3 , 0 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , INVALID , WLAN_RC_PHY_OFDM , 6000 , /* 6 Mb */
2008-08-04 00:16:41 -07:00
5400 , 0x0b , 0x00 , 12 ,
4 , 2 , 1 , 4 , 0 } ,
2008-11-18 09:08:13 +05:30
{ INVALID , INVALID , WLAN_RC_PHY_OFDM , 9000 , /* 9 Mb */
2008-08-04 00:16:41 -07:00
7800 , 0x0f , 0x00 , 18 ,
4 , 3 , 1 , 5 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 12000 , /* 12 Mb */
2008-08-04 00:16:41 -07:00
10000 , 0x0a , 0x00 , 24 ,
6 , 4 , 1 , 6 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 18000 , /* 18 Mb */
2008-08-04 00:16:41 -07:00
13900 , 0x0e , 0x00 , 36 ,
6 , 6 , 2 , 7 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 24000 , /* 24 Mb */
2008-08-04 00:16:41 -07:00
17300 , 0x09 , 0x00 , 48 ,
8 , 10 , 3 , 8 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 36000 , /* 36 Mb */
2008-08-04 00:16:41 -07:00
23000 , 0x0d , 0x00 , 72 ,
8 , 14 , 3 , 9 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 48000 , /* 48 Mb */
2008-08-04 00:16:41 -07:00
27400 , 0x08 , 0x00 , 96 ,
8 , 19 , 3 , 10 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_OFDM , 54000 , /* 54 Mb */
2008-08-04 00:16:41 -07:00
29300 , 0x0c , 0x00 , 108 ,
8 , 23 , 3 , 11 , 0 } ,
} ,
50 , /* probe interval */
50 , /* rssi reduce interval */
0 , /* Phy rates allowed initially */
} ;
static struct ath_rate_table ar5416_11b_ratetable = {
4 ,
2008-11-18 09:07:53 +05:30
{ 0 } ,
2008-08-04 00:16:41 -07:00
{
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_CCK , 1000 , /* 1 Mb */
2008-08-04 00:16:41 -07:00
900 , 0x1b , 0x00 , ( 0x80 | 2 ) ,
0 , 0 , 1 , 0 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_CCK , 2000 , /* 2 Mb */
2008-08-04 00:16:41 -07:00
1800 , 0x1a , 0x04 , ( 0x80 | 4 ) ,
1 , 1 , 1 , 1 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_CCK , 5500 , /* 5.5 Mb */
2008-08-04 00:16:41 -07:00
4300 , 0x19 , 0x04 , ( 0x80 | 11 ) ,
1 , 2 , 2 , 2 , 0 } ,
2008-11-18 09:08:13 +05:30
{ VALID , VALID , WLAN_RC_PHY_CCK , 11000 , /* 11 Mb */
2008-08-04 00:16:41 -07:00
7100 , 0x18 , 0x04 , ( 0x80 | 22 ) ,
1 , 4 , 100 , 3 , 0 } ,
} ,
100 , /* probe interval */
100 , /* rssi reduce interval */
0 , /* Phy rates allowed initially */
} ;
static inline int8_t median ( int8_t a , int8_t b , int8_t c )
{
if ( a > = b ) {
if ( b > = c )
return b ;
else if ( a > c )
return c ;
else
return a ;
} else {
if ( a > = c )
return a ;
else if ( b > = c )
return c ;
else
return b ;
}
}
2008-11-18 09:07:06 +05:30
static void ath_rc_sort_validrates ( struct ath_rate_table * rate_table ,
2008-11-18 09:08:13 +05:30
struct ath_rate_priv * ath_rc_priv )
2008-08-04 00:16:41 -07:00
{
u8 i , j , idx , idx_next ;
2008-11-18 09:03:12 +05:30
for ( i = ath_rc_priv - > max_valid_rate - 1 ; i > 0 ; i - - ) {
2008-08-04 00:16:41 -07:00
for ( j = 0 ; j < = i - 1 ; j + + ) {
2008-11-18 09:03:12 +05:30
idx = ath_rc_priv - > valid_rate_index [ j ] ;
idx_next = ath_rc_priv - > valid_rate_index [ j + 1 ] ;
2008-08-04 00:16:41 -07:00
if ( rate_table - > info [ idx ] . ratekbps >
rate_table - > info [ idx_next ] . ratekbps ) {
2008-11-18 09:03:12 +05:30
ath_rc_priv - > valid_rate_index [ j ] = idx_next ;
ath_rc_priv - > valid_rate_index [ j + 1 ] = idx ;
2008-08-04 00:16:41 -07:00
}
}
}
}
2008-11-18 09:08:13 +05:30
static void ath_rc_init_valid_txmask ( struct ath_rate_priv * ath_rc_priv )
2008-08-04 00:16:41 -07:00
{
u8 i ;
2008-11-18 09:03:12 +05:30
for ( i = 0 ; i < ath_rc_priv - > rate_table_size ; i + + )
2008-11-18 09:08:13 +05:30
ath_rc_priv - > valid_rate_index [ i ] = 0 ;
2008-08-04 00:16:41 -07:00
}
2008-11-18 09:08:13 +05:30
static inline void ath_rc_set_valid_txmask ( struct ath_rate_priv * ath_rc_priv ,
2008-08-04 00:16:41 -07:00
u8 index , int valid_tx_rate )
{
2008-11-18 09:03:12 +05:30
ASSERT ( index < = ath_rc_priv - > rate_table_size ) ;
2008-11-18 09:08:13 +05:30
ath_rc_priv - > valid_rate_index [ index ] = valid_tx_rate ? 1 : 0 ;
2008-08-04 00:16:41 -07:00
}
2008-11-18 09:08:13 +05:30
static inline int ath_rc_isvalid_txmask ( struct ath_rate_priv * ath_rc_priv ,
2008-08-04 00:16:41 -07:00
u8 index )
{
2008-11-18 09:03:12 +05:30
ASSERT ( index < = ath_rc_priv - > rate_table_size ) ;
return ath_rc_priv - > valid_rate_index [ index ] ;
2008-08-04 00:16:41 -07:00
}
2008-11-18 09:08:33 +05:30
static inline int ath_rc_get_nextvalid_txrate ( struct ath_rate_table * rate_table ,
struct ath_rate_priv * ath_rc_priv ,
u8 cur_valid_txrate ,
u8 * next_idx )
2008-08-04 00:16:41 -07:00
{
u8 i ;
2008-11-18 09:03:12 +05:30
for ( i = 0 ; i < ath_rc_priv - > max_valid_rate - 1 ; i + + ) {
if ( ath_rc_priv - > valid_rate_index [ i ] = = cur_valid_txrate ) {
* next_idx = ath_rc_priv - > valid_rate_index [ i + 1 ] ;
2008-11-18 09:08:13 +05:30
return 1 ;
2008-08-04 00:16:41 -07:00
}
}
/* No more valid rates */
* next_idx = 0 ;
2008-11-18 09:08:33 +05:30
2008-11-18 09:08:13 +05:30
return 0 ;
2008-08-04 00:16:41 -07:00
}
/* Return true only for single stream */
static int ath_rc_valid_phyrate ( u32 phy , u32 capflag , int ignore_cw )
{
2009-01-13 14:33:49 +02:00
if ( WLAN_RC_PHY_HT ( phy ) & & ! ( capflag & WLAN_RC_HT_FLAG ) )
2008-11-18 09:08:13 +05:30
return 0 ;
2008-08-04 00:16:41 -07:00
if ( WLAN_RC_PHY_DS ( phy ) & & ! ( capflag & WLAN_RC_DS_FLAG ) )
2008-11-18 09:08:13 +05:30
return 0 ;
2008-08-04 00:16:41 -07:00
if ( WLAN_RC_PHY_SGI ( phy ) & & ! ( capflag & WLAN_RC_SGI_FLAG ) )
2008-11-18 09:08:13 +05:30
return 0 ;
2008-08-04 00:16:41 -07:00
if ( ! ignore_cw & & WLAN_RC_PHY_HT ( phy ) )
if ( WLAN_RC_PHY_40 ( phy ) & & ! ( capflag & WLAN_RC_40_FLAG ) )
2008-11-18 09:08:13 +05:30
return 0 ;
2008-08-04 00:16:41 -07:00
if ( ! WLAN_RC_PHY_40 ( phy ) & & ( capflag & WLAN_RC_40_FLAG ) )
2008-11-18 09:08:13 +05:30
return 0 ;
return 1 ;
2008-08-04 00:16:41 -07:00
}
static inline int
2008-11-18 09:07:06 +05:30
ath_rc_get_nextlowervalid_txrate ( struct ath_rate_table * rate_table ,
2008-11-18 09:08:13 +05:30
struct ath_rate_priv * ath_rc_priv ,
2008-08-04 00:16:41 -07:00
u8 cur_valid_txrate , u8 * next_idx )
{
int8_t i ;
2008-11-18 09:03:12 +05:30
for ( i = 1 ; i < ath_rc_priv - > max_valid_rate ; i + + ) {
if ( ath_rc_priv - > valid_rate_index [ i ] = = cur_valid_txrate ) {
* next_idx = ath_rc_priv - > valid_rate_index [ i - 1 ] ;
2008-11-18 09:08:13 +05:30
return 1 ;
2008-08-04 00:16:41 -07:00
}
}
2008-11-18 09:08:33 +05:30
2008-11-18 09:08:13 +05:30
return 0 ;
2008-08-04 00:16:41 -07:00
}
2008-11-18 09:08:33 +05:30
static u8 ath_rc_init_validrates ( struct ath_rate_priv * ath_rc_priv ,
struct ath_rate_table * rate_table ,
u32 capflag )
2008-08-04 00:16:41 -07:00
{
u8 i , hi = 0 ;
u32 valid ;
for ( i = 0 ; i < rate_table - > rate_cnt ; i + + ) {
valid = ( ath_rc_priv - > single_stream ?
2008-08-14 13:26:55 +05:30
rate_table - > info [ i ] . valid_single_stream :
rate_table - > info [ i ] . valid ) ;
2008-11-18 09:08:13 +05:30
if ( valid = = 1 ) {
2008-08-04 00:16:41 -07:00
u32 phy = rate_table - > info [ i ] . phy ;
u8 valid_rate_count = 0 ;
2008-11-18 09:08:13 +05:30
if ( ! ath_rc_valid_phyrate ( phy , capflag , 0 ) )
2008-08-04 00:16:41 -07:00
continue ;
2008-11-18 09:03:12 +05:30
valid_rate_count = ath_rc_priv - > valid_phy_ratecnt [ phy ] ;
2008-08-04 00:16:41 -07:00
2008-11-18 09:03:12 +05:30
ath_rc_priv - > valid_phy_rateidx [ phy ] [ valid_rate_count ] = i ;
ath_rc_priv - > valid_phy_ratecnt [ phy ] + = 1 ;
2008-11-18 09:08:13 +05:30
ath_rc_set_valid_txmask ( ath_rc_priv , i , 1 ) ;
2008-08-04 00:16:41 -07:00
hi = A_MAX ( hi , i ) ;
}
}
2008-11-18 09:08:33 +05:30
2008-08-04 00:16:41 -07:00
return hi ;
}
2008-11-18 09:08:33 +05:30
static u8 ath_rc_setvalid_rates ( struct ath_rate_priv * ath_rc_priv ,
struct ath_rate_table * rate_table ,
struct ath_rateset * rateset ,
u32 capflag )
2008-08-04 00:16:41 -07:00
{
u8 i , j , hi = 0 ;
/* Use intersection of working rates and valid rates */
for ( i = 0 ; i < rateset - > rs_nrates ; i + + ) {
for ( j = 0 ; j < rate_table - > rate_cnt ; j + + ) {
u32 phy = rate_table - > info [ j ] . phy ;
u32 valid = ( ath_rc_priv - > single_stream ?
rate_table - > info [ j ] . valid_single_stream :
rate_table - > info [ j ] . valid ) ;
2008-11-18 09:08:33 +05:30
u8 rate = rateset - > rs_rates [ i ] ;
u8 dot11rate = rate_table - > info [ j ] . dot11rate ;
2008-08-04 00:16:41 -07:00
/* We allow a rate only if its valid and the
* capflag matches one of the validity
2008-11-18 09:08:13 +05:30
* ( VALID / VALID_20 / VALID_40 ) flags */
2008-08-04 00:16:41 -07:00
2008-11-18 09:08:33 +05:30
if ( ( ( rate & 0x7F ) = = ( dot11rate & 0x7F ) ) & &
( ( valid & WLAN_RC_CAP_MODE ( capflag ) ) = =
WLAN_RC_CAP_MODE ( capflag ) ) & &
! WLAN_RC_PHY_HT ( phy ) ) {
2008-08-04 00:16:41 -07:00
u8 valid_rate_count = 0 ;
2008-11-18 09:08:13 +05:30
if ( ! ath_rc_valid_phyrate ( phy , capflag , 0 ) )
2008-08-04 00:16:41 -07:00
continue ;
valid_rate_count =
2008-11-18 09:03:12 +05:30
ath_rc_priv - > valid_phy_ratecnt [ phy ] ;
2008-08-04 00:16:41 -07:00
2008-11-18 09:03:12 +05:30
ath_rc_priv - > valid_phy_rateidx [ phy ]
2008-08-04 00:16:41 -07:00
[ valid_rate_count ] = j ;
2008-11-18 09:03:12 +05:30
ath_rc_priv - > valid_phy_ratecnt [ phy ] + = 1 ;
2008-11-18 09:08:13 +05:30
ath_rc_set_valid_txmask ( ath_rc_priv , j , 1 ) ;
2008-08-04 00:16:41 -07:00
hi = A_MAX ( hi , j ) ;
}
}
}
2008-11-18 09:08:33 +05:30
2008-08-04 00:16:41 -07:00
return hi ;
}
2008-11-18 09:08:33 +05:30
static u8 ath_rc_setvalid_htrates ( struct ath_rate_priv * ath_rc_priv ,
struct ath_rate_table * rate_table ,
u8 * mcs_set , u32 capflag )
2008-08-04 00:16:41 -07:00
{
2008-11-18 09:08:33 +05:30
struct ath_rateset * rateset = ( struct ath_rateset * ) mcs_set ;
2008-08-04 00:16:41 -07:00
u8 i , j , hi = 0 ;
/* Use intersection of working rates and valid rates */
2008-11-18 09:08:33 +05:30
for ( i = 0 ; i < rateset - > rs_nrates ; i + + ) {
2008-08-04 00:16:41 -07:00
for ( j = 0 ; j < rate_table - > rate_cnt ; j + + ) {
u32 phy = rate_table - > info [ j ] . phy ;
u32 valid = ( ath_rc_priv - > single_stream ?
2008-08-14 13:26:55 +05:30
rate_table - > info [ j ] . valid_single_stream :
rate_table - > info [ j ] . valid ) ;
2008-11-18 09:08:33 +05:30
u8 rate = rateset - > rs_rates [ i ] ;
u8 dot11rate = rate_table - > info [ j ] . dot11rate ;
2008-08-04 00:16:41 -07:00
2008-11-18 09:08:33 +05:30
if ( ( ( rate & 0x7F ) ! = ( dot11rate & 0x7F ) ) | |
2008-08-14 13:26:55 +05:30
! WLAN_RC_PHY_HT ( phy ) | |
! WLAN_RC_PHY_HT_VALID ( valid , capflag ) )
2008-08-04 00:16:41 -07:00
continue ;
2008-11-18 09:08:13 +05:30
if ( ! ath_rc_valid_phyrate ( phy , capflag , 0 ) )
2008-08-04 00:16:41 -07:00
continue ;
2008-11-18 09:03:12 +05:30
ath_rc_priv - > valid_phy_rateidx [ phy ]
[ ath_rc_priv - > valid_phy_ratecnt [ phy ] ] = j ;
ath_rc_priv - > valid_phy_ratecnt [ phy ] + = 1 ;
2008-11-18 09:08:13 +05:30
ath_rc_set_valid_txmask ( ath_rc_priv , j , 1 ) ;
2008-08-04 00:16:41 -07:00
hi = A_MAX ( hi , j ) ;
}
}
2008-11-18 09:08:33 +05:30
return hi ;
2008-08-04 00:16:41 -07:00
}
static u8 ath_rc_ratefind_ht ( struct ath_softc * sc ,
2008-11-18 09:08:13 +05:30
struct ath_rate_priv * ath_rc_priv ,
2008-11-18 09:07:06 +05:30
struct ath_rate_table * rate_table ,
2008-08-14 13:26:55 +05:30
int probe_allowed , int * is_probing ,
int is_retry )
2008-08-04 00:16:41 -07:00
{
u32 dt , best_thruput , this_thruput , now_msec ;
u8 rate , next_rate , best_rate , maxindex , minindex ;
int8_t rssi_last , rssi_reduce = 0 , index = 0 ;
2008-11-18 09:08:13 +05:30
* is_probing = 0 ;
2008-08-04 00:16:41 -07:00
2008-11-18 09:03:12 +05:30
rssi_last = median ( ath_rc_priv - > rssi_last ,
ath_rc_priv - > rssi_last_prev ,
ath_rc_priv - > rssi_last_prev2 ) ;
2008-08-04 00:16:41 -07:00
/*
* Age ( reduce ) last ack rssi based on how old it is .
* The bizarre numbers are so the delta is 160 msec ,
* meaning we divide by 16.
* 0 msec < = dt < = 25 msec : don ' t derate
* 25 msec < = dt < = 185 msec : derate linearly from 0 to 10 dB
* 185 msec < = dt : derate by 10 dB
*/
now_msec = jiffies_to_msecs ( jiffies ) ;
2008-11-18 09:03:12 +05:30
dt = now_msec - ath_rc_priv - > rssi_time ;
2008-08-04 00:16:41 -07:00
if ( dt > = 185 )
rssi_reduce = 10 ;
else if ( dt > = 25 )
rssi_reduce = ( u8 ) ( ( dt - 25 ) > > 4 ) ;
/* Now reduce rssi_last by rssi_reduce */
if ( rssi_last < rssi_reduce )
rssi_last = 0 ;
else
rssi_last - = rssi_reduce ;
/*
* Now look up the rate in the rssi table and return it .
* If no rates match then we return 0 ( lowest rate )
*/
best_thruput = 0 ;
2008-11-18 09:03:12 +05:30
maxindex = ath_rc_priv - > max_valid_rate - 1 ;
2008-08-04 00:16:41 -07:00
minindex = 0 ;
best_rate = minindex ;
/*
* Try the higher rate first . It will reduce memory moving time
* if we have very good channel characteristics .
*/
for ( index = maxindex ; index > = minindex ; index - - ) {
u8 per_thres ;
2008-11-18 09:03:12 +05:30
rate = ath_rc_priv - > valid_rate_index [ index ] ;
if ( rate > ath_rc_priv - > rate_max_phy )
2008-08-04 00:16:41 -07:00
continue ;
/*
* For TCP the average collision rate is around 11 % ,
* so we ignore PERs less than this . This is to
* prevent the rate we are currently using ( whose
* PER might be in the 10 - 15 range because of TCP
* collisions ) looking worse than the next lower
* rate whose PER has decayed close to 0. If we
* used to next lower rate , its PER would grow to
* 10 - 15 and we would be worse off then staying
* at the current rate .
*/
2008-11-18 09:03:12 +05:30
per_thres = ath_rc_priv - > state [ rate ] . per ;
2008-08-04 00:16:41 -07:00
if ( per_thres < 12 )
per_thres = 12 ;
this_thruput = rate_table - > info [ rate ] . user_ratekbps *
( 100 - per_thres ) ;
if ( best_thruput < = this_thruput ) {
best_thruput = this_thruput ;
best_rate = rate ;
}
}
rate = best_rate ;
/* if we are retrying for more than half the number
* of max retries , use the min rate for the next retry
*/
if ( is_retry )
2008-11-18 09:03:12 +05:30
rate = ath_rc_priv - > valid_rate_index [ minindex ] ;
2008-08-04 00:16:41 -07:00
2008-11-18 09:03:12 +05:30
ath_rc_priv - > rssi_last_lookup = rssi_last ;
2008-08-04 00:16:41 -07:00
/*
* Must check the actual rate ( ratekbps ) to account for
* non - monoticity of 11 g ' s rate table
*/
2008-11-18 09:03:12 +05:30
if ( rate > = ath_rc_priv - > rate_max_phy & & probe_allowed ) {
rate = ath_rc_priv - > rate_max_phy ;
2008-08-04 00:16:41 -07:00
/* Probe the next allowed phy state */
/* FIXME:XXXX Check to make sure ratMax is checked properly */
if ( ath_rc_get_nextvalid_txrate ( rate_table ,
2008-11-18 09:03:12 +05:30
ath_rc_priv , rate , & next_rate ) & &
( now_msec - ath_rc_priv - > probe_time >
2008-08-04 00:16:41 -07:00
rate_table - > probe_interval ) & &
2008-11-18 09:03:12 +05:30
( ath_rc_priv - > hw_maxretry_pktcnt > = 1 ) ) {
2008-08-04 00:16:41 -07:00
rate = next_rate ;
2008-11-18 09:03:12 +05:30
ath_rc_priv - > probe_rate = rate ;
ath_rc_priv - > probe_time = now_msec ;
ath_rc_priv - > hw_maxretry_pktcnt = 0 ;
2008-11-18 09:08:13 +05:30
* is_probing = 1 ;
2008-08-04 00:16:41 -07:00
}
}
2008-11-18 09:03:12 +05:30
if ( rate > ( ath_rc_priv - > rate_table_size - 1 ) )
rate = ath_rc_priv - > rate_table_size - 1 ;
2008-08-04 00:16:41 -07:00
ASSERT ( ( rate_table - > info [ rate ] . valid & & ! ath_rc_priv - > single_stream ) | |
2008-08-14 13:26:55 +05:30
( rate_table - > info [ rate ] . valid_single_stream & &
ath_rc_priv - > single_stream ) ) ;
2008-08-04 00:16:41 -07:00
return rate ;
}
2008-11-18 09:07:06 +05:30
static void ath_rc_rate_set_series ( struct ath_rate_table * rate_table ,
2008-11-18 09:07:30 +05:30
struct ieee80211_tx_rate * rate ,
2008-11-18 09:08:33 +05:30
u8 tries , u8 rix , int rtsctsenable )
2008-08-04 00:16:41 -07:00
{
2008-11-18 09:07:30 +05:30
rate - > count = tries ;
rate - > idx = rix ;
if ( rtsctsenable )
rate - > flags | = IEEE80211_TX_RC_USE_RTS_CTS ;
if ( WLAN_RC_PHY_40 ( rate_table - > info [ rix ] . phy ) )
rate - > flags | = IEEE80211_TX_RC_40_MHZ_WIDTH ;
if ( WLAN_RC_PHY_SGI ( rate_table - > info [ rix ] . phy ) )
rate - > flags | = IEEE80211_TX_RC_SHORT_GI ;
if ( WLAN_RC_PHY_HT ( rate_table - > info [ rix ] . phy ) )
rate - > flags | = IEEE80211_TX_RC_MCS ;
2008-08-04 00:16:41 -07:00
}
static u8 ath_rc_rate_getidx ( struct ath_softc * sc ,
2008-11-18 09:08:13 +05:30
struct ath_rate_priv * ath_rc_priv ,
2008-11-18 09:07:06 +05:30
struct ath_rate_table * rate_table ,
2008-08-14 13:26:55 +05:30
u8 rix , u16 stepdown ,
u16 min_rate )
2008-08-04 00:16:41 -07:00
{
u32 j ;
u8 nextindex ;
if ( min_rate ) {
for ( j = RATE_TABLE_SIZE ; j > 0 ; j - - ) {
if ( ath_rc_get_nextlowervalid_txrate ( rate_table ,
2008-11-18 09:03:12 +05:30
ath_rc_priv , rix , & nextindex ) )
2008-08-04 00:16:41 -07:00
rix = nextindex ;
else
break ;
}
} else {
for ( j = stepdown ; j > 0 ; j - - ) {
if ( ath_rc_get_nextlowervalid_txrate ( rate_table ,
2008-11-18 09:03:12 +05:30
ath_rc_priv , rix , & nextindex ) )
2008-08-04 00:16:41 -07:00
rix = nextindex ;
else
break ;
}
}
return rix ;
}
static void ath_rc_ratefind ( struct ath_softc * sc ,
2008-11-18 09:08:13 +05:30
struct ath_rate_priv * ath_rc_priv ,
int num_tries , int num_rates ,
2008-11-18 09:07:30 +05:30
struct ieee80211_tx_info * tx_info , int * is_probe ,
2008-08-04 00:16:41 -07:00
int is_retry )
{
u8 try_per_rate = 0 , i = 0 , rix , nrix ;
struct ath_rate_table * rate_table ;
2008-11-18 09:07:30 +05:30
struct ieee80211_tx_rate * rates = tx_info - > control . rates ;
2008-08-04 00:16:41 -07:00
2008-12-07 21:41:37 +05:30
rate_table = sc - > cur_rate_table ;
2008-11-18 09:08:13 +05:30
rix = ath_rc_ratefind_ht ( sc , ath_rc_priv , rate_table , 1 ,
2008-08-14 13:26:55 +05:30
is_probe , is_retry ) ;
2008-08-04 00:16:41 -07:00
nrix = rix ;
2008-11-18 09:08:13 +05:30
if ( * is_probe ) {
2008-08-04 00:16:41 -07:00
/* set one try for probe rates. For the
* probes don ' t enable rts */
ath_rc_rate_set_series ( rate_table ,
2008-11-18 09:08:13 +05:30
& rates [ i + + ] , 1 , nrix , 0 ) ;
2008-08-04 00:16:41 -07:00
try_per_rate = ( num_tries / num_rates ) ;
/* Get the next tried/allowed rate. No RTS for the next series
* after the probe rate
*/
nrix = ath_rc_rate_getidx ( sc ,
2008-11-18 09:08:13 +05:30
ath_rc_priv , rate_table , nrix , 1 , 0 ) ;
2008-08-04 00:16:41 -07:00
ath_rc_rate_set_series ( rate_table ,
2008-11-18 09:07:30 +05:30
& rates [ i + + ] , try_per_rate , nrix , 0 ) ;
2008-08-04 00:16:41 -07:00
} else {
try_per_rate = ( num_tries / num_rates ) ;
/* Set the choosen rate. No RTS for first series entry. */
ath_rc_rate_set_series ( rate_table ,
2008-11-18 09:08:13 +05:30
& rates [ i + + ] , try_per_rate , nrix , 0 ) ;
2008-08-04 00:16:41 -07:00
}
/* Fill in the other rates for multirate retry */
for ( ; i < num_rates ; i + + ) {
u8 try_num ;
u8 min_rate ;
try_num = ( ( i + 1 ) = = num_rates ) ?
num_tries - ( try_per_rate * i ) : try_per_rate ;
2008-11-18 09:08:13 +05:30
min_rate = ( ( ( i + 1 ) = = num_rates ) & & 0 ) ;
2008-08-04 00:16:41 -07:00
nrix = ath_rc_rate_getidx ( sc , ath_rc_priv ,
2008-08-14 13:26:55 +05:30
rate_table , nrix , 1 , min_rate ) ;
2008-08-04 00:16:41 -07:00
/* All other rates in the series have RTS enabled */
ath_rc_rate_set_series ( rate_table ,
2008-11-18 09:08:13 +05:30
& rates [ i ] , try_num , nrix , 1 ) ;
2008-08-04 00:16:41 -07:00
}
/*
* NB : Change rate series to enable aggregation when operating
* at lower MCS rates . When first rate in series is MCS2
* in HT40 @ 2.4 GHz , series should look like :
*
* { MCS2 , MCS1 , MCS0 , MCS0 } .
*
* When first rate in series is MCS3 in HT20 @ 2.4 GHz , series should
* look like :
*
* { MCS3 , MCS2 , MCS1 , MCS1 }
*
* So , set fourth rate in series to be same as third one for
* above conditions .
*/
2008-12-07 21:42:10 +05:30
if ( ( sc - > hw - > conf . channel - > band = = IEEE80211_BAND_2GHZ ) & &
2008-12-23 15:58:43 -08:00
( conf_is_ht ( & sc - > hw - > conf ) ) ) {
2008-12-07 21:41:37 +05:30
u8 dot11rate = rate_table - > info [ rix ] . dot11rate ;
2008-08-04 00:16:41 -07:00
u8 phy = rate_table - > info [ rix ] . phy ;
if ( i = = 4 & &
( ( dot11rate = = 2 & & phy = = WLAN_RC_PHY_HT_40_SS ) | |
2008-08-14 13:26:55 +05:30
( dot11rate = = 3 & & phy = = WLAN_RC_PHY_HT_20_SS ) ) ) {
2008-11-18 09:07:30 +05:30
rates [ 3 ] . idx = rates [ 2 ] . idx ;
rates [ 3 ] . flags = rates [ 2 ] . flags ;
2008-08-04 00:16:41 -07:00
}
}
}
2008-11-18 09:08:33 +05:30
static bool ath_rc_update_per ( struct ath_softc * sc ,
struct ath_rate_table * rate_table ,
struct ath_rate_priv * ath_rc_priv ,
struct ath_tx_info_priv * tx_info_priv ,
int tx_rate , int xretries , int retries ,
u32 now_msec )
2008-08-04 00:16:41 -07:00
{
2008-11-18 09:08:33 +05:30
bool state_change = false ;
int count ;
2008-08-04 00:16:41 -07:00
u8 last_per ;
static u32 nretry_to_per_lookup [ 10 ] = {
100 * 0 / 1 ,
100 * 1 / 4 ,
100 * 1 / 2 ,
100 * 3 / 4 ,
100 * 4 / 5 ,
100 * 5 / 6 ,
100 * 6 / 7 ,
100 * 7 / 8 ,
100 * 8 / 9 ,
100 * 9 / 10
} ;
2008-11-18 09:03:12 +05:30
last_per = ath_rc_priv - > state [ tx_rate ] . per ;
2008-08-04 00:16:41 -07:00
if ( xretries ) {
if ( xretries = = 1 ) {
2008-11-18 09:03:12 +05:30
ath_rc_priv - > state [ tx_rate ] . per + = 30 ;
if ( ath_rc_priv - > state [ tx_rate ] . per > 100 )
ath_rc_priv - > state [ tx_rate ] . per = 100 ;
2008-08-04 00:16:41 -07:00
} else {
/* xretries == 2 */
2008-11-09 17:56:10 +01:00
count = ARRAY_SIZE ( nretry_to_per_lookup ) ;
2008-08-04 00:16:41 -07:00
if ( retries > = count )
retries = count - 1 ;
2008-11-18 09:08:33 +05:30
2008-08-04 00:16:41 -07:00
/* new_PER = 7/8*old_PER + 1/8*(currentPER) */
2008-11-18 09:03:12 +05:30
ath_rc_priv - > state [ tx_rate ] . per =
2008-11-18 09:08:33 +05:30
( u8 ) ( last_per - ( last_per > > 3 ) + ( 100 > > 3 ) ) ;
2008-08-04 00:16:41 -07:00
}
/* xretries == 1 or 2 */
2008-11-18 09:03:12 +05:30
if ( ath_rc_priv - > probe_rate = = tx_rate )
ath_rc_priv - > probe_rate = 0 ;
2008-08-04 00:16:41 -07:00
2008-11-18 09:08:33 +05:30
} else { /* xretries == 0 */
2008-11-09 17:56:10 +01:00
count = ARRAY_SIZE ( nretry_to_per_lookup ) ;
2008-08-04 00:16:41 -07:00
if ( retries > = count )
retries = count - 1 ;
2008-11-18 09:08:33 +05:30
2008-11-18 09:08:13 +05:30
if ( tx_info_priv - > n_bad_frames ) {
2008-08-14 13:26:55 +05:30
/* new_PER = 7/8*old_PER + 1/8*(currentPER)
2008-08-04 00:16:41 -07:00
* Assuming that n_frames is not 0. The current PER
* from the retries is 100 * retries / ( retries + 1 ) ,
* since the first retries attempts failed , and the
* next one worked . For the one that worked ,
* n_bad_frames subframes out of n_frames wored ,
* so the PER for that part is
* 100 * n_bad_frames / n_frames , and it contributes
* 100 * n_bad_frames / ( n_frames * ( retries + 1 ) ) to
* the above PER . The expression below is a
* simplified version of the sum of these two terms .
*/
2008-11-18 09:08:33 +05:30
if ( tx_info_priv - > n_frames > 0 ) {
int n_frames , n_bad_frames ;
u8 cur_per , new_per ;
n_bad_frames = retries * tx_info_priv - > n_frames +
tx_info_priv - > n_bad_frames ;
n_frames = tx_info_priv - > n_frames * ( retries + 1 ) ;
cur_per = ( 100 * n_bad_frames / n_frames ) > > 3 ;
new_per = ( u8 ) ( last_per - ( last_per > > 3 ) + cur_per ) ;
ath_rc_priv - > state [ tx_rate ] . per = new_per ;
}
2008-08-04 00:16:41 -07:00
} else {
2008-11-18 09:08:33 +05:30
ath_rc_priv - > state [ tx_rate ] . per =
( u8 ) ( last_per - ( last_per > > 3 ) +
( nretry_to_per_lookup [ retries ] > > 3 ) ) ;
2008-08-04 00:16:41 -07:00
}
2008-11-18 09:03:12 +05:30
ath_rc_priv - > rssi_last_prev2 = ath_rc_priv - > rssi_last_prev ;
ath_rc_priv - > rssi_last_prev = ath_rc_priv - > rssi_last ;
2008-11-18 09:08:13 +05:30
ath_rc_priv - > rssi_last = tx_info_priv - > tx . ts_rssi ;
2008-11-18 09:03:12 +05:30
ath_rc_priv - > rssi_time = now_msec ;
2008-08-04 00:16:41 -07:00
/*
* If we got at most one retry then increase the max rate if
* this was a probe . Otherwise , ignore the probe .
*/
2008-11-18 09:03:12 +05:30
if ( ath_rc_priv - > probe_rate & & ath_rc_priv - > probe_rate = = tx_rate ) {
2008-11-18 09:08:13 +05:30
if ( retries > 0 | | 2 * tx_info_priv - > n_bad_frames >
tx_info_priv - > n_frames ) {
2008-08-04 00:16:41 -07:00
/*
* Since we probed with just a single attempt ,
* any retries means the probe failed . Also ,
* if the attempt worked , but more than half
* the subframes were bad then also consider
* the probe a failure .
*/
2008-11-18 09:03:12 +05:30
ath_rc_priv - > probe_rate = 0 ;
2008-08-04 00:16:41 -07:00
} else {
u8 probe_rate = 0 ;
2008-11-18 09:08:33 +05:30
ath_rc_priv - > rate_max_phy =
ath_rc_priv - > probe_rate ;
2008-11-18 09:03:12 +05:30
probe_rate = ath_rc_priv - > probe_rate ;
2008-08-04 00:16:41 -07:00
2008-11-18 09:03:12 +05:30
if ( ath_rc_priv - > state [ probe_rate ] . per > 30 )
ath_rc_priv - > state [ probe_rate ] . per = 20 ;
2008-08-04 00:16:41 -07:00
2008-11-18 09:03:12 +05:30
ath_rc_priv - > probe_rate = 0 ;
2008-08-04 00:16:41 -07:00
/*
* Since this probe succeeded , we allow the next
* probe twice as soon . This allows the maxRate
* to move up faster if the probes are
* succesful .
*/
2008-11-18 09:08:33 +05:30
ath_rc_priv - > probe_time =
now_msec - rate_table - > probe_interval / 2 ;
2008-08-04 00:16:41 -07:00
}
}
if ( retries > 0 ) {
/*
* Don ' t update anything . We don ' t know if
* this was because of collisions or poor signal .
*
* Later : if rssi_ack is close to
2008-11-18 09:03:12 +05:30
* ath_rc_priv - > state [ txRate ] . rssi_thres and we see lots
2008-08-04 00:16:41 -07:00
* of retries , then we could increase
2008-11-18 09:03:12 +05:30
* ath_rc_priv - > state [ txRate ] . rssi_thres .
2008-08-04 00:16:41 -07:00
*/
2008-11-18 09:03:12 +05:30
ath_rc_priv - > hw_maxretry_pktcnt = 0 ;
2008-08-04 00:16:41 -07:00
} else {
2008-11-18 09:08:33 +05:30
int32_t rssi_ackAvg ;
int8_t rssi_thres ;
int8_t rssi_ack_vmin ;
2008-08-04 00:16:41 -07:00
/*
* It worked with no retries . First ignore bogus ( small )
* rssi_ack values .
*/
2008-11-18 09:03:12 +05:30
if ( tx_rate = = ath_rc_priv - > rate_max_phy & &
ath_rc_priv - > hw_maxretry_pktcnt < 255 ) {
ath_rc_priv - > hw_maxretry_pktcnt + + ;
2008-08-04 00:16:41 -07:00
}
2008-11-18 09:08:33 +05:30
if ( tx_info_priv - > tx . ts_rssi <
rate_table - > info [ tx_rate ] . rssi_ack_validmin )
goto exit ;
2008-08-04 00:16:41 -07:00
2008-11-18 09:08:33 +05:30
/* Average the rssi */
if ( tx_rate ! = ath_rc_priv - > rssi_sum_rate ) {
ath_rc_priv - > rssi_sum_rate = tx_rate ;
ath_rc_priv - > rssi_sum =
ath_rc_priv - > rssi_sum_cnt = 0 ;
}
ath_rc_priv - > rssi_sum + = tx_info_priv - > tx . ts_rssi ;
ath_rc_priv - > rssi_sum_cnt + + ;
if ( ath_rc_priv - > rssi_sum_cnt < 4 )
goto exit ;
rssi_ackAvg =
( ath_rc_priv - > rssi_sum + 2 ) / 4 ;
rssi_thres =
ath_rc_priv - > state [ tx_rate ] . rssi_thres ;
rssi_ack_vmin =
rate_table - > info [ tx_rate ] . rssi_ack_validmin ;
ath_rc_priv - > rssi_sum =
ath_rc_priv - > rssi_sum_cnt = 0 ;
/* Now reduce the current rssi threshold */
if ( ( rssi_ackAvg < rssi_thres + 2 ) & &
( rssi_thres > rssi_ack_vmin ) ) {
ath_rc_priv - > state [ tx_rate ] . rssi_thres - - ;
2008-08-04 00:16:41 -07:00
}
2008-11-18 09:08:33 +05:30
state_change = true ;
2008-08-04 00:16:41 -07:00
}
}
2008-11-18 09:08:33 +05:30
exit :
return state_change ;
}
/* Update PER, RSSI and whatever else that the code thinks it is doing.
If you can make sense of all this , you really need to go out more . */
static void ath_rc_update_ht ( struct ath_softc * sc ,
struct ath_rate_priv * ath_rc_priv ,
struct ath_tx_info_priv * tx_info_priv ,
int tx_rate , int xretries , int retries )
{
# define CHK_RSSI(rate) \
( ( ath_rc_priv - > state [ ( rate ) ] . rssi_thres + \
rate_table - > info [ ( rate ) ] . rssi_ack_deltamin ) > \
ath_rc_priv - > state [ ( rate ) + 1 ] . rssi_thres )
u32 now_msec = jiffies_to_msecs ( jiffies ) ;
int rate ;
u8 last_per ;
bool state_change = false ;
2008-12-07 21:41:37 +05:30
struct ath_rate_table * rate_table = sc - > cur_rate_table ;
2008-11-18 09:08:33 +05:30
int size = ath_rc_priv - > rate_table_size ;
if ( ( tx_rate < 0 ) | | ( tx_rate > rate_table - > rate_cnt ) )
return ;
2008-08-04 00:16:41 -07:00
2008-11-18 09:08:33 +05:30
/* To compensate for some imbalance between ctrl and ext. channel */
if ( WLAN_RC_PHY_40 ( rate_table - > info [ tx_rate ] . phy ) )
tx_info_priv - > tx . ts_rssi =
tx_info_priv - > tx . ts_rssi < 3 ? 0 :
tx_info_priv - > tx . ts_rssi - 3 ;
last_per = ath_rc_priv - > state [ tx_rate ] . per ;
/* Update PER first */
state_change = ath_rc_update_per ( sc , rate_table , ath_rc_priv ,
tx_info_priv , tx_rate , xretries ,
retries , now_msec ) ;
2008-08-04 00:16:41 -07:00
/*
* If this rate looks bad ( high PER ) then stop using it for
* a while ( except if we are probing ) .
*/
2008-11-18 09:03:12 +05:30
if ( ath_rc_priv - > state [ tx_rate ] . per > = 55 & & tx_rate > 0 & &
2008-08-14 13:26:55 +05:30
rate_table - > info [ tx_rate ] . ratekbps < =
2008-11-18 09:03:12 +05:30
rate_table - > info [ ath_rc_priv - > rate_max_phy ] . ratekbps ) {
ath_rc_get_nextlowervalid_txrate ( rate_table , ath_rc_priv ,
2008-11-18 09:08:33 +05:30
( u8 ) tx_rate , & ath_rc_priv - > rate_max_phy ) ;
2008-08-04 00:16:41 -07:00
/* Don't probe for a little while. */
2008-11-18 09:03:12 +05:30
ath_rc_priv - > probe_time = now_msec ;
2008-08-04 00:16:41 -07:00
}
if ( state_change ) {
/*
* Make sure the rates above this have higher rssi thresholds .
* ( Note : Monotonicity is kept within the OFDM rates and
* within the CCK rates . However , no adjustment is
* made to keep the rssi thresholds monotonically
* increasing between the CCK and OFDM rates . )
*/
2008-11-18 09:08:33 +05:30
for ( rate = tx_rate ; rate < size - 1 ; rate + + ) {
2008-08-04 00:16:41 -07:00
if ( rate_table - > info [ rate + 1 ] . phy ! =
2008-11-18 09:08:33 +05:30
rate_table - > info [ tx_rate ] . phy )
2008-08-04 00:16:41 -07:00
break ;
2008-11-18 09:08:33 +05:30
if ( CHK_RSSI ( rate ) ) {
2008-11-18 09:03:12 +05:30
ath_rc_priv - > state [ rate + 1 ] . rssi_thres =
2008-11-18 09:08:33 +05:30
ath_rc_priv - > state [ rate ] . rssi_thres +
rate_table - > info [ rate ] . rssi_ack_deltamin ;
2008-08-04 00:16:41 -07:00
}
}
/* Make sure the rates below this have lower rssi thresholds. */
for ( rate = tx_rate - 1 ; rate > = 0 ; rate - - ) {
if ( rate_table - > info [ rate ] . phy ! =
2008-08-14 13:26:55 +05:30
rate_table - > info [ tx_rate ] . phy )
2008-08-04 00:16:41 -07:00
break ;
2008-11-18 09:08:33 +05:30
if ( CHK_RSSI ( rate ) ) {
2008-11-18 09:03:12 +05:30
if ( ath_rc_priv - > state [ rate + 1 ] . rssi_thres <
2008-11-18 09:08:33 +05:30
rate_table - > info [ rate ] . rssi_ack_deltamin )
2008-11-18 09:03:12 +05:30
ath_rc_priv - > state [ rate ] . rssi_thres = 0 ;
2008-08-04 00:16:41 -07:00
else {
2008-11-18 09:03:12 +05:30
ath_rc_priv - > state [ rate ] . rssi_thres =
2008-11-18 09:08:33 +05:30
ath_rc_priv - > state [ rate + 1 ] . rssi_thres -
rate_table - > info [ rate ] . rssi_ack_deltamin ;
2008-08-04 00:16:41 -07:00
}
2008-11-18 09:03:12 +05:30
if ( ath_rc_priv - > state [ rate ] . rssi_thres <
2008-11-18 09:08:33 +05:30
rate_table - > info [ rate ] . rssi_ack_validmin ) {
2008-11-18 09:03:12 +05:30
ath_rc_priv - > state [ rate ] . rssi_thres =
2008-11-18 09:08:33 +05:30
rate_table - > info [ rate ] . rssi_ack_validmin ;
2008-08-04 00:16:41 -07:00
}
}
}
}
/* Make sure the rates below this have lower PER */
/* Monotonicity is kept only for rates below the current rate. */
2008-11-18 09:03:12 +05:30
if ( ath_rc_priv - > state [ tx_rate ] . per < last_per ) {
2008-08-04 00:16:41 -07:00
for ( rate = tx_rate - 1 ; rate > = 0 ; rate - - ) {
if ( rate_table - > info [ rate ] . phy ! =
2008-08-14 13:26:55 +05:30
rate_table - > info [ tx_rate ] . phy )
2008-08-04 00:16:41 -07:00
break ;
2008-11-18 09:03:12 +05:30
if ( ath_rc_priv - > state [ rate ] . per >
ath_rc_priv - > state [ rate + 1 ] . per ) {
ath_rc_priv - > state [ rate ] . per =
ath_rc_priv - > state [ rate + 1 ] . per ;
2008-08-04 00:16:41 -07:00
}
}
}
/* Maintain monotonicity for rates above the current rate */
2008-11-18 09:08:33 +05:30
for ( rate = tx_rate ; rate < size - 1 ; rate + + ) {
if ( ath_rc_priv - > state [ rate + 1 ] . per <
ath_rc_priv - > state [ rate ] . per )
2008-11-18 09:03:12 +05:30
ath_rc_priv - > state [ rate + 1 ] . per =
ath_rc_priv - > state [ rate ] . per ;
2008-08-04 00:16:41 -07:00
}
/* Every so often, we reduce the thresholds and
* PER ( different for CCK and OFDM ) . */
2008-11-18 09:03:12 +05:30
if ( now_msec - ath_rc_priv - > rssi_down_time > =
2008-08-14 13:26:55 +05:30
rate_table - > rssi_reduce_interval ) {
2008-08-04 00:16:41 -07:00
2008-11-18 09:08:33 +05:30
for ( rate = 0 ; rate < size ; rate + + ) {
2008-11-18 09:03:12 +05:30
if ( ath_rc_priv - > state [ rate ] . rssi_thres >
2008-08-14 13:26:55 +05:30
rate_table - > info [ rate ] . rssi_ack_validmin )
2008-11-18 09:03:12 +05:30
ath_rc_priv - > state [ rate ] . rssi_thres - = 1 ;
2008-08-04 00:16:41 -07:00
}
2008-11-18 09:03:12 +05:30
ath_rc_priv - > rssi_down_time = now_msec ;
2008-08-04 00:16:41 -07:00
}
/* Every so often, we reduce the thresholds
* and PER ( different for CCK and OFDM ) . */
2008-11-18 09:03:12 +05:30
if ( now_msec - ath_rc_priv - > per_down_time > =
2008-08-14 13:26:55 +05:30
rate_table - > rssi_reduce_interval ) {
2008-11-18 09:08:33 +05:30
for ( rate = 0 ; rate < size ; rate + + ) {
2008-11-18 09:03:12 +05:30
ath_rc_priv - > state [ rate ] . per =
7 * ath_rc_priv - > state [ rate ] . per / 8 ;
2008-08-04 00:16:41 -07:00
}
2008-11-18 09:03:12 +05:30
ath_rc_priv - > per_down_time = now_msec ;
2008-08-04 00:16:41 -07:00
}
2008-11-18 09:08:33 +05:30
# undef CHK_RSSI
}
static int ath_rc_get_rateindex ( struct ath_rate_table * rate_table ,
struct ieee80211_tx_rate * rate )
{
int rix ;
if ( ( rate - > flags & IEEE80211_TX_RC_40_MHZ_WIDTH ) & &
( rate - > flags & IEEE80211_TX_RC_SHORT_GI ) )
rix = rate_table - > info [ rate - > idx ] . ht_index ;
else if ( rate - > flags & IEEE80211_TX_RC_SHORT_GI )
rix = rate_table - > info [ rate - > idx ] . sgi_index ;
else if ( rate - > flags & IEEE80211_TX_RC_40_MHZ_WIDTH )
rix = rate_table - > info [ rate - > idx ] . cw40index ;
else
rix = rate_table - > info [ rate - > idx ] . base_index ;
return rix ;
2008-08-04 00:16:41 -07:00
}
2008-11-18 09:08:13 +05:30
static void ath_rc_tx_status ( struct ath_softc * sc ,
struct ath_rate_priv * ath_rc_priv ,
struct ieee80211_tx_info * tx_info ,
int final_ts_idx , int xretries , int long_retry )
2008-08-04 00:16:41 -07:00
{
2008-11-18 09:08:13 +05:30
struct ath_tx_info_priv * tx_info_priv = ATH_TX_INFO_PRIV ( tx_info ) ;
2008-08-04 00:16:41 -07:00
struct ath_rate_table * rate_table ;
2008-11-18 09:07:30 +05:30
struct ieee80211_tx_rate * rates = tx_info - > status . rates ;
2008-08-04 00:16:41 -07:00
u8 flags ;
2008-11-18 09:08:33 +05:30
u32 i = 0 , rix ;
2008-08-04 00:16:41 -07:00
2008-12-07 21:41:37 +05:30
rate_table = sc - > cur_rate_table ;
2008-08-04 00:16:41 -07:00
/*
* If the first rate is not the final index , there
* are intermediate rate failures to be processed .
*/
if ( final_ts_idx ! = 0 ) {
/* Process intermediate rates that failed.*/
2008-11-18 09:08:33 +05:30
for ( i = 0 ; i < final_ts_idx ; i + + ) {
if ( rates [ i ] . count ! = 0 & & ( rates [ i ] . idx > = 0 ) ) {
flags = rates [ i ] . flags ;
2008-08-04 00:16:41 -07:00
/* If HT40 and we have switched mode from
* 40 to 20 = > don ' t update */
2008-11-18 09:08:33 +05:30
2008-11-18 09:07:30 +05:30
if ( ( flags & IEEE80211_TX_RC_40_MHZ_WIDTH ) & &
2008-11-18 09:07:53 +05:30
( ath_rc_priv - > rc_phy_mode ! = WLAN_RC_40_FLAG ) )
2008-08-04 00:16:41 -07:00
return ;
2008-11-18 09:07:53 +05:30
2008-11-18 09:08:33 +05:30
rix = ath_rc_get_rateindex ( rate_table , & rates [ i ] ) ;
2008-08-04 00:16:41 -07:00
ath_rc_update_ht ( sc , ath_rc_priv ,
2008-11-18 09:08:13 +05:30
tx_info_priv , rix ,
2008-08-04 00:16:41 -07:00
xretries ? 1 : 2 ,
2008-11-18 09:08:33 +05:30
rates [ i ] . count ) ;
2008-08-04 00:16:41 -07:00
}
}
} else {
/*
* Handle the special case of MIMO PS burst , where the second
* aggregate is sent out with only one rate and one try .
* Treating it as an excessive retry penalizes the rate
* inordinately .
*/
2008-11-18 09:07:30 +05:30
if ( rates [ 0 ] . count = = 1 & & xretries = = 1 )
2008-08-04 00:16:41 -07:00
xretries = 2 ;
}
2008-11-18 09:08:33 +05:30
flags = rates [ i ] . flags ;
2008-08-04 00:16:41 -07:00
/* If HT40 and we have switched mode from 40 to 20 => don't update */
2008-11-18 09:07:30 +05:30
if ( ( flags & IEEE80211_TX_RC_40_MHZ_WIDTH ) & &
2008-11-18 09:07:53 +05:30
( ath_rc_priv - > rc_phy_mode ! = WLAN_RC_40_FLAG ) ) {
2008-08-04 00:16:41 -07:00
return ;
2008-11-18 09:07:53 +05:30
}
2008-08-04 00:16:41 -07:00
2008-11-18 09:08:33 +05:30
rix = ath_rc_get_rateindex ( rate_table , & rates [ i ] ) ;
2008-11-18 09:08:13 +05:30
ath_rc_update_ht ( sc , ath_rc_priv , tx_info_priv , rix ,
2008-11-18 09:08:33 +05:30
xretries , long_retry ) ;
2008-08-04 00:16:41 -07:00
}
2008-11-27 09:46:27 +05:30
static struct ath_rate_table * ath_choose_rate_table ( struct ath_softc * sc ,
enum ieee80211_band band ,
bool is_ht , bool is_cw_40 )
{
int mode = 0 ;
switch ( band ) {
case IEEE80211_BAND_2GHZ :
mode = ATH9K_MODE_11G ;
if ( is_ht )
mode = ATH9K_MODE_11NG_HT20 ;
if ( is_cw_40 )
mode = ATH9K_MODE_11NG_HT40PLUS ;
break ;
case IEEE80211_BAND_5GHZ :
mode = ATH9K_MODE_11A ;
if ( is_ht )
mode = ATH9K_MODE_11NA_HT20 ;
if ( is_cw_40 )
mode = ATH9K_MODE_11NA_HT40PLUS ;
break ;
default :
2008-11-28 22:18:05 +05:30
DPRINTF ( sc , ATH_DBG_CONFIG , " Invalid band \n " ) ;
2008-11-27 09:46:27 +05:30
return NULL ;
}
BUG_ON ( mode > = ATH9K_MODE_MAX ) ;
2008-11-28 22:18:05 +05:30
DPRINTF ( sc , ATH_DBG_CONFIG , " Choosing rate table for mode: %d \n " , mode ) ;
2008-11-27 09:46:27 +05:30
return sc - > hw_rate_table [ mode ] ;
}
2008-11-18 09:06:44 +05:30
static void ath_rc_init ( struct ath_softc * sc ,
2008-11-18 09:08:13 +05:30
struct ath_rate_priv * ath_rc_priv ,
2008-11-18 09:06:44 +05:30
struct ieee80211_supported_band * sband ,
struct ieee80211_sta * sta )
2008-08-04 00:16:41 -07:00
{
struct ath_rate_table * rate_table = NULL ;
2008-11-18 09:06:44 +05:30
struct ath_rateset * rateset = & ath_rc_priv - > neg_rates ;
u8 * ht_mcs = ( u8 * ) & ath_rc_priv - > neg_ht_rates ;
2008-08-04 00:16:41 -07:00
u8 i , j , k , hi = 0 , hthi = 0 ;
2008-11-27 09:46:27 +05:30
/* FIXME: Adhoc */
2008-12-01 13:38:55 -08:00
if ( ( sc - > sc_ah - > ah_opmode = = NL80211_IFTYPE_STATION ) | |
( sc - > sc_ah - > ah_opmode = = NL80211_IFTYPE_ADHOC ) ) {
2008-11-27 09:46:27 +05:30
bool is_cw_40 = sta - > ht_cap . cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ;
rate_table = ath_choose_rate_table ( sc , sband - > band ,
sta - > ht_cap . ht_supported ,
is_cw_40 ) ;
2008-12-01 13:38:55 -08:00
} else if ( sc - > sc_ah - > ah_opmode = = NL80211_IFTYPE_AP ) {
2008-12-07 21:42:10 +05:30
/* cur_rate_table would be set on init through config() */
rate_table = sc - > cur_rate_table ;
2008-11-27 09:46:27 +05:30
}
2008-08-04 00:16:41 -07:00
2008-11-27 09:46:27 +05:30
if ( ! rate_table ) {
DPRINTF ( sc , ATH_DBG_FATAL , " Rate table not initialized \n " ) ;
return ;
}
2008-11-18 09:06:44 +05:30
2008-11-27 09:46:27 +05:30
if ( sta - > ht_cap . ht_supported ) {
2008-11-18 09:06:44 +05:30
ath_rc_priv - > ht_cap = ( WLAN_RC_HT_FLAG | WLAN_RC_DS_FLAG ) ;
if ( sta - > ht_cap . cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 )
ath_rc_priv - > ht_cap | = WLAN_RC_40_FLAG ;
}
2008-08-04 00:16:41 -07:00
/* Initial rate table size. Will change depending
* on the working rate set */
2008-11-18 09:08:13 +05:30
ath_rc_priv - > rate_table_size = RATE_TABLE_SIZE ;
2008-08-04 00:16:41 -07:00
/* Initialize thresholds according to the global rate table */
2008-11-18 09:06:44 +05:30
for ( i = 0 ; i < ath_rc_priv - > rate_table_size ; i + + ) {
2008-11-18 09:03:12 +05:30
ath_rc_priv - > state [ i ] . rssi_thres =
2008-08-04 00:16:41 -07:00
rate_table - > info [ i ] . rssi_ack_validmin ;
2008-11-18 09:03:12 +05:30
ath_rc_priv - > state [ i ] . per = 0 ;
2008-08-04 00:16:41 -07:00
}
/* Determine the valid rates */
2008-11-18 09:03:12 +05:30
ath_rc_init_valid_txmask ( ath_rc_priv ) ;
2008-08-04 00:16:41 -07:00
for ( i = 0 ; i < WLAN_RC_PHY_MAX ; i + + ) {
for ( j = 0 ; j < MAX_TX_RATE_PHY ; j + + )
2008-11-18 09:03:12 +05:30
ath_rc_priv - > valid_phy_rateidx [ i ] [ j ] = 0 ;
ath_rc_priv - > valid_phy_ratecnt [ i ] = 0 ;
2008-08-04 00:16:41 -07:00
}
2008-11-18 09:06:44 +05:30
ath_rc_priv - > rc_phy_mode = ( ath_rc_priv - > ht_cap & WLAN_RC_40_FLAG ) ;
2008-08-04 00:16:41 -07:00
/* Set stream capability */
2008-11-18 09:06:44 +05:30
ath_rc_priv - > single_stream = ( ath_rc_priv - > ht_cap & WLAN_RC_DS_FLAG ) ? 0 : 1 ;
2008-08-04 00:16:41 -07:00
if ( ! rateset - > rs_nrates ) {
/* No working rate, just initialize valid rates */
2008-11-18 09:08:33 +05:30
hi = ath_rc_init_validrates ( ath_rc_priv , rate_table ,
2008-11-18 09:06:44 +05:30
ath_rc_priv - > ht_cap ) ;
2008-08-04 00:16:41 -07:00
} else {
/* Use intersection of working rates and valid rates */
2008-11-18 09:08:33 +05:30
hi = ath_rc_setvalid_rates ( ath_rc_priv , rate_table ,
2008-11-18 09:06:44 +05:30
rateset , ath_rc_priv - > ht_cap ) ;
if ( ath_rc_priv - > ht_cap & WLAN_RC_HT_FLAG ) {
2008-11-18 09:08:33 +05:30
hthi = ath_rc_setvalid_htrates ( ath_rc_priv ,
2008-08-04 00:16:41 -07:00
rate_table ,
ht_mcs ,
2008-11-18 09:06:44 +05:30
ath_rc_priv - > ht_cap ) ;
2008-08-04 00:16:41 -07:00
}
hi = A_MAX ( hi , hthi ) ;
}
2008-11-18 09:03:12 +05:30
ath_rc_priv - > rate_table_size = hi + 1 ;
ath_rc_priv - > rate_max_phy = 0 ;
2008-11-18 09:08:13 +05:30
ASSERT ( ath_rc_priv - > rate_table_size < = RATE_TABLE_SIZE ) ;
2008-08-04 00:16:41 -07:00
for ( i = 0 , k = 0 ; i < WLAN_RC_PHY_MAX ; i + + ) {
2008-11-18 09:03:12 +05:30
for ( j = 0 ; j < ath_rc_priv - > valid_phy_ratecnt [ i ] ; j + + ) {
ath_rc_priv - > valid_rate_index [ k + + ] =
ath_rc_priv - > valid_phy_rateidx [ i ] [ j ] ;
2008-08-04 00:16:41 -07:00
}
2008-11-18 09:08:13 +05:30
if ( ! ath_rc_valid_phyrate ( i , rate_table - > initial_ratemax , 1 )
2008-11-18 09:03:12 +05:30
| | ! ath_rc_priv - > valid_phy_ratecnt [ i ] )
2008-08-04 00:16:41 -07:00
continue ;
2008-11-18 09:03:12 +05:30
ath_rc_priv - > rate_max_phy = ath_rc_priv - > valid_phy_rateidx [ i ] [ j - 1 ] ;
2008-08-04 00:16:41 -07:00
}
2008-11-18 09:08:13 +05:30
ASSERT ( ath_rc_priv - > rate_table_size < = RATE_TABLE_SIZE ) ;
ASSERT ( k < = RATE_TABLE_SIZE ) ;
2008-08-04 00:16:41 -07:00
2008-11-18 09:03:12 +05:30
ath_rc_priv - > max_valid_rate = k ;
ath_rc_sort_validrates ( rate_table , ath_rc_priv ) ;
ath_rc_priv - > rate_max_phy = ath_rc_priv - > valid_rate_index [ k - 4 ] ;
2008-12-07 21:41:37 +05:30
sc - > cur_rate_table = rate_table ;
2008-08-04 00:16:41 -07:00
}
/* Rate Control callbacks */
2008-09-18 18:14:18 +02:00
static void ath_tx_status ( void * priv , struct ieee80211_supported_band * sband ,
struct ieee80211_sta * sta , void * priv_sta ,
2008-08-04 00:16:41 -07:00
struct sk_buff * skb )
{
struct ath_softc * sc = priv ;
2008-11-18 09:08:13 +05:30
struct ath_rate_priv * ath_rc_priv = priv_sta ;
struct ath_tx_info_priv * tx_info_priv = NULL ;
2008-08-04 00:16:41 -07:00
struct ieee80211_tx_info * tx_info = IEEE80211_SKB_CB ( skb ) ;
struct ieee80211_hdr * hdr ;
2008-11-18 09:08:13 +05:30
int final_ts_idx , tx_status = 0 , is_underrun = 0 ;
2008-08-04 00:16:41 -07:00
__le16 fc ;
hdr = ( struct ieee80211_hdr * ) skb - > data ;
fc = hdr - > frame_control ;
2008-11-18 09:08:13 +05:30
tx_info_priv = ATH_TX_INFO_PRIV ( tx_info ) ;
final_ts_idx = tx_info_priv - > tx . ts_rateindex ;
2008-08-04 00:16:41 -07:00
2008-11-24 12:07:55 +05:30
if ( ! priv_sta | | ! ieee80211_is_data ( fc ) | |
2008-11-20 11:51:18 +05:30
! tx_info_priv - > update_rc )
2008-11-18 09:08:13 +05:30
goto exit ;
2008-10-21 12:40:02 +02:00
2008-11-18 09:08:13 +05:30
if ( tx_info_priv - > tx . ts_status & ATH9K_TXERR_FILT )
goto exit ;
2008-10-21 12:40:02 +02:00
2008-11-18 09:08:13 +05:30
/*
* If underrun error is seen assume it as an excessive retry only
* if prefetch trigger level have reached the max ( 0x3f for 5416 )
* Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY
* times . This affects how ratectrl updates PER for the failed rate .
*/
if ( tx_info_priv - > tx . ts_flags &
( ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN ) & &
( ( sc - > sc_ah - > ah_txTrigLevel ) > = ath_rc_priv - > tx_triglevel_max ) ) {
tx_status = 1 ;
is_underrun = 1 ;
}
if ( ( tx_info_priv - > tx . ts_status & ATH9K_TXERR_XRETRY ) | |
( tx_info_priv - > tx . ts_status & ATH9K_TXERR_FIFO ) )
tx_status = 1 ;
ath_rc_tx_status ( sc , ath_rc_priv , tx_info , final_ts_idx , tx_status ,
( is_underrun ) ? ATH_11N_TXMAXTRY :
tx_info_priv - > tx . ts_longretry ) ;
exit :
2008-10-21 12:40:02 +02:00
kfree ( tx_info_priv ) ;
2008-08-04 00:16:41 -07:00
}
2008-10-21 12:40:02 +02:00
static void ath_get_rate ( void * priv , struct ieee80211_sta * sta , void * priv_sta ,
struct ieee80211_tx_rate_control * txrc )
2008-08-04 00:16:41 -07:00
{
2008-10-21 12:40:02 +02:00
struct ieee80211_supported_band * sband = txrc - > sband ;
struct sk_buff * skb = txrc - > skb ;
2008-08-04 00:16:41 -07:00
struct ieee80211_hdr * hdr = ( struct ieee80211_hdr * ) skb - > data ;
2008-09-18 18:14:18 +02:00
struct ath_softc * sc = priv ;
2008-08-04 00:16:41 -07:00
struct ieee80211_hw * hw = sc - > hw ;
2008-11-18 09:08:13 +05:30
struct ath_rate_priv * ath_rc_priv = priv_sta ;
2008-08-04 00:16:41 -07:00
struct ieee80211_tx_info * tx_info = IEEE80211_SKB_CB ( skb ) ;
2008-11-18 09:08:13 +05:30
int is_probe = 0 ;
2008-08-04 00:16:41 -07:00
__le16 fc = hdr - > frame_control ;
/* lowest rate for management and multicast/broadcast frames */
2008-12-17 13:30:31 +02:00
if ( ! ieee80211_is_data ( fc ) | | is_multicast_ether_addr ( hdr - > addr1 ) | |
! sta ) {
2008-11-18 09:07:30 +05:30
tx_info - > control . rates [ 0 ] . idx = rate_lowest_index ( sband , sta ) ;
tx_info - > control . rates [ 0 ] . count =
is_multicast_ether_addr ( hdr - > addr1 ) ? 1 : ATH_MGT_TXMAXTRY ;
2008-08-04 00:16:41 -07:00
return ;
}
/* Find tx rate for unicast frames */
2008-11-18 09:08:13 +05:30
ath_rc_ratefind ( sc , ath_rc_priv , ATH_11N_TXMAXTRY , 4 ,
tx_info , & is_probe , false ) ;
2008-08-04 00:16:41 -07:00
/* Check if aggregation has to be enabled for this tid */
2008-12-23 15:58:43 -08:00
if ( conf_is_ht ( & hw - > conf ) ) {
2008-08-04 00:16:41 -07:00
if ( ieee80211_is_data_qos ( fc ) ) {
2008-11-18 09:08:13 +05:30
u8 * qc , tid ;
struct ath_node * an ;
2008-08-04 00:16:41 -07:00
qc = ieee80211_get_qos_ctl ( hdr ) ;
tid = qc [ 0 ] & 0xf ;
2008-10-29 10:13:31 +05:30
an = ( struct ath_node * ) sta - > drv_priv ;
2008-08-04 00:16:41 -07:00
2008-10-29 10:18:14 +05:30
if ( ath_tx_aggr_check ( sc , an , tid ) )
ieee80211_start_tx_ba_session ( hw , hdr - > addr1 , tid ) ;
2008-08-04 00:16:41 -07:00
}
}
}
2008-09-18 18:14:18 +02:00
static void ath_rate_init ( void * priv , struct ieee80211_supported_band * sband ,
struct ieee80211_sta * sta , void * priv_sta )
2008-08-04 00:16:41 -07:00
{
2008-09-18 18:14:18 +02:00
struct ath_softc * sc = priv ;
2008-11-18 09:08:13 +05:30
struct ath_rate_priv * ath_rc_priv = priv_sta ;
2008-08-04 00:16:41 -07:00
int i , j = 0 ;
2008-11-18 09:04:00 +05:30
for ( i = 0 ; i < sband - > n_bitrates ; i + + ) {
if ( sta - > supp_rates [ sband - > band ] & BIT ( i ) ) {
ath_rc_priv - > neg_rates . rs_rates [ j ]
= ( sband - > bitrates [ i ] . bitrate * 2 ) / 10 ;
j + + ;
}
}
ath_rc_priv - > neg_rates . rs_nrates = j ;
2008-08-04 00:16:41 -07:00
2008-10-23 12:15:19 +05:30
if ( sta - > ht_cap . ht_supported ) {
2008-11-18 09:04:00 +05:30
for ( i = 0 , j = 0 ; i < 77 ; i + + ) {
2008-10-14 16:58:37 +02:00
if ( sta - > ht_cap . mcs . rx_mask [ i / 8 ] & ( 1 < < ( i % 8 ) ) )
2008-08-14 13:26:55 +05:30
ath_rc_priv - > neg_ht_rates . rs_rates [ j + + ] = i ;
2008-08-04 00:16:41 -07:00
if ( j = = ATH_RATE_MAX )
break ;
}
2008-08-14 13:26:55 +05:30
ath_rc_priv - > neg_ht_rates . rs_nrates = j ;
2008-08-04 00:16:41 -07:00
}
2008-11-18 09:04:00 +05:30
2008-11-18 09:06:44 +05:30
ath_rc_init ( sc , priv_sta , sband , sta ) ;
2008-08-04 00:16:41 -07:00
}
2008-09-18 18:14:18 +02:00
static void * ath_rate_alloc ( struct ieee80211_hw * hw , struct dentry * debugfsdir )
2008-08-04 00:16:41 -07:00
{
2008-09-18 18:14:18 +02:00
return hw - > priv ;
2008-08-04 00:16:41 -07:00
}
static void ath_rate_free ( void * priv )
{
return ;
}
2008-09-18 18:14:18 +02:00
static void * ath_rate_alloc_sta ( void * priv , struct ieee80211_sta * sta , gfp_t gfp )
2008-08-04 00:16:41 -07:00
{
struct ath_softc * sc = priv ;
2008-11-18 09:08:13 +05:30
struct ath_rate_priv * rate_priv ;
2008-08-04 00:16:41 -07:00
2008-11-18 09:08:13 +05:30
rate_priv = kzalloc ( sizeof ( struct ath_rate_priv ) , gfp ) ;
2008-08-04 00:16:41 -07:00
if ( ! rate_priv ) {
2008-08-14 13:26:55 +05:30
DPRINTF ( sc , ATH_DBG_FATAL ,
2008-11-28 22:18:05 +05:30
" Unable to allocate private rc structure \n " ) ;
2008-08-04 00:16:41 -07:00
return NULL ;
}
2008-11-18 09:03:36 +05:30
rate_priv - > rssi_down_time = jiffies_to_msecs ( jiffies ) ;
2008-11-18 09:07:06 +05:30
rate_priv - > tx_triglevel_max = sc - > sc_ah - > ah_caps . tx_triglevel_max ;
2008-08-14 13:26:55 +05:30
2008-08-04 00:16:41 -07:00
return rate_priv ;
}
2008-09-18 18:14:18 +02:00
static void ath_rate_free_sta ( void * priv , struct ieee80211_sta * sta ,
void * priv_sta )
2008-08-04 00:16:41 -07:00
{
2008-11-18 09:08:13 +05:30
struct ath_rate_priv * rate_priv = priv_sta ;
2008-11-18 09:03:36 +05:30
kfree ( rate_priv ) ;
2008-08-04 00:16:41 -07:00
}
static struct rate_control_ops ath_rate_ops = {
. module = NULL ,
. name = " ath9k_rate_control " ,
. tx_status = ath_tx_status ,
. get_rate = ath_get_rate ,
. rate_init = ath_rate_init ,
. alloc = ath_rate_alloc ,
. free = ath_rate_free ,
. alloc_sta = ath_rate_alloc_sta ,
2008-09-18 18:14:18 +02:00
. free_sta = ath_rate_free_sta ,
2008-08-04 00:16:41 -07:00
} ;
2008-11-18 09:07:53 +05:30
static void ath_setup_rate_table ( struct ath_softc * sc ,
struct ath_rate_table * rate_table )
{
int i ;
for ( i = 0 ; i < 256 ; i + + )
rate_table - > rateCodeToIndex [ i ] = ( u8 ) - 1 ;
for ( i = 0 ; i < rate_table - > rate_cnt ; i + + ) {
u8 code = rate_table - > info [ i ] . ratecode ;
u8 cix = rate_table - > info [ i ] . ctrl_rate ;
u8 sh = rate_table - > info [ i ] . short_preamble ;
rate_table - > rateCodeToIndex [ code ] = i ;
rate_table - > rateCodeToIndex [ code | sh ] = i ;
rate_table - > info [ i ] . lpAckDuration =
ath9k_hw_computetxtime ( sc - > sc_ah , rate_table ,
WLAN_CTRL_FRAME_SIZE ,
cix ,
false ) ;
rate_table - > info [ i ] . spAckDuration =
ath9k_hw_computetxtime ( sc - > sc_ah , rate_table ,
WLAN_CTRL_FRAME_SIZE ,
cix ,
true ) ;
}
}
2008-11-18 09:07:06 +05:30
void ath_rate_attach ( struct ath_softc * sc )
{
sc - > hw_rate_table [ ATH9K_MODE_11B ] =
& ar5416_11b_ratetable ;
sc - > hw_rate_table [ ATH9K_MODE_11A ] =
& ar5416_11a_ratetable ;
sc - > hw_rate_table [ ATH9K_MODE_11G ] =
& ar5416_11g_ratetable ;
sc - > hw_rate_table [ ATH9K_MODE_11NA_HT20 ] =
& ar5416_11na_ratetable ;
sc - > hw_rate_table [ ATH9K_MODE_11NG_HT20 ] =
& ar5416_11ng_ratetable ;
sc - > hw_rate_table [ ATH9K_MODE_11NA_HT40PLUS ] =
& ar5416_11na_ratetable ;
sc - > hw_rate_table [ ATH9K_MODE_11NA_HT40MINUS ] =
& ar5416_11na_ratetable ;
sc - > hw_rate_table [ ATH9K_MODE_11NG_HT40PLUS ] =
& ar5416_11ng_ratetable ;
sc - > hw_rate_table [ ATH9K_MODE_11NG_HT40MINUS ] =
& ar5416_11ng_ratetable ;
2008-11-18 09:07:53 +05:30
ath_setup_rate_table ( sc , & ar5416_11b_ratetable ) ;
ath_setup_rate_table ( sc , & ar5416_11a_ratetable ) ;
ath_setup_rate_table ( sc , & ar5416_11g_ratetable ) ;
ath_setup_rate_table ( sc , & ar5416_11na_ratetable ) ;
ath_setup_rate_table ( sc , & ar5416_11ng_ratetable ) ;
2008-11-18 09:07:06 +05:30
}
2008-08-04 00:16:41 -07:00
int ath_rate_control_register ( void )
{
return ieee80211_rate_control_register ( & ath_rate_ops ) ;
}
void ath_rate_control_unregister ( void )
{
ieee80211_rate_control_unregister ( & ath_rate_ops ) ;
}