From 9f1661718c7fcf82e25c6aed20b729ee372d9d65 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sun, 26 Apr 2009 16:08:50 +0200 Subject: rt2x00: Add support for L2 padding during TX/RX Some hardware require L2 padding between header and payload because both must be aligned to a 4-byte boundary. This hardware also is easier during the RX path since we no longer need to move the entire payload but rather only the header to remove the padding (mac80211 only wants the payload to be 4-byte aligned). Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt2x00dev.c') diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 5752aaae906b..e15086af7278 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -227,6 +227,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); enum data_queue_qid qid = skb_get_queue_mapping(entry->skb); + unsigned int header_length = ieee80211_get_hdrlen_from_skb(entry->skb); u8 rate_idx, rate_flags; /* @@ -234,6 +235,12 @@ void rt2x00lib_txdone(struct queue_entry *entry, */ rt2x00queue_unmap_skb(rt2x00dev, entry->skb); + /* + * Remove L2 padding which was added during + */ + if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags)) + rt2x00queue_payload_align(entry->skb, true, header_length); + /* * If the IV/EIV data was stripped from the frame before it was * passed to the hardware, we should now reinsert it again because @@ -241,7 +248,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, * frame as it was passed to us. */ if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) - rt2x00crypto_tx_insert_iv(entry->skb); + rt2x00crypto_tx_insert_iv(entry->skb, header_length); /* * Send frame to debugfs immediately, after this call is completed @@ -325,7 +332,7 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, struct ieee80211_supported_band *sband; const struct rt2x00_rate *rate; unsigned int header_length; - unsigned int align; + bool l2pad; unsigned int i; int idx = -1; @@ -348,12 +355,15 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, memset(&rxdesc, 0, sizeof(rxdesc)); rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc); + /* Trim buffer to correct size */ + skb_trim(entry->skb, rxdesc.size); + /* * The data behind the ieee80211 header must be * aligned on a 4 byte boundary. */ header_length = ieee80211_get_hdrlen_from_skb(entry->skb); - align = ((unsigned long)(entry->skb->data + header_length)) & 3; + l2pad = !!(rxdesc.dev_flags & RXDONE_L2PAD); /* * Hardware might have stripped the IV/EIV/ICV data, @@ -362,18 +372,11 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, * in which case we should reinsert the data into the frame. */ if ((rxdesc.dev_flags & RXDONE_CRYPTO_IV) && - (rxdesc.flags & RX_FLAG_IV_STRIPPED)) { - rt2x00crypto_rx_insert_iv(entry->skb, align, - header_length, &rxdesc); - } else if (align) { - skb_push(entry->skb, align); - /* Move entire frame in 1 command */ - memmove(entry->skb->data, entry->skb->data + align, - rxdesc.size); - } - - /* Update data pointers, trim buffer to correct size */ - skb_trim(entry->skb, rxdesc.size); + (rxdesc.flags & RX_FLAG_IV_STRIPPED)) + rt2x00crypto_rx_insert_iv(entry->skb, l2pad, header_length, + &rxdesc); + else + rt2x00queue_payload_align(entry->skb, l2pad, header_length); /* * Update RX statistics. -- cgit v1.2.3 From 35f00cfcc06bb85e0659f9847400518008d78145 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sun, 26 Apr 2009 16:09:32 +0200 Subject: 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 Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 92 ++++++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 25 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt2x00dev.c') diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index e15086af7278..f2270845072a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -323,19 +323,54 @@ void rt2x00lib_txdone(struct queue_entry *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; bool l2pad; - unsigned int i; - int idx = -1; - + int rate_idx; /* * Allocate a new sk_buffer. If no new buffer available, drop the * received frame and reuse the existing buffer. @@ -379,26 +414,17 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, rt2x00queue_payload_align(entry->skb, l2pad, header_length); /* - * Update RX statistics. + * 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. */ - 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; + 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; } /* @@ -408,7 +434,7 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, 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; @@ -443,72 +469,84 @@ const struct rt2x00_rate rt2x00_supported_rates[12] = { .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), }, }; @@ -584,6 +622,8 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, 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)); } /* @@ -600,6 +640,8 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, 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; -- cgit v1.2.3 From ce4c45e099a81b2bc820b6e145aa9058c5acf0bd Mon Sep 17 00:00:00 2001 From: Alexandre Becholey Date: Tue, 19 May 2009 17:52:56 +0200 Subject: rt73usb: fix for master mode Report status unknown as if there were successfully transmitted. This will avoid hostapd to disassociate because it doesn't understand what a status unknown is. Signed-off-by: Alexandre Becholey Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt2x00dev.c') diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index f2270845072a..57813e72c808 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -260,7 +260,8 @@ void rt2x00lib_txdone(struct queue_entry *entry, * Update TX statistics. */ rt2x00dev->link.qual.tx_success += - test_bit(TXDONE_SUCCESS, &txdesc->flags); + test_bit(TXDONE_SUCCESS, &txdesc->flags) || + test_bit(TXDONE_UNKNOWN, &txdesc->flags); rt2x00dev->link.qual.tx_failed += test_bit(TXDONE_FAILURE, &txdesc->flags); @@ -278,14 +279,16 @@ void rt2x00lib_txdone(struct queue_entry *entry, tx_info->status.rates[1].idx = -1; /* terminate */ if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { - if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) + if (test_bit(TXDONE_SUCCESS, &txdesc->flags) || + test_bit(TXDONE_UNKNOWN, &txdesc->flags)) tx_info->flags |= IEEE80211_TX_STAT_ACK; else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) rt2x00dev->low_level_stats.dot11ACKFailureCount++; } if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { - if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) + if (test_bit(TXDONE_SUCCESS, &txdesc->flags) || + test_bit(TXDONE_UNKNOWN, &txdesc->flags)) rt2x00dev->low_level_stats.dot11RTSSuccessCount++; else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) rt2x00dev->low_level_stats.dot11RTSFailureCount++; -- cgit v1.2.3