rt2x00: Fix HT40 operation in rt2800.
authorGertjan van Wingerde <gwingerde@gmail.com>
Thu, 3 Jun 2010 08:52:08 +0000 (10:52 +0200)
committerIvo van Doorn <IvDoorn@gmail.com>
Thu, 3 Jun 2010 08:52:08 +0000 (10:52 +0200)
Closer inspection of the legacy Ralink driver reveals that in case of HT40+
or HT40- we must adjust the frequency settings that we program to the device.
Implement the same adjustment in the rt2x00 code.

With this HT40 seems to work for all devices supported by rt2800pci and
rt2800usb.

Signed-off-by: Gertjan van Wingerde <gwingerde@gmail.com>
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2x00config.c
drivers/net/wireless/rt2x00/rt2x00ht.c
drivers/net/wireless/rt2x00/rt2x00lib.h

index 9aa480117172c3e2ea0dc73b82880fdc93f5659e..bebbda5ffaab54b2e22c7b66e010bc4ca3e8e01d 100644 (file)
@@ -2531,11 +2531,8 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        else
                spec->ht.ht_supported = false;
 
-       /*
-        * Don't set IEEE80211_HT_CAP_SUP_WIDTH_20_40 for now as it causes
-        * reception problems with HT40 capable 11n APs
-        */
        spec->ht.cap =
+           IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
            IEEE80211_HT_CAP_GRN_FLD |
            IEEE80211_HT_CAP_SGI_20 |
            IEEE80211_HT_CAP_SGI_40 |
index 098315a271ca0473486fcc9fdb8e7ad7928ecea8..8dbd634dae27dd0bd5412ae131b96302d3082c63 100644 (file)
@@ -170,23 +170,27 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
                      unsigned int ieee80211_flags)
 {
        struct rt2x00lib_conf libconf;
+       u16 hw_value;
 
        memset(&libconf, 0, sizeof(libconf));
 
        libconf.conf = conf;
 
        if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) {
-               if (conf_is_ht40(conf))
+               if (conf_is_ht40(conf)) {
                        __set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
-               else
+                       hw_value = rt2x00ht_center_channel(rt2x00dev, conf);
+               } else {
                        __clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
+                       hw_value = conf->channel->hw_value;
+               }
 
                memcpy(&libconf.rf,
-                      &rt2x00dev->spec.channels[conf->channel->hw_value],
+                      &rt2x00dev->spec.channels[hw_value],
                       sizeof(libconf.rf));
 
                memcpy(&libconf.channel,
-                      &rt2x00dev->spec.channels_info[conf->channel->hw_value],
+                      &rt2x00dev->spec.channels_info[hw_value],
                       sizeof(libconf.channel));
        }
 
index 5a407602ce3e2da54bae581765e89a7842fe8935..c4b749da4302aa006e4cb0834e7f2a89ed961a68 100644 (file)
@@ -84,3 +84,31 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
        else
                txdesc->txop = TXOP_HTTXOP;
 }
+
+u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev,
+                           struct ieee80211_conf *conf)
+{
+       struct hw_mode_spec *spec = &rt2x00dev->spec;
+       int center_channel;
+       u16 i;
+
+       /*
+        * Initialize center channel to current channel.
+        */
+       center_channel = spec->channels[conf->channel->hw_value].channel;
+
+       /*
+        * Adjust center channel to HT40+ and HT40- operation.
+        */
+       if (conf_is_ht40_plus(conf))
+               center_channel += 2;
+       else if (conf_is_ht40_minus(conf))
+               center_channel -= (center_channel == 14) ? 1 : 2;
+
+       for (i = 0; i < spec->num_channels; i++)
+               if (spec->channels[i].channel == center_channel)
+                       return i;
+
+       WARN_ON(1);
+       return conf->channel->hw_value;
+}
index 822affc9b4cad91201064fbd1bdf68d771de8944..ed27de1de57bd02d635f0f3fe18a1b4e1415b14b 100644 (file)
@@ -367,12 +367,21 @@ static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb,
 void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
                                   struct txentry_desc *txdesc,
                                   const struct rt2x00_rate *hwrate);
+
+u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev,
+                           struct ieee80211_conf *conf);
 #else
 static inline void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
                                                 struct txentry_desc *txdesc,
                                                 const struct rt2x00_rate *hwrate)
 {
 }
+
+static inline u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev,
+                                         struct ieee80211_conf *conf)
+{
+       return conf->channel->hw_value;
+}
 #endif /* CONFIG_RT2X00_LIB_HT */
 
 /*