123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515 |
- From adf33d3a207846709e2a5fb006f17dbc9225f7a9 Mon Sep 17 00:00:00 2001
- From: Ivo van Doorn <[email protected]>
- Date: Fri, 23 Jan 2009 17:10:06 +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 <[email protected]>
- ---
- 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;
- };
-
- /*
- @@ -603,6 +607,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 - 2009 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,
- + const struct rt2x00_rate *hwrate)
- +{
- + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
- + struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0];
- +
- + 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 (txrate->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 (txrate->flags & IEEE80211_TX_RC_MCS)
- + txdesc->rate_mode = RATE_MODE_HT_MIX;
- + if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD)
- + txdesc->rate_mode = RATE_MODE_HT_GREENFIELD;
- + if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
- + __set_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags);
- + if (txrate->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,
- + const struct rt2x00_rate *hwrate);
- +#else
- +static inline void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
- + struct txentry_desc *txdesc,
- + const struct rt2x00_rate *hwrate)
- +{
- +}
- +#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
- @@ -326,6 +326,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, hwrate);
- rt2x00queue_create_tx_descriptor_seq(entry, txdesc);
- rt2x00queue_create_tx_descriptor_plcp(entry, txdesc, hwrate);
- }
- --- 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;
|