diff options
Diffstat (limited to 'package/mac80211/patches/301-rt2x00-Implement-support-for-802.11n.patch')
-rw-r--r-- | package/mac80211/patches/301-rt2x00-Implement-support-for-802.11n.patch | 515 |
1 files changed, 515 insertions, 0 deletions
diff --git a/package/mac80211/patches/301-rt2x00-Implement-support-for-802.11n.patch b/package/mac80211/patches/301-rt2x00-Implement-support-for-802.11n.patch new file mode 100644 index 0000000000..a6e76bce37 --- /dev/null +++ b/package/mac80211/patches/301-rt2x00-Implement-support-for-802.11n.patch @@ -0,0 +1,515 @@ +From 42d5399c2743dbd1ddaaadc8cb04adbfc65cc970 Mon Sep 17 00:00:00 2001 +From: Ivo van Doorn <IvDoorn@gmail.com> +Date: Sat, 10 Jan 2009 11:01:10 +0100 +Subject: [PATCH] rt2x00: Implement support for 802.11n + +Extend rt2x00lib capabilities to support 802.11n, +it still lacks aggregation support, but that can +be added in the future. + +Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com> +--- + drivers/net/wireless/rt2x00/Kconfig | 3 + + drivers/net/wireless/rt2x00/Makefile | 1 + + drivers/net/wireless/rt2x00/rt2x00.h | 5 ++ + drivers/net/wireless/rt2x00/rt2x00config.c | 5 ++ + drivers/net/wireless/rt2x00/rt2x00dev.c | 91 ++++++++++++++++++++------- + drivers/net/wireless/rt2x00/rt2x00ht.c | 69 +++++++++++++++++++++ + drivers/net/wireless/rt2x00/rt2x00lib.h | 24 +++++++ + drivers/net/wireless/rt2x00/rt2x00queue.c | 1 + + drivers/net/wireless/rt2x00/rt2x00queue.h | 26 +++++++- + 9 files changed, 197 insertions(+), 28 deletions(-) + create mode 100644 drivers/net/wireless/rt2x00/rt2x00ht.c + +--- a/drivers/net/wireless/rt2x00/Makefile ++++ b/drivers/net/wireless/rt2x00/Makefile +@@ -8,6 +8,7 @@ rt2x00lib-$(CONFIG_RT2X00_LIB_CRYPTO) += + rt2x00lib-$(CONFIG_RT2X00_LIB_RFKILL) += rt2x00rfkill.o + rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o + rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o ++rt2x00lib-$(CONFIG_RT2X00_LIB_HT) += rt2x00ht.o + + obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o + obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o +--- a/drivers/net/wireless/rt2x00/rt2x00.h ++++ b/drivers/net/wireless/rt2x00/rt2x00.h +@@ -108,6 +108,7 @@ + */ + #define ACK_SIZE 14 + #define IEEE80211_HEADER 24 ++#define AGGREGATION_SIZE 3840 + #define PLCP 48 + #define BEACON 100 + #define PREAMBLE 144 +@@ -357,6 +358,7 @@ static inline struct rt2x00_intf* vif_to + * for @tx_power_a, @tx_power_bg and @channels. + * @channels: Device/chipset specific channel values (See &struct rf_channel). + * @channels_info: Additional information for channels (See &struct channel_info). ++ * @ht: Driver HT Capabilities (See &ieee80211_sta_ht_cap). + */ + struct hw_mode_spec { + unsigned int supported_bands; +@@ -370,6 +372,8 @@ struct hw_mode_spec { + unsigned int num_channels; + const struct rf_channel *channels; + const struct channel_info *channels_info; ++ ++ struct ieee80211_sta_ht_cap ht; + }; + + /* +@@ -604,6 +608,7 @@ enum rt2x00_flags { + CONFIG_EXTERNAL_LNA_BG, + CONFIG_DOUBLE_ANTENNA, + CONFIG_DISABLE_LINK_TUNING, ++ CONFIG_CHANNEL_HT40, + }; + + /* +--- a/drivers/net/wireless/rt2x00/rt2x00config.c ++++ b/drivers/net/wireless/rt2x00/rt2x00config.c +@@ -173,6 +173,11 @@ void rt2x00lib_config(struct rt2x00_dev + libconf.conf = conf; + + if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) { ++ if (conf_is_ht40(conf)) ++ __set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); ++ else ++ __clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); ++ + memcpy(&libconf.rf, + &rt2x00dev->spec.channels[conf->channel->hw_value], + sizeof(libconf.rf)); +--- a/drivers/net/wireless/rt2x00/rt2x00dev.c ++++ b/drivers/net/wireless/rt2x00/rt2x00dev.c +@@ -315,18 +315,54 @@ void rt2x00lib_txdone(struct queue_entry + } + EXPORT_SYMBOL_GPL(rt2x00lib_txdone); + ++static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev, ++ struct rxdone_entry_desc *rxdesc) ++{ ++ struct ieee80211_supported_band *sband; ++ const struct rt2x00_rate *rate; ++ unsigned int i; ++ int signal; ++ int type; ++ ++ /* ++ * For non-HT rates the MCS value needs to contain the ++ * actually used rate modulation (CCK or OFDM). ++ */ ++ if (rxdesc->dev_flags & RXDONE_SIGNAL_MCS) ++ signal = RATE_MCS(rxdesc->rate_mode, rxdesc->signal); ++ else ++ signal = rxdesc->signal; ++ ++ type = (rxdesc->dev_flags & RXDONE_SIGNAL_MASK); ++ ++ sband = &rt2x00dev->bands[rt2x00dev->curr_band]; ++ for (i = 0; i < sband->n_bitrates; i++) { ++ rate = rt2x00_get_rate(sband->bitrates[i].hw_value); ++ ++ if (((type == RXDONE_SIGNAL_PLCP) && ++ (rate->plcp == signal)) || ++ ((type == RXDONE_SIGNAL_BITRATE) && ++ (rate->bitrate == signal)) || ++ ((type == RXDONE_SIGNAL_MCS) && ++ (rate->mcs == signal))) { ++ return i; ++ } ++ } ++ ++ WARNING(rt2x00dev, "Frame received with unrecognized signal, " ++ "signal=0x%.4x, type=%d.\n", signal, type); ++ return 0; ++} ++ + void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, + struct queue_entry *entry) + { + struct rxdone_entry_desc rxdesc; + struct sk_buff *skb; + struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status; +- struct ieee80211_supported_band *sband; +- const struct rt2x00_rate *rate; + unsigned int header_length; + unsigned int align; +- unsigned int i; +- int idx = -1; ++ int rate_idx; + + /* + * Allocate a new sk_buffer. If no new buffer available, drop the +@@ -375,26 +411,17 @@ void rt2x00lib_rxdone(struct rt2x00_dev + skb_trim(entry->skb, rxdesc.size); + + /* +- * Update RX statistics. +- */ +- sband = &rt2x00dev->bands[rt2x00dev->curr_band]; +- for (i = 0; i < sband->n_bitrates; i++) { +- rate = rt2x00_get_rate(sband->bitrates[i].hw_value); +- +- if (((rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) && +- (rate->plcp == rxdesc.signal)) || +- ((rxdesc.dev_flags & RXDONE_SIGNAL_BITRATE) && +- (rate->bitrate == rxdesc.signal))) { +- idx = i; +- break; +- } +- } +- +- if (idx < 0) { +- WARNING(rt2x00dev, "Frame received with unrecognized signal," +- "signal=0x%.2x, type=%d.\n", rxdesc.signal, +- (rxdesc.dev_flags & RXDONE_SIGNAL_MASK)); +- idx = 0; ++ * Check if the frame was received using HT. In that case, ++ * the rate is the MCS index and should be passed to mac80211 ++ * directly. Otherwise we need to translate the signal to ++ * the correct bitrate index. ++ */ ++ if (rxdesc.rate_mode == RATE_MODE_CCK || ++ rxdesc.rate_mode == RATE_MODE_OFDM) { ++ rate_idx = rt2x00lib_rxdone_read_signal(rt2x00dev, &rxdesc); ++ } else { ++ rxdesc.flags |= RX_FLAG_HT; ++ rate_idx = rxdesc.signal; + } + + /* +@@ -404,7 +431,7 @@ void rt2x00lib_rxdone(struct rt2x00_dev + rt2x00debug_update_crypto(rt2x00dev, &rxdesc); + + rx_status->mactime = rxdesc.timestamp; +- rx_status->rate_idx = idx; ++ rx_status->rate_idx = rate_idx; + rx_status->qual = rt2x00link_calculate_signal(rt2x00dev, rxdesc.rssi); + rx_status->signal = rxdesc.rssi; + rx_status->noise = rxdesc.noise; +@@ -439,72 +466,84 @@ const struct rt2x00_rate rt2x00_supporte + .bitrate = 10, + .ratemask = BIT(0), + .plcp = 0x00, ++ .mcs = RATE_MCS(RATE_MODE_CCK, 0), + }, + { + .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE, + .bitrate = 20, + .ratemask = BIT(1), + .plcp = 0x01, ++ .mcs = RATE_MCS(RATE_MODE_CCK, 1), + }, + { + .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE, + .bitrate = 55, + .ratemask = BIT(2), + .plcp = 0x02, ++ .mcs = RATE_MCS(RATE_MODE_CCK, 2), + }, + { + .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE, + .bitrate = 110, + .ratemask = BIT(3), + .plcp = 0x03, ++ .mcs = RATE_MCS(RATE_MODE_CCK, 3), + }, + { + .flags = DEV_RATE_OFDM, + .bitrate = 60, + .ratemask = BIT(4), + .plcp = 0x0b, ++ .mcs = RATE_MCS(RATE_MODE_OFDM, 0), + }, + { + .flags = DEV_RATE_OFDM, + .bitrate = 90, + .ratemask = BIT(5), + .plcp = 0x0f, ++ .mcs = RATE_MCS(RATE_MODE_OFDM, 1), + }, + { + .flags = DEV_RATE_OFDM, + .bitrate = 120, + .ratemask = BIT(6), + .plcp = 0x0a, ++ .mcs = RATE_MCS(RATE_MODE_OFDM, 2), + }, + { + .flags = DEV_RATE_OFDM, + .bitrate = 180, + .ratemask = BIT(7), + .plcp = 0x0e, ++ .mcs = RATE_MCS(RATE_MODE_OFDM, 3), + }, + { + .flags = DEV_RATE_OFDM, + .bitrate = 240, + .ratemask = BIT(8), + .plcp = 0x09, ++ .mcs = RATE_MCS(RATE_MODE_OFDM, 4), + }, + { + .flags = DEV_RATE_OFDM, + .bitrate = 360, + .ratemask = BIT(9), + .plcp = 0x0d, ++ .mcs = RATE_MCS(RATE_MODE_OFDM, 5), + }, + { + .flags = DEV_RATE_OFDM, + .bitrate = 480, + .ratemask = BIT(10), + .plcp = 0x08, ++ .mcs = RATE_MCS(RATE_MODE_OFDM, 6), + }, + { + .flags = DEV_RATE_OFDM, + .bitrate = 540, + .ratemask = BIT(11), + .plcp = 0x0c, ++ .mcs = RATE_MCS(RATE_MODE_OFDM, 7), + }, + }; + +@@ -580,6 +619,8 @@ static int rt2x00lib_probe_hw_modes(stru + rt2x00dev->bands[IEEE80211_BAND_2GHZ].bitrates = rates; + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &rt2x00dev->bands[IEEE80211_BAND_2GHZ]; ++ memcpy(&rt2x00dev->bands[IEEE80211_BAND_2GHZ].ht_cap, ++ &spec->ht, sizeof(spec->ht)); + } + + /* +@@ -596,6 +637,8 @@ static int rt2x00lib_probe_hw_modes(stru + rt2x00dev->bands[IEEE80211_BAND_5GHZ].bitrates = &rates[4]; + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = + &rt2x00dev->bands[IEEE80211_BAND_5GHZ]; ++ memcpy(&rt2x00dev->bands[IEEE80211_BAND_5GHZ].ht_cap, ++ &spec->ht, sizeof(spec->ht)); + } + + return 0; +--- /dev/null ++++ b/drivers/net/wireless/rt2x00/rt2x00ht.c +@@ -0,0 +1,69 @@ ++/* ++ Copyright (C) 2004 - 2008 rt2x00 SourceForge Project ++ <http://rt2x00.serialmonkey.com> ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the ++ Free Software Foundation, Inc., ++ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++/* ++ Module: rt2x00lib ++ Abstract: rt2x00 HT specific routines. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++ ++#include "rt2x00.h" ++#include "rt2x00lib.h" ++ ++void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, ++ struct txentry_desc *txdesc, ++ struct ieee80211_rate *rate) ++{ ++ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); ++ const struct rt2x00_rate *hwrate = rt2x00_get_rate(rate->hw_value); ++ ++ if (tx_info->control.sta) ++ txdesc->mpdu_density = ++ tx_info->control.sta->ht_cap.ampdu_density; ++ else ++ txdesc->mpdu_density = 0; ++ ++ txdesc->ba_size = 0; /* FIXME: What value is needed? */ ++ txdesc->stbc = 0; /* FIXME: What value is needed? */ ++ ++ txdesc->mcs = rt2x00_get_rate_mcs(hwrate->mcs); ++ if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) ++ txdesc->mcs |= 0x08; ++ ++ /* ++ * Convert flags ++ */ ++ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) ++ __set_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags); ++ ++ /* ++ * Determine HT Mix/Greenfield rate mode ++ */ ++ if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_MCS) ++ txdesc->rate_mode = RATE_MODE_HT_MIX; ++ if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD) ++ txdesc->rate_mode = RATE_MODE_HT_GREENFIELD; ++ if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ++ __set_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags); ++ if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_SHORT_GI) ++ __set_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags); ++} +--- a/drivers/net/wireless/rt2x00/rt2x00lib.h ++++ b/drivers/net/wireless/rt2x00/rt2x00lib.h +@@ -48,6 +48,7 @@ struct rt2x00_rate { + unsigned short ratemask; + + unsigned short plcp; ++ unsigned short mcs; + }; + + extern const struct rt2x00_rate rt2x00_supported_rates[12]; +@@ -57,6 +58,14 @@ static inline const struct rt2x00_rate * + return &rt2x00_supported_rates[hw_value & 0xff]; + } + ++#define RATE_MCS(__mode, __mcs) \ ++ ( (((__mode) & 0x00ff) << 8) | ((__mcs) & 0x00ff) ) ++ ++static inline int rt2x00_get_rate_mcs(const u16 mcs_value) ++{ ++ return (mcs_value & 0x00ff); ++} ++ + /* + * Radio control handlers. + */ +@@ -330,6 +339,21 @@ static inline void rt2x00crypto_rx_inser + #endif /* CONFIG_RT2X00_LIB_CRYPTO */ + + /* ++ * HT handlers. ++ */ ++#ifdef CONFIG_RT2X00_LIB_HT ++void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, ++ struct txentry_desc *txdesc, ++ struct ieee80211_rate *rate); ++#else ++static inline void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, ++ struct txentry_desc *txdesc, ++ struct ieee80211_rate *rate) ++{ ++} ++#endif /* CONFIG_RT2X00_LIB_HT */ ++ ++/* + * RFkill handlers. + */ + #ifdef CONFIG_RT2X00_LIB_RFKILL +--- a/drivers/net/wireless/rt2x00/rt2x00queue.c ++++ b/drivers/net/wireless/rt2x00/rt2x00queue.c +@@ -325,6 +325,7 @@ static void rt2x00queue_create_tx_descri + * Apply TX descriptor handling by components + */ + rt2x00crypto_create_tx_descriptor(entry, txdesc); ++ rt2x00ht_create_tx_descriptor(entry, txdesc, rate); + rt2x00queue_create_tx_descriptor_seq(entry, txdesc); + rt2x00queue_create_tx_descriptor_plcp(entry, txdesc, rate); + } +--- a/drivers/net/wireless/rt2x00/rt2x00queue.h ++++ b/drivers/net/wireless/rt2x00/rt2x00queue.h +@@ -145,6 +145,7 @@ static inline struct skb_frame_desc* get + * + * @RXDONE_SIGNAL_PLCP: Signal field contains the plcp value. + * @RXDONE_SIGNAL_BITRATE: Signal field contains the bitrate value. ++ * @RXDONE_SIGNAL_MCS: Signal field contains the mcs value. + * @RXDONE_MY_BSS: Does this frame originate from device's BSS. + * @RXDONE_CRYPTO_IV: Driver provided IV/EIV data. + * @RXDONE_CRYPTO_ICV: Driver provided ICV data. +@@ -152,9 +153,10 @@ static inline struct skb_frame_desc* get + enum rxdone_entry_desc_flags { + RXDONE_SIGNAL_PLCP = 1 << 0, + RXDONE_SIGNAL_BITRATE = 1 << 1, +- RXDONE_MY_BSS = 1 << 2, +- RXDONE_CRYPTO_IV = 1 << 3, +- RXDONE_CRYPTO_ICV = 1 << 4, ++ RXDONE_SIGNAL_MCS = 1 << 2, ++ RXDONE_MY_BSS = 1 << 3, ++ RXDONE_CRYPTO_IV = 1 << 4, ++ RXDONE_CRYPTO_ICV = 1 << 5, + }; + + /** +@@ -163,7 +165,7 @@ enum rxdone_entry_desc_flags { + * from &rxdone_entry_desc to a signal value type. + */ + #define RXDONE_SIGNAL_MASK \ +- ( RXDONE_SIGNAL_PLCP | RXDONE_SIGNAL_BITRATE ) ++ ( RXDONE_SIGNAL_PLCP | RXDONE_SIGNAL_BITRATE | RXDONE_SIGNAL_MCS ) + + /** + * struct rxdone_entry_desc: RX Entry descriptor +@@ -177,6 +179,7 @@ enum rxdone_entry_desc_flags { + * @size: Data size of the received frame. + * @flags: MAC80211 receive flags (See &enum mac80211_rx_flags). + * @dev_flags: Ralink receive flags (See &enum rxdone_entry_desc_flags). ++ * @rate_mode: Rate mode (See @enum rate_modulation). + * @cipher: Cipher type used during decryption. + * @cipher_status: Decryption status. + * @iv: IV/EIV data used during decryption. +@@ -190,6 +193,7 @@ struct rxdone_entry_desc { + int size; + int flags; + int dev_flags; ++ u16 rate_mode; + u8 cipher; + u8 cipher_status; + +@@ -243,6 +247,9 @@ struct txdone_entry_desc { + * @ENTRY_TXD_ENCRYPT_PAIRWISE: Use pairwise key table (instead of shared). + * @ENTRY_TXD_ENCRYPT_IV: Generate IV/EIV in hardware. + * @ENTRY_TXD_ENCRYPT_MMIC: Generate MIC in hardware. ++ * @ENTRY_TXD_HT_AMPDU: This frame is part of an AMPDU. ++ * @ENTRY_TXD_HT_BW_40: Use 40MHz Bandwidth. ++ * @ENTRY_TXD_HT_SHORT_GI: Use short GI. + */ + enum txentry_desc_flags { + ENTRY_TXD_RTS_FRAME, +@@ -258,6 +265,9 @@ enum txentry_desc_flags { + ENTRY_TXD_ENCRYPT_PAIRWISE, + ENTRY_TXD_ENCRYPT_IV, + ENTRY_TXD_ENCRYPT_MMIC, ++ ENTRY_TXD_HT_AMPDU, ++ ENTRY_TXD_HT_BW_40, ++ ENTRY_TXD_HT_SHORT_GI, + }; + + /** +@@ -271,7 +281,11 @@ enum txentry_desc_flags { + * @length_low: PLCP length low word. + * @signal: PLCP signal. + * @service: PLCP service. ++ * @msc: MCS. ++ * @stbc: STBC. ++ * @ba_size: BA size. + * @rate_mode: Rate mode (See @enum rate_modulation). ++ * @mpdu_density: MDPU density. + * @retry_limit: Max number of retries. + * @aifs: AIFS value. + * @ifs: IFS value. +@@ -291,7 +305,11 @@ struct txentry_desc { + u16 signal; + u16 service; + ++ u16 mcs; ++ u16 stbc; ++ u16 ba_size; + u16 rate_mode; ++ u16 mpdu_density; + + short retry_limit; + short aifs; |