All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 1/2] ath9k: properly use the mac80211 rate control api
@ 2009-11-23 21:21 Felix Fietkau
  2009-11-23 21:22 ` [PATCH v3 2/2] ath9k: clean up rc rate table Felix Fietkau
  0 siblings, 1 reply; 2+ messages in thread
From: Felix Fietkau @ 2009-11-23 21:21 UTC (permalink / raw)
  To: linux-wireless; +Cc: Luis R. Rodriguez, John W. Linville

This patch changes ath9k to pass proper MCS indexes and flags
between the RC and the rest of the driver code.
sc->cur_rate_table remains, as it's used by the RC code internally,
but the rest of the driver code no longer uses it, so a potential
new RC for ath9k would not have to update it.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
---
- replaces sc->hw usage with common->hw
- initializes unused tx status rates to -1 for minstrel compatibility
- split up for easier review
- tested in ap mode with minstrel against a legacy STA
- v2: fix bisectability
- v3: fix a compiler warning with debug support disabled

--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -19,132 +19,133 @@
 
 static const struct ath_rate_table ar5416_11na_ratetable = {
 	42,
+	8, /* MCS start */
 	{
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
-			5400, 0x0b, 0x00, 12,
+			5400, 0, 0x00, 12,
 			0, 0, 0, 0, 0, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
-			7800,  0x0f, 0x00, 18,
+			7800,  1, 0x00, 18,
 			0, 1, 1, 1, 1, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
-			10000, 0x0a, 0x00, 24,
+			10000, 2, 0x00, 24,
 			2, 2, 2, 2, 2, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
-			13900, 0x0e, 0x00, 36,
+			13900, 3, 0x00, 36,
 			2,  3, 3, 3, 3, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
-			17300, 0x09, 0x00, 48,
+			17300, 4, 0x00, 48,
 			4,  4, 4, 4, 4, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
-			23000, 0x0d, 0x00, 72,
+			23000, 5, 0x00, 72,
 			4,  5, 5, 5, 5, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
-			27400, 0x08, 0x00, 96,
+			27400, 6, 0x00, 96,
 			4,  6, 6, 6, 6, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
-			29300, 0x0c, 0x00, 108,
+			29300, 7, 0x00, 108,
 			4,  7, 7, 7, 7, 0 },
 		{ VALID_2040, VALID_2040, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
-			6400, 0x80, 0x00, 0,
+			6400, 0, 0x00, 0,
 			0, 8, 24, 8, 24, 3216 },
 		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
-			12700, 0x81, 0x00, 1,
+			12700, 1, 0x00, 1,
 			2, 9, 25, 9, 25, 6434 },
 		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
-			18800, 0x82, 0x00, 2,
+			18800, 2, 0x00, 2,
 			2, 10, 26, 10, 26, 9650 },
 		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
-			25000, 0x83, 0x00, 3,
+			25000, 3, 0x00, 3,
 			4,  11, 27, 11, 27, 12868 },
 		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
-			36700, 0x84, 0x00, 4,
+			36700, 4, 0x00, 4,
 			4,  12, 28, 12, 28, 19304 },
 		{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
-			48100, 0x85, 0x00, 5,
+			48100, 5, 0x00, 5,
 			4,  13, 29, 13, 29, 25740 },
 		{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
-			53500, 0x86, 0x00, 6,
+			53500, 6, 0x00, 6,
 			4,  14, 30, 14, 30,  28956 },
 		{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
-			59000, 0x87, 0x00, 7,
+			59000, 7, 0x00, 7,
 			4,  15, 31, 15, 32, 32180 },
 		{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
-			12700, 0x88, 0x00,
+			12700, 8, 0x00,
 			8, 3, 16, 33, 16, 33, 6430 },
 		{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
-			24800, 0x89, 0x00, 9,
+			24800, 9, 0x00, 9,
 			2, 17, 34, 17, 34, 12860 },
 		{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
-			36600, 0x8a, 0x00, 10,
+			36600, 10, 0x00, 10,
 			2, 18, 35, 18, 35, 19300 },
 		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
-			48100, 0x8b, 0x00, 11,
+			48100, 11, 0x00, 11,
 			4,  19, 36, 19, 36, 25736 },
 		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
-			69500, 0x8c, 0x00, 12,
+			69500, 12, 0x00, 12,
 			4,  20, 37, 20, 37, 38600 },
 		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
-			89500, 0x8d, 0x00, 13,
+			89500, 13, 0x00, 13,
 			4,  21, 38, 21, 38, 51472 },
 		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
-			98900, 0x8e, 0x00, 14,
+			98900, 14, 0x00, 14,
 			4,  22, 39, 22, 39, 57890 },
 		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
-			108300, 0x8f, 0x00, 15,
+			108300, 15, 0x00, 15,
 			4,  23, 40, 23, 41, 64320 },
 		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
-			13200, 0x80, 0x00, 0,
+			13200, 0, 0x00, 0,
 			0, 8, 24, 24, 24, 6684 },
 		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
-			25900, 0x81, 0x00, 1,
+			25900, 1, 0x00, 1,
 			2, 9, 25, 25, 25, 13368 },
 		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
-			38600, 0x82, 0x00, 2,
+			38600, 2, 0x00, 2,
 			2, 10, 26, 26, 26, 20052 },
 		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
-			49800, 0x83, 0x00, 3,
+			49800, 3, 0x00, 3,
 			4,  11, 27, 27, 27, 26738 },
 		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
-			72200, 0x84, 0x00, 4,
+			72200, 4, 0x00, 4,
 			4,  12, 28, 28, 28, 40104 },
 		{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
-			92900, 0x85, 0x00, 5,
+			92900, 5, 0x00, 5,
 			4,  13, 29, 29, 29, 53476 },
 		{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
-			102700, 0x86, 0x00, 6,
+			102700, 6, 0x00, 6,
 			4,  14, 30, 30, 30, 60156 },
 		{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
-			112000, 0x87, 0x00, 7,
+			112000, 7, 0x00, 7,
 			4,  15, 31, 32, 32, 66840 },
 		{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
-			122000, 0x87, 0x00, 7,
+			122000, 7, 0x00, 7,
 			4,  15, 31, 32, 32, 74200 },
 		{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
-			25800, 0x88, 0x00, 8,
+			25800, 8, 0x00, 8,
 			0, 16, 33, 33, 33, 13360 },
 		{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
-			49800, 0x89, 0x00, 9,
+			49800, 9, 0x00, 9,
 			2, 17, 34, 34, 34, 26720 },
 		{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
-			71900, 0x8a, 0x00, 10,
+			71900, 10, 0x00, 10,
 			2, 18, 35, 35, 35, 40080 },
 		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
-			92500, 0x8b, 0x00, 11,
+			92500, 11, 0x00, 11,
 			4,  19, 36, 36, 36, 53440 },
 		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
-			130300, 0x8c, 0x00, 12,
+			130300, 12, 0x00, 12,
 			4,  20, 37, 37, 37, 80160 },
 		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
-			162800, 0x8d, 0x00, 13,
+			162800, 13, 0x00, 13,
 			4,  21, 38, 38, 38, 106880 },
 		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
-			178200, 0x8e, 0x00, 14,
+			178200, 14, 0x00, 14,
 			4,  22, 39, 39, 39, 120240 },
 		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
-			192100, 0x8f, 0x00, 15,
+			192100, 15, 0x00, 15,
 			4,  23, 40, 41, 41, 133600 },
 		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
-			207000, 0x8f, 0x00, 15,
+			207000, 15, 0x00, 15,
 			4,  23, 40, 41, 41, 148400 },
 	},
 	50,  /* probe interval */
@@ -156,144 +157,145 @@ static const struct ath_rate_table ar541
 
 static const struct ath_rate_table ar5416_11ng_ratetable = {
 	46,
+	12, /* MCS start */
 	{
 		{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
-			900, 0x1b, 0x00, 2,
+			900, 0, 0x00, 2,
 			0, 0, 0, 0, 0, 0 },
 		{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
-			1900, 0x1a, 0x04, 4,
+			1900, 1, 0x04, 4,
 			1, 1, 1, 1, 1, 0 },
 		{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
-			4900, 0x19, 0x04, 11,
+			4900, 2, 0x04, 11,
 			2, 2, 2, 2, 2, 0 },
 		{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
-			8100, 0x18, 0x04, 22,
+			8100, 3, 0x04, 22,
 			3, 3, 3, 3, 3, 0 },
 		{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
-			5400, 0x0b, 0x00, 12,
+			5400, 4, 0x00, 12,
 			4, 4, 4, 4, 4, 0 },
 		{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
-			7800, 0x0f, 0x00, 18,
+			7800, 5, 0x00, 18,
 			4, 5, 5, 5, 5, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
-			10100, 0x0a, 0x00, 24,
+			10100, 6, 0x00, 24,
 			6, 6, 6, 6, 6, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
-			14100,  0x0e, 0x00, 36,
+			14100, 7, 0x00, 36,
 			6, 7, 7, 7, 7, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
-			17700, 0x09, 0x00, 48,
+			17700, 8, 0x00, 48,
 			8,  8, 8, 8, 8, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
-			23700, 0x0d, 0x00, 72,
+			23700, 9, 0x00, 72,
 			8,  9, 9, 9, 9, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
-			27400, 0x08, 0x00, 96,
+			27400, 10, 0x00, 96,
 			8,  10, 10, 10, 10, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
-			30900, 0x0c, 0x00, 108,
+			30900, 11, 0x00, 108,
 			8,  11, 11, 11, 11, 0 },
 		{ INVALID, INVALID, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
-			6400, 0x80, 0x00, 0,
+			6400, 0, 0x00, 0,
 			4, 12, 28, 12, 28, 3216 },
 		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
-			12700, 0x81, 0x00, 1,
+			12700, 1, 0x00, 1,
 			6, 13, 29, 13, 29, 6434 },
 		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
-			18800, 0x82, 0x00, 2,
+			18800, 2, 0x00, 2,
 			6, 14, 30, 14, 30, 9650 },
 		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
-			25000, 0x83, 0x00, 3,
+			25000, 3, 0x00, 3,
 			8,  15, 31, 15, 31, 12868 },
 		{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
-			36700, 0x84, 0x00, 4,
+			36700, 4, 0x00, 4,
 			8,  16, 32, 16, 32, 19304 },
 		{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
-			48100, 0x85, 0x00, 5,
+			48100, 5, 0x00, 5,
 			8,  17, 33, 17, 33, 25740 },
 		{ INVALID,  VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
-			53500, 0x86, 0x00, 6,
+			53500, 6, 0x00, 6,
 			8,  18, 34, 18, 34, 28956 },
 		{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
-			59000, 0x87, 0x00, 7,
+			59000, 7, 0x00, 7,
 			8,  19, 35, 19, 36, 32180 },
 		{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
-			12700, 0x88, 0x00, 8,
+			12700, 8, 0x00, 8,
 			4, 20, 37, 20, 37, 6430 },
 		{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
-			24800, 0x89, 0x00, 9,
+			24800, 9, 0x00, 9,
 			6, 21, 38, 21, 38, 12860 },
 		{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
-			36600, 0x8a, 0x00, 10,
+			36600, 10, 0x00, 10,
 			6, 22, 39, 22, 39, 19300 },
 		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
-			48100, 0x8b, 0x00, 11,
+			48100, 11, 0x00, 11,
 			8,  23, 40, 23, 40, 25736 },
 		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
-			69500, 0x8c, 0x00, 12,
+			69500, 12, 0x00, 12,
 			8,  24, 41, 24, 41, 38600 },
 		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
-			89500, 0x8d, 0x00, 13,
+			89500, 13, 0x00, 13,
 			8,  25, 42, 25, 42, 51472 },
 		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
-			98900, 0x8e, 0x00, 14,
+			98900, 14, 0x00, 14,
 			8,  26, 43, 26, 44, 57890 },
 		{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
-			108300, 0x8f, 0x00, 15,
+			108300, 15, 0x00, 15,
 			8,  27, 44, 27, 45, 64320 },
 		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
-			13200, 0x80, 0x00, 0,
+			13200, 0, 0x00, 0,
 			8, 12, 28, 28, 28, 6684 },
 		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
-			25900, 0x81, 0x00, 1,
+			25900, 1, 0x00, 1,
 			8, 13, 29, 29, 29, 13368 },
 		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
-			38600, 0x82, 0x00, 2,
+			38600, 2, 0x00, 2,
 			8, 14, 30, 30, 30, 20052 },
 		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
-			49800, 0x83, 0x00, 3,
+			49800, 3, 0x00, 3,
 			8,  15, 31, 31, 31, 26738 },
 		{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
-			72200, 0x84, 0x00, 4,
+			72200, 4, 0x00, 4,
 			8,  16, 32, 32, 32, 40104 },
 		{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
-			92900, 0x85, 0x00, 5,
+			92900, 5, 0x00, 5,
 			8,  17, 33, 33, 33, 53476 },
 		{ INVALID,  VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
-			102700, 0x86, 0x00, 6,
+			102700, 6, 0x00, 6,
 			8,  18, 34, 34, 34, 60156 },
 		{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
-			112000, 0x87, 0x00, 7,
+			112000, 7, 0x00, 7,
 			8,  19, 35, 36, 36, 66840 },
 		{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
-			122000, 0x87, 0x00, 7,
+			122000, 7, 0x00, 7,
 			8,  19, 35, 36, 36, 74200 },
 		{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
-			25800, 0x88, 0x00, 8,
+			25800, 8, 0x00, 8,
 			8, 20, 37, 37, 37, 13360 },
 		{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
-			49800, 0x89, 0x00, 9,
+			49800, 9, 0x00, 9,
 			8, 21, 38, 38, 38, 26720 },
 		{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
-			71900, 0x8a, 0x00, 10,
+			71900, 10, 0x00, 10,
 			8, 22, 39, 39, 39, 40080 },
 		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
-			92500, 0x8b, 0x00, 11,
+			92500, 11, 0x00, 11,
 			8,  23, 40, 40, 40, 53440 },
 		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
-			130300, 0x8c, 0x00, 12,
+			130300, 12, 0x00, 12,
 			8,  24, 41, 41, 41, 80160 },
 		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
-			162800, 0x8d, 0x00, 13,
+			162800, 13, 0x00, 13,
 			8,  25, 42, 42, 42, 106880 },
 		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
-			178200, 0x8e, 0x00, 14,
+			178200, 14, 0x00, 14,
 			8,  26, 43, 43, 43, 120240 },
 		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
-			192100, 0x8f, 0x00, 15,
+			192100, 15, 0x00, 15,
 			8,  27, 44, 45, 45, 133600 },
 		{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
-			207000, 0x8f, 0x00, 15,
+			207000, 15, 0x00, 15,
 			8,  27, 44, 45, 45, 148400 },
 		},
 	50,  /* probe interval */
@@ -302,30 +304,31 @@ static const struct ath_rate_table ar541
 
 static const struct ath_rate_table ar5416_11a_ratetable = {
 	8,
+	0,
 	{
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
-			5400, 0x0b, 0x00, (0x80|12),
+			5400, 0, 0x00, 12,
 			0, 0, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
-			7800, 0x0f, 0x00, 18,
+			7800, 1, 0x00, 18,
 			0, 1, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
-			10000, 0x0a, 0x00, (0x80|24),
+			10000, 2, 0x00, 24,
 			2, 2, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
-			13900, 0x0e, 0x00, 36,
+			13900, 3, 0x00, 36,
 			2, 3, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
-			17300, 0x09, 0x00, (0x80|48),
+			17300, 4, 0x00, 48,
 			4,  4, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
-			23000, 0x0d, 0x00, 72,
+			23000, 5, 0x00, 72,
 			4,  5, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
-			27400, 0x08, 0x00, 96,
+			27400, 6, 0x00, 96,
 			4,  6, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
-			29300, 0x0c, 0x00, 108,
+			29300, 7, 0x00, 108,
 			4,  7, 0 },
 	},
 	50,  /* probe interval */
@@ -334,48 +337,63 @@ static const struct ath_rate_table ar541
 
 static const struct ath_rate_table ar5416_11g_ratetable = {
 	12,
+	0,
 	{
 		{ VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
-			900, 0x1b, 0x00, 2,
+			900, 0, 0x00, 2,
 			0, 0, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
-			1900, 0x1a, 0x04, 4,
+			1900, 1, 0x04, 4,
 			1, 1, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
-			4900, 0x19, 0x04, 11,
+			4900, 2, 0x04, 11,
 			2, 2, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
-			8100, 0x18, 0x04, 22,
+			8100, 3, 0x04, 22,
 			3, 3, 0 },
 		{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
-			5400, 0x0b, 0x00, 12,
+			5400, 4, 0x00, 12,
 			4, 4, 0 },
 		{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
-			7800, 0x0f, 0x00, 18,
+			7800, 5, 0x00, 18,
 			4, 5, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
-			10000, 0x0a, 0x00, 24,
+			10000, 6, 0x00, 24,
 			6, 6, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
-			13900, 0x0e, 0x00, 36,
+			13900, 7, 0x00, 36,
 			6, 7, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
-			17300, 0x09, 0x00, 48,
+			17300, 8, 0x00, 48,
 			8,  8, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
-			23000, 0x0d, 0x00, 72,
+			23000, 9, 0x00, 72,
 			8,  9, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
-			27400, 0x08, 0x00, 96,
+			27400, 10, 0x00, 96,
 			8,  10, 0 },
 		{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
-			29300, 0x0c, 0x00, 108,
+			29300, 11, 0x00, 108,
 			8,  11, 0 },
 	},
 	50,  /* probe interval */
 	0,   /* Phy rates allowed initially */
 };
 
+static const struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX] = {
+	[ATH9K_MODE_11A] = &ar5416_11a_ratetable,
+	[ATH9K_MODE_11G] = &ar5416_11g_ratetable,
+	[ATH9K_MODE_11NA_HT20] = &ar5416_11na_ratetable,
+	[ATH9K_MODE_11NG_HT20] = &ar5416_11ng_ratetable,
+	[ATH9K_MODE_11NA_HT40PLUS] = &ar5416_11na_ratetable,
+	[ATH9K_MODE_11NA_HT40MINUS] = &ar5416_11na_ratetable,
+	[ATH9K_MODE_11NG_HT40PLUS] = &ar5416_11ng_ratetable,
+	[ATH9K_MODE_11NG_HT40MINUS] = &ar5416_11ng_ratetable,
+};
+
+static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table,
+				struct ieee80211_tx_rate *rate);
+
 static inline int8_t median(int8_t a, int8_t b, int8_t c)
 {
 	if (a >= b) {
@@ -534,7 +552,7 @@ static u8 ath_rc_setvalid_rates(struct a
 			 * capflag matches one of the validity
 			 * (VALID/VALID_20/VALID_40) flags */
 
-			if (((rate & 0x7F) == (dot11rate & 0x7F)) &&
+			if ((rate == dot11rate) &&
 			    ((valid & WLAN_RC_CAP_MODE(capflag)) ==
 			     WLAN_RC_CAP_MODE(capflag)) &&
 			    !WLAN_RC_PHY_HT(phy)) {
@@ -576,8 +594,7 @@ static u8 ath_rc_setvalid_htrates(struct
 			u8 rate = rateset->rs_rates[i];
 			u8 dot11rate = rate_table->info[j].dot11rate;
 
-			if (((rate & 0x7F) != (dot11rate & 0x7F)) ||
-			    !WLAN_RC_PHY_HT(phy) ||
+			if ((rate != dot11rate) || !WLAN_RC_PHY_HT(phy) ||
 			    !WLAN_RC_PHY_HT_VALID(valid, capflag))
 				continue;
 
@@ -696,18 +713,20 @@ static void ath_rc_rate_set_series(const
 				   u8 tries, u8 rix, int rtsctsenable)
 {
 	rate->count = tries;
-	rate->idx = rix;
+	rate->idx = rate_table->info[rix].ratecode;
 
 	if (txrc->short_preamble)
 		rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
 	if (txrc->rts || 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))
+
+	if (WLAN_RC_PHY_HT(rate_table->info[rix].phy)) {
 		rate->flags |= IEEE80211_TX_RC_MCS;
+		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;
+	}
 }
 
 static void ath_rc_rate_set_rtscts(struct ath_softc *sc,
@@ -720,7 +739,7 @@ static void ath_rc_rate_set_rtscts(struc
 	/* get the cix for the lowest valid rix */
 	for (i = 3; i >= 0; i--) {
 		if (rates[i].count && (rates[i].idx >= 0)) {
-			rix = rates[i].idx;
+			rix = ath_rc_get_rateindex(rate_table, &rates[i]);
 			break;
 		}
 	}
@@ -1080,15 +1099,19 @@ static int ath_rc_get_rateindex(const st
 {
 	int rix;
 
+	if (!(rate->flags & IEEE80211_TX_RC_MCS))
+		return rate->idx;
+
+	rix = rate->idx + rate_table->mcs_start;
 	if ((rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
 	    (rate->flags & IEEE80211_TX_RC_SHORT_GI))
-		rix = rate_table->info[rate->idx].ht_index;
+		rix = rate_table->info[rix].ht_index;
 	else if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
-		rix = rate_table->info[rate->idx].sgi_index;
+		rix = rate_table->info[rix].sgi_index;
 	else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
-		rix = rate_table->info[rate->idx].cw40index;
+		rix = rate_table->info[rix].cw40index;
 	else
-		rix = rate_table->info[rate->idx].base_index;
+		rix = rate_table->info[rix].base_index;
 
 	return rix;
 }
@@ -1183,7 +1206,9 @@ struct ath_rate_table *ath_choose_rate_t
 
 	ath_print(common, ATH_DBG_CONFIG,
 		  "Choosing rate table for mode: %d\n", mode);
-	return sc->hw_rate_table[mode];
+
+	sc->cur_rate_mode = mode;
+	return hw_rate_table[mode];
 }
 
 static void ath_rc_init(struct ath_softc *sc,
@@ -1197,12 +1222,6 @@ static void ath_rc_init(struct ath_softc
 	u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates;
 	u8 i, j, k, hi = 0, hthi = 0;
 
-	if (!rate_table) {
-		ath_print(common, ATH_DBG_FATAL,
-			  "Rate table not initialized\n");
-		return;
-	}
-
 	/* Initial rate table size. Will change depending
 	 * on the working rate set */
 	ath_rc_priv->rate_table_size = RATE_TABLE_SIZE;
@@ -1357,7 +1376,8 @@ static void ath_tx_status(void *priv, st
 		}
 	}
 
-	ath_debug_stat_rc(sc, skb);
+	ath_debug_stat_rc(sc, ath_rc_get_rateindex(sc->cur_rate_table,
+		&tx_info->status.rates[final_ts_idx]));
 }
 
 static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
@@ -1365,7 +1385,7 @@ static void ath_rate_init(void *priv, st
 {
 	struct ath_softc *sc = priv;
 	struct ath_rate_priv *ath_rc_priv = priv_sta;
-	const struct ath_rate_table *rate_table = NULL;
+	const struct ath_rate_table *rate_table;
 	bool is_cw40, is_sgi40;
 	int i, j = 0;
 
@@ -1397,11 +1417,9 @@ static void ath_rate_init(void *priv, st
 	    (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) ||
 	    (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)) {
 		rate_table = ath_choose_rate_table(sc, sband->band,
-						   sta->ht_cap.ht_supported,
-						   is_cw40);
-	} else if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
-		/* cur_rate_table would be set on init through config() */
-		rate_table = sc->cur_rate_table;
+		                      sta->ht_cap.ht_supported, is_cw40);
+	} else {
+		rate_table = hw_rate_table[sc->cur_rate_mode];
 	}
 
 	ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, is_cw40, is_sgi40);
@@ -1445,6 +1463,7 @@ static void ath_rate_update(void *priv, 
 			ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
 				  "Operating HT Bandwidth changed to: %d\n",
 				  sc->hw->conf.channel_type);
+			sc->cur_rate_table = hw_rate_table[sc->cur_rate_mode];
 		}
 	}
 }
@@ -1497,26 +1516,6 @@ static struct rate_control_ops ath_rate_
 	.free_sta = ath_rate_free_sta,
 };
 
-void ath_rate_attach(struct ath_softc *sc)
-{
-	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;
-}
-
 int ath_rate_control_register(void)
 {
 	return ieee80211_rate_control_register(&ath_rate_ops);
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -70,6 +70,29 @@ static int ath_tx_num_badfrms(struct ath
 static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
 			     int nbad, int txok, bool update_rc);
 
+enum {
+	MCS_DEFAULT,
+	MCS_HT40,
+	MCS_HT40_SGI,
+};
+
+static int ath_max_4ms_framelen[3][16] = {
+	[MCS_DEFAULT] = {
+		3216,  6434,  9650,  12868, 19304, 25740,  28956,  32180,
+		6430,  12860, 19300, 25736, 38600, 51472,  57890,  64320,
+	},
+	[MCS_HT40] = {
+		6684,  13368, 20052, 26738, 40104, 53476,  60156,  66840,
+		13360, 26720, 40080, 53440, 80160, 106880, 120240, 133600,
+	},
+	[MCS_HT40_SGI] = {
+		/* TODO: Only MCS 7 and 15 updated, recalculate the rest */
+		6684,  13368, 20052, 26738, 40104, 53476,  60156,  74200,
+		13360, 26720, 40080, 53440, 80160, 106880, 120240, 148400,
+	}
+};
+
+
 /*********************/
 /* Aggregation logic */
 /*********************/
@@ -459,7 +482,6 @@ static void ath_tx_complete_aggr(struct 
 static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
 			   struct ath_atx_tid *tid)
 {
-	const struct ath_rate_table *rate_table = sc->cur_rate_table;
 	struct sk_buff *skb;
 	struct ieee80211_tx_info *tx_info;
 	struct ieee80211_tx_rate *rates;
@@ -480,12 +502,20 @@ static u32 ath_lookup_rate(struct ath_so
 
 	for (i = 0; i < 4; i++) {
 		if (rates[i].count) {
-			if (!WLAN_RC_PHY_HT(rate_table->info[rates[i].idx].phy)) {
+			int modeidx;
+			if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) {
 				legacy = 1;
 				break;
 			}
 
-			frmlen = rate_table->info[rates[i].idx].max_4ms_framelen;
+			if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
+				modeidx = MCS_HT40_SGI;
+			else if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+				modeidx = MCS_HT40;
+			else
+				modeidx = MCS_DEFAULT;
+
+			frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx];
 			max_4ms_framelen = min(max_4ms_framelen, frmlen);
 		}
 	}
@@ -523,12 +553,11 @@ static u32 ath_lookup_rate(struct ath_so
 static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
 				  struct ath_buf *bf, u16 frmlen)
 {
-	const struct ath_rate_table *rt = sc->cur_rate_table;
 	struct sk_buff *skb = bf->bf_mpdu;
 	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
 	u32 nsymbits, nsymbols;
 	u16 minlen;
-	u8 rc, flags, rix;
+	u8 flags, rix;
 	int width, half_gi, ndelim, mindelim;
 
 	/* Select standard number of delimiters based on frame length alone */
@@ -558,7 +587,6 @@ static int ath_compute_num_delims(struct
 
 	rix = tx_info->control.rates[0].idx;
 	flags = tx_info->control.rates[0].flags;
-	rc = rt->info[rix].ratecode;
 	width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
 	half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
 
@@ -570,7 +598,7 @@ static int ath_compute_num_delims(struct
 	if (nsymbols == 0)
 		nsymbols = 1;
 
-	nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width];
+	nsymbits = bits_per_symbol[rix][width];
 	minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
 
 	if (frmlen < minlen) {
@@ -1425,22 +1453,14 @@ static int setup_tx_flags(struct ath_sof
 static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
 			    int width, int half_gi, bool shortPreamble)
 {
-	const struct ath_rate_table *rate_table = sc->cur_rate_table;
 	u32 nbits, nsymbits, duration, nsymbols;
-	u8 rc;
 	int streams, pktlen;
 
 	pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen;
-	rc = rate_table->info[rix].ratecode;
-
-	/* for legacy rates, use old function to compute packet duration */
-	if (!IS_HT_RATE(rc))
-		return ath9k_hw_computetxtime(sc->sc_ah, rate_table, pktlen,
-					      rix, shortPreamble);
 
 	/* find number of symbols: PLCP + data */
 	nbits = (pktlen << 3) + OFDM_PLCP_BITS;
-	nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width];
+	nsymbits = bits_per_symbol[rix][width];
 	nsymbols = (nbits + nsymbits - 1) / nsymbits;
 
 	if (!half_gi)
@@ -1449,7 +1469,7 @@ static u32 ath_pkt_duration(struct ath_s
 		duration = SYMBOL_TIME_HALFGI(nsymbols);
 
 	/* addup duration for legacy/ht training and signal fields */
-	streams = HT_RC_2_STREAMS(rc);
+	streams = HT_RC_2_STREAMS(rix);
 	duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
 
 	return duration;
@@ -1458,11 +1478,11 @@ static u32 ath_pkt_duration(struct ath_s
 static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
 {
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-	const struct ath_rate_table *rt = sc->cur_rate_table;
 	struct ath9k_11n_rate_series series[4];
 	struct sk_buff *skb;
 	struct ieee80211_tx_info *tx_info;
 	struct ieee80211_tx_rate *rates;
+	const struct ieee80211_rate *rate;
 	struct ieee80211_hdr *hdr;
 	int i, flags = 0;
 	u8 rix = 0, ctsrate = 0;
@@ -1481,11 +1501,10 @@ static void ath_buf_set_rate(struct ath_
 	 * checking the BSS's global flag.
 	 * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
 	 */
+	rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
+	ctsrate = rate->hw_value;
 	if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
-		ctsrate = rt->info[tx_info->control.rts_cts_rate_idx].ratecode |
-			rt->info[tx_info->control.rts_cts_rate_idx].short_preamble;
-	else
-		ctsrate = rt->info[tx_info->control.rts_cts_rate_idx].ratecode;
+		ctsrate |= rate->hw_value_short;
 
 	/*
 	 * ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive.
@@ -1508,6 +1527,9 @@ static void ath_buf_set_rate(struct ath_
 		flags &= ~(ATH9K_TXDESC_RTSENA);
 
 	for (i = 0; i < 4; i++) {
+		bool is_40, is_sgi, is_sp;
+		int phy;
+
 		if (!rates[i].count || (rates[i].idx < 0))
 			continue;
 
@@ -1515,12 +1537,6 @@ static void ath_buf_set_rate(struct ath_
 		series[i].Tries = rates[i].count;
 		series[i].ChSel = common->tx_chainmask;
 
-		if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
-			series[i].Rate = rt->info[rix].ratecode |
-				rt->info[rix].short_preamble;
-		else
-			series[i].Rate = rt->info[rix].ratecode;
-
 		if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)
 			series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
 		if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
@@ -1528,10 +1544,36 @@ static void ath_buf_set_rate(struct ath_
 		if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
 			series[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
 
-		series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
-			 (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) != 0,
-			 (rates[i].flags & IEEE80211_TX_RC_SHORT_GI),
-			 (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE));
+		is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
+		is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
+		is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
+
+		if (rates[i].flags & IEEE80211_TX_RC_MCS) {
+			/* MCS rates */
+			series[i].Rate = rix | 0x80;
+			series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
+				 is_40, is_sgi, is_sp);
+			continue;
+		}
+
+		/* legcay rates */
+		if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
+		    !(rate->flags & IEEE80211_RATE_ERP_G))
+			phy = WLAN_RC_PHY_CCK;
+		else
+			phy = WLAN_RC_PHY_OFDM;
+
+		rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
+		series[i].Rate = rate->hw_value;
+		if (rate->hw_value_short) {
+			if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
+				series[i].Rate |= rate->hw_value_short;
+		} else {
+			is_sp = false;
+		}
+
+		series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
+			phy, rate->bitrate * 100, bf->bf_frmlen, rix, is_sp);
 	}
 
 	/* set dur_update_en for l-sig computation except for PS-Poll frames */
@@ -1920,8 +1962,10 @@ static void ath_tx_rc_status(struct ath_
 		}
 	}
 
-	for (i = tx_rateindex + 1; i < hw->max_rates; i++)
+	for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
 		tx_info->status.rates[i].count = 0;
+		tx_info->status.rates[i].idx = -1;
+	}
 
 	tx_info->status.rates[tx_rateindex].count = bf->bf_retries + 1;
 }
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -21,7 +21,6 @@
 #include <linux/device.h>
 #include <linux/leds.h>
 
-#include "rc.h"
 #include "debug.h"
 #include "common.h"
 
@@ -423,6 +422,7 @@ struct ath_led {
 #define SC_OP_BT_PRIORITY_DETECTED BIT(21)
 
 struct ath_wiphy;
+struct ath_rate_table;
 
 struct ath_softc {
 	struct ieee80211_hw *hw;
@@ -467,9 +467,8 @@ struct ath_softc {
 	struct ath_rx rx;
 	struct ath_tx tx;
 	struct ath_beacon beacon;
-	struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX];
-	const struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX];
 	const struct ath_rate_table *cur_rate_table;
+	enum wireless_mode cur_rate_mode;
 	struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
 
 	struct ath_led radio_led;
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -105,37 +105,55 @@ static struct ieee80211_channel ath9k_5g
 	CHAN5G(5825, 37), /* Channel 165 */
 };
 
+/* Atheros hardware rate code addition for short premble */
+#define SHPCHECK(__hw_rate, __flags) \
+	((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0)
+
+#define RATE(_bitrate, _hw_rate, _flags) {              \
+	.bitrate        = (_bitrate),                   \
+	.flags          = (_flags),                     \
+	.hw_value       = (_hw_rate),                   \
+	.hw_value_short = (SHPCHECK(_hw_rate, _flags))  \
+}
+
+static struct ieee80211_rate ath9k_legacy_rates[] = {
+	RATE(10, 0x1b, 0),
+	RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE),
+	RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE),
+	RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE),
+	RATE(60, 0x0b, 0),
+	RATE(90, 0x0f, 0),
+	RATE(120, 0x0a, 0),
+	RATE(180, 0x0e, 0),
+	RATE(240, 0x09, 0),
+	RATE(360, 0x0d, 0),
+	RATE(480, 0x08, 0),
+	RATE(540, 0x0c, 0),
+};
+
 static void ath_cache_conf_rate(struct ath_softc *sc,
 				struct ieee80211_conf *conf)
 {
 	switch (conf->channel->band) {
 	case IEEE80211_BAND_2GHZ:
 		if (conf_is_ht20(conf))
-			sc->cur_rate_table =
-			  sc->hw_rate_table[ATH9K_MODE_11NG_HT20];
+			sc->cur_rate_mode = ATH9K_MODE_11NG_HT20;
 		else if (conf_is_ht40_minus(conf))
-			sc->cur_rate_table =
-			  sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS];
+			sc->cur_rate_mode = ATH9K_MODE_11NG_HT40MINUS;
 		else if (conf_is_ht40_plus(conf))
-			sc->cur_rate_table =
-			  sc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS];
+			sc->cur_rate_mode = ATH9K_MODE_11NG_HT40PLUS;
 		else
-			sc->cur_rate_table =
-			  sc->hw_rate_table[ATH9K_MODE_11G];
+			sc->cur_rate_mode = ATH9K_MODE_11G;
 		break;
 	case IEEE80211_BAND_5GHZ:
 		if (conf_is_ht20(conf))
-			sc->cur_rate_table =
-			  sc->hw_rate_table[ATH9K_MODE_11NA_HT20];
+			sc->cur_rate_mode = ATH9K_MODE_11NA_HT20;
 		else if (conf_is_ht40_minus(conf))
-			sc->cur_rate_table =
-			  sc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS];
+			sc->cur_rate_mode = ATH9K_MODE_11NA_HT40MINUS;
 		else if (conf_is_ht40_plus(conf))
-			sc->cur_rate_table =
-			  sc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS];
+			sc->cur_rate_mode = ATH9K_MODE_11NA_HT40PLUS;
 		else
-			sc->cur_rate_table =
-			  sc->hw_rate_table[ATH9K_MODE_11A];
+			sc->cur_rate_mode = ATH9K_MODE_11A;
 		break;
 	default:
 		BUG_ON(1);
@@ -191,51 +209,6 @@ static u8 parse_mpdudensity(u8 mpdudensi
 	}
 }
 
-static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band)
-{
-	const struct ath_rate_table *rate_table = NULL;
-	struct ieee80211_supported_band *sband;
-	struct ieee80211_rate *rate;
-	int i, maxrates;
-
-	switch (band) {
-	case IEEE80211_BAND_2GHZ:
-		rate_table = sc->hw_rate_table[ATH9K_MODE_11G];
-		break;
-	case IEEE80211_BAND_5GHZ:
-		rate_table = sc->hw_rate_table[ATH9K_MODE_11A];
-		break;
-	default:
-		break;
-	}
-
-	if (rate_table == NULL)
-		return;
-
-	sband = &sc->sbands[band];
-	rate = sc->rates[band];
-
-	if (rate_table->rate_cnt > ATH_RATE_MAX)
-		maxrates = ATH_RATE_MAX;
-	else
-		maxrates = rate_table->rate_cnt;
-
-	for (i = 0; i < maxrates; i++) {
-		rate[i].bitrate = rate_table->info[i].ratekbps / 100;
-		rate[i].hw_value = rate_table->info[i].ratecode;
-		if (rate_table->info[i].short_preamble) {
-			rate[i].hw_value_short = rate_table->info[i].ratecode |
-				rate_table->info[i].short_preamble;
-			rate[i].flags = IEEE80211_RATE_SHORT_PREAMBLE;
-		}
-		sband->n_bitrates++;
-
-		ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
-			  "Rate: %2dMbps, ratecode: %2d\n",
-			  rate[i].bitrate / 10, rate[i].hw_value);
-	}
-}
-
 static struct ath9k_channel *ath_get_curchannel(struct ath_softc *sc,
 						struct ieee80211_hw *hw)
 {
@@ -1713,12 +1686,6 @@ static int ath_init_softc(u16 devid, str
 	/* default to MONITOR mode */
 	sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR;
 
-	/* Setup rate tables */
-
-	ath_rate_attach(sc);
-	ath_setup_rates(sc, IEEE80211_BAND_2GHZ);
-	ath_setup_rates(sc, IEEE80211_BAND_5GHZ);
-
 	/*
 	 * Allocate hardware transmit queues: one queue for
 	 * beacon frames and one data queue for each QoS
@@ -1839,19 +1806,22 @@ static int ath_init_softc(u16 devid, str
 	/* setup channels and rates */
 
 	sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable;
-	sc->sbands[IEEE80211_BAND_2GHZ].bitrates =
-		sc->rates[IEEE80211_BAND_2GHZ];
 	sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
 	sc->sbands[IEEE80211_BAND_2GHZ].n_channels =
 		ARRAY_SIZE(ath9k_2ghz_chantable);
+	sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates;
+	sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
+		ARRAY_SIZE(ath9k_legacy_rates);
 
 	if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) {
 		sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable;
-		sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
-			sc->rates[IEEE80211_BAND_5GHZ];
 		sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
 		sc->sbands[IEEE80211_BAND_5GHZ].n_channels =
 			ARRAY_SIZE(ath9k_5ghz_chantable);
+		sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
+			ath9k_legacy_rates + 4;
+		sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
+			ARRAY_SIZE(ath9k_legacy_rates) - 4;
 	}
 
 	switch (ah->btcoex_hw.scheme) {
--- a/drivers/net/wireless/ath/ath9k/rc.h
+++ b/drivers/net/wireless/ath/ath9k/rc.h
@@ -104,6 +104,7 @@ enum {
  */
 struct ath_rate_table {
 	int rate_cnt;
+	int mcs_start;
 	struct {
 		int valid;
 		int valid_single_stream;
@@ -179,8 +180,6 @@ enum ath9k_internal_frame_type {
 	ATH9K_INT_UNPAUSE
 };
 
-void ath_rate_attach(struct ath_softc *sc);
-u8 ath_rate_findrateix(struct ath_softc *sc, u8 dot11_rate);
 int ath_rate_control_register(void);
 void ath_rate_control_unregister(void);
 
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -65,9 +65,9 @@ static void ath_beacon_setup(struct ath_
 	struct ath_common *common = ath9k_hw_common(ah);
 	struct ath_desc *ds;
 	struct ath9k_11n_rate_series series[4];
-	const struct ath_rate_table *rt;
 	int flags, antenna, ctsrate = 0, ctsduration = 0;
-	u8 rate;
+	struct ieee80211_supported_band *sband;
+	u8 rate = 0;
 
 	ds = bf->bf_desc;
 	flags = ATH9K_TXDESC_NOACK;
@@ -91,10 +91,10 @@ static void ath_beacon_setup(struct ath_
 
 	ds->ds_data = bf->bf_buf_addr;
 
-	rt = sc->cur_rate_table;
-	rate = rt->info[0].ratecode;
+	sband = &sc->sbands[common->hw->conf.channel->band];
+	rate = sband->bitrates[0].hw_value;
 	if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
-		rate |= rt->info[0].short_preamble;
+		rate |= sband->bitrates[0].hw_value_short;
 
 	ath9k_hw_set11n_txdesc(ah, ds, skb->len + FCS_LEN,
 			       ATH9K_PKT_TYPE_BEACON,
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -18,6 +18,7 @@
 #define DEBUG_H
 
 #include "hw.h"
+#include "rc.h"
 
 struct ath_txq;
 struct ath_buf;
@@ -138,7 +139,7 @@ void ath9k_exit_debug(struct ath_hw *ah)
 int ath9k_debug_create_root(void);
 void ath9k_debug_remove_root(void);
 void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
-void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb);
+void ath_debug_stat_rc(struct ath_softc *sc, int final_rate);
 void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq,
 		       struct ath_buf *bf);
 void ath_debug_stat_retries(struct ath_softc *sc, int rix,
@@ -170,7 +171,7 @@ static inline void ath_debug_stat_interr
 }
 
 static inline void ath_debug_stat_rc(struct ath_softc *sc,
-				     struct sk_buff *skb)
+				     int final_rate)
 {
 }
 
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -255,21 +255,11 @@ static const struct file_operations fops
 	.owner = THIS_MODULE
 };
 
-void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb)
+void ath_debug_stat_rc(struct ath_softc *sc, int final_rate)
 {
-	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-	struct ieee80211_tx_rate *rates = tx_info->status.rates;
-	int final_ts_idx = 0, idx, i;
 	struct ath_rc_stats *stats;
 
-	for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
-		if (!rates[i].count)
-			break;
-
-		final_ts_idx = i;
-	}
-	idx = rates[final_ts_idx].idx;
-	stats = &sc->debug.stats.rcstats[idx];
+	stats = &sc->debug.stats.rcstats[final_rate];
 	stats->success++;
 }
 
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -149,22 +149,19 @@ bool ath9k_get_channel_edges(struct ath_
 }
 
 u16 ath9k_hw_computetxtime(struct ath_hw *ah,
-			   const struct ath_rate_table *rates,
+			   u8 phy, int kbps,
 			   u32 frameLen, u16 rateix,
 			   bool shortPreamble)
 {
 	u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
-	u32 kbps;
-
-	kbps = rates->info[rateix].ratekbps;
 
 	if (kbps == 0)
 		return 0;
 
-	switch (rates->info[rateix].phy) {
+	switch (phy) {
 	case WLAN_RC_PHY_CCK:
 		phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
-		if (shortPreamble && rates->info[rateix].short_preamble)
+		if (shortPreamble)
 			phyTime >>= 1;
 		numBits = frameLen << 3;
 		txTime = CCK_SIFS_TIME + phyTime + ((numBits * 1000) / kbps);
@@ -195,8 +192,7 @@ u16 ath9k_hw_computetxtime(struct ath_hw
 		break;
 	default:
 		ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
-			  "Unknown phy %u (rate ix %u)\n",
-			  rates->info[rateix].phy, rateix);
+			  "Unknown phy %u (rate ix %u)\n", phy, rateix);
 		txTime = 0;
 		break;
 	}
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -647,7 +647,7 @@ bool ath9k_hw_wait(struct ath_hw *ah, u3
 u32 ath9k_hw_reverse_bits(u32 val, u32 n);
 bool ath9k_get_channel_edges(struct ath_hw *ah, u16 flags, u16 *low, u16 *high);
 u16 ath9k_hw_computetxtime(struct ath_hw *ah,
-			   const struct ath_rate_table *rates,
+			   u8 phy, int kbps,
 			   u32 frameLen, u16 rateix, bool shortPreamble);
 void ath9k_hw_get_channel_centers(struct ath_hw *ah,
 				  struct ath9k_channel *chan,
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -616,7 +616,6 @@ enum ath9k_cipher {
 
 struct ath_hw;
 struct ath9k_channel;
-struct ath_rate_table;
 
 u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q);
 void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp);

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2009-11-23 21:22 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-11-23 21:21 [PATCH v3 1/2] ath9k: properly use the mac80211 rate control api Felix Fietkau
2009-11-23 21:22 ` [PATCH v3 2/2] ath9k: clean up rc rate table Felix Fietkau

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.