mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-11-28 09:53:07 +02:00
090f16f6fb
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@12948 3c298f89-4303-0410-b956-a3cf2f4a3e73
3006 lines
105 KiB
Diff
3006 lines
105 KiB
Diff
Subject: mac80211/drivers: rewrite the rate control API
|
|
|
|
So after the previous changes we were still unhappy with how
|
|
convoluted the API is and decided to make things simpler for
|
|
everybody. This completely changes the rate control API, now
|
|
taking into account 802.11n with MCS rates and more control,
|
|
most drivers don't support that though.
|
|
|
|
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
|
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
|
|
---
|
|
drivers/net/wireless/adm8211.c | 21 -
|
|
drivers/net/wireless/ath5k/base.c | 34 +-
|
|
drivers/net/wireless/ath9k/main.c | 18 -
|
|
drivers/net/wireless/ath9k/rc.c | 40 +--
|
|
drivers/net/wireless/ath9k/xmit.c | 28 +-
|
|
drivers/net/wireless/b43/dma.c | 4
|
|
drivers/net/wireless/b43/main.c | 2
|
|
drivers/net/wireless/b43/pio.c | 4
|
|
drivers/net/wireless/b43/xmit.c | 60 +++-
|
|
drivers/net/wireless/b43/xmit.h | 5
|
|
drivers/net/wireless/b43legacy/dma.c | 46 ++-
|
|
drivers/net/wireless/b43legacy/main.c | 2
|
|
drivers/net/wireless/b43legacy/pio.c | 31 ++
|
|
drivers/net/wireless/b43legacy/xmit.c | 26 +-
|
|
drivers/net/wireless/b43legacy/xmit.h | 2
|
|
drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 57 +---
|
|
drivers/net/wireless/iwlwifi/iwl-3945.c | 62 ++++-
|
|
drivers/net/wireless/iwlwifi/iwl-3945.h | 2
|
|
drivers/net/wireless/iwlwifi/iwl-4965.c | 8
|
|
drivers/net/wireless/iwlwifi/iwl-5000.c | 8
|
|
drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 37 +-
|
|
drivers/net/wireless/iwlwifi/iwl-core.c | 19 -
|
|
drivers/net/wireless/iwlwifi/iwl3945-base.c | 5
|
|
drivers/net/wireless/libertas_tf/main.c | 4
|
|
drivers/net/wireless/mac80211_hwsim.c | 12
|
|
drivers/net/wireless/p54/p54common.c | 16 -
|
|
drivers/net/wireless/rt2x00/rt2x00dev.c | 11
|
|
drivers/net/wireless/rt2x00/rt2x00mac.c | 14 -
|
|
drivers/net/wireless/rt2x00/rt2x00queue.c | 11
|
|
drivers/net/wireless/rtl8180_dev.c | 28 +-
|
|
drivers/net/wireless/rtl8187_dev.c | 10
|
|
drivers/net/wireless/zd1211rw/zd_mac.c | 28 +-
|
|
include/net/mac80211.h | 206 +++++++++-------
|
|
net/mac80211/ieee80211_i.h | 8
|
|
net/mac80211/main.c | 54 +++-
|
|
net/mac80211/mesh_hwmp.c | 6
|
|
net/mac80211/rate.c | 50 +---
|
|
net/mac80211/rate.h | 5
|
|
net/mac80211/rc80211_minstrel.c | 72 ++---
|
|
net/mac80211/rc80211_pid.h | 1
|
|
net/mac80211/rc80211_pid_algo.c | 26 +-
|
|
net/mac80211/rc80211_pid_debugfs.c | 5
|
|
net/mac80211/sta_info.h | 4
|
|
net/mac80211/tx.c | 347 +++++++++++-----------------
|
|
net/mac80211/wext.c | 4
|
|
45 files changed, 781 insertions(+), 662 deletions(-)
|
|
|
|
--- a/include/net/mac80211.h
|
|
+++ b/include/net/mac80211.h
|
|
@@ -222,29 +222,24 @@ struct ieee80211_bss_conf {
|
|
* These flags are used with the @flags member of &ieee80211_tx_info.
|
|
*
|
|
* @IEEE80211_TX_CTL_REQ_TX_STATUS: request TX status callback for this frame.
|
|
- * @IEEE80211_TX_CTL_USE_RTS_CTS: use RTS-CTS before sending frame
|
|
- * @IEEE80211_TX_CTL_USE_CTS_PROTECT: use CTS protection for the frame (e.g.,
|
|
- * for combined 802.11g / 802.11b networks)
|
|
+ * @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence
|
|
+ * number to this frame, taking care of not overwriting the fragment
|
|
+ * number and increasing the sequence number only when the
|
|
+ * IEEE80211_TX_CTL_FIRST_FRAGMENT flags is set. mac80211 will properly
|
|
+ * assign sequence numbers to QoS-data frames but cannot do so correctly
|
|
+ * for non-QoS-data and management frames because beacons need them from
|
|
+ * that counter as well and mac80211 cannot guarantee proper sequencing.
|
|
+ * If this flag is set, the driver should instruct the hardware to
|
|
+ * assign a sequence number to the frame or assign one itself. Cf. IEEE
|
|
+ * 802.11-2007 7.1.3.4.1 paragraph 3. This flag will always be set for
|
|
+ * beacons always be clear for frames without a sequence number field.
|
|
* @IEEE80211_TX_CTL_NO_ACK: tell the low level not to wait for an ack
|
|
- * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: TBD
|
|
* @IEEE80211_TX_CTL_CLEAR_PS_FILT: clear powersave filter for destination
|
|
* station
|
|
- * @IEEE80211_TX_CTL_REQUEUE: TBD
|
|
* @IEEE80211_TX_CTL_FIRST_FRAGMENT: this is a first fragment of the frame
|
|
- * @IEEE80211_TX_CTL_SHORT_PREAMBLE: TBD
|
|
- * @IEEE80211_TX_CTL_LONG_RETRY_LIMIT: this frame should be send using the
|
|
- * through set_retry_limit configured long retry value
|
|
* @IEEE80211_TX_CTL_SEND_AFTER_DTIM: send this frame after DTIM beacon
|
|
* @IEEE80211_TX_CTL_AMPDU: this frame should be sent as part of an A-MPDU
|
|
- * @IEEE80211_TX_CTL_OFDM_HT: this frame can be sent in HT OFDM rates. number
|
|
- * of streams when this flag is on can be extracted from antenna_sel_tx,
|
|
- * so if 1 antenna is marked use SISO, 2 antennas marked use MIMO, n
|
|
- * antennas marked use MIMO_n.
|
|
- * @IEEE80211_TX_CTL_GREEN_FIELD: use green field protection for this frame
|
|
- * @IEEE80211_TX_CTL_40_MHZ_WIDTH: send this frame using 40 Mhz channel width
|
|
- * @IEEE80211_TX_CTL_DUP_DATA: duplicate data frame on both 20 Mhz channels
|
|
- * @IEEE80211_TX_CTL_SHORT_GI: send this frame using short guard interval
|
|
- * @IEEE80211_TX_CTL_INJECTED: TBD
|
|
+ * @IEEE80211_TX_CTL_INJECTED: Frame was injected, internal to mac80211.
|
|
* @IEEE80211_TX_STAT_TX_FILTERED: The frame was not transmitted
|
|
* because the destination STA was in powersave mode.
|
|
* @IEEE80211_TX_STAT_ACK: Frame was acknowledged
|
|
@@ -252,42 +247,41 @@ struct ieee80211_bss_conf {
|
|
* is for the whole aggregation.
|
|
* @IEEE80211_TX_STAT_AMPDU_NO_BACK: no block ack was returned,
|
|
* so consider using block ack request (BAR).
|
|
- * @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence
|
|
- * number to this frame, taking care of not overwriting the fragment
|
|
- * number and increasing the sequence number only when the
|
|
- * IEEE80211_TX_CTL_FIRST_FRAGMENT flags is set. mac80211 will properly
|
|
- * assign sequence numbers to QoS-data frames but cannot do so correctly
|
|
- * for non-QoS-data and management frames because beacons need them from
|
|
- * that counter as well and mac80211 cannot guarantee proper sequencing.
|
|
- * If this flag is set, the driver should instruct the hardware to
|
|
- * assign a sequence number to the frame or assign one itself. Cf. IEEE
|
|
- * 802.11-2007 7.1.3.4.1 paragraph 3. This flag will always be set for
|
|
- * beacons always be clear for frames without a sequence number field.
|
|
+ * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: internal to mac80211, can be
|
|
+ * set by rate control algorithms to indicate probe rate, will
|
|
+ * be cleared for fragmented frames (except on the last fragment)
|
|
+ * @IEEE80211_TX_CTL_REQUEUE: REMOVE THIS
|
|
*/
|
|
enum mac80211_tx_control_flags {
|
|
IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0),
|
|
- IEEE80211_TX_CTL_USE_RTS_CTS = BIT(2),
|
|
- IEEE80211_TX_CTL_USE_CTS_PROTECT = BIT(3),
|
|
- IEEE80211_TX_CTL_NO_ACK = BIT(4),
|
|
- IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(5),
|
|
- IEEE80211_TX_CTL_CLEAR_PS_FILT = BIT(6),
|
|
- IEEE80211_TX_CTL_REQUEUE = BIT(7),
|
|
- IEEE80211_TX_CTL_FIRST_FRAGMENT = BIT(8),
|
|
- IEEE80211_TX_CTL_SHORT_PREAMBLE = BIT(9),
|
|
- IEEE80211_TX_CTL_LONG_RETRY_LIMIT = BIT(10),
|
|
- IEEE80211_TX_CTL_SEND_AFTER_DTIM = BIT(12),
|
|
- IEEE80211_TX_CTL_AMPDU = BIT(13),
|
|
- IEEE80211_TX_CTL_OFDM_HT = BIT(14),
|
|
- IEEE80211_TX_CTL_GREEN_FIELD = BIT(15),
|
|
- IEEE80211_TX_CTL_40_MHZ_WIDTH = BIT(16),
|
|
- IEEE80211_TX_CTL_DUP_DATA = BIT(17),
|
|
- IEEE80211_TX_CTL_SHORT_GI = BIT(18),
|
|
- IEEE80211_TX_CTL_INJECTED = BIT(19),
|
|
- IEEE80211_TX_STAT_TX_FILTERED = BIT(20),
|
|
- IEEE80211_TX_STAT_ACK = BIT(21),
|
|
- IEEE80211_TX_STAT_AMPDU = BIT(22),
|
|
- IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(23),
|
|
- IEEE80211_TX_CTL_ASSIGN_SEQ = BIT(24),
|
|
+ IEEE80211_TX_CTL_ASSIGN_SEQ = BIT(1),
|
|
+ IEEE80211_TX_CTL_NO_ACK = BIT(2),
|
|
+ IEEE80211_TX_CTL_CLEAR_PS_FILT = BIT(3),
|
|
+ IEEE80211_TX_CTL_FIRST_FRAGMENT = BIT(4),
|
|
+ IEEE80211_TX_CTL_SEND_AFTER_DTIM = BIT(5),
|
|
+ IEEE80211_TX_CTL_AMPDU = BIT(6),
|
|
+ IEEE80211_TX_CTL_INJECTED = BIT(7),
|
|
+ IEEE80211_TX_STAT_TX_FILTERED = BIT(8),
|
|
+ IEEE80211_TX_STAT_ACK = BIT(9),
|
|
+ IEEE80211_TX_STAT_AMPDU = BIT(10),
|
|
+ IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11),
|
|
+ IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12),
|
|
+
|
|
+ /* XXX: remove this */
|
|
+ IEEE80211_TX_CTL_REQUEUE = BIT(13),
|
|
+};
|
|
+
|
|
+enum mac80211_rate_control_flags {
|
|
+ IEEE80211_TX_RC_USE_RTS_CTS = BIT(0),
|
|
+ IEEE80211_TX_RC_USE_CTS_PROTECT = BIT(1),
|
|
+ IEEE80211_TX_RC_USE_SHORT_PREAMBLE = BIT(2),
|
|
+
|
|
+ /* rate index is an MCS rate number instead of an index */
|
|
+ IEEE80211_TX_RC_MCS = BIT(3),
|
|
+ IEEE80211_TX_RC_GREEN_FIELD = BIT(4),
|
|
+ IEEE80211_TX_RC_40_MHZ_WIDTH = BIT(5),
|
|
+ IEEE80211_TX_RC_DUP_DATA = BIT(6),
|
|
+ IEEE80211_TX_RC_SHORT_GI = BIT(7),
|
|
};
|
|
|
|
|
|
@@ -296,18 +290,26 @@ enum mac80211_tx_control_flags {
|
|
#define IEEE80211_TX_INFO_DRIVER_DATA_PTRS \
|
|
(IEEE80211_TX_INFO_DRIVER_DATA_SIZE / sizeof(void *))
|
|
|
|
-/* maximum number of alternate rate retry stages */
|
|
-#define IEEE80211_TX_MAX_ALTRATE 3
|
|
+/* maximum number of rate stages */
|
|
+#define IEEE80211_TX_MAX_RATES 4
|
|
|
|
/**
|
|
- * struct ieee80211_tx_altrate - alternate rate selection/status
|
|
+ * struct ieee80211_tx_rate - rate selection/status
|
|
*
|
|
- * @rate_idx: rate index to attempt to send with
|
|
+ * @idx: rate index to attempt to send with
|
|
+ * @flags: rate control flags (&enum mac80211_rate_control_flags)
|
|
* @limit: number of retries before fallback
|
|
+ *
|
|
+ * A value of -1 for @idx indicates an invalid rate and, if used
|
|
+ * in an array of retry rates, that no more rates should be tried.
|
|
+ *
|
|
+ * When used for transmit status reporting, the driver should
|
|
+ * always report the rate along with the flags it used.
|
|
*/
|
|
-struct ieee80211_tx_altrate {
|
|
- s8 rate_idx;
|
|
- u8 limit;
|
|
+struct ieee80211_tx_rate {
|
|
+ s8 idx;
|
|
+ u8 count;
|
|
+ u8 flags;
|
|
};
|
|
|
|
/**
|
|
@@ -322,15 +324,12 @@ struct ieee80211_tx_altrate {
|
|
* it may be NULL.
|
|
*
|
|
* @flags: transmit info flags, defined above
|
|
- * @band: TBD
|
|
- * @tx_rate_idx: TBD
|
|
+ * @band: the band to transmit on (use for checking for races)
|
|
* @antenna_sel_tx: antenna to use, 0 for automatic diversity
|
|
* @control: union for control data
|
|
* @status: union for status data
|
|
* @driver_data: array of driver_data pointers
|
|
* @retry_count: number of retries
|
|
- * @excessive_retries: set to 1 if the frame was retried many times
|
|
- * but not acknowledged
|
|
* @ampdu_ack_len: number of aggregated frames.
|
|
* relevant only if IEEE80211_TX_STATUS_AMPDU was set.
|
|
* @ampdu_ack_map: block ack bit map for the aggregation.
|
|
@@ -341,28 +340,28 @@ struct ieee80211_tx_info {
|
|
/* common information */
|
|
u32 flags;
|
|
u8 band;
|
|
- s8 tx_rate_idx;
|
|
+
|
|
u8 antenna_sel_tx;
|
|
|
|
- /* 1 byte hole */
|
|
+ /* 2 byte hole */
|
|
|
|
union {
|
|
struct {
|
|
+ union {
|
|
+ struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES];
|
|
+ /* we need the jiffies only before rate control */
|
|
+ unsigned long jiffies;
|
|
+ };
|
|
+ s8 rts_cts_rate_idx;
|
|
/* NB: vif can be NULL for injected frames */
|
|
struct ieee80211_vif *vif;
|
|
struct ieee80211_key_conf *hw_key;
|
|
struct ieee80211_sta *sta;
|
|
- unsigned long jiffies;
|
|
- s8 rts_cts_rate_idx;
|
|
- u8 retry_limit;
|
|
- struct ieee80211_tx_altrate retries[IEEE80211_TX_MAX_ALTRATE];
|
|
} control;
|
|
struct {
|
|
+ struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES];
|
|
u64 ampdu_ack_map;
|
|
int ack_signal;
|
|
- struct ieee80211_tx_altrate retries[IEEE80211_TX_MAX_ALTRATE + 1];
|
|
- u8 retry_count;
|
|
- bool excessive_retries;
|
|
u8 ampdu_ack_len;
|
|
} status;
|
|
void *driver_data[IEEE80211_TX_INFO_DRIVER_DATA_PTRS];
|
|
@@ -374,6 +373,22 @@ static inline struct ieee80211_tx_info *
|
|
return (struct ieee80211_tx_info *)skb->cb;
|
|
}
|
|
|
|
+static inline void
|
|
+ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) !=
|
|
+ offsetof(struct ieee80211_tx_info, control.rates));
|
|
+ /* clear the rate counts */
|
|
+ for (i = 0; i < IEEE80211_TX_MAX_RATES; i++)
|
|
+ info->status.rates[i].count = 0;
|
|
+
|
|
+ memset(&info->status.ampdu_ack_map, 0,
|
|
+ sizeof(struct ieee80211_tx_info) -
|
|
+ offsetof(struct ieee80211_tx_info, status.ampdu_ack_map));
|
|
+}
|
|
+
|
|
|
|
/**
|
|
* enum mac80211_rx_flags - receive flags
|
|
@@ -875,8 +890,8 @@ enum ieee80211_hw_flags {
|
|
* @sta_data_size: size (in bytes) of the drv_priv data area
|
|
* within &struct ieee80211_sta.
|
|
*
|
|
- * @max_altrates: maximum number of alternate rate retry stages
|
|
- * @max_altrate_tries: maximum number of tries for each stage
|
|
+ * @max_rates: maximum number of alternate rate retry stages
|
|
+ * @max_rate_tries: maximum number of tries for each stage
|
|
*/
|
|
struct ieee80211_hw {
|
|
struct ieee80211_conf conf;
|
|
@@ -893,8 +908,8 @@ struct ieee80211_hw {
|
|
u16 ampdu_queues;
|
|
u16 max_listen_interval;
|
|
s8 max_signal;
|
|
- u8 max_altrates;
|
|
- u8 max_altrate_tries;
|
|
+ u8 max_rates;
|
|
+ u8 max_rate_tries;
|
|
};
|
|
|
|
/**
|
|
@@ -933,9 +948,9 @@ static inline struct ieee80211_rate *
|
|
ieee80211_get_tx_rate(const struct ieee80211_hw *hw,
|
|
const struct ieee80211_tx_info *c)
|
|
{
|
|
- if (WARN_ON(c->tx_rate_idx < 0))
|
|
+ if (WARN_ON(c->control.rates[0].idx < 0))
|
|
return NULL;
|
|
- return &hw->wiphy->bands[c->band]->bitrates[c->tx_rate_idx];
|
|
+ return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[0].idx];
|
|
}
|
|
|
|
static inline struct ieee80211_rate *
|
|
@@ -951,9 +966,9 @@ static inline struct ieee80211_rate *
|
|
ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
|
|
const struct ieee80211_tx_info *c, int idx)
|
|
{
|
|
- if (c->control.retries[idx].rate_idx < 0)
|
|
+ if (c->control.rates[idx + 1].idx < 0)
|
|
return NULL;
|
|
- return &hw->wiphy->bands[c->band]->bitrates[c->control.retries[idx].rate_idx];
|
|
+ return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[idx + 1].idx];
|
|
}
|
|
|
|
/**
|
|
@@ -1847,17 +1862,28 @@ struct ieee80211_sta *ieee80211_find_sta
|
|
|
|
|
|
/* Rate control API */
|
|
+
|
|
/**
|
|
- * struct rate_selection - rate information for/from rate control algorithms
|
|
+ * struct ieee80211_tx_rate_control - rate control information for/from RC algo
|
|
*
|
|
- * @rate_idx: selected transmission rate index
|
|
- * @nonerp_idx: Non-ERP rate to use instead if ERP cannot be used
|
|
- * @probe_idx: rate for probing (or -1)
|
|
- * @max_rate_idx: maximum rate index that can be used, this is
|
|
- * input to the algorithm and will be enforced
|
|
- */
|
|
-struct rate_selection {
|
|
- s8 rate_idx, nonerp_idx, probe_idx, max_rate_idx;
|
|
+ * @sband: The band this frame is being transmitted on.
|
|
+ * @bss_conf: the current BSS configuration
|
|
+ * @reported_rate: The rate control algorithm can fill this in to indicate
|
|
+ * which rate should be reported to userspace as the current rate and
|
|
+ * used for rate calculations in the mesh network.
|
|
+ * @rts: whether RTS will be used for this frame because it is longer than the
|
|
+ * RTS threshold
|
|
+ * @short_preamble: whether mac80211 will request short-preamble transmission
|
|
+ * if the selected rate supports it
|
|
+ * @max_rate_idx: user-requested maximum rate (not MCS for now)
|
|
+ */
|
|
+struct ieee80211_tx_rate_control {
|
|
+ struct ieee80211_supported_band *sband;
|
|
+ struct ieee80211_bss_conf *bss_conf;
|
|
+ struct sk_buff *skb;
|
|
+ struct ieee80211_tx_rate reported_rate;
|
|
+ bool rts, short_preamble;
|
|
+ u8 max_rate_idx;
|
|
};
|
|
|
|
struct rate_control_ops {
|
|
@@ -1876,10 +1902,8 @@ struct rate_control_ops {
|
|
void (*tx_status)(void *priv, struct ieee80211_supported_band *sband,
|
|
struct ieee80211_sta *sta, void *priv_sta,
|
|
struct sk_buff *skb);
|
|
- void (*get_rate)(void *priv, struct ieee80211_supported_band *sband,
|
|
- struct ieee80211_sta *sta, void *priv_sta,
|
|
- struct sk_buff *skb,
|
|
- struct rate_selection *sel);
|
|
+ void (*get_rate)(void *priv, struct ieee80211_sta *sta, void *priv_sta,
|
|
+ struct ieee80211_tx_rate_control *txrc);
|
|
|
|
void (*add_sta_debugfs)(void *priv, void *priv_sta,
|
|
struct dentry *dir);
|
|
--- a/net/mac80211/main.c
|
|
+++ b/net/mac80211/main.c
|
|
@@ -41,6 +41,8 @@
|
|
*/
|
|
struct ieee80211_tx_status_rtap_hdr {
|
|
struct ieee80211_radiotap_header hdr;
|
|
+ u8 rate;
|
|
+ u8 padding_for_rate;
|
|
__le16 tx_flags;
|
|
u8 data_retries;
|
|
} __attribute__ ((packed));
|
|
@@ -463,13 +465,28 @@ void ieee80211_tx_status(struct ieee8021
|
|
struct ieee80211_sub_if_data *sdata;
|
|
struct net_device *prev_dev = NULL;
|
|
struct sta_info *sta;
|
|
+ int retry_count = -1, i;
|
|
+
|
|
+ for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
|
+ /* the HW cannot have attempted that rate */
|
|
+ if (i >= hw->max_rates) {
|
|
+ info->status.rates[i].idx = -1;
|
|
+ info->status.rates[i].count = 0;
|
|
+ }
|
|
+
|
|
+ retry_count += info->status.rates[i].count;
|
|
+ }
|
|
+ if (retry_count < 0)
|
|
+ retry_count = 0;
|
|
|
|
rcu_read_lock();
|
|
|
|
+ sband = local->hw.wiphy->bands[info->band];
|
|
+
|
|
sta = sta_info_get(local, hdr->addr1);
|
|
|
|
if (sta) {
|
|
- if (info->status.excessive_retries &&
|
|
+ if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
|
|
test_sta_flags(sta, WLAN_STA_PS)) {
|
|
/*
|
|
* The STA is in power save mode, so assume
|
|
@@ -500,12 +517,11 @@ void ieee80211_tx_status(struct ieee8021
|
|
rcu_read_unlock();
|
|
return;
|
|
} else {
|
|
- if (info->status.excessive_retries)
|
|
+ if (!(info->flags & IEEE80211_TX_STAT_ACK))
|
|
sta->tx_retry_failed++;
|
|
- sta->tx_retry_count += info->status.retry_count;
|
|
+ sta->tx_retry_count += retry_count;
|
|
}
|
|
|
|
- sband = local->hw.wiphy->bands[info->band];
|
|
rate_control_tx_status(local, sband, sta, skb);
|
|
}
|
|
|
|
@@ -526,9 +542,9 @@ void ieee80211_tx_status(struct ieee8021
|
|
local->dot11TransmittedFrameCount++;
|
|
if (is_multicast_ether_addr(hdr->addr1))
|
|
local->dot11MulticastTransmittedFrameCount++;
|
|
- if (info->status.retry_count > 0)
|
|
+ if (retry_count > 0)
|
|
local->dot11RetryCount++;
|
|
- if (info->status.retry_count > 1)
|
|
+ if (retry_count > 1)
|
|
local->dot11MultipleRetryCount++;
|
|
}
|
|
|
|
@@ -572,19 +588,30 @@ void ieee80211_tx_status(struct ieee8021
|
|
rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
|
|
rthdr->hdr.it_present =
|
|
cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
|
|
- (1 << IEEE80211_RADIOTAP_DATA_RETRIES));
|
|
+ (1 << IEEE80211_RADIOTAP_DATA_RETRIES) |
|
|
+ (1 << IEEE80211_RADIOTAP_RATE));
|
|
|
|
if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
|
|
!is_multicast_ether_addr(hdr->addr1))
|
|
rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
|
|
|
|
- if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) &&
|
|
- (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT))
|
|
+ /*
|
|
+ * XXX: Once radiotap gets the bitmap reset thing the vendor
|
|
+ * extensions proposal contains, we can actually report
|
|
+ * the whole set of tries we did.
|
|
+ */
|
|
+ if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
|
|
+ (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
|
|
rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
|
|
- else if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
|
|
+ else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
|
|
rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
|
|
+ if (info->status.rates[0].idx >= 0 &&
|
|
+ !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS))
|
|
+ rthdr->rate = sband->bitrates[
|
|
+ info->status.rates[0].idx].bitrate / 5;
|
|
|
|
- rthdr->data_retries = info->status.retry_count;
|
|
+ /* for now report the total retry_count */
|
|
+ rthdr->data_retries = retry_count;
|
|
|
|
/* XXX: is this sufficient for BPF? */
|
|
skb_set_mac_header(skb, 0);
|
|
@@ -669,8 +696,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(
|
|
BUG_ON(!ops->configure_filter);
|
|
local->ops = ops;
|
|
|
|
- local->hw.queues = 1; /* default */
|
|
-
|
|
+ /* set up some defaults */
|
|
+ local->hw.queues = 1;
|
|
+ local->hw.max_rates = 1;
|
|
local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
|
|
local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
|
|
local->hw.conf.long_frame_max_tx_count = 4;
|
|
--- a/net/mac80211/tx.c
|
|
+++ b/net/mac80211/tx.c
|
|
@@ -46,13 +46,20 @@ static __le16 ieee80211_duration(struct
|
|
struct ieee80211_local *local = tx->local;
|
|
struct ieee80211_supported_band *sband;
|
|
struct ieee80211_hdr *hdr;
|
|
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
|
+
|
|
+ /* assume HW handles this */
|
|
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS)
|
|
+ return 0;
|
|
+
|
|
+ /* uh huh? */
|
|
+ if (WARN_ON(info->control.rates[0].idx < 0))
|
|
+ return 0;
|
|
|
|
sband = local->hw.wiphy->bands[tx->channel->band];
|
|
- txrate = &sband->bitrates[tx->rate_idx];
|
|
+ txrate = &sband->bitrates[info->control.rates[0].idx];
|
|
|
|
- erp = 0;
|
|
- if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
|
|
- erp = txrate->flags & IEEE80211_RATE_ERP_G;
|
|
+ erp = txrate->flags & IEEE80211_RATE_ERP_G;
|
|
|
|
/*
|
|
* data and mgmt (except PS Poll):
|
|
@@ -439,140 +446,123 @@ ieee80211_tx_h_select_key(struct ieee802
|
|
static ieee80211_tx_result debug_noinline
|
|
ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
|
|
{
|
|
- struct rate_selection rsel;
|
|
- struct ieee80211_supported_band *sband;
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
|
+ struct ieee80211_hdr *hdr = (void *)tx->skb->data;
|
|
+ struct ieee80211_supported_band *sband;
|
|
+ struct ieee80211_rate *rate;
|
|
+ int i, len;
|
|
+ bool inval = false, rts = false, short_preamble = false;
|
|
+ struct ieee80211_tx_rate_control txrc;
|
|
|
|
- sband = tx->local->hw.wiphy->bands[tx->channel->band];
|
|
+ memset(&txrc, 0, sizeof(txrc));
|
|
|
|
- if (likely(tx->rate_idx < 0)) {
|
|
- rate_control_get_rate(tx->sdata, sband, tx->sta,
|
|
- tx->skb, &rsel);
|
|
- if (tx->sta)
|
|
- tx->sta->last_txrate_idx = rsel.rate_idx;
|
|
- tx->rate_idx = rsel.rate_idx;
|
|
- if (unlikely(rsel.probe_idx >= 0)) {
|
|
- info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
|
|
- tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
|
|
- info->control.retries[0].rate_idx = tx->rate_idx;
|
|
- info->control.retries[0].limit = tx->local->hw.max_altrate_tries;
|
|
- tx->rate_idx = rsel.probe_idx;
|
|
- } else if (info->control.retries[0].limit == 0)
|
|
- info->control.retries[0].rate_idx = -1;
|
|
+ sband = tx->local->hw.wiphy->bands[tx->channel->band];
|
|
|
|
- if (unlikely(tx->rate_idx < 0))
|
|
- return TX_DROP;
|
|
- } else
|
|
- info->control.retries[0].rate_idx = -1;
|
|
+ len = min_t(int, tx->skb->len + FCS_LEN,
|
|
+ tx->local->fragmentation_threshold);
|
|
|
|
- if (tx->sdata->vif.bss_conf.use_cts_prot &&
|
|
- (tx->flags & IEEE80211_TX_FRAGMENTED) && (rsel.nonerp_idx >= 0)) {
|
|
- tx->last_frag_rate_idx = tx->rate_idx;
|
|
- if (rsel.probe_idx >= 0)
|
|
- tx->flags &= ~IEEE80211_TX_PROBE_LAST_FRAG;
|
|
- else
|
|
- tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
|
|
- tx->rate_idx = rsel.nonerp_idx;
|
|
- info->tx_rate_idx = rsel.nonerp_idx;
|
|
- info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
|
|
- } else {
|
|
- tx->last_frag_rate_idx = tx->rate_idx;
|
|
- info->tx_rate_idx = tx->rate_idx;
|
|
+ /* set up the tx rate control struct we give the RC algo */
|
|
+ txrc.sband = sband;
|
|
+ txrc.bss_conf = &tx->sdata->vif.bss_conf;
|
|
+ txrc.skb = tx->skb;
|
|
+ txrc.reported_rate.idx = -1;
|
|
+ txrc.max_rate_idx = tx->sdata->max_ratectrl_rateidx;
|
|
+
|
|
+ /* set up RTS protection if desired */
|
|
+ if (tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD &&
|
|
+ len > tx->local->rts_threshold) {
|
|
+ txrc.rts = rts = true;
|
|
}
|
|
- info->tx_rate_idx = tx->rate_idx;
|
|
|
|
- return TX_CONTINUE;
|
|
-}
|
|
+ /* XXX: Is this really the right thing to check? */
|
|
+ if (ieee80211_is_data(hdr->frame_control) &&
|
|
+ tx->sdata->vif.bss_conf.use_short_preamble &&
|
|
+ (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE)))
|
|
+ txrc.short_preamble = short_preamble = true;
|
|
|
|
-static ieee80211_tx_result debug_noinline
|
|
-ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
|
|
-{
|
|
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
|
|
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
|
- struct ieee80211_supported_band *sband;
|
|
|
|
- sband = tx->local->hw.wiphy->bands[tx->channel->band];
|
|
+ rate_control_get_rate(tx->sdata, tx->sta, &txrc);
|
|
+
|
|
+ if (unlikely(info->control.rates[0].idx < 0))
|
|
+ return TX_DROP;
|
|
+
|
|
+ if (txrc.reported_rate.idx < 0)
|
|
+ txrc.reported_rate = info->control.rates[0];
|
|
|
|
if (tx->sta)
|
|
- info->control.sta = &tx->sta->sta;
|
|
+ tx->sta->last_tx_rate = txrc.reported_rate;
|
|
|
|
- if (!info->control.retry_limit) {
|
|
- if (!is_multicast_ether_addr(hdr->addr1)) {
|
|
- int len = min_t(int, tx->skb->len + FCS_LEN,
|
|
- tx->local->fragmentation_threshold);
|
|
- if (len > tx->local->rts_threshold
|
|
- && tx->local->rts_threshold <
|
|
- IEEE80211_MAX_RTS_THRESHOLD) {
|
|
- info->flags |= IEEE80211_TX_CTL_USE_RTS_CTS;
|
|
- info->flags |=
|
|
- IEEE80211_TX_CTL_LONG_RETRY_LIMIT;
|
|
- info->control.retry_limit =
|
|
- tx->local->hw.conf.long_frame_max_tx_count - 1;
|
|
- } else {
|
|
- info->control.retry_limit =
|
|
- tx->local->hw.conf.short_frame_max_tx_count - 1;
|
|
- }
|
|
- } else {
|
|
- info->control.retry_limit = 1;
|
|
- }
|
|
- }
|
|
+ if (unlikely(!info->control.rates[0].count))
|
|
+ info->control.rates[0].count = 1;
|
|
|
|
- if (tx->flags & IEEE80211_TX_FRAGMENTED) {
|
|
- /* Do not use multiple retry rates when sending fragmented
|
|
- * frames.
|
|
- * TODO: The last fragment could still use multiple retry
|
|
- * rates. */
|
|
- info->control.retries[0].rate_idx = -1;
|
|
- }
|
|
-
|
|
- /* Use CTS protection for unicast frames sent using extended rates if
|
|
- * there are associated non-ERP stations and RTS/CTS is not configured
|
|
- * for the frame. */
|
|
- if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) &&
|
|
- (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_ERP_G) &&
|
|
- (tx->flags & IEEE80211_TX_UNICAST) &&
|
|
- tx->sdata->vif.bss_conf.use_cts_prot &&
|
|
- !(info->flags & IEEE80211_TX_CTL_USE_RTS_CTS))
|
|
- info->flags |= IEEE80211_TX_CTL_USE_CTS_PROTECT;
|
|
-
|
|
- /* Transmit data frames using short preambles if the driver supports
|
|
- * short preambles at the selected rate and short preambles are
|
|
- * available on the network at the current point in time. */
|
|
- if (ieee80211_is_data(hdr->frame_control) &&
|
|
- (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
|
|
- tx->sdata->vif.bss_conf.use_short_preamble &&
|
|
- (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) {
|
|
- info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
|
|
+ if (is_multicast_ether_addr(hdr->addr1)) {
|
|
+ /*
|
|
+ * XXX: verify the rate is in the basic rateset
|
|
+ */
|
|
+ return TX_CONTINUE;
|
|
}
|
|
|
|
- if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
|
|
- (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
|
|
- struct ieee80211_rate *rate;
|
|
- s8 baserate = -1;
|
|
- int idx;
|
|
+ for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
|
+ /*
|
|
+ * make sure there's no valid rate following
|
|
+ * an invalid one, just in case drivers don't
|
|
+ * take the API seriously to stop at -1.
|
|
+ */
|
|
+ if (inval) {
|
|
+ info->control.rates[i].idx = -1;
|
|
+ continue;
|
|
+ }
|
|
+ if (info->control.rates[i].idx < 0) {
|
|
+ inval = true;
|
|
+ continue;
|
|
+ }
|
|
|
|
- /* Do not use multiple retry rates when using RTS/CTS */
|
|
- info->control.retries[0].rate_idx = -1;
|
|
+ /*
|
|
+ * For now assume MCS is already set up correctly, this
|
|
+ * needs to be fixed.
|
|
+ */
|
|
+ if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) {
|
|
+ WARN_ON(info->control.rates[i].idx > 76);
|
|
+ continue;
|
|
+ }
|
|
|
|
- /* Use min(data rate, max base rate) as CTS/RTS rate */
|
|
- rate = &sband->bitrates[tx->rate_idx];
|
|
+ /* set up RTS protection if desired */
|
|
+ if (rts) {
|
|
+ info->control.rates[i].flags |=
|
|
+ IEEE80211_TX_RC_USE_RTS_CTS;
|
|
+ rts = true;
|
|
+ }
|
|
|
|
- for (idx = 0; idx < sband->n_bitrates; idx++) {
|
|
- if (sband->bitrates[idx].bitrate > rate->bitrate)
|
|
- continue;
|
|
- if (tx->sdata->vif.bss_conf.basic_rates & BIT(idx) &&
|
|
- (baserate < 0 ||
|
|
- (sband->bitrates[baserate].bitrate
|
|
- < sband->bitrates[idx].bitrate)))
|
|
- baserate = idx;
|
|
+ /* RC is busted */
|
|
+ if (WARN_ON(info->control.rates[i].idx >=
|
|
+ sband->n_bitrates)) {
|
|
+ info->control.rates[i].idx = -1;
|
|
+ continue;
|
|
}
|
|
|
|
- if (baserate >= 0)
|
|
- info->control.rts_cts_rate_idx = baserate;
|
|
- else
|
|
- info->control.rts_cts_rate_idx = 0;
|
|
+ rate = &sband->bitrates[info->control.rates[i].idx];
|
|
+
|
|
+ /* set up short preamble */
|
|
+ if (short_preamble &&
|
|
+ rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
|
|
+ info->control.rates[i].flags |=
|
|
+ IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
|
|
+
|
|
+ /* set up G protection */
|
|
+ if (!rts && tx->sdata->vif.bss_conf.use_cts_prot &&
|
|
+ rate->flags & IEEE80211_RATE_ERP_G)
|
|
+ info->control.rates[i].flags |=
|
|
+ IEEE80211_TX_RC_USE_CTS_PROTECT;
|
|
}
|
|
|
|
+ return TX_CONTINUE;
|
|
+}
|
|
+
|
|
+static ieee80211_tx_result debug_noinline
|
|
+ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
|
|
+{
|
|
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
|
|
+
|
|
if (tx->sta)
|
|
info->control.sta = &tx->sta->sta;
|
|
|
|
@@ -680,6 +670,7 @@ ieee80211_tx_h_fragment(struct ieee80211
|
|
left = payload_len - per_fragm;
|
|
for (i = 0; i < num_fragm - 1; i++) {
|
|
struct ieee80211_hdr *fhdr;
|
|
+ struct ieee80211_tx_info *info;
|
|
size_t copylen;
|
|
|
|
if (left <= 0)
|
|
@@ -694,20 +685,44 @@ ieee80211_tx_h_fragment(struct ieee80211
|
|
IEEE80211_ENCRYPT_TAILROOM);
|
|
if (!frag)
|
|
goto fail;
|
|
+
|
|
/* Make sure that all fragments use the same priority so
|
|
* that they end up using the same TX queue */
|
|
frag->priority = first->priority;
|
|
+
|
|
skb_reserve(frag, tx->local->tx_headroom +
|
|
IEEE80211_ENCRYPT_HEADROOM);
|
|
+
|
|
+ /* copy TX information */
|
|
+ info = IEEE80211_SKB_CB(frag);
|
|
+ memcpy(info, first->cb, sizeof(frag->cb));
|
|
+
|
|
+ /* copy/fill in 802.11 header */
|
|
fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen);
|
|
memcpy(fhdr, first->data, hdrlen);
|
|
- if (i == num_fragm - 2)
|
|
- fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS);
|
|
fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG));
|
|
+
|
|
+ if (i == num_fragm - 2) {
|
|
+ /* clear MOREFRAGS bit for the last fragment */
|
|
+ fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS);
|
|
+ } else {
|
|
+ /*
|
|
+ * No multi-rate retries for fragmented frames, that
|
|
+ * would completely throw off the NAV at other STAs.
|
|
+ */
|
|
+ info->control.rates[1].idx = -1;
|
|
+ info->control.rates[2].idx = -1;
|
|
+ info->control.rates[3].idx = -1;
|
|
+ BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 4);
|
|
+ info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
|
|
+ }
|
|
+
|
|
+ /* copy data */
|
|
copylen = left > per_fragm ? per_fragm : left;
|
|
memcpy(skb_put(frag, copylen), pos, copylen);
|
|
- memcpy(frag->cb, first->cb, sizeof(frag->cb));
|
|
+
|
|
skb_copy_queue_mapping(frag, first);
|
|
+
|
|
frag->do_not_encrypt = first->do_not_encrypt;
|
|
|
|
pos += copylen;
|
|
@@ -767,12 +782,10 @@ ieee80211_tx_h_calculate_duration(struct
|
|
tx->extra_frag[0]->len);
|
|
|
|
for (i = 0; i < tx->num_extra_frag; i++) {
|
|
- if (i + 1 < tx->num_extra_frag) {
|
|
+ if (i + 1 < tx->num_extra_frag)
|
|
next_len = tx->extra_frag[i + 1]->len;
|
|
- } else {
|
|
+ else
|
|
next_len = 0;
|
|
- tx->rate_idx = tx->last_frag_rate_idx;
|
|
- }
|
|
|
|
hdr = (struct ieee80211_hdr *)tx->extra_frag[i]->data;
|
|
hdr->duration_id = ieee80211_duration(tx, 0, next_len);
|
|
@@ -825,7 +838,6 @@ __ieee80211_parse_tx_radiotap(struct iee
|
|
(struct ieee80211_radiotap_header *) skb->data;
|
|
struct ieee80211_supported_band *sband;
|
|
int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len);
|
|
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
|
|
sband = tx->local->hw.wiphy->bands[tx->channel->band];
|
|
|
|
@@ -839,8 +851,6 @@ __ieee80211_parse_tx_radiotap(struct iee
|
|
*/
|
|
|
|
while (!ret) {
|
|
- int i, target_rate;
|
|
-
|
|
ret = ieee80211_radiotap_iterator_next(&iterator);
|
|
|
|
if (ret)
|
|
@@ -854,38 +864,6 @@ __ieee80211_parse_tx_radiotap(struct iee
|
|
* get_unaligned((type *)iterator.this_arg) to dereference
|
|
* iterator.this_arg for type "type" safely on all arches.
|
|
*/
|
|
- case IEEE80211_RADIOTAP_RATE:
|
|
- /*
|
|
- * radiotap rate u8 is in 500kbps units eg, 0x02=1Mbps
|
|
- * ieee80211 rate int is in 100kbps units eg, 0x0a=1Mbps
|
|
- */
|
|
- target_rate = (*iterator.this_arg) * 5;
|
|
- for (i = 0; i < sband->n_bitrates; i++) {
|
|
- struct ieee80211_rate *r;
|
|
-
|
|
- r = &sband->bitrates[i];
|
|
-
|
|
- if (r->bitrate == target_rate) {
|
|
- tx->rate_idx = i;
|
|
- break;
|
|
- }
|
|
- }
|
|
- break;
|
|
-
|
|
- case IEEE80211_RADIOTAP_ANTENNA:
|
|
- /*
|
|
- * radiotap uses 0 for 1st ant, mac80211 is 1 for
|
|
- * 1st ant
|
|
- */
|
|
- info->antenna_sel_tx = (*iterator.this_arg) + 1;
|
|
- break;
|
|
-
|
|
-#if 0
|
|
- case IEEE80211_RADIOTAP_DBM_TX_POWER:
|
|
- control->power_level = *iterator.this_arg;
|
|
- break;
|
|
-#endif
|
|
-
|
|
case IEEE80211_RADIOTAP_FLAGS:
|
|
if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) {
|
|
/*
|
|
@@ -951,8 +929,6 @@ __ieee80211_tx_prepare(struct ieee80211_
|
|
tx->local = local;
|
|
tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
|
tx->channel = local->hw.conf.channel;
|
|
- tx->rate_idx = -1;
|
|
- tx->last_frag_rate_idx = -1;
|
|
/*
|
|
* Set this flag (used below to indicate "automatic fragmentation"),
|
|
* it will be cleared/left by radiotap as desired.
|
|
@@ -1053,23 +1029,11 @@ static int __ieee80211_tx(struct ieee802
|
|
if (!tx->extra_frag[i])
|
|
continue;
|
|
info = IEEE80211_SKB_CB(tx->extra_frag[i]);
|
|
- info->flags &= ~(IEEE80211_TX_CTL_USE_RTS_CTS |
|
|
- IEEE80211_TX_CTL_USE_CTS_PROTECT |
|
|
- IEEE80211_TX_CTL_CLEAR_PS_FILT |
|
|
+ info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT |
|
|
IEEE80211_TX_CTL_FIRST_FRAGMENT);
|
|
if (netif_subqueue_stopped(local->mdev,
|
|
tx->extra_frag[i]))
|
|
return IEEE80211_TX_FRAG_AGAIN;
|
|
- if (i == tx->num_extra_frag) {
|
|
- info->tx_rate_idx = tx->last_frag_rate_idx;
|
|
-
|
|
- if (tx->flags & IEEE80211_TX_PROBE_LAST_FRAG)
|
|
- info->flags |=
|
|
- IEEE80211_TX_CTL_RATE_CTRL_PROBE;
|
|
- else
|
|
- info->flags &=
|
|
- ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
|
|
- }
|
|
|
|
ret = local->ops->tx(local_to_hw(local),
|
|
tx->extra_frag[i]);
|
|
@@ -1206,9 +1170,6 @@ retry:
|
|
store->skb = skb;
|
|
store->extra_frag = tx.extra_frag;
|
|
store->num_extra_frag = tx.num_extra_frag;
|
|
- store->last_frag_rate_idx = tx.last_frag_rate_idx;
|
|
- store->last_frag_rate_ctrl_probe =
|
|
- !!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG);
|
|
}
|
|
out:
|
|
rcu_read_unlock();
|
|
@@ -1767,10 +1728,7 @@ void ieee80211_tx_pending(unsigned long
|
|
store = &local->pending_packet[i];
|
|
tx.extra_frag = store->extra_frag;
|
|
tx.num_extra_frag = store->num_extra_frag;
|
|
- tx.last_frag_rate_idx = store->last_frag_rate_idx;
|
|
tx.flags = 0;
|
|
- if (store->last_frag_rate_ctrl_probe)
|
|
- tx.flags |= IEEE80211_TX_PROBE_LAST_FRAG;
|
|
ret = __ieee80211_tx(local, store->skb, &tx);
|
|
if (ret) {
|
|
if (ret == IEEE80211_TX_FRAG_AGAIN)
|
|
@@ -1858,7 +1816,6 @@ struct sk_buff *ieee80211_beacon_get(str
|
|
struct ieee80211_sub_if_data *sdata = NULL;
|
|
struct ieee80211_if_ap *ap = NULL;
|
|
struct ieee80211_if_sta *ifsta = NULL;
|
|
- struct rate_selection rsel;
|
|
struct beacon_data *beacon;
|
|
struct ieee80211_supported_band *sband;
|
|
enum ieee80211_band band = local->hw.conf.channel->band;
|
|
@@ -1962,32 +1919,22 @@ struct sk_buff *ieee80211_beacon_get(str
|
|
skb->do_not_encrypt = 1;
|
|
|
|
info->band = band;
|
|
- rate_control_get_rate(sdata, sband, NULL, skb, &rsel);
|
|
-
|
|
- if (unlikely(rsel.rate_idx < 0)) {
|
|
- if (net_ratelimit()) {
|
|
- printk(KERN_DEBUG "%s: ieee80211_beacon_get: "
|
|
- "no rate found\n",
|
|
- wiphy_name(local->hw.wiphy));
|
|
- }
|
|
- dev_kfree_skb_any(skb);
|
|
- skb = NULL;
|
|
- goto out;
|
|
- }
|
|
+ /*
|
|
+ * XXX: For now, always use the lowest rate
|
|
+ */
|
|
+ info->control.rates[0].idx = 0;
|
|
+ info->control.rates[0].count = 1;
|
|
+ info->control.rates[1].idx = -1;
|
|
+ info->control.rates[2].idx = -1;
|
|
+ info->control.rates[3].idx = -1;
|
|
+ BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 4);
|
|
|
|
info->control.vif = vif;
|
|
- info->tx_rate_idx = rsel.rate_idx;
|
|
|
|
info->flags |= IEEE80211_TX_CTL_NO_ACK;
|
|
info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
|
|
info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
|
|
- if (sdata->vif.bss_conf.use_short_preamble &&
|
|
- sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE)
|
|
- info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
|
|
-
|
|
- info->control.retry_limit = 1;
|
|
-
|
|
-out:
|
|
+ out:
|
|
rcu_read_unlock();
|
|
return skb;
|
|
}
|
|
--- a/net/mac80211/ieee80211_i.h
|
|
+++ b/net/mac80211/ieee80211_i.h
|
|
@@ -142,7 +142,6 @@ typedef unsigned __bitwise__ ieee80211_t
|
|
#define IEEE80211_TX_FRAGMENTED BIT(0)
|
|
#define IEEE80211_TX_UNICAST BIT(1)
|
|
#define IEEE80211_TX_PS_BUFFERED BIT(2)
|
|
-#define IEEE80211_TX_PROBE_LAST_FRAG BIT(3)
|
|
|
|
struct ieee80211_tx_data {
|
|
struct sk_buff *skb;
|
|
@@ -153,11 +152,6 @@ struct ieee80211_tx_data {
|
|
struct ieee80211_key *key;
|
|
|
|
struct ieee80211_channel *channel;
|
|
- s8 rate_idx;
|
|
- /* use this rate (if set) for last fragment; rate can
|
|
- * be set to lower rate for the first fragments, e.g.,
|
|
- * when using CTS protection with IEEE 802.11g. */
|
|
- s8 last_frag_rate_idx;
|
|
|
|
/* Extra fragments (in addition to the first fragment
|
|
* in skb) */
|
|
@@ -203,9 +197,7 @@ struct ieee80211_rx_data {
|
|
struct ieee80211_tx_stored_packet {
|
|
struct sk_buff *skb;
|
|
struct sk_buff **extra_frag;
|
|
- s8 last_frag_rate_idx;
|
|
int num_extra_frag;
|
|
- bool last_frag_rate_ctrl_probe;
|
|
};
|
|
|
|
struct beacon_data {
|
|
--- a/net/mac80211/rate.c
|
|
+++ b/net/mac80211/rate.c
|
|
@@ -199,48 +199,44 @@ static void rate_control_release(struct
|
|
}
|
|
|
|
void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
|
|
- struct ieee80211_supported_band *sband,
|
|
- struct sta_info *sta, struct sk_buff *skb,
|
|
- struct rate_selection *sel)
|
|
+ struct sta_info *sta,
|
|
+ struct ieee80211_tx_rate_control *txrc)
|
|
{
|
|
struct rate_control_ref *ref = sdata->local->rate_ctrl;
|
|
void *priv_sta = NULL;
|
|
struct ieee80211_sta *ista = NULL;
|
|
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
|
|
int i;
|
|
|
|
- sel->rate_idx = -1;
|
|
- sel->nonerp_idx = -1;
|
|
- sel->probe_idx = -1;
|
|
- sel->max_rate_idx = sdata->max_ratectrl_rateidx;
|
|
-
|
|
if (sta) {
|
|
ista = &sta->sta;
|
|
priv_sta = sta->rate_ctrl_priv;
|
|
}
|
|
|
|
+ for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
|
+ info->control.rates[i].idx = -1;
|
|
+ info->control.rates[i].flags = 0;
|
|
+ info->control.rates[i].count = 1;
|
|
+ }
|
|
+
|
|
if (sta && sdata->force_unicast_rateidx > -1)
|
|
- sel->rate_idx = sdata->force_unicast_rateidx;
|
|
+ info->control.rates[0].idx = sdata->force_unicast_rateidx;
|
|
else
|
|
- ref->ops->get_rate(ref->priv, sband, ista, priv_sta, skb, sel);
|
|
+ ref->ops->get_rate(ref->priv, ista, priv_sta, txrc);
|
|
|
|
- if (sdata->max_ratectrl_rateidx > -1 &&
|
|
- sel->rate_idx > sdata->max_ratectrl_rateidx)
|
|
- sel->rate_idx = sdata->max_ratectrl_rateidx;
|
|
-
|
|
- BUG_ON(sel->rate_idx < 0);
|
|
-
|
|
- /* Select a non-ERP backup rate. */
|
|
- if (sel->nonerp_idx < 0) {
|
|
- for (i = 0; i < sband->n_bitrates; i++) {
|
|
- struct ieee80211_rate *rate = &sband->bitrates[i];
|
|
- if (sband->bitrates[sel->rate_idx].bitrate < rate->bitrate)
|
|
- break;
|
|
-
|
|
- if (rate_supported(ista, sband->band, i) &&
|
|
- !(rate->flags & IEEE80211_RATE_ERP_G))
|
|
- sel->nonerp_idx = i;
|
|
- }
|
|
+ /*
|
|
+ * try to enforce the maximum rate the user wanted
|
|
+ */
|
|
+ if (sdata->max_ratectrl_rateidx > -1)
|
|
+ for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
|
+ if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS)
|
|
+ continue;
|
|
+ info->control.rates[i].idx =
|
|
+ min_t(s8, info->control.rates[i].idx,
|
|
+ sdata->max_ratectrl_rateidx);
|
|
}
|
|
+
|
|
+ BUG_ON(info->control.rates[0].idx < 0);
|
|
}
|
|
|
|
struct rate_control_ref *rate_control_get(struct rate_control_ref *ref)
|
|
--- a/net/mac80211/rate.h
|
|
+++ b/net/mac80211/rate.h
|
|
@@ -31,9 +31,8 @@ struct rate_control_ref {
|
|
struct rate_control_ref *rate_control_alloc(const char *name,
|
|
struct ieee80211_local *local);
|
|
void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
|
|
- struct ieee80211_supported_band *sband,
|
|
- struct sta_info *sta, struct sk_buff *skb,
|
|
- struct rate_selection *sel);
|
|
+ struct sta_info *sta,
|
|
+ struct ieee80211_tx_rate_control *txrc);
|
|
struct rate_control_ref *rate_control_get(struct rate_control_ref *ref);
|
|
void rate_control_put(struct rate_control_ref *ref);
|
|
|
|
--- a/net/mac80211/sta_info.h
|
|
+++ b/net/mac80211/sta_info.h
|
|
@@ -196,7 +196,7 @@ struct sta_ampdu_mlme {
|
|
* @tx_packets: number of RX/TX MSDUs
|
|
* @tx_bytes: TBD
|
|
* @tx_fragments: number of transmitted MPDUs
|
|
- * @last_txrate_idx: Index of the last used transmit rate
|
|
+ * @last_txrate: description of the last used transmit rate
|
|
* @tid_seq: TBD
|
|
* @ampdu_mlme: TBD
|
|
* @timer_to_tid: identity mapping to ID timers
|
|
@@ -267,7 +267,7 @@ struct sta_info {
|
|
unsigned long tx_packets;
|
|
unsigned long tx_bytes;
|
|
unsigned long tx_fragments;
|
|
- unsigned int last_txrate_idx;
|
|
+ struct ieee80211_tx_rate last_tx_rate;
|
|
u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
|
|
|
|
/*
|
|
--- a/net/mac80211/wext.c
|
|
+++ b/net/mac80211/wext.c
|
|
@@ -636,8 +636,8 @@ static int ieee80211_ioctl_giwrate(struc
|
|
|
|
sta = sta_info_get(local, sdata->u.sta.bssid);
|
|
|
|
- if (sta && sta->last_txrate_idx < sband->n_bitrates)
|
|
- rate->value = sband->bitrates[sta->last_txrate_idx].bitrate;
|
|
+ if (sta && !(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS))
|
|
+ rate->value = sband->bitrates[sta->last_tx_rate.idx].bitrate;
|
|
else
|
|
rate->value = 0;
|
|
|
|
--- a/net/mac80211/mesh_hwmp.c
|
|
+++ b/net/mac80211/mesh_hwmp.c
|
|
@@ -218,12 +218,16 @@ static u32 airtime_link_metric_get(struc
|
|
|
|
if (sta->fail_avg >= 100)
|
|
return MAX_METRIC;
|
|
+
|
|
+ if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)
|
|
+ return MAX_METRIC;
|
|
+
|
|
err = (sta->fail_avg << ARITH_SHIFT) / 100;
|
|
|
|
/* bitrate is in units of 100 Kbps, while we need rate in units of
|
|
* 1Mbps. This will be corrected on tx_time computation.
|
|
*/
|
|
- rate = sband->bitrates[sta->last_txrate_idx].bitrate;
|
|
+ rate = sband->bitrates[sta->last_tx_rate.idx].bitrate;
|
|
tx_time = (device_constant + 10 * test_frame_len / rate);
|
|
estimated_retx = ((1 << (2 * ARITH_SHIFT)) / (s_unit - err));
|
|
result = (tx_time * estimated_retx) >> (2 * ARITH_SHIFT) ;
|
|
--- a/net/mac80211/rc80211_pid_algo.c
|
|
+++ b/net/mac80211/rc80211_pid_algo.c
|
|
@@ -241,7 +241,7 @@ static void rate_control_pid_tx_status(v
|
|
|
|
/* Ignore all frames that were sent with a different rate than the rate
|
|
* we currently advise mac80211 to use. */
|
|
- if (info->tx_rate_idx != spinfo->txrate_idx)
|
|
+ if (info->status.rates[0].idx != spinfo->txrate_idx)
|
|
return;
|
|
|
|
spinfo->tx_num_xmit++;
|
|
@@ -253,10 +253,10 @@ static void rate_control_pid_tx_status(v
|
|
/* We count frames that totally failed to be transmitted as two bad
|
|
* frames, those that made it out but had some retries as one good and
|
|
* one bad frame. */
|
|
- if (info->status.excessive_retries) {
|
|
+ if (!(info->flags & IEEE80211_TX_STAT_ACK)) {
|
|
spinfo->tx_num_failed += 2;
|
|
spinfo->tx_num_xmit++;
|
|
- } else if (info->status.retry_count) {
|
|
+ } else if (info->status.rates[0].count) {
|
|
spinfo->tx_num_failed++;
|
|
spinfo->tx_num_xmit++;
|
|
}
|
|
@@ -270,23 +270,31 @@ static void rate_control_pid_tx_status(v
|
|
}
|
|
|
|
static void
|
|
-rate_control_pid_get_rate(void *priv, struct ieee80211_supported_band *sband,
|
|
- struct ieee80211_sta *sta, void *priv_sta,
|
|
- struct sk_buff *skb,
|
|
- struct rate_selection *sel)
|
|
+rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta,
|
|
+ void *priv_sta,
|
|
+ struct ieee80211_tx_rate_control *txrc)
|
|
{
|
|
+ struct sk_buff *skb = txrc->skb;
|
|
+ struct ieee80211_supported_band *sband = txrc->sband;
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
|
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
struct rc_pid_sta_info *spinfo = priv_sta;
|
|
int rateidx;
|
|
u16 fc;
|
|
|
|
+ /* XXX: Should use the user-configured values */
|
|
+ if (txrc->rts)
|
|
+ info->control.rates[0].count = 4; /* long retry count */
|
|
+ else
|
|
+ info->control.rates[0].count = 7; /* short retry count */
|
|
+
|
|
/* Send management frames and broadcast/multicast data using lowest
|
|
* rate. */
|
|
fc = le16_to_cpu(hdr->frame_control);
|
|
if (!sta || !spinfo ||
|
|
(fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
|
|
is_multicast_ether_addr(hdr->addr1)) {
|
|
- sel->rate_idx = rate_lowest_index(sband, sta);
|
|
+ info->control.rates[0].idx = rate_lowest_index(sband, sta);
|
|
return;
|
|
}
|
|
|
|
@@ -295,7 +303,7 @@ rate_control_pid_get_rate(void *priv, st
|
|
if (rateidx >= sband->n_bitrates)
|
|
rateidx = sband->n_bitrates - 1;
|
|
|
|
- sel->rate_idx = rateidx;
|
|
+ info->control.rates[0].idx = rateidx;
|
|
|
|
#ifdef CONFIG_MAC80211_DEBUGFS
|
|
rate_control_pid_event_tx_rate(&spinfo->events,
|
|
--- a/net/mac80211/rc80211_minstrel.c
|
|
+++ b/net/mac80211/rc80211_minstrel.c
|
|
@@ -169,30 +169,20 @@ minstrel_tx_status(void *priv, struct ie
|
|
{
|
|
struct minstrel_sta_info *mi = priv_sta;
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
- struct ieee80211_tx_altrate *ar = info->status.retries;
|
|
- struct minstrel_priv *mp = priv;
|
|
- int i, ndx, tries;
|
|
- int success = 0;
|
|
+ struct ieee80211_tx_rate *ar = info->status.rates;
|
|
+ int i, ndx;
|
|
+ int success;
|
|
|
|
- if (!info->status.excessive_retries)
|
|
- success = 1;
|
|
+ success = !!(info->flags & IEEE80211_TX_STAT_ACK);
|
|
|
|
- if (!mp->has_mrr || (ar[0].rate_idx < 0)) {
|
|
- ndx = rix_to_ndx(mi, info->tx_rate_idx);
|
|
- tries = info->status.retry_count + 1;
|
|
- mi->r[ndx].success += success;
|
|
- mi->r[ndx].attempts += tries;
|
|
- return;
|
|
- }
|
|
-
|
|
- for (i = 0; i < 4; i++) {
|
|
- if (ar[i].rate_idx < 0)
|
|
+ for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
|
+ if (ar[i].idx < 0)
|
|
break;
|
|
|
|
- ndx = rix_to_ndx(mi, ar[i].rate_idx);
|
|
- mi->r[ndx].attempts += ar[i].limit + 1;
|
|
+ ndx = rix_to_ndx(mi, ar[i].idx);
|
|
+ mi->r[ndx].attempts += ar[i].count;
|
|
|
|
- if ((i != 3) && (ar[i + 1].rate_idx < 0))
|
|
+ if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0))
|
|
mi->r[ndx].success += success;
|
|
}
|
|
|
|
@@ -210,9 +200,9 @@ minstrel_get_retry_count(struct minstrel
|
|
{
|
|
unsigned int retry = mr->adjusted_retry_count;
|
|
|
|
- if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
|
|
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
|
|
retry = max(2U, min(mr->retry_count_rtscts, retry));
|
|
- else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
|
|
+ else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
|
|
retry = max(2U, min(mr->retry_count_cts, retry));
|
|
return retry;
|
|
}
|
|
@@ -234,14 +224,15 @@ minstrel_get_next_sample(struct minstrel
|
|
}
|
|
|
|
void
|
|
-minstrel_get_rate(void *priv, struct ieee80211_supported_band *sband,
|
|
- struct ieee80211_sta *sta, void *priv_sta,
|
|
- struct sk_buff *skb, struct rate_selection *sel)
|
|
+minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
|
|
+ void *priv_sta, struct ieee80211_tx_rate_control *txrc)
|
|
{
|
|
+ struct sk_buff *skb = txrc->skb;
|
|
+ struct ieee80211_supported_band *sband = txrc->sband;
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
struct minstrel_sta_info *mi = priv_sta;
|
|
struct minstrel_priv *mp = priv;
|
|
- struct ieee80211_tx_altrate *ar = info->control.retries;
|
|
+ struct ieee80211_tx_rate *ar = info->control.rates;
|
|
unsigned int ndx, sample_ndx = 0;
|
|
bool mrr;
|
|
bool sample_slower = false;
|
|
@@ -251,16 +242,12 @@ minstrel_get_rate(void *priv, struct iee
|
|
int sample_rate;
|
|
|
|
if (!sta || !mi || use_low_rate(skb)) {
|
|
- sel->rate_idx = rate_lowest_index(sband, sta);
|
|
+ ar[0].idx = rate_lowest_index(sband, sta);
|
|
+ ar[0].count = mp->max_retry;
|
|
return;
|
|
}
|
|
|
|
- mrr = mp->has_mrr;
|
|
-
|
|
- /* mac80211 does not allow mrr for RTS/CTS */
|
|
- if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
|
|
- (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT))
|
|
- mrr = false;
|
|
+ mrr = mp->has_mrr && !txrc->rts && !txrc->bss_conf->use_cts_prot;
|
|
|
|
if (time_after(jiffies, mi->stats_update + (mp->update_interval *
|
|
HZ) / 1000))
|
|
@@ -315,13 +302,12 @@ minstrel_get_rate(void *priv, struct iee
|
|
mi->sample_deferred++;
|
|
}
|
|
}
|
|
- sel->rate_idx = mi->r[ndx].rix;
|
|
- info->control.retry_limit = minstrel_get_retry_count(&mi->r[ndx], info);
|
|
+ ar[0].idx = mi->r[ndx].rix;
|
|
+ ar[0].count = minstrel_get_retry_count(&mi->r[ndx], info);
|
|
|
|
if (!mrr) {
|
|
- ar[0].rate_idx = mi->lowest_rix;
|
|
- ar[0].limit = mp->max_retry;
|
|
- ar[1].rate_idx = -1;
|
|
+ ar[1].idx = mi->lowest_rix;
|
|
+ ar[1].count = mp->max_retry;
|
|
return;
|
|
}
|
|
|
|
@@ -336,9 +322,9 @@ minstrel_get_rate(void *priv, struct iee
|
|
}
|
|
mrr_ndx[1] = mi->max_prob_rate;
|
|
mrr_ndx[2] = 0;
|
|
- for (i = 0; i < 3; i++) {
|
|
- ar[i].rate_idx = mi->r[mrr_ndx[i]].rix;
|
|
- ar[i].limit = mi->r[mrr_ndx[i]].adjusted_retry_count;
|
|
+ for (i = 1; i < 4; i++) {
|
|
+ ar[i].idx = mi->r[mrr_ndx[i - 1]].rix;
|
|
+ ar[i].count = mi->r[mrr_ndx[i - 1]].adjusted_retry_count;
|
|
}
|
|
}
|
|
|
|
@@ -532,13 +518,13 @@ minstrel_alloc(struct ieee80211_hw *hw,
|
|
/* maximum time that the hw is allowed to stay in one MRR segment */
|
|
mp->segment_size = 6000;
|
|
|
|
- if (hw->max_altrate_tries > 0)
|
|
- mp->max_retry = hw->max_altrate_tries;
|
|
+ if (hw->max_rate_tries > 0)
|
|
+ mp->max_retry = hw->max_rate_tries;
|
|
else
|
|
/* safe default, does not necessarily have to match hw properties */
|
|
mp->max_retry = 7;
|
|
|
|
- if (hw->max_altrates >= 3)
|
|
+ if (hw->max_rates >= 4)
|
|
mp->has_mrr = true;
|
|
|
|
mp->hw = hw;
|
|
--- a/net/mac80211/rc80211_pid_debugfs.c
|
|
+++ b/net/mac80211/rc80211_pid_debugfs.c
|
|
@@ -43,6 +43,7 @@ void rate_control_pid_event_tx_status(st
|
|
{
|
|
union rc_pid_event_data evd;
|
|
|
|
+ evd.flags = stat->flags;
|
|
memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_info));
|
|
rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_STATUS, &evd);
|
|
}
|
|
@@ -167,8 +168,8 @@ static ssize_t rate_control_pid_events_r
|
|
switch (ev->type) {
|
|
case RC_PID_EVENT_TYPE_TX_STATUS:
|
|
p += snprintf(pb + p, length - p, "tx_status %u %u",
|
|
- ev->data.tx_status.status.excessive_retries,
|
|
- ev->data.tx_status.status.retry_count);
|
|
+ !(ev->data.flags & IEEE80211_TX_STAT_ACK),
|
|
+ ev->data.tx_status.status.rates[0].idx);
|
|
break;
|
|
case RC_PID_EVENT_TYPE_RATE_CHANGE:
|
|
p += snprintf(pb + p, length - p, "rate_change %d %d",
|
|
--- a/net/mac80211/rc80211_pid.h
|
|
+++ b/net/mac80211/rc80211_pid.h
|
|
@@ -61,6 +61,7 @@ enum rc_pid_event_type {
|
|
union rc_pid_event_data {
|
|
/* RC_PID_EVENT_TX_STATUS */
|
|
struct {
|
|
+ u32 flags;
|
|
struct ieee80211_tx_info tx_status;
|
|
};
|
|
/* RC_PID_EVENT_TYPE_RATE_CHANGE */
|
|
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
|
|
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
|
|
@@ -296,15 +296,14 @@ static void zd_op_stop(struct ieee80211_
|
|
* If no status information has been requested, the skb is freed.
|
|
*/
|
|
static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
|
|
- u32 flags, int ackssi, bool success)
|
|
+ int ackssi, bool success)
|
|
{
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
|
|
- memset(&info->status, 0, sizeof(info->status));
|
|
+ ieee80211_tx_info_clear_status(info);
|
|
|
|
- if (!success)
|
|
- info->status.excessive_retries = 1;
|
|
- info->flags |= flags;
|
|
+ if (success)
|
|
+ info->flags |= IEEE80211_TX_STAT_ACK;
|
|
info->status.ack_signal = ackssi;
|
|
ieee80211_tx_status_irqsafe(hw, skb);
|
|
}
|
|
@@ -326,7 +325,7 @@ void zd_mac_tx_failed(struct ieee80211_h
|
|
if (skb == NULL)
|
|
return;
|
|
|
|
- tx_status(hw, skb, 0, 0, 0);
|
|
+ tx_status(hw, skb, 0, 0);
|
|
}
|
|
|
|
/**
|
|
@@ -347,7 +346,7 @@ void zd_mac_tx_to_dev(struct sk_buff *sk
|
|
skb_pull(skb, sizeof(struct zd_ctrlset));
|
|
if (unlikely(error ||
|
|
(info->flags & IEEE80211_TX_CTL_NO_ACK))) {
|
|
- tx_status(hw, skb, 0, 0, !error);
|
|
+ tx_status(hw, skb, 0, !error);
|
|
} else {
|
|
struct sk_buff_head *q =
|
|
&zd_hw_mac(hw)->ack_wait_queue;
|
|
@@ -406,7 +405,8 @@ static int zd_calc_tx_length_us(u8 *serv
|
|
}
|
|
|
|
static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
|
|
- struct ieee80211_hdr *header, u32 flags)
|
|
+ struct ieee80211_hdr *header,
|
|
+ struct ieee80211_tx_info *info)
|
|
{
|
|
/*
|
|
* CONTROL TODO:
|
|
@@ -417,7 +417,7 @@ static void cs_set_control(struct zd_mac
|
|
cs->control = 0;
|
|
|
|
/* First fragment */
|
|
- if (flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
|
|
+ if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
|
|
cs->control |= ZD_CS_NEED_RANDOM_BACKOFF;
|
|
|
|
/* Multicast */
|
|
@@ -428,10 +428,10 @@ static void cs_set_control(struct zd_mac
|
|
if (ieee80211_is_pspoll(header->frame_control))
|
|
cs->control |= ZD_CS_PS_POLL_FRAME;
|
|
|
|
- if (flags & IEEE80211_TX_CTL_USE_RTS_CTS)
|
|
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
|
|
cs->control |= ZD_CS_RTS;
|
|
|
|
- if (flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
|
|
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
|
|
cs->control |= ZD_CS_SELF_CTS;
|
|
|
|
/* FIXME: Management frame? */
|
|
@@ -517,12 +517,12 @@ static int fill_ctrlset(struct zd_mac *m
|
|
txrate = ieee80211_get_tx_rate(mac->hw, info);
|
|
|
|
cs->modulation = txrate->hw_value;
|
|
- if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE)
|
|
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
|
|
cs->modulation = txrate->hw_value_short;
|
|
|
|
cs->tx_length = cpu_to_le16(frag_len);
|
|
|
|
- cs_set_control(mac, cs, hdr, info->flags);
|
|
+ cs_set_control(mac, cs, hdr, info);
|
|
|
|
packet_length = frag_len + sizeof(struct zd_ctrlset) + 10;
|
|
ZD_ASSERT(packet_length <= 0xffff);
|
|
@@ -618,7 +618,7 @@ static int filter_ack(struct ieee80211_h
|
|
if (likely(!compare_ether_addr(tx_hdr->addr2, rx_hdr->addr1)))
|
|
{
|
|
__skb_unlink(skb, q);
|
|
- tx_status(hw, skb, IEEE80211_TX_STAT_ACK, stats->signal, 1);
|
|
+ tx_status(hw, skb, stats->signal, 1);
|
|
goto out;
|
|
}
|
|
}
|
|
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
|
|
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
|
|
@@ -499,6 +499,7 @@ void rt2x00lib_txdone(struct queue_entry
|
|
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
|
|
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
|
|
enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
|
|
+ bool rts;
|
|
|
|
/*
|
|
* Unmap the skb.
|
|
@@ -528,14 +529,14 @@ void rt2x00lib_txdone(struct queue_entry
|
|
rt2x00dev->link.qual.tx_failed +=
|
|
test_bit(TXDONE_FAILURE, &txdesc->flags);
|
|
|
|
+ rts = !!(tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS);
|
|
+
|
|
/*
|
|
* Initialize TX status
|
|
*/
|
|
- memset(&tx_info->status, 0, sizeof(tx_info->status));
|
|
+ ieee80211_tx_info_clear_status(tx_info);
|
|
tx_info->status.ack_signal = 0;
|
|
- tx_info->status.excessive_retries =
|
|
- test_bit(TXDONE_EXCESSIVE_RETRY, &txdesc->flags);
|
|
- tx_info->status.retry_count = txdesc->retry;
|
|
+ tx_info->status.rates[0].count = txdesc->retry + 1;
|
|
|
|
if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
|
|
if (test_bit(TXDONE_SUCCESS, &txdesc->flags))
|
|
@@ -544,7 +545,7 @@ void rt2x00lib_txdone(struct queue_entry
|
|
rt2x00dev->low_level_stats.dot11ACKFailureCount++;
|
|
}
|
|
|
|
- if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
|
|
+ if (rts) {
|
|
if (test_bit(TXDONE_SUCCESS, &txdesc->flags))
|
|
rt2x00dev->low_level_stats.dot11RTSSuccessCount++;
|
|
else if (test_bit(TXDONE_FAILURE, &txdesc->flags))
|
|
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
|
|
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
|
|
@@ -39,7 +39,7 @@ static int rt2x00mac_tx_rts_cts(struct r
|
|
unsigned int data_length;
|
|
int retval = 0;
|
|
|
|
- if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
|
|
+ if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
|
|
data_length = sizeof(struct ieee80211_cts);
|
|
else
|
|
data_length = sizeof(struct ieee80211_rts);
|
|
@@ -64,11 +64,11 @@ static int rt2x00mac_tx_rts_cts(struct r
|
|
*/
|
|
memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb));
|
|
rts_info = IEEE80211_SKB_CB(skb);
|
|
- rts_info->flags &= ~IEEE80211_TX_CTL_USE_RTS_CTS;
|
|
- rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT;
|
|
+ rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_RTS_CTS;
|
|
+ rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_CTS_PROTECT;
|
|
rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS;
|
|
|
|
- if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
|
|
+ if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
|
|
rts_info->flags |= IEEE80211_TX_CTL_NO_ACK;
|
|
else
|
|
rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
|
|
@@ -84,7 +84,7 @@ static int rt2x00mac_tx_rts_cts(struct r
|
|
data_length += rt2x00crypto_tx_overhead(tx_info);
|
|
#endif /* CONFIG_RT2X00_LIB_CRYPTO */
|
|
|
|
- if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
|
|
+ if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
|
|
ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif,
|
|
frag_skb->data, data_length, tx_info,
|
|
(struct ieee80211_cts *)(skb->data));
|
|
@@ -146,8 +146,8 @@ int rt2x00mac_tx(struct ieee80211_hw *hw
|
|
* inside the hardware.
|
|
*/
|
|
frame_control = le16_to_cpu(ieee80211hdr->frame_control);
|
|
- if ((tx_info->flags & (IEEE80211_TX_CTL_USE_RTS_CTS |
|
|
- IEEE80211_TX_CTL_USE_CTS_PROTECT)) &&
|
|
+ if ((tx_info->control.rates[0].flags & (IEEE80211_TX_RC_USE_RTS_CTS |
|
|
+ IEEE80211_TX_RC_USE_CTS_PROTECT)) &&
|
|
!rt2x00dev->ops->hw->set_rts_threshold) {
|
|
if (rt2x00queue_available(queue) <= 1)
|
|
goto exit_fail;
|
|
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
|
|
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
|
|
@@ -230,8 +230,15 @@ static void rt2x00queue_create_tx_descri
|
|
/*
|
|
* Determine retry information.
|
|
*/
|
|
- txdesc->retry_limit = tx_info->control.retry_limit;
|
|
- if (tx_info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
|
|
+ txdesc->retry_limit = tx_info->control.rates[0].count - 1;
|
|
+ /*
|
|
+ * XXX: If at this point we knew whether the HW is going to use
|
|
+ * the RETRY_MODE bit or the retry_limit (currently all
|
|
+ * use the RETRY_MODE bit) we could do something like b43
|
|
+ * does, set the RETRY_MODE bit when the RC algorithm is
|
|
+ * requesting more than the long retry limit.
|
|
+ */
|
|
+ if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
|
|
__set_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags);
|
|
|
|
/*
|
|
--- a/drivers/net/wireless/adm8211.c
|
|
+++ b/drivers/net/wireless/adm8211.c
|
|
@@ -341,15 +341,14 @@ static void adm8211_interrupt_tci(struct
|
|
pci_unmap_single(priv->pdev, info->mapping,
|
|
info->skb->len, PCI_DMA_TODEVICE);
|
|
|
|
- memset(&txi->status, 0, sizeof(txi->status));
|
|
+ ieee80211_tx_info_clear_status(txi);
|
|
+
|
|
skb_pull(skb, sizeof(struct adm8211_tx_hdr));
|
|
memcpy(skb_push(skb, info->hdrlen), skb->cb, info->hdrlen);
|
|
- if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) {
|
|
- if (status & TDES0_STATUS_ES)
|
|
- txi->status.excessive_retries = 1;
|
|
- else
|
|
- txi->flags |= IEEE80211_TX_STAT_ACK;
|
|
- }
|
|
+ if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) &&
|
|
+ !(status & TDES0_STATUS_ES))
|
|
+ txi->flags |= IEEE80211_TX_STAT_ACK;
|
|
+
|
|
ieee80211_tx_status_irqsafe(dev, skb);
|
|
|
|
info->skb = NULL;
|
|
@@ -1691,8 +1690,10 @@ static int adm8211_tx(struct ieee80211_h
|
|
struct ieee80211_hdr *hdr;
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, info);
|
|
+ u8 rc_flags;
|
|
|
|
- short_preamble = !!(txrate->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE);
|
|
+ rc_flags = info->control.rates[0].flags;
|
|
+ short_preamble = !!(rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
|
|
plcp_signal = txrate->bitrate;
|
|
|
|
hdr = (struct ieee80211_hdr *)skb->data;
|
|
@@ -1724,10 +1725,10 @@ static int adm8211_tx(struct ieee80211_h
|
|
if (short_preamble)
|
|
txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE);
|
|
|
|
- if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
|
|
+ if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS)
|
|
txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS);
|
|
|
|
- txhdr->retry_limit = info->control.retry_limit;
|
|
+ txhdr->retry_limit = info->control.rates[0].count;
|
|
|
|
adm8211_tx_raw(dev, skb, plcp_signal, hdrlen);
|
|
|
|
--- a/drivers/net/wireless/ath5k/base.c
|
|
+++ b/drivers/net/wireless/ath5k/base.c
|
|
@@ -542,8 +542,8 @@ ath5k_pci_probe(struct pci_dev *pdev,
|
|
|
|
/* set up multi-rate retry capabilities */
|
|
if (sc->ah->ah_version == AR5K_AR5212) {
|
|
- hw->max_altrates = 3;
|
|
- hw->max_altrate_tries = 11;
|
|
+ hw->max_rates = 4;
|
|
+ hw->max_rate_tries = 11;
|
|
}
|
|
|
|
/* Finish private driver data initialization */
|
|
@@ -1188,7 +1188,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc
|
|
ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL,
|
|
(sc->power_level * 2),
|
|
ieee80211_get_tx_rate(sc->hw, info)->hw_value,
|
|
- info->control.retry_limit, keyidx, 0, flags, 0, 0);
|
|
+ info->control.rates[0].count, keyidx, 0, flags, 0, 0);
|
|
if (ret)
|
|
goto err_unmap;
|
|
|
|
@@ -1200,7 +1200,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc
|
|
break;
|
|
|
|
mrr_rate[i] = rate->hw_value;
|
|
- mrr_tries[i] = info->control.retries[i].limit;
|
|
+ mrr_tries[i] = info->control.rates[i + 1].count;
|
|
}
|
|
|
|
ah->ah_setup_mrr_tx_desc(ah, ds,
|
|
@@ -1846,30 +1846,26 @@ ath5k_tx_processq(struct ath5k_softc *sc
|
|
pci_unmap_single(sc->pdev, bf->skbaddr, skb->len,
|
|
PCI_DMA_TODEVICE);
|
|
|
|
- memset(&info->status, 0, sizeof(info->status));
|
|
- info->tx_rate_idx = ath5k_hw_to_driver_rix(sc,
|
|
- ts.ts_rate[ts.ts_final_idx]);
|
|
- info->status.retry_count = ts.ts_longretry;
|
|
-
|
|
+ ieee80211_tx_info_clear_status(info);
|
|
for (i = 0; i < 4; i++) {
|
|
- struct ieee80211_tx_altrate *r =
|
|
- &info->status.retries[i];
|
|
+ struct ieee80211_tx_rate *r =
|
|
+ &info->status.rates[i];
|
|
|
|
if (ts.ts_rate[i]) {
|
|
- r->rate_idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]);
|
|
- r->limit = ts.ts_retry[i];
|
|
+ r->idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]);
|
|
+ r->count = ts.ts_retry[i];
|
|
} else {
|
|
- r->rate_idx = -1;
|
|
- r->limit = 0;
|
|
+ r->idx = -1;
|
|
+ r->count = 0;
|
|
}
|
|
}
|
|
|
|
- info->status.excessive_retries = 0;
|
|
+ /* count the successful attempt as well */
|
|
+ info->status.rates[ts.ts_final_idx].count++;
|
|
+
|
|
if (unlikely(ts.ts_status)) {
|
|
sc->ll_stats.dot11ACKFailureCount++;
|
|
- if (ts.ts_status & AR5K_TXERR_XRETRY)
|
|
- info->status.excessive_retries = 1;
|
|
- else if (ts.ts_status & AR5K_TXERR_FILT)
|
|
+ if (ts.ts_status & AR5K_TXERR_FILT)
|
|
info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
|
|
} else {
|
|
info->flags |= IEEE80211_TX_STAT_ACK;
|
|
--- a/drivers/net/wireless/ath9k/main.c
|
|
+++ b/drivers/net/wireless/ath9k/main.c
|
|
@@ -461,12 +461,13 @@ void ath_tx_complete(struct ath_softc *s
|
|
DPRINTF(sc, ATH_DBG_XMIT,
|
|
"%s: TX complete: skb: %p\n", __func__, skb);
|
|
|
|
+ ieee80211_tx_info_clear_status(tx_info);
|
|
if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK ||
|
|
tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
|
|
- /* free driver's private data area of tx_info */
|
|
- if (tx_info->driver_data[0] != NULL)
|
|
- kfree(tx_info->driver_data[0]);
|
|
- tx_info->driver_data[0] = NULL;
|
|
+ /* free driver's private data area of tx_info, XXX: HACK! */
|
|
+ if (tx_info->control.vif != NULL)
|
|
+ kfree(tx_info->control.vif);
|
|
+ tx_info->control.vif = NULL;
|
|
}
|
|
|
|
if (tx_status->flags & ATH_TX_BAR) {
|
|
@@ -474,17 +475,12 @@ void ath_tx_complete(struct ath_softc *s
|
|
tx_status->flags &= ~ATH_TX_BAR;
|
|
}
|
|
|
|
- if (tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY)) {
|
|
- if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
|
|
- /* Frame was not ACKed, but an ACK was expected */
|
|
- tx_info->status.excessive_retries = 1;
|
|
- }
|
|
- } else {
|
|
+ if (!(tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
|
|
/* Frame was ACKed */
|
|
tx_info->flags |= IEEE80211_TX_STAT_ACK;
|
|
}
|
|
|
|
- tx_info->status.retry_count = tx_status->retries;
|
|
+ tx_info->status.rates[0].count = tx_status->retries + 1;
|
|
|
|
ieee80211_tx_status(hw, skb);
|
|
if (an)
|
|
--- a/drivers/net/wireless/ath9k/rc.c
|
|
+++ b/drivers/net/wireless/ath9k/rc.c
|
|
@@ -1864,24 +1864,21 @@ static void ath_tx_status(void *priv, st
|
|
|
|
hdr = (struct ieee80211_hdr *)skb->data;
|
|
fc = hdr->frame_control;
|
|
- tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
|
|
+ /* XXX: UGLY HACK!! */
|
|
+ tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
|
|
|
|
spin_lock_bh(&sc->node_lock);
|
|
an = ath_node_find(sc, hdr->addr1);
|
|
spin_unlock_bh(&sc->node_lock);
|
|
|
|
- if (!an || !priv_sta || !ieee80211_is_data(fc)) {
|
|
- if (tx_info->driver_data[0] != NULL) {
|
|
- kfree(tx_info->driver_data[0]);
|
|
- tx_info->driver_data[0] = NULL;
|
|
- }
|
|
+ if (tx_info_priv == NULL)
|
|
return;
|
|
- }
|
|
- if (tx_info->driver_data[0] != NULL) {
|
|
+
|
|
+ if (an && priv_sta && ieee80211_is_data(fc))
|
|
ath_rate_tx_complete(sc, an, priv_sta, tx_info_priv);
|
|
- kfree(tx_info->driver_data[0]);
|
|
- tx_info->driver_data[0] = NULL;
|
|
- }
|
|
+
|
|
+ kfree(tx_info_priv);
|
|
+ tx_info->control.vif = NULL;
|
|
}
|
|
|
|
static void ath_tx_aggr_resp(struct ath_softc *sc,
|
|
@@ -1927,10 +1924,11 @@ static void ath_tx_aggr_resp(struct ath_
|
|
}
|
|
}
|
|
|
|
-static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband,
|
|
- struct ieee80211_sta *sta, void *priv_sta,
|
|
- struct sk_buff *skb, struct rate_selection *sel)
|
|
+static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
|
|
+ struct ieee80211_tx_rate_control *txrc)
|
|
{
|
|
+ struct ieee80211_supported_band *sband = txrc->sband;
|
|
+ struct sk_buff *skb = txrc->skb;
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
|
struct ath_softc *sc = priv;
|
|
struct ieee80211_hw *hw = sc->hw;
|
|
@@ -1946,17 +1944,17 @@ static void ath_get_rate(void *priv, str
|
|
|
|
DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
|
|
|
|
- /* allocate driver private area of tx_info */
|
|
- tx_info->driver_data[0] = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC);
|
|
- ASSERT(tx_info->driver_data[0] != NULL);
|
|
- tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
|
|
+ /* allocate driver private area of tx_info, XXX: UGLY HACK! */
|
|
+ tx_info->control.vif = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC);
|
|
+ tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
|
|
+ ASSERT(tx_info_priv != NULL);
|
|
|
|
lowest_idx = rate_lowest_index(sband, sta);
|
|
tx_info_priv->min_rate = (sband->bitrates[lowest_idx].bitrate * 2) / 10;
|
|
/* lowest rate for management and multicast/broadcast frames */
|
|
if (!ieee80211_is_data(fc) ||
|
|
is_multicast_ether_addr(hdr->addr1) || !sta) {
|
|
- sel->rate_idx = lowest_idx;
|
|
+ tx_info->control.rates[0].idx = lowest_idx;
|
|
return;
|
|
}
|
|
|
|
@@ -1967,8 +1965,10 @@ static void ath_get_rate(void *priv, str
|
|
tx_info_priv->rcs,
|
|
&is_probe,
|
|
false);
|
|
+#if 0
|
|
if (is_probe)
|
|
sel->probe_idx = ath_rc_priv->tx_ratectrl.probe_rate;
|
|
+#endif
|
|
|
|
/* Ratecontrol sometimes returns invalid rate index */
|
|
if (tx_info_priv->rcs[0].rix != 0xff)
|
|
@@ -1976,7 +1976,7 @@ static void ath_get_rate(void *priv, str
|
|
else
|
|
tx_info_priv->rcs[0].rix = ath_rc_priv->prev_data_rix;
|
|
|
|
- sel->rate_idx = tx_info_priv->rcs[0].rix;
|
|
+ tx_info->control.rates[0].idx = tx_info_priv->rcs[0].rix;
|
|
|
|
/* Check if aggregation has to be enabled for this tid */
|
|
|
|
--- a/drivers/net/wireless/ath9k/xmit.c
|
|
+++ b/drivers/net/wireless/ath9k/xmit.c
|
|
@@ -168,7 +168,9 @@ static void fill_min_rates(struct sk_buf
|
|
|
|
hdr = (struct ieee80211_hdr *)skb->data;
|
|
fc = hdr->frame_control;
|
|
- tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
|
|
+
|
|
+ /* XXX: HACK! */
|
|
+ tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
|
|
|
|
if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) {
|
|
txctl->use_minrate = 1;
|
|
@@ -288,13 +290,16 @@ static int ath_tx_prepare(struct ath_sof
|
|
|
|
if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
|
|
txctl->flags |= ATH9K_TXDESC_NOACK;
|
|
- if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
|
|
+
|
|
+ if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
|
|
txctl->flags |= ATH9K_TXDESC_RTSENA;
|
|
|
|
/*
|
|
* Setup for rate calculations.
|
|
*/
|
|
- tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
|
|
+
|
|
+ /* XXX: HACK! */
|
|
+ tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
|
|
rcs = tx_info_priv->rcs;
|
|
|
|
if (ieee80211_is_data(fc) && !txctl->use_minrate) {
|
|
@@ -854,7 +859,9 @@ static int ath_tx_send_normal(struct ath
|
|
|
|
skb = (struct sk_buff *)bf->bf_mpdu;
|
|
tx_info = IEEE80211_SKB_CB(skb);
|
|
- tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
|
|
+
|
|
+ /* XXX: HACK! */
|
|
+ tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
|
|
memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
|
|
|
|
/* update starting sequence number for subsequent ADDBA request */
|
|
@@ -1248,8 +1255,9 @@ static int ath_tx_processq(struct ath_so
|
|
}
|
|
skb = bf->bf_mpdu;
|
|
tx_info = IEEE80211_SKB_CB(skb);
|
|
- tx_info_priv = (struct ath_tx_info_priv *)
|
|
- tx_info->driver_data[0];
|
|
+
|
|
+ /* XXX: HACK! */
|
|
+ tx_info_priv = (struct ath_tx_info_priv *) tx_info->control.vif;
|
|
if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT)
|
|
tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
|
|
if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 &&
|
|
@@ -1430,7 +1438,8 @@ static int ath_tx_send_ampdu(struct ath_
|
|
|
|
skb = (struct sk_buff *)bf->bf_mpdu;
|
|
tx_info = IEEE80211_SKB_CB(skb);
|
|
- tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
|
|
+ /* XXX: HACK! */
|
|
+ tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
|
|
memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
|
|
|
|
/* Add sub-frame to BAW */
|
|
@@ -1464,7 +1473,7 @@ static u32 ath_lookup_rate(struct ath_so
|
|
skb = (struct sk_buff *)bf->bf_mpdu;
|
|
tx_info = IEEE80211_SKB_CB(skb);
|
|
tx_info_priv = (struct ath_tx_info_priv *)
|
|
- tx_info->driver_data[0];
|
|
+ tx_info->control.vif; /* XXX: HACK! */
|
|
memcpy(bf->bf_rcs,
|
|
tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
|
|
|
|
@@ -1924,7 +1933,8 @@ static int ath_tx_start_dma(struct ath_s
|
|
|
|
bf->bf_flags = txctl->flags;
|
|
bf->bf_keytype = txctl->keytype;
|
|
- tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
|
|
+ /* XXX: HACK! */
|
|
+ tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
|
|
rcs = tx_info_priv->rcs;
|
|
bf->bf_rcs[0] = rcs[0];
|
|
bf->bf_rcs[1] = rcs[1];
|
|
--- a/drivers/net/wireless/b43/dma.c
|
|
+++ b/drivers/net/wireless/b43/dma.c
|
|
@@ -1387,13 +1387,13 @@ void b43_dma_handle_txstatus(struct b43_
|
|
|
|
info = IEEE80211_SKB_CB(meta->skb);
|
|
|
|
- memset(&info->status, 0, sizeof(info->status));
|
|
+ ieee80211_tx_info_clear_status(info);
|
|
|
|
/*
|
|
* Call back to inform the ieee80211 subsystem about
|
|
* the status of the transmission.
|
|
*/
|
|
- frame_succeed = b43_fill_txstatus_report(info, status);
|
|
+ frame_succeed = b43_fill_txstatus_report(dev, info, status);
|
|
#ifdef CONFIG_B43_DEBUG
|
|
if (frame_succeed)
|
|
ring->nr_succeed_tx_packets++;
|
|
--- a/drivers/net/wireless/b43/main.c
|
|
+++ b/drivers/net/wireless/b43/main.c
|
|
@@ -4563,7 +4563,7 @@ static int b43_wireless_init(struct ssb_
|
|
BIT(NL80211_IFTYPE_ADHOC);
|
|
|
|
hw->queues = b43_modparam_qos ? 4 : 1;
|
|
- hw->max_altrates = 1;
|
|
+ hw->max_rates = 2;
|
|
SET_IEEE80211_DEV(hw, dev->dev);
|
|
if (is_valid_ether_addr(sprom->et1mac))
|
|
SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
|
|
--- a/drivers/net/wireless/b43/pio.c
|
|
+++ b/drivers/net/wireless/b43/pio.c
|
|
@@ -587,9 +587,9 @@ void b43_pio_handle_txstatus(struct b43_
|
|
spin_lock(&q->lock); /* IRQs are already disabled. */
|
|
|
|
info = IEEE80211_SKB_CB(pack->skb);
|
|
- memset(&info->status, 0, sizeof(info->status));
|
|
+ ieee80211_tx_info_clear_status(info);
|
|
|
|
- b43_fill_txstatus_report(info, status);
|
|
+ b43_fill_txstatus_report(dev, info, status);
|
|
|
|
total_len = pack->skb->len + b43_txhdr_size(dev);
|
|
total_len = roundup(total_len, 4);
|
|
--- a/drivers/net/wireless/b43/xmit.c
|
|
+++ b/drivers/net/wireless/b43/xmit.c
|
|
@@ -185,7 +185,7 @@ int b43_generate_txhdr(struct b43_wldev
|
|
u8 *_txhdr,
|
|
const unsigned char *fragment_data,
|
|
unsigned int fragment_len,
|
|
- const struct ieee80211_tx_info *info,
|
|
+ struct ieee80211_tx_info *info,
|
|
u16 cookie)
|
|
{
|
|
struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr;
|
|
@@ -202,6 +202,7 @@ int b43_generate_txhdr(struct b43_wldev
|
|
u16 phy_ctl = 0;
|
|
u8 extra_ft = 0;
|
|
struct ieee80211_rate *txrate;
|
|
+ struct ieee80211_tx_rate *rates;
|
|
|
|
memset(txhdr, 0, sizeof(*txhdr));
|
|
|
|
@@ -291,7 +292,7 @@ int b43_generate_txhdr(struct b43_wldev
|
|
phy_ctl |= B43_TXH_PHY_ENC_OFDM;
|
|
else
|
|
phy_ctl |= B43_TXH_PHY_ENC_CCK;
|
|
- if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE)
|
|
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
|
|
phy_ctl |= B43_TXH_PHY_SHORTPRMBL;
|
|
|
|
switch (b43_ieee80211_antenna_sanitize(dev, info->antenna_sel_tx)) {
|
|
@@ -314,6 +315,7 @@ int b43_generate_txhdr(struct b43_wldev
|
|
B43_WARN_ON(1);
|
|
}
|
|
|
|
+ rates = info->control.rates;
|
|
/* MAC control */
|
|
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
|
|
mac_ctl |= B43_TXH_MAC_ACK;
|
|
@@ -324,12 +326,22 @@ int b43_generate_txhdr(struct b43_wldev
|
|
mac_ctl |= B43_TXH_MAC_STMSDU;
|
|
if (phy->type == B43_PHYTYPE_A)
|
|
mac_ctl |= B43_TXH_MAC_5GHZ;
|
|
- if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
|
|
+
|
|
+ /* Overwrite rates[0].count to make the retry calculation
|
|
+ * in the tx status easier. need the actual retry limit to
|
|
+ * detect whether the fallback rate was used.
|
|
+ */
|
|
+ if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
|
|
+ (rates[0].count <= dev->wl->hw->conf.long_frame_max_tx_count)) {
|
|
+ rates[0].count = dev->wl->hw->conf.long_frame_max_tx_count;
|
|
mac_ctl |= B43_TXH_MAC_LONGFRAME;
|
|
+ } else {
|
|
+ rates[0].count = dev->wl->hw->conf.short_frame_max_tx_count;
|
|
+ }
|
|
|
|
/* Generate the RTS or CTS-to-self frame */
|
|
- if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
|
|
- (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
|
|
+ if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
|
|
+ (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) {
|
|
unsigned int len;
|
|
struct ieee80211_hdr *hdr;
|
|
int rts_rate, rts_rate_fb;
|
|
@@ -344,7 +356,7 @@ int b43_generate_txhdr(struct b43_wldev
|
|
rts_rate_fb = b43_calc_fallback_rate(rts_rate);
|
|
rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
|
|
|
|
- if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
|
|
+ if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
|
|
struct ieee80211_cts *cts;
|
|
|
|
if (b43_is_old_txhdr_format(dev)) {
|
|
@@ -687,10 +699,18 @@ void b43_handle_txstatus(struct b43_wlde
|
|
/* Fill out the mac80211 TXstatus report based on the b43-specific
|
|
* txstatus report data. This returns a boolean whether the frame was
|
|
* successfully transmitted. */
|
|
-bool b43_fill_txstatus_report(struct ieee80211_tx_info *report,
|
|
+bool b43_fill_txstatus_report(struct b43_wldev *dev,
|
|
+ struct ieee80211_tx_info *report,
|
|
const struct b43_txstatus *status)
|
|
{
|
|
bool frame_success = 1;
|
|
+ int retry_limit;
|
|
+
|
|
+ /* preserve the confiured retry limit before clearing the status
|
|
+ * The xmit function has overwritten the rc's value with the actual
|
|
+ * retry limit done by the hardware */
|
|
+ retry_limit = report->status.rates[0].count;
|
|
+ ieee80211_tx_info_clear_status(report);
|
|
|
|
if (status->acked) {
|
|
/* The frame was ACKed. */
|
|
@@ -700,14 +720,32 @@ bool b43_fill_txstatus_report(struct iee
|
|
if (!(report->flags & IEEE80211_TX_CTL_NO_ACK)) {
|
|
/* ...but we expected an ACK. */
|
|
frame_success = 0;
|
|
- report->status.excessive_retries = 1;
|
|
}
|
|
}
|
|
if (status->frame_count == 0) {
|
|
/* The frame was not transmitted at all. */
|
|
- report->status.retry_count = 0;
|
|
- } else
|
|
- report->status.retry_count = status->frame_count - 1;
|
|
+ report->status.rates[0].count = 0;
|
|
+ } else if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) {
|
|
+ /*
|
|
+ * If the short retries (RTS, not data frame) have exceeded
|
|
+ * the limit, the hw will not have tried the selected rate,
|
|
+ * but will have used the fallback rate instead.
|
|
+ * Don't let the rate control count attempts for the selected
|
|
+ * rate in this case, otherwise the statistics will be off.
|
|
+ */
|
|
+ report->status.rates[0].count = 0;
|
|
+ report->status.rates[1].count = status->frame_count;
|
|
+ } else {
|
|
+ if (status->frame_count > retry_limit) {
|
|
+ report->status.rates[0].count = retry_limit;
|
|
+ report->status.rates[1].count = status->frame_count -
|
|
+ retry_limit;
|
|
+
|
|
+ } else {
|
|
+ report->status.rates[0].count = status->frame_count;
|
|
+ report->status.rates[1].idx = -1;
|
|
+ }
|
|
+ }
|
|
|
|
return frame_success;
|
|
}
|
|
--- a/drivers/net/wireless/b43/xmit.h
|
|
+++ b/drivers/net/wireless/b43/xmit.h
|
|
@@ -178,7 +178,7 @@ int b43_generate_txhdr(struct b43_wldev
|
|
u8 * txhdr,
|
|
const unsigned char *fragment_data,
|
|
unsigned int fragment_len,
|
|
- const struct ieee80211_tx_info *txctl, u16 cookie);
|
|
+ struct ieee80211_tx_info *txctl, u16 cookie);
|
|
|
|
/* Transmit Status */
|
|
struct b43_txstatus {
|
|
@@ -294,7 +294,8 @@ void b43_rx(struct b43_wldev *dev, struc
|
|
|
|
void b43_handle_txstatus(struct b43_wldev *dev,
|
|
const struct b43_txstatus *status);
|
|
-bool b43_fill_txstatus_report(struct ieee80211_tx_info *report,
|
|
+bool b43_fill_txstatus_report(struct b43_wldev *dev,
|
|
+ struct ieee80211_tx_info *report,
|
|
const struct b43_txstatus *status);
|
|
|
|
void b43_tx_suspend(struct b43_wldev *dev);
|
|
--- a/drivers/net/wireless/b43legacy/dma.c
|
|
+++ b/drivers/net/wireless/b43legacy/dma.c
|
|
@@ -1411,6 +1411,7 @@ void b43legacy_dma_handle_txstatus(struc
|
|
struct b43legacy_dmaring *ring;
|
|
struct b43legacy_dmadesc_generic *desc;
|
|
struct b43legacy_dmadesc_meta *meta;
|
|
+ int retry_limit;
|
|
int slot;
|
|
|
|
ring = parse_cookie(dev, status->cookie, &slot);
|
|
@@ -1437,25 +1438,42 @@ void b43legacy_dma_handle_txstatus(struc
|
|
struct ieee80211_tx_info *info;
|
|
BUG_ON(!meta->skb);
|
|
info = IEEE80211_SKB_CB(meta->skb);
|
|
- /* Call back to inform the ieee80211 subsystem about the
|
|
- * status of the transmission.
|
|
- * Some fields of txstat are already filled in dma_tx().
|
|
- */
|
|
|
|
- memset(&info->status, 0, sizeof(info->status));
|
|
+ /* preserve the confiured retry limit before clearing the status
|
|
+ * The xmit function has overwritten the rc's value with the actual
|
|
+ * retry limit done by the hardware */
|
|
+ retry_limit = info->status.rates[0].count;
|
|
+ ieee80211_tx_info_clear_status(info);
|
|
|
|
- if (status->acked) {
|
|
+ if (status->acked)
|
|
info->flags |= IEEE80211_TX_STAT_ACK;
|
|
+
|
|
+ if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) {
|
|
+ /*
|
|
+ * If the short retries (RTS, not data frame) have exceeded
|
|
+ * the limit, the hw will not have tried the selected rate,
|
|
+ * but will have used the fallback rate instead.
|
|
+ * Don't let the rate control count attempts for the selected
|
|
+ * rate in this case, otherwise the statistics will be off.
|
|
+ */
|
|
+ info->status.rates[0].count = 0;
|
|
+ info->status.rates[1].count = status->frame_count;
|
|
} else {
|
|
- if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
|
|
- info->status.excessive_retries = 1;
|
|
+ if (status->frame_count > retry_limit) {
|
|
+ info->status.rates[0].count = retry_limit;
|
|
+ info->status.rates[1].count = status->frame_count -
|
|
+ retry_limit;
|
|
+
|
|
+ } else {
|
|
+ info->status.rates[0].count = status->frame_count;
|
|
+ info->status.rates[1].idx = -1;
|
|
+ }
|
|
}
|
|
- if (status->frame_count == 0) {
|
|
- /* The frame was not transmitted at all. */
|
|
- info->status.retry_count = 0;
|
|
- } else
|
|
- info->status.retry_count = status->frame_count
|
|
- - 1;
|
|
+
|
|
+ /* Call back to inform the ieee80211 subsystem about the
|
|
+ * status of the transmission.
|
|
+ * Some fields of txstat are already filled in dma_tx().
|
|
+ */
|
|
ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb);
|
|
/* skb is freed by ieee80211_tx_status_irqsafe() */
|
|
meta->skb = NULL;
|
|
--- a/drivers/net/wireless/b43legacy/main.c
|
|
+++ b/drivers/net/wireless/b43legacy/main.c
|
|
@@ -3691,7 +3691,7 @@ static int b43legacy_wireless_init(struc
|
|
BIT(NL80211_IFTYPE_WDS) |
|
|
BIT(NL80211_IFTYPE_ADHOC);
|
|
hw->queues = 1; /* FIXME: hardware has more queues */
|
|
- hw->max_altrates = 1;
|
|
+ hw->max_rates = 2;
|
|
SET_IEEE80211_DEV(hw, dev->dev);
|
|
if (is_valid_ether_addr(sprom->et1mac))
|
|
SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
|
|
--- a/drivers/net/wireless/b43legacy/pio.c
|
|
+++ b/drivers/net/wireless/b43legacy/pio.c
|
|
@@ -491,6 +491,7 @@ void b43legacy_pio_handle_txstatus(struc
|
|
struct b43legacy_pioqueue *queue;
|
|
struct b43legacy_pio_txpacket *packet;
|
|
struct ieee80211_tx_info *info;
|
|
+ int retry_limit;
|
|
|
|
queue = parse_cookie(dev, status->cookie, &packet);
|
|
B43legacy_WARN_ON(!queue);
|
|
@@ -503,11 +504,37 @@ void b43legacy_pio_handle_txstatus(struc
|
|
sizeof(struct b43legacy_txhdr_fw3));
|
|
|
|
info = IEEE80211_SKB_CB(packet->skb);
|
|
- memset(&info->status, 0, sizeof(info->status));
|
|
+
|
|
+ /* preserve the confiured retry limit before clearing the status
|
|
+ * The xmit function has overwritten the rc's value with the actual
|
|
+ * retry limit done by the hardware */
|
|
+ retry_limit = info->status.rates[0].count;
|
|
+ ieee80211_tx_info_clear_status(info);
|
|
|
|
if (status->acked)
|
|
info->flags |= IEEE80211_TX_STAT_ACK;
|
|
- info->status.retry_count = status->frame_count - 1;
|
|
+
|
|
+ if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) {
|
|
+ /*
|
|
+ * If the short retries (RTS, not data frame) have exceeded
|
|
+ * the limit, the hw will not have tried the selected rate,
|
|
+ * but will have used the fallback rate instead.
|
|
+ * Don't let the rate control count attempts for the selected
|
|
+ * rate in this case, otherwise the statistics will be off.
|
|
+ */
|
|
+ info->status.rates[0].count = 0;
|
|
+ info->status.rates[1].count = status->frame_count;
|
|
+ } else {
|
|
+ if (status->frame_count > retry_limit) {
|
|
+ info->status.rates[0].count = retry_limit;
|
|
+ info->status.rates[1].count = status->frame_count -
|
|
+ retry_limit;
|
|
+
|
|
+ } else {
|
|
+ info->status.rates[0].count = status->frame_count;
|
|
+ info->status.rates[1].idx = -1;
|
|
+ }
|
|
+ }
|
|
ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb);
|
|
packet->skb = NULL;
|
|
|
|
--- a/drivers/net/wireless/b43legacy/xmit.c
|
|
+++ b/drivers/net/wireless/b43legacy/xmit.c
|
|
@@ -188,7 +188,7 @@ static int generate_txhdr_fw3(struct b43
|
|
struct b43legacy_txhdr_fw3 *txhdr,
|
|
const unsigned char *fragment_data,
|
|
unsigned int fragment_len,
|
|
- const struct ieee80211_tx_info *info,
|
|
+ struct ieee80211_tx_info *info,
|
|
u16 cookie)
|
|
{
|
|
const struct ieee80211_hdr *wlhdr;
|
|
@@ -201,6 +201,7 @@ static int generate_txhdr_fw3(struct b43
|
|
u32 mac_ctl = 0;
|
|
u16 phy_ctl = 0;
|
|
struct ieee80211_rate *tx_rate;
|
|
+ struct ieee80211_tx_rate *rates;
|
|
|
|
wlhdr = (const struct ieee80211_hdr *)fragment_data;
|
|
|
|
@@ -274,7 +275,7 @@ static int generate_txhdr_fw3(struct b43
|
|
/* PHY TX Control word */
|
|
if (rate_ofdm)
|
|
phy_ctl |= B43legacy_TX4_PHY_OFDM;
|
|
- if (dev->short_preamble)
|
|
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
|
|
phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL;
|
|
switch (info->antenna_sel_tx) {
|
|
case 0:
|
|
@@ -291,6 +292,7 @@ static int generate_txhdr_fw3(struct b43
|
|
}
|
|
|
|
/* MAC control */
|
|
+ rates = info->control.rates;
|
|
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
|
|
mac_ctl |= B43legacy_TX4_MAC_ACK;
|
|
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
|
|
@@ -299,12 +301,22 @@ static int generate_txhdr_fw3(struct b43
|
|
mac_ctl |= B43legacy_TX4_MAC_STMSDU;
|
|
if (rate_fb_ofdm)
|
|
mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM;
|
|
- if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
|
|
+
|
|
+ /* Overwrite rates[0].count to make the retry calculation
|
|
+ * in the tx status easier. need the actual retry limit to
|
|
+ * detect whether the fallback rate was used.
|
|
+ */
|
|
+ if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
|
|
+ (rates[0].count <= dev->wl->hw->conf.long_frame_max_tx_count)) {
|
|
+ rates[0].count = dev->wl->hw->conf.long_frame_max_tx_count;
|
|
mac_ctl |= B43legacy_TX4_MAC_LONGFRAME;
|
|
+ } else {
|
|
+ rates[0].count = dev->wl->hw->conf.short_frame_max_tx_count;
|
|
+ }
|
|
|
|
/* Generate the RTS or CTS-to-self frame */
|
|
- if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
|
|
- (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
|
|
+ if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
|
|
+ (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) {
|
|
unsigned int len;
|
|
struct ieee80211_hdr *hdr;
|
|
int rts_rate;
|
|
@@ -319,7 +331,7 @@ static int generate_txhdr_fw3(struct b43
|
|
if (rts_rate_fb_ofdm)
|
|
mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM;
|
|
|
|
- if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
|
|
+ if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
|
|
ieee80211_ctstoself_get(dev->wl->hw,
|
|
info->control.vif,
|
|
fragment_data,
|
|
@@ -362,7 +374,7 @@ int b43legacy_generate_txhdr(struct b43l
|
|
u8 *txhdr,
|
|
const unsigned char *fragment_data,
|
|
unsigned int fragment_len,
|
|
- const struct ieee80211_tx_info *info,
|
|
+ struct ieee80211_tx_info *info,
|
|
u16 cookie)
|
|
{
|
|
return generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr,
|
|
--- a/drivers/net/wireless/b43legacy/xmit.h
|
|
+++ b/drivers/net/wireless/b43legacy/xmit.h
|
|
@@ -80,7 +80,7 @@ int b43legacy_generate_txhdr(struct b43l
|
|
u8 *txhdr,
|
|
const unsigned char *fragment_data,
|
|
unsigned int fragment_len,
|
|
- const struct ieee80211_tx_info *info,
|
|
+ struct ieee80211_tx_info *info,
|
|
u16 cookie);
|
|
|
|
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
|
|
@@ -422,34 +422,6 @@ static void rs_free_sta(void *priv, stru
|
|
}
|
|
|
|
|
|
-/*
|
|
- * get ieee prev rate from rate scale table.
|
|
- * for A and B mode we need to overright prev
|
|
- * value
|
|
- */
|
|
-static int rs_adjust_next_rate(struct iwl3945_priv *priv, int rate)
|
|
-{
|
|
- int next_rate = iwl3945_get_prev_ieee_rate(rate);
|
|
-
|
|
- switch (priv->band) {
|
|
- case IEEE80211_BAND_5GHZ:
|
|
- if (rate == IWL_RATE_12M_INDEX)
|
|
- next_rate = IWL_RATE_9M_INDEX;
|
|
- else if (rate == IWL_RATE_6M_INDEX)
|
|
- next_rate = IWL_RATE_6M_INDEX;
|
|
- break;
|
|
-/* XXX cannot be invoked in current mac80211 so not a regression
|
|
- case MODE_IEEE80211B:
|
|
- if (rate == IWL_RATE_11M_INDEX_TABLE)
|
|
- next_rate = IWL_RATE_5M_INDEX_TABLE;
|
|
- break;
|
|
- */
|
|
- default:
|
|
- break;
|
|
- }
|
|
-
|
|
- return next_rate;
|
|
-}
|
|
/**
|
|
* rs_tx_status - Update rate control values based on Tx results
|
|
*
|
|
@@ -460,17 +432,21 @@ static void rs_tx_status(void *priv_rate
|
|
struct ieee80211_sta *sta, void *priv_sta,
|
|
struct sk_buff *skb)
|
|
{
|
|
- u8 retries, current_count;
|
|
+ u8 retries = 0, current_count;
|
|
int scale_rate_index, first_index, last_index;
|
|
unsigned long flags;
|
|
struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate;
|
|
struct iwl3945_rs_sta *rs_sta = priv_sta;
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
+ int i;
|
|
|
|
IWL_DEBUG_RATE("enter\n");
|
|
|
|
- retries = info->status.retry_count;
|
|
- first_index = sband->bitrates[info->tx_rate_idx].hw_value;
|
|
+ for (i = 0; i < IEEE80211_TX_MAX_RATES; i++)
|
|
+ retries += info->status.rates[i].count;
|
|
+ retries--;
|
|
+
|
|
+ first_index = sband->bitrates[info->status.rates[0].idx].hw_value;
|
|
if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) {
|
|
IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index);
|
|
return;
|
|
@@ -502,7 +478,7 @@ static void rs_tx_status(void *priv_rate
|
|
last_index = scale_rate_index;
|
|
} else {
|
|
current_count = priv->retry_rate;
|
|
- last_index = rs_adjust_next_rate(priv,
|
|
+ last_index = iwl3945_rs_next_rate(priv,
|
|
scale_rate_index);
|
|
}
|
|
|
|
@@ -518,7 +494,7 @@ static void rs_tx_status(void *priv_rate
|
|
|
|
if (retries)
|
|
scale_rate_index =
|
|
- rs_adjust_next_rate(priv, scale_rate_index);
|
|
+ iwl3945_rs_next_rate(priv, scale_rate_index);
|
|
}
|
|
|
|
|
|
@@ -630,10 +606,11 @@ static u16 iwl3945_get_adjacent_rate(str
|
|
* rate table and must reference the driver allocated rate table
|
|
*
|
|
*/
|
|
-static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
|
|
- struct ieee80211_sta *sta, void *priv_sta,
|
|
- struct sk_buff *skb, struct rate_selection *sel)
|
|
+static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
|
|
+ void *priv_sta, struct ieee80211_tx_rate_control *txrc)
|
|
{
|
|
+ struct ieee80211_supported_band *sband = txrc->sband;
|
|
+ struct sk_buff *skb = txrc->skb;
|
|
u8 low = IWL_RATE_INVALID;
|
|
u8 high = IWL_RATE_INVALID;
|
|
u16 high_low;
|
|
@@ -649,6 +626,7 @@ static void rs_get_rate(void *priv_r, st
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
|
u16 fc, rate_mask;
|
|
struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_r;
|
|
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
DECLARE_MAC_BUF(mac);
|
|
|
|
IWL_DEBUG_RATE("enter\n");
|
|
@@ -660,7 +638,7 @@ static void rs_get_rate(void *priv_r, st
|
|
is_multicast_ether_addr(hdr->addr1) ||
|
|
!sta || !priv_sta) {
|
|
IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
|
|
- sel->rate_idx = rate_lowest_index(sband, sta);
|
|
+ info->control.rates[0].idx = rate_lowest_index(sband, sta);
|
|
return;
|
|
}
|
|
|
|
@@ -793,9 +771,10 @@ static void rs_get_rate(void *priv_r, st
|
|
|
|
rs_sta->last_txrate_idx = index;
|
|
if (sband->band == IEEE80211_BAND_5GHZ)
|
|
- sel->rate_idx = rs_sta->last_txrate_idx - IWL_FIRST_OFDM_RATE;
|
|
+ info->control.rates[0].idx = rs_sta->last_txrate_idx -
|
|
+ IWL_FIRST_OFDM_RATE;
|
|
else
|
|
- sel->rate_idx = rs_sta->last_txrate_idx;
|
|
+ info->control.rates[0].idx = rs_sta->last_txrate_idx;
|
|
|
|
IWL_DEBUG_RATE("leave: %d\n", index);
|
|
}
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
|
|
@@ -261,6 +261,35 @@ static inline const char *iwl3945_get_tx
|
|
}
|
|
#endif
|
|
|
|
+/*
|
|
+ * get ieee prev rate from rate scale table.
|
|
+ * for A and B mode we need to overright prev
|
|
+ * value
|
|
+ */
|
|
+int iwl3945_rs_next_rate(struct iwl3945_priv *priv, int rate)
|
|
+{
|
|
+ int next_rate = iwl3945_get_prev_ieee_rate(rate);
|
|
+
|
|
+ switch (priv->band) {
|
|
+ case IEEE80211_BAND_5GHZ:
|
|
+ if (rate == IWL_RATE_12M_INDEX)
|
|
+ next_rate = IWL_RATE_9M_INDEX;
|
|
+ else if (rate == IWL_RATE_6M_INDEX)
|
|
+ next_rate = IWL_RATE_6M_INDEX;
|
|
+ break;
|
|
+/* XXX cannot be invoked in current mac80211 so not a regression
|
|
+ case MODE_IEEE80211B:
|
|
+ if (rate == IWL_RATE_11M_INDEX_TABLE)
|
|
+ next_rate = IWL_RATE_5M_INDEX_TABLE;
|
|
+ break;
|
|
+ */
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return next_rate;
|
|
+}
|
|
+
|
|
|
|
/**
|
|
* iwl3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd
|
|
@@ -308,6 +337,7 @@ static void iwl3945_rx_reply_tx(struct i
|
|
struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
|
|
u32 status = le32_to_cpu(tx_resp->status);
|
|
int rate_idx;
|
|
+ int fail, i;
|
|
|
|
if ((index >= txq->q.n_bd) || (iwl3945_x2_queue_used(&txq->q, index) == 0)) {
|
|
IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
|
|
@@ -318,9 +348,33 @@ static void iwl3945_rx_reply_tx(struct i
|
|
}
|
|
|
|
info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
|
|
- memset(&info->status, 0, sizeof(info->status));
|
|
+ ieee80211_tx_info_clear_status(info);
|
|
+
|
|
+ /* Fill the MRR chain with some info about on-chip retransmissions */
|
|
+ rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate);
|
|
+ if (info->band == IEEE80211_BAND_5GHZ)
|
|
+ rate_idx -= IWL_FIRST_OFDM_RATE;
|
|
+
|
|
+ info->status.rates[0].count = tx_resp->failure_frame + 1;
|
|
+ fail = tx_resp->failure_frame;
|
|
+ for(i = 0; i < 4; i++) {
|
|
+ int next = iwl3945_rs_next_rate(priv, rate_idx);
|
|
+
|
|
+ info->status.rates[i].idx = rate_idx;
|
|
+
|
|
+ if ((rate_idx == next) || (i == 3)) {
|
|
+ info->status.rates[i].count = fail;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ info->status.rates[i].count = priv->retry_rate;
|
|
+ fail -= priv->retry_rate;
|
|
+ rate_idx = next;
|
|
+ if (fail <= 0)
|
|
+ break;
|
|
+ }
|
|
+ info->status.rates[i].count++; /* add final attempt */
|
|
|
|
- info->status.retry_count = tx_resp->failure_frame;
|
|
/* tx_status->rts_retry_count = tx_resp->failure_rts; */
|
|
info->flags |= ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ?
|
|
IEEE80211_TX_STAT_ACK : 0;
|
|
@@ -329,10 +383,6 @@ static void iwl3945_rx_reply_tx(struct i
|
|
txq_id, iwl3945_get_tx_fail_reason(status), status,
|
|
tx_resp->rate, tx_resp->failure_frame);
|
|
|
|
- rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate);
|
|
- if (info->band == IEEE80211_BAND_5GHZ)
|
|
- rate_idx -= IWL_FIRST_OFDM_RATE;
|
|
- info->tx_rate_idx = rate_idx;
|
|
IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
|
|
iwl3945_tx_queue_reclaim(priv, txq_id, index);
|
|
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
|
|
@@ -954,6 +954,8 @@ static inline int is_channel_ibss(const
|
|
extern const struct iwl3945_channel_info *iwl3945_get_channel_info(
|
|
const struct iwl3945_priv *priv, enum ieee80211_band band, u16 channel);
|
|
|
|
+extern int iwl3945_rs_next_rate(struct iwl3945_priv *priv, int rate);
|
|
+
|
|
/* Requires full declaration of iwl3945_priv before including */
|
|
#include "iwl-3945-io.h"
|
|
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
|
|
@@ -88,26 +88,27 @@ EXPORT_SYMBOL(iwl_rates);
|
|
* translate ucode response to mac80211 tx status control values
|
|
*/
|
|
void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
|
|
- struct ieee80211_tx_info *control)
|
|
+ struct ieee80211_tx_info *info)
|
|
{
|
|
int rate_index;
|
|
+ struct ieee80211_tx_rate *r = &info->control.rates[0];
|
|
|
|
- control->antenna_sel_tx =
|
|
+ info->antenna_sel_tx =
|
|
((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS);
|
|
if (rate_n_flags & RATE_MCS_HT_MSK)
|
|
- control->flags |= IEEE80211_TX_CTL_OFDM_HT;
|
|
+ r->flags |= IEEE80211_TX_RC_MCS;
|
|
if (rate_n_flags & RATE_MCS_GF_MSK)
|
|
- control->flags |= IEEE80211_TX_CTL_GREEN_FIELD;
|
|
+ r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
|
|
if (rate_n_flags & RATE_MCS_FAT_MSK)
|
|
- control->flags |= IEEE80211_TX_CTL_40_MHZ_WIDTH;
|
|
+ r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
|
|
if (rate_n_flags & RATE_MCS_DUP_MSK)
|
|
- control->flags |= IEEE80211_TX_CTL_DUP_DATA;
|
|
+ r->flags |= IEEE80211_TX_RC_DUP_DATA;
|
|
if (rate_n_flags & RATE_MCS_SGI_MSK)
|
|
- control->flags |= IEEE80211_TX_CTL_SHORT_GI;
|
|
+ r->flags |= IEEE80211_TX_RC_SHORT_GI;
|
|
rate_index = iwl_hwrate_to_plcp_idx(rate_n_flags);
|
|
- if (control->band == IEEE80211_BAND_5GHZ)
|
|
+ if (info->band == IEEE80211_BAND_5GHZ)
|
|
rate_index -= IWL_FIRST_OFDM_RATE;
|
|
- control->tx_rate_idx = rate_index;
|
|
+ r->idx = rate_index;
|
|
}
|
|
EXPORT_SYMBOL(iwl_hwrate_to_tx_control);
|
|
|
|
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
|
|
@@ -2397,6 +2397,7 @@ static void iwl3945_build_tx_cmd_basic(s
|
|
{
|
|
__le16 fc = hdr->frame_control;
|
|
__le32 tx_flags = cmd->cmd.tx.tx_flags;
|
|
+ u8 rc_flags = info->control.rates[0].flags;
|
|
|
|
cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
|
|
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
|
|
@@ -2423,10 +2424,10 @@ static void iwl3945_build_tx_cmd_basic(s
|
|
tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
|
|
}
|
|
|
|
- if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
|
|
+ if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
|
|
tx_flags |= TX_CMD_FLG_RTS_MSK;
|
|
tx_flags &= ~TX_CMD_FLG_CTS_MSK;
|
|
- } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
|
|
+ } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
|
|
tx_flags &= ~TX_CMD_FLG_RTS_MSK;
|
|
tx_flags |= TX_CMD_FLG_CTS_MSK;
|
|
}
|
|
--- a/drivers/net/wireless/mac80211_hwsim.c
|
|
+++ b/drivers/net/wireless/mac80211_hwsim.c
|
|
@@ -209,7 +209,7 @@ static bool mac80211_hwsim_tx_frame(stru
|
|
/* TODO: set mactime */
|
|
rx_status.freq = data->channel->center_freq;
|
|
rx_status.band = data->channel->band;
|
|
- rx_status.rate_idx = info->tx_rate_idx;
|
|
+ rx_status.rate_idx = info->control.rates[0].idx;
|
|
/* TODO: simulate signal strength (and optional packet drop) */
|
|
|
|
/* Copy skb to all enabled radios that are on the current frequency */
|
|
@@ -269,13 +269,9 @@ static int mac80211_hwsim_tx(struct ieee
|
|
if (txi->control.sta)
|
|
hwsim_check_sta_magic(txi->control.sta);
|
|
|
|
- memset(&txi->status, 0, sizeof(txi->status));
|
|
- if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) {
|
|
- if (ack)
|
|
- txi->flags |= IEEE80211_TX_STAT_ACK;
|
|
- else
|
|
- txi->status.excessive_retries = 1;
|
|
- }
|
|
+ ieee80211_tx_info_clear_status(txi);
|
|
+ if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && ack)
|
|
+ txi->flags |= IEEE80211_TX_STAT_ACK;
|
|
ieee80211_tx_status_irqsafe(hw, skb);
|
|
return NETDEV_TX_OK;
|
|
}
|
|
--- a/drivers/net/wireless/rtl8180_dev.c
|
|
+++ b/drivers/net/wireless/rtl8180_dev.c
|
|
@@ -182,15 +182,13 @@ static void rtl8180_handle_tx(struct iee
|
|
skb->len, PCI_DMA_TODEVICE);
|
|
|
|
info = IEEE80211_SKB_CB(skb);
|
|
- memset(&info->status, 0, sizeof(info->status));
|
|
+ ieee80211_tx_info_clear_status(info);
|
|
|
|
- if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
|
|
- if (flags & RTL818X_TX_DESC_FLAG_TX_OK)
|
|
- info->flags |= IEEE80211_TX_STAT_ACK;
|
|
- else
|
|
- info->status.excessive_retries = 1;
|
|
- }
|
|
- info->status.retry_count = flags & 0xFF;
|
|
+ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
|
|
+ (flags & RTL818X_TX_DESC_FLAG_TX_OK))
|
|
+ info->flags |= IEEE80211_TX_STAT_ACK;
|
|
+
|
|
+ info->status.rates[0].count = (flags & 0xFF) + 1;
|
|
|
|
ieee80211_tx_status_irqsafe(dev, skb);
|
|
if (ring->entries - skb_queue_len(&ring->queue) == 2)
|
|
@@ -243,6 +241,7 @@ static int rtl8180_tx(struct ieee80211_h
|
|
unsigned int idx, prio;
|
|
dma_addr_t mapping;
|
|
u32 tx_flags;
|
|
+ u8 rc_flags;
|
|
u16 plcp_len = 0;
|
|
__le16 rts_duration = 0;
|
|
|
|
@@ -261,15 +260,16 @@ static int rtl8180_tx(struct ieee80211_h
|
|
tx_flags |= RTL818X_TX_DESC_FLAG_DMA |
|
|
RTL818X_TX_DESC_FLAG_NO_ENC;
|
|
|
|
- if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
|
|
+ rc_flags = info->control.rates[0].flags;
|
|
+ if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
|
|
tx_flags |= RTL818X_TX_DESC_FLAG_RTS;
|
|
tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
|
|
- } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
|
|
+ } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
|
|
tx_flags |= RTL818X_TX_DESC_FLAG_CTS;
|
|
tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
|
|
}
|
|
|
|
- if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
|
|
+ if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS)
|
|
rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len,
|
|
info);
|
|
|
|
@@ -292,9 +292,9 @@ static int rtl8180_tx(struct ieee80211_h
|
|
entry->plcp_len = cpu_to_le16(plcp_len);
|
|
entry->tx_buf = cpu_to_le32(mapping);
|
|
entry->frame_len = cpu_to_le32(skb->len);
|
|
- entry->flags2 = info->control.retries[0].rate_idx >= 0 ?
|
|
+ entry->flags2 = info->control.rates[1].idx >= 0 ?
|
|
ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0;
|
|
- entry->retry_limit = info->control.retry_limit;
|
|
+ entry->retry_limit = info->control.rates[0].count;
|
|
entry->flags = cpu_to_le32(tx_flags);
|
|
__skb_queue_tail(&ring->queue, skb);
|
|
if (ring->entries - skb_queue_len(&ring->queue) < 2)
|
|
@@ -856,7 +856,7 @@ static int __devinit rtl8180_probe(struc
|
|
priv = dev->priv;
|
|
priv->pdev = pdev;
|
|
|
|
- dev->max_altrates = 1;
|
|
+ dev->max_rates = 2;
|
|
SET_IEEE80211_DEV(dev, &pdev->dev);
|
|
pci_set_drvdata(pdev, dev);
|
|
|
|
--- a/drivers/net/wireless/rtl8187_dev.c
|
|
+++ b/drivers/net/wireless/rtl8187_dev.c
|
|
@@ -163,7 +163,7 @@ static void rtl8187_tx_cb(struct urb *ur
|
|
usb_free_urb(info->driver_data[1]);
|
|
skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) :
|
|
sizeof(struct rtl8187_tx_hdr));
|
|
- memset(&info->status, 0, sizeof(info->status));
|
|
+ ieee80211_tx_info_clear_status(info);
|
|
info->flags |= IEEE80211_TX_STAT_ACK;
|
|
ieee80211_tx_status_irqsafe(hw, skb);
|
|
}
|
|
@@ -192,12 +192,12 @@ static int rtl8187_tx(struct ieee80211_h
|
|
flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24;
|
|
if (ieee80211_has_morefrags(((struct ieee80211_hdr *)skb->data)->frame_control))
|
|
flags |= RTL818X_TX_DESC_FLAG_MOREFRAG;
|
|
- if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
|
|
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
|
|
flags |= RTL818X_TX_DESC_FLAG_RTS;
|
|
flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
|
|
rts_dur = ieee80211_rts_duration(dev, priv->vif,
|
|
skb->len, info);
|
|
- } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
|
|
+ } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
|
|
flags |= RTL818X_TX_DESC_FLAG_CTS;
|
|
flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
|
|
}
|
|
@@ -208,7 +208,7 @@ static int rtl8187_tx(struct ieee80211_h
|
|
hdr->flags = cpu_to_le32(flags);
|
|
hdr->len = 0;
|
|
hdr->rts_duration = rts_dur;
|
|
- hdr->retry = cpu_to_le32(info->control.retry_limit << 8);
|
|
+ hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8);
|
|
buf = hdr;
|
|
|
|
ep = 2;
|
|
@@ -226,7 +226,7 @@ static int rtl8187_tx(struct ieee80211_h
|
|
memset(hdr, 0, sizeof(*hdr));
|
|
hdr->flags = cpu_to_le32(flags);
|
|
hdr->rts_duration = rts_dur;
|
|
- hdr->retry = cpu_to_le32(info->control.retry_limit << 8);
|
|
+ hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8);
|
|
hdr->tx_duration =
|
|
ieee80211_generic_frame_duration(dev, priv->vif,
|
|
skb->len, txrate);
|
|
--- a/drivers/net/wireless/p54/p54common.c
|
|
+++ b/drivers/net/wireless/p54/p54common.c
|
|
@@ -577,7 +577,7 @@ static void p54_rx_frame_sent(struct iee
|
|
__skb_unlink(entry, &priv->tx_queue);
|
|
spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
|
|
|
|
- memset(&info->status, 0, sizeof(info->status));
|
|
+ ieee80211_tx_info_clear_status(info);
|
|
entry_hdr = (struct p54_control_hdr *) entry->data;
|
|
entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data;
|
|
if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0)
|
|
@@ -587,10 +587,8 @@ static void p54_rx_frame_sent(struct iee
|
|
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
|
|
if (!(payload->status & 0x01))
|
|
info->flags |= IEEE80211_TX_STAT_ACK;
|
|
- else
|
|
- info->status.excessive_retries = 1;
|
|
}
|
|
- info->status.retry_count = payload->retries - 1;
|
|
+ info->status.rates[0].count = payload->retries;
|
|
info->status.ack_signal = p54_rssi_to_dbm(dev,
|
|
le16_to_cpu(payload->ack_rssi));
|
|
skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
|
|
@@ -816,6 +814,7 @@ static int p54_tx(struct ieee80211_hw *d
|
|
size_t padding, len;
|
|
u8 rate;
|
|
u8 cts_rate = 0x20;
|
|
+ u8 rc_flags;
|
|
|
|
current_queue = &priv->tx_stats[skb_get_queue_mapping(skb) + 4];
|
|
if (unlikely(current_queue->len > current_queue->limit))
|
|
@@ -838,18 +837,19 @@ static int p54_tx(struct ieee80211_hw *d
|
|
hdr->magic1 = cpu_to_le16(0x0010);
|
|
hdr->len = cpu_to_le16(len);
|
|
hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1);
|
|
- hdr->retry1 = hdr->retry2 = info->control.retry_limit;
|
|
+ hdr->retry1 = hdr->retry2 = info->control.rates[0].count;
|
|
|
|
/* TODO: add support for alternate retry TX rates */
|
|
rate = ieee80211_get_tx_rate(dev, info)->hw_value;
|
|
- if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) {
|
|
+ rc_flags = info->control.rates[0].flags;
|
|
+ if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) {
|
|
rate |= 0x10;
|
|
cts_rate |= 0x10;
|
|
}
|
|
- if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
|
|
+ if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
|
|
rate |= 0x40;
|
|
cts_rate |= ieee80211_get_rts_cts_rate(dev, info)->hw_value;
|
|
- } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
|
|
+ } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
|
|
rate |= 0x20;
|
|
cts_rate |= ieee80211_get_rts_cts_rate(dev, info)->hw_value;
|
|
}
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
|
|
@@ -619,10 +619,10 @@ static void iwl4965_gain_computation(str
|
|
static void iwl4965_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
|
|
__le32 *tx_flags)
|
|
{
|
|
- if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
|
|
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
|
|
*tx_flags |= TX_CMD_FLG_RTS_MSK;
|
|
*tx_flags &= ~TX_CMD_FLG_CTS_MSK;
|
|
- } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
|
|
+ } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
|
|
*tx_flags &= ~TX_CMD_FLG_RTS_MSK;
|
|
*tx_flags |= TX_CMD_FLG_CTS_MSK;
|
|
}
|
|
@@ -2070,7 +2070,7 @@ static int iwl4965_tx_status_reply_tx(st
|
|
agg->frame_count, agg->start_idx, idx);
|
|
|
|
info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
|
|
- info->status.retry_count = tx_resp->failure_frame;
|
|
+ info->status.rates[0].count = tx_resp->failure_frame + 1;
|
|
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
|
|
info->flags |= iwl_is_tx_success(status)?
|
|
IEEE80211_TX_STAT_ACK : 0;
|
|
@@ -2227,7 +2227,7 @@ static void iwl4965_rx_reply_tx(struct i
|
|
iwl_txq_check_empty(priv, sta_id, tid, txq_id);
|
|
}
|
|
} else {
|
|
- info->status.retry_count = tx_resp->failure_frame;
|
|
+ info->status.rates[0].count = tx_resp->failure_frame + 1;
|
|
info->flags |=
|
|
iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0;
|
|
iwl_hwrate_to_tx_control(priv,
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
|
|
@@ -390,8 +390,8 @@ static void iwl5000_chain_noise_reset(st
|
|
static void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
|
|
__le32 *tx_flags)
|
|
{
|
|
- if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
|
|
- (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT))
|
|
+ if ((info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
|
|
+ (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
|
|
*tx_flags |= TX_CMD_FLG_RTS_CTS_MSK;
|
|
else
|
|
*tx_flags &= ~TX_CMD_FLG_RTS_CTS_MSK;
|
|
@@ -1136,7 +1136,7 @@ static int iwl5000_tx_status_reply_tx(st
|
|
agg->frame_count, agg->start_idx, idx);
|
|
|
|
info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
|
|
- info->status.retry_count = tx_resp->failure_frame;
|
|
+ info->status.rates[0].count = tx_resp->failure_frame + 1;
|
|
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
|
|
info->flags |= iwl_is_tx_success(status)?
|
|
IEEE80211_TX_STAT_ACK : 0;
|
|
@@ -1289,7 +1289,7 @@ static void iwl5000_rx_reply_tx(struct i
|
|
iwl_txq_check_empty(priv, sta_id, tid, txq_id);
|
|
}
|
|
} else {
|
|
- info->status.retry_count = tx_resp->failure_frame;
|
|
+ info->status.rates[0].count = tx_resp->failure_frame + 1;
|
|
info->flags =
|
|
iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0;
|
|
iwl_hwrate_to_tx_control(priv,
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
|
|
@@ -800,7 +800,7 @@ static void rs_tx_status(void *priv_r, s
|
|
!(info->flags & IEEE80211_TX_STAT_AMPDU))
|
|
return;
|
|
|
|
- retries = info->status.retry_count;
|
|
+ retries = info->status.rates[0].count + 1;
|
|
|
|
if (retries > 15)
|
|
retries = 15;
|
|
@@ -832,20 +832,15 @@ static void rs_tx_status(void *priv_r, s
|
|
if (priv->band == IEEE80211_BAND_5GHZ)
|
|
rs_index -= IWL_FIRST_OFDM_RATE;
|
|
|
|
- if ((info->tx_rate_idx < 0) ||
|
|
- (tbl_type.is_SGI ^
|
|
- !!(info->flags & IEEE80211_TX_CTL_SHORT_GI)) ||
|
|
- (tbl_type.is_fat ^
|
|
- !!(info->flags & IEEE80211_TX_CTL_40_MHZ_WIDTH)) ||
|
|
- (tbl_type.is_dup ^
|
|
- !!(info->flags & IEEE80211_TX_CTL_DUP_DATA)) ||
|
|
- (tbl_type.ant_type ^ info->antenna_sel_tx) ||
|
|
- (!!(tx_rate & RATE_MCS_HT_MSK) ^
|
|
- !!(info->flags & IEEE80211_TX_CTL_OFDM_HT)) ||
|
|
- (!!(tx_rate & RATE_MCS_GF_MSK) ^
|
|
- !!(info->flags & IEEE80211_TX_CTL_GREEN_FIELD)) ||
|
|
+ if ((info->status.rates[0].idx < 0) ||
|
|
+ (tbl_type.is_SGI != !!(info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) ||
|
|
+ (tbl_type.is_fat != !!(info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) ||
|
|
+ (tbl_type.is_dup != !!(info->status.rates[0].flags & IEEE80211_TX_RC_DUP_DATA)) ||
|
|
+ (tbl_type.ant_type != info->antenna_sel_tx) ||
|
|
+ (!!(tx_rate & RATE_MCS_HT_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) ||
|
|
+ (!!(tx_rate & RATE_MCS_GF_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD)) ||
|
|
(hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate !=
|
|
- hw->wiphy->bands[info->band]->bitrates[info->tx_rate_idx].bitrate)) {
|
|
+ hw->wiphy->bands[info->band]->bitrates[info->status.rates[0].idx].bitrate)) {
|
|
IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate);
|
|
goto out;
|
|
}
|
|
@@ -2103,15 +2098,17 @@ static void rs_initialize_lq(struct iwl_
|
|
return;
|
|
}
|
|
|
|
-static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
|
|
- struct ieee80211_sta *sta, void *priv_sta,
|
|
- struct sk_buff *skb, struct rate_selection *sel)
|
|
+static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
|
|
+ struct ieee80211_tx_rate_control *txrc)
|
|
{
|
|
|
|
int i;
|
|
+ struct sk_buff *skb = txrc->skb;
|
|
+ struct ieee80211_supported_band *sband = txrc->sband;
|
|
struct iwl_priv *priv = (struct iwl_priv *)priv_r;
|
|
struct ieee80211_conf *conf = &priv->hw->conf;
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
|
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
__le16 fc;
|
|
struct iwl_lq_sta *lq_sta;
|
|
|
|
@@ -2122,7 +2119,7 @@ static void rs_get_rate(void *priv_r, st
|
|
fc = hdr->frame_control;
|
|
if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) ||
|
|
!sta || !priv_sta) {
|
|
- sel->rate_idx = rate_lowest_index(sband, sta);
|
|
+ info->control.rates[0].idx = rate_lowest_index(sband, sta);
|
|
return;
|
|
}
|
|
|
|
@@ -2149,13 +2146,13 @@ static void rs_get_rate(void *priv_r, st
|
|
}
|
|
|
|
if ((i < 0) || (i > IWL_RATE_COUNT)) {
|
|
- sel->rate_idx = rate_lowest_index(sband, sta);
|
|
+ info->control.rates[0].idx = rate_lowest_index(sband, sta);
|
|
return;
|
|
}
|
|
|
|
if (sband->band == IEEE80211_BAND_5GHZ)
|
|
i -= IWL_FIRST_OFDM_RATE;
|
|
- sel->rate_idx = i;
|
|
+ info->control.rates[0].idx = i;
|
|
}
|
|
|
|
static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
|