ar9170: support HT receive and channel config
authorJohannes Berg <johannes@sipsolutions.net>
Mon, 20 Apr 2009 16:27:04 +0000 (18:27 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 22 Apr 2009 20:57:17 +0000 (16:57 -0400)
This patch adds support for configuring HT40 channels
and receiving HT40 to ar9170. Receiving aggregation
doesn't seem to work right now, so it's not enabled.
Same goes for TX aggregation, but that probably needs
even more work.

With this, I can receive roughly 33 Mbits/sec.

The HT capabilities are a little odd, I tried following
otus here -- in particular having SGI_40 but not SGI_20
is a little weird but afaict that's what otus does.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ar9170/ar9170.h
drivers/net/wireless/ath/ar9170/main.c

index 2522a190fdfba58f9b233e0c063de651c844016f..b6a1bff67cab15ce198413fc35f299dd9238a26a 100644 (file)
@@ -60,6 +60,21 @@ enum ar9170_bw {
        __AR9170_NUM_BW,
 };
 
+static inline enum ar9170_bw nl80211_to_ar9170(enum nl80211_channel_type type)
+{
+       switch (type) {
+       case NL80211_CHAN_NO_HT:
+       case NL80211_CHAN_HT20:
+               return AR9170_BW_20;
+       case NL80211_CHAN_HT40MINUS:
+               return AR9170_BW_40_BELOW;
+       case NL80211_CHAN_HT40PLUS:
+               return AR9170_BW_40_ABOVE;
+       default:
+               BUG();
+       }
+}
+
 enum ar9170_rf_init_mode {
        AR9170_RFI_NONE,
        AR9170_RFI_WARM,
index 857416c80199117c78fee398cfe8cd0a220ccd48..4682fe2f3f3ca5db8e477c12c81e39b953af9cdd 100644 (file)
@@ -142,11 +142,36 @@ static struct ieee80211_channel ar9170_5ghz_chantable[] = {
 };
 #undef CHAN
 
+#define AR9170_HT_CAP                                                  \
+{                                                                      \
+       .ht_supported   = true,                                         \
+       .cap            = IEEE80211_HT_CAP_MAX_AMSDU |                  \
+                         IEEE80211_HT_CAP_SM_PS |                      \
+                         IEEE80211_HT_CAP_SUP_WIDTH_20_40 |            \
+                         IEEE80211_HT_CAP_SGI_40 |                     \
+                         IEEE80211_HT_CAP_DSSSCCK40 |                  \
+                         IEEE80211_HT_CAP_SM_PS,                       \
+       .ampdu_factor   = 3, /* ?? */                                   \
+       .ampdu_density  = 7, /* ?? */                                   \
+       .mcs            = {                                             \
+               .rx_mask = { 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, },     \
+       },                                                              \
+}
+
 static struct ieee80211_supported_band ar9170_band_2GHz = {
        .channels       = ar9170_2ghz_chantable,
        .n_channels     = ARRAY_SIZE(ar9170_2ghz_chantable),
        .bitrates       = ar9170_g_ratetable,
        .n_bitrates     = ar9170_g_ratetable_size,
+       .ht_cap         = AR9170_HT_CAP,
+};
+
+static struct ieee80211_supported_band ar9170_band_5GHz = {
+       .channels       = ar9170_5ghz_chantable,
+       .n_channels     = ARRAY_SIZE(ar9170_5ghz_chantable),
+       .bitrates       = ar9170_a_ratetable,
+       .n_bitrates     = ar9170_a_ratetable_size,
+       .ht_cap         = AR9170_HT_CAP,
 };
 
 #ifdef AR9170_QUEUE_DEBUG
@@ -190,13 +215,6 @@ static void ar9170_dump_station_tx_status_queue(struct ar9170 *ar,
 }
 #endif /* AR9170_QUEUE_DEBUG */
 
-static struct ieee80211_supported_band ar9170_band_5GHz = {
-       .channels       = ar9170_5ghz_chantable,
-       .n_channels     = ARRAY_SIZE(ar9170_5ghz_chantable),
-       .bitrates       = ar9170_a_ratetable,
-       .n_bitrates     = ar9170_a_ratetable_size,
-};
-
 void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb,
                             bool valid_status, u16 tx_status)
 {
@@ -1077,7 +1095,8 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed)
 
        if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
                err = ar9170_set_channel(ar, hw->conf.channel,
-                                        AR9170_RFI_NONE, AR9170_BW_20);
+                               AR9170_RFI_NONE,
+                               nl80211_to_ar9170(hw->conf.channel_type));
                if (err)
                        goto out;
                /* adjust slot time for 5 GHz */
@@ -1499,6 +1518,24 @@ static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue,
        return ret;
 }
 
+static int ar9170_ampdu_action(struct ieee80211_hw *hw,
+                              enum ieee80211_ampdu_mlme_action action,
+                              struct ieee80211_sta *sta, u16 tid, u16 *ssn)
+{
+       switch (action) {
+       case IEEE80211_AMPDU_RX_START:
+       case IEEE80211_AMPDU_RX_STOP:
+               /*
+                * Something goes wrong -- RX locks up
+                * after a while of receiving aggregated
+                * frames -- not enabling for now.
+                */
+               return -EOPNOTSUPP;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
 static const struct ieee80211_ops ar9170_ops = {
        .start                  = ar9170_op_start,
        .stop                   = ar9170_op_stop,
@@ -1515,6 +1552,7 @@ static const struct ieee80211_ops ar9170_ops = {
        .sta_notify             = ar9170_sta_notify,
        .get_stats              = ar9170_get_stats,
        .get_tx_stats           = ar9170_get_tx_stats,
+       .ampdu_action           = ar9170_ampdu_action,
 };
 
 void *ar9170_alloc(size_t priv_size)