diff options
Diffstat (limited to 'package/mac80211')
| -rw-r--r-- | package/mac80211/Makefile | 4 | ||||
| -rw-r--r-- | package/mac80211/patches/100-define.patch | 14 | ||||
| -rw-r--r-- | package/mac80211/patches/110-ath5k_stat.patch | 6 | ||||
| -rw-r--r-- | package/mac80211/patches/200-hwkey_len.patch | 183 | ||||
| -rw-r--r-- | package/mac80211/patches/200-minstrel_default.patch (renamed from package/mac80211/patches/299-compat_minstrel.patch) | 2 | ||||
| -rw-r--r-- | package/mac80211/patches/210-mrr.patch | 183 | ||||
| -rw-r--r-- | package/mac80211/patches/210-remove_unused_stuff.patch | 44 | ||||
| -rw-r--r-- | package/mac80211/patches/250-ath5k_mrr.patch | 208 | ||||
| -rw-r--r-- | package/mac80211/patches/300-minstrel.patch | 928 | ||||
| -rw-r--r-- | package/mac80211/patches/300-minstrel_no_mrr.patch | 31 | ||||
| -rw-r--r-- | package/mac80211/patches/310-b43_txstatus.patch | 98 | 
11 files changed, 179 insertions, 1522 deletions
diff --git a/package/mac80211/Makefile b/package/mac80211/Makefile index cd1feed8c..3d5960363 100644 --- a/package/mac80211/Makefile +++ b/package/mac80211/Makefile @@ -13,8 +13,8 @@ PKG_NAME:=mac80211  PKG_RELEASE:=1  ifneq ($(CONFIG_LINUX_2_6_27),) -  PKG_VERSION:=2008-09-28 -  PKG_SOURCE_URL:=http://www.orbit-lab.org/kernel/compat-wireless-2.6/2008/09 +  PKG_VERSION:=2008-10-08 +  PKG_SOURCE_URL:=http://www.orbit-lab.org/kernel/compat-wireless-2.6/2008/10  else    PKG_VERSION:=2008-08-06    PKG_SOURCE_URL:=http://www.orbit-lab.org/kernel/compat-wireless-2.6/2008/08 diff --git a/package/mac80211/patches/100-define.patch b/package/mac80211/patches/100-define.patch deleted file mode 100644 index b41cad694..000000000 --- a/package/mac80211/patches/100-define.patch +++ /dev/null @@ -1,14 +0,0 @@ ---- a/include/net/compat.h -+++ b/include/net/compat.h -@@ -6,6 +6,11 @@ - #include <linux/compat_autoconf.h> -  - #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)) -+#include <linux/if_ether.h> -+ -+#ifndef ETH_P_PAE -+#define ETH_P_PAE 0x888E      /* Port Access Entity (IEEE 802.1X) */ -+#endif - #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)) */ -  - #endif /* LINUX_26_COMPAT_H */ diff --git a/package/mac80211/patches/110-ath5k_stat.patch b/package/mac80211/patches/110-ath5k_stat.patch index 2cd954851..2c8d2f98b 100644 --- a/package/mac80211/patches/110-ath5k_stat.patch +++ b/package/mac80211/patches/110-ath5k_stat.patch @@ -5,7 +5,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>  --- a/drivers/net/wireless/ath5k/base.c  +++ b/drivers/net/wireless/ath5k/base.c -@@ -707,19 +707,6 @@ +@@ -724,19 +724,6 @@ ath5k_attach(struct pci_dev *pdev, struc   	ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device);   	/* @@ -27,7 +27,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>   	 */  --- a/drivers/net/wireless/ath5k/base.h  +++ b/drivers/net/wireless/ath5k/base.h -@@ -99,6 +99,12 @@ +@@ -99,6 +99,12 @@ struct ath5k_led   #define ATH_CHAN_MAX	(14+14+14+252+20)   #endif @@ -40,7 +40,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>   /* Software Carrier, keeps track of the driver state    * associated with an instance of a device */   struct ath5k_softc { -@@ -129,10 +135,6 @@ +@@ -129,10 +135,6 @@ struct ath5k_softc {   	u16			cachelsz;	/* cache line size */   	DECLARE_BITMAP(status, 4); diff --git a/package/mac80211/patches/200-hwkey_len.patch b/package/mac80211/patches/200-hwkey_len.patch deleted file mode 100644 index 20deeb778..000000000 --- a/package/mac80211/patches/200-hwkey_len.patch +++ /dev/null @@ -1,183 +0,0 @@ -Free up 2 bytes in skb->cb to be used for multi-rate retry later. -Move iv_len and icv_len initialization into key alloc. - -Signed-off-by: Felix Fietkau <nbd@openwrt.org> - ---- a/include/net/mac80211.h -+++ b/include/net/mac80211.h -@@ -337,8 +337,6 @@ - 			unsigned long jiffies; - 			s8 rts_cts_rate_idx, alt_retry_rate_idx; - 			u8 retry_limit; --			u8 icv_len; --			u8 iv_len; - 		} control; - 		struct { - 			u64 ampdu_ack_map; -@@ -635,6 +633,8 @@ -  */ - struct ieee80211_key_conf { - 	enum ieee80211_key_alg alg; -+	u8 icv_len; -+	u8 iv_len; - 	u8 hw_key_idx; - 	u8 flags; - 	s8 keyidx; ---- a/drivers/net/wireless/b43/xmit.c -+++ b/drivers/net/wireless/b43/xmit.c -@@ -252,7 +252,7 @@ - 		} -  - 		/* Hardware appends ICV. */ --		plcp_fragment_len += info->control.icv_len; -+		plcp_fragment_len += info->control.hw_key->icv_len; -  - 		key_idx = b43_kidx_to_fw(dev, key_idx); - 		mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) & -@@ -260,7 +260,7 @@ - 		mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) & - 			   B43_TXH_MAC_KEYALG; - 		wlhdr_len = ieee80211_hdrlen(fctl); --		iv_len = min((size_t) info->control.iv_len, -+		iv_len = min((size_t) info->control.hw_key->iv_len, - 			     ARRAY_SIZE(txhdr->iv)); - 		memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); - 	} ---- a/drivers/net/wireless/b43legacy/xmit.c -+++ b/drivers/net/wireless/b43legacy/xmit.c -@@ -243,7 +243,7 @@ -  - 		if (key->enabled) { - 			/* Hardware appends ICV. */ --			plcp_fragment_len += info->control.icv_len; -+			plcp_fragment_len += info->control.hw_key->icv_len; -  - 			key_idx = b43legacy_kidx_to_fw(dev, key_idx); - 			mac_ctl |= (key_idx << B43legacy_TX4_MAC_KEYIDX_SHIFT) & -@@ -252,7 +252,7 @@ - 				   B43legacy_TX4_MAC_KEYALG_SHIFT) & - 				   B43legacy_TX4_MAC_KEYALG; - 			wlhdr_len = ieee80211_hdrlen(wlhdr->frame_control); --			iv_len = min((size_t)info->control.iv_len, -+			iv_len = min((size_t)info->control.hw_key->iv_len, - 				     ARRAY_SIZE(txhdr->iv)); - 			memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len); - 		} else { ---- a/net/mac80211/wep.c -+++ b/net/mac80211/wep.c -@@ -313,9 +313,6 @@ - { - 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -  --	info->control.iv_len = WEP_IV_LEN; --	info->control.icv_len = WEP_ICV_LEN; -- - 	if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { - 		if (ieee80211_wep_encrypt(tx->local, skb, tx->key)) - 			return -1; ---- a/net/mac80211/wpa.c -+++ b/net/mac80211/wpa.c -@@ -152,9 +152,6 @@ - 	int len, tail; - 	u8 *pos; -  --	info->control.icv_len = TKIP_ICV_LEN; --	info->control.iv_len = TKIP_IV_LEN; -- - 	if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && - 	    !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { - 		/* hwaccel - with no need for preallocated room for IV/ICV */ -@@ -374,9 +371,6 @@ - 	u8 *pos, *pn; - 	int i; -  --	info->control.icv_len = CCMP_MIC_LEN; --	info->control.iv_len = CCMP_HDR_LEN; -- - 	if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && - 	    !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { - 		/* hwaccel - with no need for preallocated room for CCMP " ---- a/drivers/net/wireless/ath5k/base.c -+++ b/drivers/net/wireless/ath5k/base.c -@@ -1164,7 +1164,7 @@ -  - 	if (info->control.hw_key) { - 		keyidx = info->control.hw_key->hw_key_idx; --		pktlen += info->control.icv_len; -+		pktlen += info->control.hw_key->icv_len; - 	} - 	ret = ah->ah_setup_tx_desc(ah, ds, pktlen, - 		ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, ---- a/drivers/net/wireless/ath9k/xmit.c -+++ b/drivers/net/wireless/ath9k/xmit.c -@@ -237,7 +237,7 @@ -  - 	if (tx_info->control.hw_key) { - 		txctl->keyix = tx_info->control.hw_key->hw_key_idx; --		txctl->frmlen += tx_info->control.icv_len; -+		txctl->frmlen += tx_info->control.hw_key->icv_len; -  - 		if (tx_info->control.hw_key->alg == ALG_WEP) - 			txctl->keytype = ATH9K_KEY_TYPE_WEP; ---- a/drivers/net/wireless/rt2x00/rt2x00crypto.c -+++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c -@@ -56,10 +56,10 @@ - 	 * note that these lengths should only be added when - 	 * mac80211 does not generate it. - 	 */ --	overhead += tx_info->control.icv_len; -+	overhead += key->icv_len; -  - 	if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) --		overhead += tx_info->control.iv_len; -+		overhead += key->iv_len; -  - 	if (!(key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) { - 		if (key->alg == ALG_TKIP) ---- a/drivers/net/wireless/rt2x00/rt2x00queue.c -+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c -@@ -374,7 +374,7 @@ - 	struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); - 	struct txentry_desc txdesc; - 	struct skb_frame_desc *skbdesc; --	unsigned int iv_len = IEEE80211_SKB_CB(skb)->control.iv_len; -+	unsigned int iv_len; -  - 	if (unlikely(rt2x00queue_full(queue))) - 		return -EINVAL; -@@ -410,8 +410,11 @@ - 	 * the frame so we can provide it to the driver seperately. - 	 */ - 	if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) && --	    !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) -+	    !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags) && -+		(IEEE80211_SKB_CB(skb)->control.hw_key != NULL)) { -+		iv_len = IEEE80211_SKB_CB(skb)->control.hw_key->iv_len; - 		rt2x00crypto_tx_remove_iv(skb, iv_len); -+	} -  - 	/* - 	 * It could be possible that the queue was corrupted and this ---- a/net/mac80211/key.c -+++ b/net/mac80211/key.c -@@ -281,6 +281,20 @@ - 	key->conf.alg = alg; - 	key->conf.keyidx = idx; - 	key->conf.keylen = key_len; -+	switch (alg) { -+	case ALG_WEP: -+		key->conf.iv_len = WEP_IV_LEN; -+		key->conf.icv_len = WEP_ICV_LEN; -+		break; -+	case ALG_TKIP: -+		key->conf.iv_len = TKIP_IV_LEN; -+		key->conf.icv_len = TKIP_ICV_LEN; -+		break; -+	case ALG_CCMP: -+		key->conf.iv_len = CCMP_HDR_LEN; -+		key->conf.icv_len = CCMP_MIC_LEN; -+		break; -+	} - 	memcpy(key->conf.key, key_data, key_len); - 	INIT_LIST_HEAD(&key->list); - 	INIT_LIST_HEAD(&key->todo); diff --git a/package/mac80211/patches/299-compat_minstrel.patch b/package/mac80211/patches/200-minstrel_default.patch index 01b01609b..6d6e72839 100644 --- a/package/mac80211/patches/299-compat_minstrel.patch +++ b/package/mac80211/patches/200-minstrel_default.patch @@ -1,6 +1,6 @@  --- a/config.mk  +++ b/config.mk -@@ -47,8 +47,9 @@ +@@ -47,8 +47,9 @@ endif   endif # build check   endif # kernel Makefile check diff --git a/package/mac80211/patches/210-mrr.patch b/package/mac80211/patches/210-mrr.patch deleted file mode 100644 index 389478824..000000000 --- a/package/mac80211/patches/210-mrr.patch +++ /dev/null @@ -1,183 +0,0 @@ -This patch adjusts the rate control API to allow multi-rate retry -if supported by the driver. The ieee80211_hw struct specifies how -many alternate rate selections the driver supports. - -Signed-off-by: Felix Fietkau <nbd@openwrt.org> - ---- a/include/net/mac80211.h -+++ b/include/net/mac80211.h -@@ -292,6 +292,20 @@ - #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 -+ -+/** -+ * struct ieee80211_tx_altrate - alternate rate selection/status -+ * -+ * @rate_idx: rate index to attempt to send with -+ * @limit: number of retries before fallback -+ */ -+struct ieee80211_tx_altrate { -+	s8 rate_idx; -+	u8 limit; -+}; -+ - /** -  * struct ieee80211_tx_info - skb transmit information -  * -@@ -335,12 +349,14 @@ - 			struct ieee80211_key_conf *hw_key; - 			struct ieee80211_sta *sta; - 			unsigned long jiffies; --			s8 rts_cts_rate_idx, alt_retry_rate_idx; -+			s8 rts_cts_rate_idx; - 			u8 retry_limit; -+			struct ieee80211_tx_altrate retries[IEEE80211_TX_MAX_ALTRATE]; - 		} control; - 		struct { - 			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; -@@ -828,6 +844,9 @@ -  *	within &struct ieee80211_vif. -  * @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 -  */ - struct ieee80211_hw { - 	struct ieee80211_conf conf; -@@ -844,6 +863,8 @@ - 	u16 ampdu_queues; - 	u16 max_listen_interval; - 	s8 max_signal; -+	u8 max_altrates; -+	u8 max_altrate_tries; - }; -  - struct ieee80211_hw *wiphy_to_hw(struct wiphy *wiphy); -@@ -900,11 +921,11 @@ -  - static inline struct ieee80211_rate * - ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, --			     const struct ieee80211_tx_info *c) -+			     const struct ieee80211_tx_info *c, int idx) - { --	if (c->control.alt_retry_rate_idx < 0) -+	if (c->control.retries[idx].rate_idx < 0) - 		return NULL; --	return &hw->wiphy->bands[c->band]->bitrates[c->control.alt_retry_rate_idx]; -+	return &hw->wiphy->bands[c->band]->bitrates[c->control.retries[idx].rate_idx]; - } -  - /** ---- a/drivers/net/wireless/b43/xmit.c -+++ b/drivers/net/wireless/b43/xmit.c -@@ -208,7 +208,7 @@ - 	txrate = ieee80211_get_tx_rate(dev->wl->hw, info); - 	rate = txrate ? txrate->hw_value : B43_CCK_RATE_1MB; - 	rate_ofdm = b43_is_ofdm_rate(rate); --	fbrate = ieee80211_get_alt_retry_rate(dev->wl->hw, info) ? : txrate; -+	fbrate = ieee80211_get_alt_retry_rate(dev->wl->hw, info, 0) ? : txrate; - 	rate_fb = fbrate->hw_value; - 	rate_fb_ofdm = b43_is_ofdm_rate(rate_fb); -  ---- a/drivers/net/wireless/b43legacy/xmit.c -+++ b/drivers/net/wireless/b43legacy/xmit.c -@@ -210,7 +210,7 @@ -  - 	rate = tx_rate->hw_value; - 	rate_ofdm = b43legacy_is_ofdm_rate(rate); --	rate_fb = ieee80211_get_alt_retry_rate(dev->wl->hw, info) ? : tx_rate; -+	rate_fb = ieee80211_get_alt_retry_rate(dev->wl->hw, info, 0) ? : tx_rate; - 	rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb->hw_value); -  - 	txhdr->mac_frame_ctl = wlhdr->frame_control; ---- a/drivers/net/wireless/rtl8180_dev.c -+++ b/drivers/net/wireless/rtl8180_dev.c -@@ -292,8 +292,8 @@ - 	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.alt_retry_rate_idx >= 0 ? --		ieee80211_get_alt_retry_rate(dev, info)->bitrate << 4 : 0; -+	entry->flags2 = info->control.retries[0].rate_idx >= 0 ? -+		ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0; - 	entry->retry_limit = info->control.retry_limit; - 	entry->flags = cpu_to_le32(tx_flags); - 	__skb_queue_tail(&ring->queue, skb); -@@ -855,6 +855,7 @@ - 	priv = dev->priv; - 	priv->pdev = pdev; -  -+	dev->max_altrates = 1; - 	SET_IEEE80211_DEV(dev, &pdev->dev); - 	pci_set_drvdata(pdev, dev); -  ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -454,15 +454,16 @@ - 		if (unlikely(rsel.probe_idx >= 0)) { - 			info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; - 			tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG; --			info->control.alt_retry_rate_idx = tx->rate_idx; -+			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 --			info->control.alt_retry_rate_idx = -1; -+		} else if (info->control.retries[0].limit == 0) -+			info->control.retries[0].rate_idx = -1; -  - 		if (unlikely(tx->rate_idx < 0)) - 			return TX_DROP; - 	} else --		info->control.alt_retry_rate_idx = -1; -+		info->control.retries[0].rate_idx = -1; -  - 	if (tx->sdata->bss_conf.use_cts_prot && - 	    (tx->flags & IEEE80211_TX_FRAGMENTED) && (rsel.nonerp_idx >= 0)) { -@@ -521,7 +522,7 @@ - 		 * frames. - 		 * TODO: The last fragment could still use multiple retry - 		 * rates. */ --		info->control.alt_retry_rate_idx = -1; -+		info->control.retries[0].rate_idx = -1; - 	} -  - 	/* Use CTS protection for unicast frames sent using extended rates if -@@ -551,7 +552,7 @@ - 		int idx; -  - 		/* Do not use multiple retry rates when using RTS/CTS */ --		info->control.alt_retry_rate_idx = -1; -+		info->control.retries[0].rate_idx = -1; -  - 		/* Use min(data rate, max base rate) as CTS/RTS rate */ - 		rate = &sband->bitrates[tx->rate_idx]; ---- a/drivers/net/wireless/b43/main.c -+++ b/drivers/net/wireless/b43/main.c -@@ -4588,6 +4588,7 @@ - 		BIT(NL80211_IFTYPE_ADHOC); -  - 	hw->queues = b43_modparam_qos ? 4 : 1; -+	hw->max_altrates = 1; - 	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/main.c -+++ b/drivers/net/wireless/b43legacy/main.c -@@ -3710,6 +3710,7 @@ - 		BIT(NL80211_IFTYPE_WDS) | - 		BIT(NL80211_IFTYPE_ADHOC); - 	hw->queues = 1; /* FIXME: hardware has more queues */ -+	hw->max_altrates = 1; - 	SET_IEEE80211_DEV(hw, dev->dev); - 	if (is_valid_ether_addr(sprom->et1mac)) - 		SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac); diff --git a/package/mac80211/patches/210-remove_unused_stuff.patch b/package/mac80211/patches/210-remove_unused_stuff.patch new file mode 100644 index 000000000..044dc837e --- /dev/null +++ b/package/mac80211/patches/210-remove_unused_stuff.patch @@ -0,0 +1,44 @@ +--- a/config.mk ++++ b/config.mk +@@ -99,12 +99,12 @@ CONFIG_B43LEGACY_PIO=y + CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y +  + # The Intel ipws +-CONFIG_IPW2100=m +-CONFIG_IPW2100_MONITOR=y +-CONFIG_IPW2200=m +-CONFIG_IPW2200_MONITOR=y +-CONFIG_IPW2200_RADIOTAP=y +-CONFIG_IPW2200_PROMISCUOUS=y ++# CONFIG_IPW2100=m ++# CONFIG_IPW2100_MONITOR=y ++# CONFIG_IPW2200=m ++# CONFIG_IPW2200_MONITOR=y ++# CONFIG_IPW2200_RADIOTAP=y ++# CONFIG_IPW2200_PROMISCUOUS=y + # The above enables use a second interface prefixed 'rtap'. + #           Example usage: + # +@@ -117,9 +117,9 @@ CONFIG_IPW2200_PROMISCUOUS=y + # it on via sysfs: + # + # % echo 1 > /sys/bus/pci/drivers/ipw2200/*/rtap_iface +-CONFIG_IPW2200_QOS=y ++# CONFIG_IPW2200_QOS=y +  +-NEED_IEEE80211=y ++# NEED_IEEE80211=y +  + CONFIG_P54_PCI=m +  +@@ -216,8 +216,8 @@ CONFIG_SSB_PCICORE_HOSTMODE=n + # CONFIG_SSB_DRIVER_EXTIF=y +  + ifneq ($(CONFIG_USB),) +-CONFIG_LIBERTAS_USB=m +-NEED_LIBERTAS=y ++#CONFIG_LIBERTAS_USB=m ++#NEED_LIBERTAS=y + endif + ifneq ($(CONFIG_PCMCIA),) + CONFIG_LIBERTAS_CS=m diff --git a/package/mac80211/patches/250-ath5k_mrr.patch b/package/mac80211/patches/250-ath5k_mrr.patch deleted file mode 100644 index ff15fd4b7..000000000 --- a/package/mac80211/patches/250-ath5k_mrr.patch +++ /dev/null @@ -1,208 +0,0 @@ -Clean up the tx status reporting, fix retry counters (short retries are -virtual collisions, not actual retries). Implement multi-rate retry -support. -This also fixes strong throughput fluctuations with rc80211_pid - -Signed-off-by: Felix Fietkau <nbd@openwrt.org> - ---- a/drivers/net/wireless/ath5k/base.c -+++ b/drivers/net/wireless/ath5k/base.c -@@ -530,6 +530,12 @@ - 		goto err_irq; - 	} -  -+	/* set up multi-rate retry capabilities */ -+	if (sc->ah->ah_version == AR5K_AR5212) { -+		hw->max_altrates = 3; -+		hw->max_altrate_tries = 11; -+	} -+ - 	/* Finish private driver data initialization */ - 	ret = ath5k_attach(pdev, hw); - 	if (ret) -@@ -1149,7 +1155,9 @@ - 	struct sk_buff *skb = bf->skb; - 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - 	unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID; --	int ret; -+	struct ieee80211_rate *rate; -+	unsigned int mrr_rate[3], mrr_tries[3]; -+	int i, ret; -  - 	flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK; -  -@@ -1174,6 +1182,22 @@ - 	if (ret) - 		goto err_unmap; -  -+	memset(mrr_rate, 0, sizeof(mrr_rate)); -+	memset(mrr_tries, 0, sizeof(mrr_tries)); -+	for (i = 0; i < 3; i++) { -+		rate = ieee80211_get_alt_retry_rate(sc->hw, info, i); -+		if (!rate) -+			break; -+ -+		mrr_rate[i] = rate->hw_value; -+		mrr_tries[i] = info->control.retries[i].limit; -+	} -+ -+	ah->ah_setup_mrr_tx_desc(ah, ds, -+		mrr_rate[0], mrr_tries[0], -+		mrr_rate[1], mrr_tries[1], -+		mrr_rate[2], mrr_tries[2]); -+ - 	ds->ds_link = 0; - 	ds->ds_data = bf->skbaddr; -  -@@ -1790,7 +1814,7 @@ - 	struct ath5k_desc *ds; - 	struct sk_buff *skb; - 	struct ieee80211_tx_info *info; --	int ret; -+	int i, ret; -  - 	spin_lock(&txq->lock); - 	list_for_each_entry_safe(bf, bf0, &txq->q, list) { -@@ -1812,7 +1836,25 @@ - 		pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, - 				PCI_DMA_TODEVICE); -  --		info->status.retry_count = ts.ts_shortretry + ts.ts_longretry / 6; -+		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; -+ -+		for (i = 0; i < 4; i++) { -+			struct ieee80211_tx_altrate *r = -+				&info->status.retries[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]; -+			} else { -+				r->rate_idx = -1; -+				r->limit = 0; -+			} -+		} -+ -+		info->status.excessive_retries = 0; - 		if (unlikely(ts.ts_status)) { - 			sc->ll_stats.dot11ACKFailureCount++; - 			if (ts.ts_status & AR5K_TXERR_XRETRY) ---- a/drivers/net/wireless/ath5k/desc.c -+++ b/drivers/net/wireless/ath5k/desc.c -@@ -318,6 +318,15 @@ - 	return 0; - } -  -+/* no mrr support for cards older than 5212 */ -+static int -+ath5k_hw_setup_no_mrr(struct ath5k_hw *ah, struct ath5k_desc *desc, -+	unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, -+	u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3) -+{ -+	return 0; -+} -+ - /* -  * Proccess the tx status descriptor on 5210/5211 -  */ -@@ -352,8 +361,10 @@ - 		AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); - 	ts->ts_antenna = 1; - 	ts->ts_status = 0; --	ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_0, -+	ts->ts_rate[0] = AR5K_REG_MS(tx_ctl->tx_control_0, - 		AR5K_2W_TX_DESC_CTL0_XMIT_RATE); -+	ts->ts_retry[0] = ts->ts_longretry; -+	ts->ts_final_idx = 0; -  - 	if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { - 		if (tx_status->tx_status_0 & -@@ -405,29 +416,43 @@ - 		AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1; - 	ts->ts_status = 0; -  --	switch (AR5K_REG_MS(tx_status->tx_status_1, --			AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX)) { --	case 0: --		ts->ts_rate = tx_ctl->tx_control_3 & --			AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; --		break; -+	ts->ts_final_idx = AR5K_REG_MS(tx_status->tx_status_1, -+			AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX); -+ -+	/* The longretry counter has the number of un-acked retries -+	 * for the final rate. To get the total number of retries -+	 * we have to add the retry counters for the other rates -+	 * as well -+	 */ -+	ts->ts_retry[ts->ts_final_idx] = ts->ts_longretry; -+	switch (ts->ts_final_idx) { -+	case 3: -+		ts->ts_rate[3] = AR5K_REG_MS(tx_ctl->tx_control_3, -+			AR5K_4W_TX_DESC_CTL3_XMIT_RATE3); -+ -+		ts->ts_retry[2] = AR5K_REG_MS(tx_ctl->tx_control_2, -+			AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); -+		ts->ts_longretry += ts->ts_retry[2]; -+		/* fall through */ -+	case 2: -+		ts->ts_rate[2] = AR5K_REG_MS(tx_ctl->tx_control_3, -+			AR5K_4W_TX_DESC_CTL3_XMIT_RATE2); -+ -+		ts->ts_retry[1] = AR5K_REG_MS(tx_ctl->tx_control_2, -+			AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); -+		ts->ts_longretry += ts->ts_retry[1]; -+		/* fall through */ - 	case 1: --		ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3, -+		ts->ts_rate[1] = AR5K_REG_MS(tx_ctl->tx_control_3, - 			AR5K_4W_TX_DESC_CTL3_XMIT_RATE1); --		ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2, -+ -+		ts->ts_retry[0] = AR5K_REG_MS(tx_ctl->tx_control_2, - 			AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); --		break; --	case 2: --		ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3, --			AR5K_4W_TX_DESC_CTL3_XMIT_RATE2); --		ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2, --			AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); --		break; --	case 3: --		ts->ts_rate = AR5K_REG_MS(tx_ctl->tx_control_3, --			AR5K_4W_TX_DESC_CTL3_XMIT_RATE3); --		ts->ts_longretry += AR5K_REG_MS(tx_ctl->tx_control_2, --			AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3); -+		ts->ts_longretry += ts->ts_retry[0]; -+		/* fall through */ -+	case 0: -+		ts->ts_rate[0] = tx_ctl->tx_control_3 & -+			AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; - 		break; - 	} -  -@@ -653,7 +678,7 @@ - 	} else { - 		ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc; - 		ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc; --		ah->ah_setup_mrr_tx_desc = ath5k_hw_setup_mrr_tx_desc; -+		ah->ah_setup_mrr_tx_desc = ath5k_hw_setup_no_mrr; - 		ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status; - 	} -  ---- a/drivers/net/wireless/ath5k/ath5k.h -+++ b/drivers/net/wireless/ath5k/ath5k.h -@@ -418,7 +418,9 @@ - 	u16	ts_seqnum; - 	u16	ts_tstamp; - 	u8	ts_status; --	u8	ts_rate; -+	u8	ts_rate[4]; -+	u8	ts_retry[4]; -+	u8	ts_final_idx; - 	s8	ts_rssi; - 	u8	ts_shortretry; - 	u8	ts_longretry; diff --git a/package/mac80211/patches/300-minstrel.patch b/package/mac80211/patches/300-minstrel.patch deleted file mode 100644 index ee1887a6c..000000000 --- a/package/mac80211/patches/300-minstrel.patch +++ /dev/null @@ -1,928 +0,0 @@ ---- /dev/null -+++ b/net/mac80211/rc80211_minstrel.c -@@ -0,0 +1,583 @@ -+/* -+ * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Based on minstrel.c: -+ *   Copyright (C) 2005-2007 Derek Smithies <derek@indranet.co.nz> -+ *   Sponsored by Indranet Technologies Ltd -+ * -+ * Based on sample.c: -+ *   Copyright (c) 2005 John Bicket -+ *   All rights reserved. -+ * -+ *   Redistribution and use in source and binary forms, with or without -+ *   modification, are permitted provided that the following conditions -+ *   are met: -+ *   1. Redistributions of source code must retain the above copyright -+ *      notice, this list of conditions and the following disclaimer, -+ *      without modification. -+ *   2. Redistributions in binary form must reproduce at minimum a disclaimer -+ *      similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any -+ *      redistribution must be conditioned upon including a substantially -+ *      similar Disclaimer requirement for further binary redistribution. -+ *   3. Neither the names of the above-listed copyright holders nor the names -+ *      of any contributors may be used to endorse or promote products derived -+ *      from this software without specific prior written permission. -+ * -+ *   Alternatively, this software may be distributed under the terms of the -+ *   GNU General Public License ("GPL") version 2 as published by the Free -+ *   Software Foundation. -+ * -+ *   NO WARRANTY -+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -+ *   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -+ *   LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY -+ *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -+ *   THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, -+ *   OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ *   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -+ *   IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ *   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -+ *   THE POSSIBILITY OF SUCH DAMAGES. -+ */ -+#include <linux/netdevice.h> -+#include <linux/types.h> -+#include <linux/skbuff.h> -+#include <linux/debugfs.h> -+#include <linux/random.h> -+#include <linux/ieee80211.h> -+#include <net/mac80211.h> -+#include "rate.h" -+#include "rc80211_minstrel.h" -+ -+#define SAMPLE_COLUMNS	10 -+#define SAMPLE_TBL(_mi, _idx, _col) \ -+		_mi->sample_table[(_idx * SAMPLE_COLUMNS) + _col] -+ -+/* convert mac80211 rate index to local array index */ -+static inline int -+rix_to_ndx(struct minstrel_sta_info *mi, int rix) -+{ -+	int i = rix; -+	for (i = rix; i >= 0; i--) -+		if (mi->r[i].rix == rix) -+			break; -+	WARN_ON(mi->r[i].rix != rix); -+	return i; -+} -+ -+static inline bool -+use_low_rate(struct sk_buff *skb) -+{ -+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; -+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -+	u16 fc; -+ -+	fc = le16_to_cpu(hdr->frame_control); -+ -+	return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || -+		(fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || -+		is_multicast_ether_addr(hdr->addr1)); -+} -+ -+ -+static void -+minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) -+{ -+	u32 max_tp = 0, index_max_tp = 0, index_max_tp2 = 0; -+	u32 max_prob = 0, index_max_prob = 0; -+	u32 usecs; -+	u32 p; -+	int i; -+ -+	mi->stats_update = jiffies; -+	for (i = 0; i < mi->n_rates; i++) { -+		struct minstrel_rate *mr = &mi->r[i]; -+ -+		usecs = mr->perfect_tx_time; -+		if (!usecs) -+			usecs = 1000000; -+ -+		/* To avoid rounding issues, probabilities scale from 0 (0%) -+		 * to 18000 (100%) */ -+		if (mr->attempts) { -+			p = (mr->success * 18000) / mr->attempts; -+			mr->succ_hist += mr->success; -+			mr->att_hist += mr->attempts; -+			mr->cur_prob = p; -+			p = ((p * (100 - mp->ewma_level)) + (mr->probability * -+				mp->ewma_level)) / 100; -+			mr->probability = p; -+			mr->cur_tp = p * (1000000 / usecs); -+		} -+ -+		mr->last_success = mr->success; -+		mr->last_attempts = mr->attempts; -+		mr->success = 0; -+		mr->attempts = 0; -+ -+		/* Sample less often below the 10% chance of success. -+		 * Sample less often above the 95% chance of success. */ -+		if ((mr->probability > 17100) || (mr->probability < 1800)) { -+			mr->adjusted_retry_count = mr->retry_count >> 1; -+			if (mr->adjusted_retry_count > 2) -+				mr->adjusted_retry_count = 2; -+		} else { -+			mr->adjusted_retry_count = mr->retry_count; -+		} -+		if (!mr->adjusted_retry_count) -+			mr->adjusted_retry_count = 2; -+	} -+ -+	for (i = 0; i < mi->n_rates; i++) { -+		struct minstrel_rate *mr = &mi->r[i]; -+		if (max_tp < mr->cur_tp) { -+			index_max_tp = i; -+			max_tp = mr->cur_tp; -+		} -+		if (max_prob < mr->probability) { -+			index_max_prob = i; -+			max_prob = mr->probability; -+		} -+	} -+ -+	max_tp = 0; -+	for (i = 0; i < mi->n_rates; i++) { -+		struct minstrel_rate *mr = &mi->r[i]; -+ -+		if (i == index_max_tp) -+			continue; -+ -+		if (max_tp < mr->cur_tp) { -+			index_max_tp2 = i; -+			max_tp = mr->cur_tp; -+		} -+	} -+	mi->max_tp_rate = index_max_tp; -+	mi->max_tp_rate2 = index_max_tp2; -+	mi->max_prob_rate = index_max_prob; -+} -+ -+static void -+minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, -+                   struct ieee80211_sta *sta, void *priv_sta, -+		   struct sk_buff *skb) -+{ -+	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; -+ -+	if (!info->status.excessive_retries) -+		success = 1; -+ -+	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) -+			break; -+ -+		ndx = rix_to_ndx(mi, ar[i].rate_idx); -+		mi->r[ndx].attempts += ar[i].limit + 1; -+ -+		if ((i != 3) && (ar[i + 1].rate_idx < 0)) -+			mi->r[ndx].success += success; -+	} -+ -+	if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && (i >= 0)) -+		mi->sample_count++; -+ -+	if (mi->sample_deferred > 0) -+		mi->sample_deferred--; -+} -+ -+ -+static inline unsigned int -+minstrel_get_retry_count(struct minstrel_rate *mr, -+                         struct ieee80211_tx_info *info) -+{ -+	unsigned int retry = mr->adjusted_retry_count; -+ -+	if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) -+		retry = max(2U, min(mr->retry_count_rtscts, retry)); -+	else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) -+		retry = max(2U, min(mr->retry_count_cts, retry)); -+	return retry; -+} -+ -+ -+static int -+minstrel_get_next_sample(struct minstrel_sta_info *mi) -+{ -+	unsigned int sample_ndx; -+	sample_ndx = SAMPLE_TBL(mi, mi->sample_idx, mi->sample_column); -+	mi->sample_idx++; -+	if (mi->sample_idx > (mi->n_rates - 2)) { -+		mi->sample_idx = 0; -+		mi->sample_column++; -+		if (mi->sample_column >= SAMPLE_COLUMNS) -+			mi->sample_column = 0; -+	} -+	return sample_ndx; -+} -+ -+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) -+{ -+	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; -+	unsigned int ndx, sample_ndx = 0; -+	bool mrr; -+	bool sample_slower = false; -+	bool sample = false; -+	int i, delta; -+	int mrr_ndx[3]; -+	int sample_rate; -+ -+	if (!sta || !mi || use_low_rate(skb)) { -+		sel->rate_idx = rate_lowest_index(sband, sta); -+		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; -+ -+	if (time_after(jiffies, mi->stats_update + (mp->update_interval * -+			HZ) / 1000)) -+		minstrel_update_stats(mp, mi); -+ -+	ndx = mi->max_tp_rate; -+ -+	if (mrr) -+		sample_rate = mp->lookaround_rate_mrr; -+	else -+		sample_rate = mp->lookaround_rate; -+ -+	mi->packet_count++; -+	delta = (mi->packet_count * sample_rate / 100) - -+			(mi->sample_count + mi->sample_deferred / 2); -+ -+	/* delta > 0: sampling required */ -+	if (delta > 0) { -+		if (mi->packet_count >= 10000) { -+			mi->sample_deferred = 0; -+			mi->sample_count = 0; -+			mi->packet_count = 0; -+		} else if (delta > mi->n_rates * 2) { -+			/* With multi-rate retry, not every planned sample -+			 * attempt actually gets used, due to the way the retry -+			 * chain is set up - [max_tp,sample,prob,lowest] for -+			 * sample_rate < max_tp. -+			 * -+			 * If there's too much sampling backlog and the link -+			 * starts getting worse, minstrel would start bursting -+			 * out lots of sampling frames, which would result -+			 * in a large throughput loss. */ -+			mi->sample_count += (delta - mi->n_rates * 2); -+		} -+ -+		sample_ndx = minstrel_get_next_sample(mi); -+		sample = true; -+		sample_slower = mrr && (mi->r[sample_ndx].perfect_tx_time > -+			mi->r[ndx].perfect_tx_time); -+ -+		if (!sample_slower) { -+			ndx = sample_ndx; -+			mi->sample_count++; -+		} else { -+			/* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark -+			 * packets that have the sampling rate deferred to the -+			 * second MRR stage. Increase the sample counter only -+			 * if the deferred sample rate was actually used. -+			 * Use the sample_deferred counter to make sure that -+			 * the sampling is not done in large bursts */ -+			info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; -+			mi->sample_deferred++; -+		} -+	} -+	sel->rate_idx = mi->r[ndx].rix; -+	info->control.retry_limit = 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; -+		return; -+	} -+ -+	/* MRR setup */ -+	if (sample) { -+		if (sample_slower) -+			mrr_ndx[0] = sample_ndx; -+		else -+			mrr_ndx[0] = mi->max_tp_rate; -+	} else { -+		mrr_ndx[0] = mi->max_tp_rate2; -+	} -+	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; -+	} -+} -+ -+ -+static void -+calc_rate_durations(struct minstrel_sta_info *mi, struct ieee80211_local *local, -+                    struct minstrel_rate *d, struct ieee80211_rate *rate) -+{ -+	int erp = !!(rate->flags & IEEE80211_RATE_ERP_G); -+ -+	d->perfect_tx_time = ieee80211_frame_duration(local, 1200, -+			rate->bitrate, erp, 1); -+	d->ack_time = ieee80211_frame_duration(local, 10, -+			rate->bitrate, erp, 1); -+} -+ -+static void -+init_sample_table(struct minstrel_sta_info *mi) -+{ -+	unsigned int i, col, new_idx; -+	unsigned int n_srates = mi->n_rates - 1; -+	u8 rnd[8]; -+ -+	mi->sample_column = 0; -+	mi->sample_idx = 0; -+	memset(mi->sample_table, 0, SAMPLE_COLUMNS * mi->n_rates); -+ -+	for (col = 0; col < SAMPLE_COLUMNS; col++) { -+		for (i = 0; i < n_srates; i++) { -+			get_random_bytes(rnd, sizeof(rnd)); -+			new_idx = (i + rnd[i & 7]) % n_srates; -+ -+			while (SAMPLE_TBL(mi, new_idx, col) != 0) -+				new_idx = (new_idx + 1) % n_srates; -+ -+			/* Don't sample the slowest rate (i.e. slowest base -+			 * rate). We must presume that the slowest rate works -+			 * fine, or else other management frames will also be -+			 * failing and the link will break */ -+			SAMPLE_TBL(mi, new_idx, col) = i + 1; -+		} -+	} -+} -+ -+static void -+minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband, -+               struct ieee80211_sta *sta, void *priv_sta) -+{ -+	struct minstrel_sta_info *mi = priv_sta; -+	struct minstrel_priv *mp = priv; -+	struct minstrel_rate *mr_ctl; -+	unsigned int i, n = 0; -+	unsigned int t_slot = 9; /* FIXME: get real slot time */ -+ -+	mi->lowest_rix = rate_lowest_index(sband, sta); -+	mr_ctl = &mi->r[rix_to_ndx(mi, mi->lowest_rix)]; -+	mi->sp_ack_dur = mr_ctl->ack_time; -+ -+	for (i = 0; i < sband->n_bitrates; i++) { -+		struct minstrel_rate *mr = &mi->r[n]; -+		unsigned int tx_time = 0, tx_time_cts = 0, tx_time_rtscts = 0; -+		unsigned int tx_time_single; -+		unsigned int cw = mp->cw_min; -+ -+		if (!rate_supported(sta, sband->band, i)) -+			continue; -+		n++; -+		memset(mr, 0, sizeof(*mr)); -+ -+		mr->rix = i; -+		mr->bitrate = sband->bitrates[i].bitrate / 5; -+		calc_rate_durations(mi, hw_to_local(mp->hw), mr, -+				&sband->bitrates[i]); -+ -+		/* calculate maximum number of retransmissions before -+		 * fallback (based on maximum segment size) */ -+		mr->retry_count = 1; -+		mr->retry_count_cts = 1; -+		mr->retry_count_rtscts = 1; -+		tx_time = mr->perfect_tx_time + mi->sp_ack_dur; -+		do { -+			/* add one retransmission */ -+			tx_time_single = mr->ack_time + mr->perfect_tx_time; -+ -+			/* contention window */ -+			tx_time_single += t_slot + min(cw, mp->cw_max); -+			cw = (cw + 1) << 1; -+ -+			tx_time += tx_time_single; -+			tx_time_cts += tx_time_single + mi->sp_ack_dur; -+			tx_time_rtscts += tx_time_single + 2 * mi->sp_ack_dur; -+			if ((tx_time_cts < mp->segment_size) && -+				(mr->retry_count_cts < mp->max_retry)) -+				mr->retry_count_cts++; -+			if ((tx_time_rtscts < mp->segment_size) && -+				(mr->retry_count_rtscts < mp->max_retry)) -+				mr->retry_count_rtscts++; -+		} while ((tx_time < mp->segment_size) && -+				(++mr->retry_count < mp->max_retry)); -+		mr->adjusted_retry_count = mr->retry_count; -+	} -+ -+	for (i = n; i < sband->n_bitrates; i++) { -+		struct minstrel_rate *mr = &mi->r[i]; -+		mr->rix = -1; -+	} -+ -+	mi->n_rates = n; -+	mi->stats_update = jiffies; -+ -+	init_sample_table(mi); -+} -+ -+static void * -+minstrel_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) -+{ -+	struct ieee80211_supported_band *sband; -+	struct minstrel_sta_info *mi; -+	struct minstrel_priv *mp = priv; -+	struct ieee80211_hw *hw = mp->hw; -+	int max_rates = 0; -+	int i; -+ -+	mi = kzalloc(sizeof(struct minstrel_sta_info), gfp); -+	if (!mi) -+		return NULL; -+ -+	for (i = 0; i < IEEE80211_NUM_BANDS; i++) { -+		sband = hw->wiphy->bands[hw->conf.channel->band]; -+		if (sband->n_bitrates > max_rates) -+			max_rates = sband->n_bitrates; -+	} -+ -+	mi->r = kzalloc(sizeof(struct minstrel_rate) * max_rates, gfp); -+	if (!mi->r) -+		goto error; -+ -+	mi->sample_table = kmalloc(SAMPLE_COLUMNS * max_rates, gfp); -+	if (!mi->sample_table) -+		goto error1; -+ -+	mi->stats_update = jiffies; -+	return mi; -+ -+error1: -+	kfree(mi->r); -+error: -+	kfree(mi); -+	return NULL; -+} -+ -+static void -+minstrel_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta) -+{ -+	struct minstrel_sta_info *mi = priv_sta; -+ -+	kfree(mi->sample_table); -+	kfree(mi->r); -+	kfree(mi); -+} -+ -+static void -+minstrel_clear(void *priv) -+{ -+} -+ -+static void * -+minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) -+{ -+	struct minstrel_priv *mp; -+ -+	mp = kzalloc(sizeof(struct minstrel_priv), GFP_ATOMIC); -+	if (!mp) -+		return NULL; -+ -+	/* contention window settings -+	 * Just an approximation. Using the per-queue values would complicate -+	 * the calculations and is probably unnecessary */ -+	mp->cw_min = 15; -+	mp->cw_max = 1023; -+ -+	/* number of packets (in %) to use for sampling other rates -+	 * sample less often for non-mrr packets, because the overhead -+	 * is much higher than with mrr */ -+	mp->lookaround_rate = 5; -+	mp->lookaround_rate_mrr = 10; -+ -+	/* moving average weight for EWMA */ -+	mp->ewma_level = 75; -+ -+	/* 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; -+	else -+		/* safe default, does not necessarily have to match hw properties */ -+		mp->max_retry = 7; -+ -+	if (hw->max_altrates >= 3) -+		mp->has_mrr = true; -+ -+	mp->hw = hw; -+	mp->update_interval = 100; -+ -+	return mp; -+} -+ -+static void -+minstrel_free(void *priv) -+{ -+	kfree(priv); -+} -+ -+static struct rate_control_ops mac80211_minstrel = { -+	.name = "minstrel", -+	.tx_status = minstrel_tx_status, -+	.get_rate = minstrel_get_rate, -+	.rate_init = minstrel_rate_init, -+	.clear = minstrel_clear, -+	.alloc = minstrel_alloc, -+	.free = minstrel_free, -+	.alloc_sta = minstrel_alloc_sta, -+	.free_sta = minstrel_free_sta, -+#ifdef CONFIG_MAC80211_DEBUGFS -+	.add_sta_debugfs = minstrel_add_sta_debugfs, -+	.remove_sta_debugfs = minstrel_remove_sta_debugfs, -+#endif -+}; -+ -+int __init -+rc80211_minstrel_init(void) -+{ -+	return ieee80211_rate_control_register(&mac80211_minstrel); -+} -+ -+void -+rc80211_minstrel_exit(void) -+{ -+	ieee80211_rate_control_unregister(&mac80211_minstrel); -+} -+ ---- a/net/mac80211/Makefile -+++ b/net/mac80211/Makefile -@@ -41,4 +41,8 @@ - rc80211_pid-y := rc80211_pid_algo.o - rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o -  -+rc80211_minstrel-y := rc80211_minstrel.o -+rc80211_minstrel-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_debugfs.o -+ - mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc80211_pid-y) -+mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y) ---- a/net/mac80211/main.c -+++ b/net/mac80211/main.c -@@ -1015,6 +1015,10 @@ - 	BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, driver_data) + - 	             IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb)); -  -+	ret = rc80211_minstrel_init(); -+	if (ret) -+		return ret; -+ - 	ret = rc80211_pid_init(); - 	if (ret) - 		return ret; -@@ -1027,6 +1031,7 @@ - static void __exit ieee80211_exit(void) - { - 	rc80211_pid_exit(); -+	rc80211_minstrel_exit(); -  - 	/* - 	 * For key todo, it'll be empty by now but the work ---- a/net/mac80211/rate.h -+++ b/net/mac80211/rate.h -@@ -125,4 +125,18 @@ - } - #endif -  -+#ifdef CONFIG_MAC80211_RC_MINSTREL -+extern int rc80211_minstrel_init(void); -+extern void rc80211_minstrel_exit(void); -+#else -+static inline int rc80211_minstrel_init(void) -+{ -+	return 0; -+} -+static inline void rc80211_minstrel_exit(void) -+{ -+} -+#endif -+ -+ - #endif /* IEEE80211_RATE_H */ ---- /dev/null -+++ b/net/mac80211/rc80211_minstrel.h -@@ -0,0 +1,85 @@ -+/* -+ * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef __RC_MINSTREL_H -+#define __RC_MINSTREL_H -+ -+struct minstrel_rate { -+	int bitrate; -+	int rix; -+ -+	unsigned int perfect_tx_time; -+	unsigned int ack_time; -+ -+	unsigned int retry_count; -+	unsigned int retry_count_cts; -+	unsigned int retry_count_rtscts; -+	unsigned int adjusted_retry_count; -+ -+	u32 success; -+	u32 attempts; -+	u32 last_attempts; -+	u32 last_success; -+ -+	/* parts per thousand */ -+	u32 cur_prob; -+	u32 probability; -+ -+	/* per-rate throughput */ -+	u32 cur_tp; -+	u32 throughput; -+ -+	u64 succ_hist; -+	u64 att_hist; -+}; -+ -+struct minstrel_sta_info { -+	unsigned long stats_update; -+	unsigned int sp_ack_dur; -+	unsigned int rate_avg; -+ -+	unsigned int lowest_rix; -+ -+	unsigned int max_tp_rate; -+	unsigned int max_tp_rate2; -+	unsigned int max_prob_rate; -+	unsigned int packet_count; -+	unsigned int sample_count; -+	int sample_deferred; -+ -+	unsigned int sample_idx; -+	unsigned int sample_column; -+ -+	int n_rates; -+	struct minstrel_rate *r; -+ -+	/* sampling table */ -+	u8 *sample_table; -+ -+#ifdef CONFIG_MAC80211_DEBUGFS -+	struct dentry *dbg_stats; -+#endif -+}; -+ -+struct minstrel_priv { -+	struct ieee80211_hw *hw; -+	bool has_mrr; -+	unsigned int cw_min; -+	unsigned int cw_max; -+	unsigned int max_retry; -+	unsigned int ewma_level; -+	unsigned int segment_size; -+	unsigned int update_interval; -+	unsigned int lookaround_rate; -+	unsigned int lookaround_rate_mrr; -+}; -+ -+void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); -+void minstrel_remove_sta_debugfs(void *priv, void *priv_sta); -+ -+#endif ---- /dev/null -+++ b/net/mac80211/rc80211_minstrel_debugfs.c -@@ -0,0 +1,164 @@ -+/* -+ * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Based on minstrel.c: -+ *   Copyright (C) 2005-2007 Derek Smithies <derek@indranet.co.nz> -+ *   Sponsored by Indranet Technologies Ltd -+ * -+ * Based on sample.c: -+ *   Copyright (c) 2005 John Bicket -+ *   All rights reserved. -+ * -+ *   Redistribution and use in source and binary forms, with or without -+ *   modification, are permitted provided that the following conditions -+ *   are met: -+ *   1. Redistributions of source code must retain the above copyright -+ *      notice, this list of conditions and the following disclaimer, -+ *      without modification. -+ *   2. Redistributions in binary form must reproduce at minimum a disclaimer -+ *      similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any -+ *      redistribution must be conditioned upon including a substantially -+ *      similar Disclaimer requirement for further binary redistribution. -+ *   3. Neither the names of the above-listed copyright holders nor the names -+ *      of any contributors may be used to endorse or promote products derived -+ *      from this software without specific prior written permission. -+ * -+ *   Alternatively, this software may be distributed under the terms of the -+ *   GNU General Public License ("GPL") version 2 as published by the Free -+ *   Software Foundation. -+ * -+ *   NO WARRANTY -+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -+ *   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -+ *   LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY -+ *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -+ *   THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, -+ *   OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -+ *   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -+ *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -+ *   IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -+ *   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -+ *   THE POSSIBILITY OF SUCH DAMAGES. -+ */ -+#include <linux/netdevice.h> -+#include <linux/types.h> -+#include <linux/skbuff.h> -+#include <linux/debugfs.h> -+#include <linux/ieee80211.h> -+#include <net/mac80211.h> -+#include "rc80211_minstrel.h" -+ -+struct minstrel_stats_info { -+	struct minstrel_sta_info *mi; -+	char buf[4096]; -+	size_t len; -+}; -+ -+static int -+minstrel_stats_open(struct inode *inode, struct file *file) -+{ -+	struct minstrel_sta_info *mi = inode->i_private; -+	struct minstrel_stats_info *ms; -+	unsigned int i, tp, prob, eprob; -+	char *p; -+ -+	ms = kmalloc(sizeof(*ms), GFP_KERNEL); -+	if (!ms) -+		return -ENOMEM; -+ -+	file->private_data = ms; -+	p = ms->buf; -+	p += sprintf(p, "rate     throughput  ewma prob   this prob  " -+			"this succ/attempt   success    attempts\n"); -+	for (i = 0; i < mi->n_rates; i++) { -+		struct minstrel_rate *mr = &mi->r[i]; -+ -+		*(p++) = (i == mi->max_tp_rate) ? 'T' : ' '; -+		*(p++) = (i == mi->max_tp_rate2) ? 't' : ' '; -+		*(p++) = (i == mi->max_prob_rate) ? 'P' : ' '; -+		p += sprintf(p, "%3u%s", mr->bitrate / 2, -+				(mr->bitrate & 1 ? ".5" : "  ")); -+ -+		tp = ((mr->cur_tp * 96) / 18000) >> 10; -+		prob = mr->cur_prob / 18; -+		eprob = mr->probability / 18; -+ -+		p += sprintf(p, "  %6u.%1u   %6u.%1u   %6u.%1u        " -+				"%3u(%3u)   %8llu    %8llu\n", -+				tp / 10, tp % 10, -+				eprob / 10, eprob % 10, -+				prob / 10, prob % 10, -+				mr->last_success, -+				mr->last_attempts, -+				mr->succ_hist, -+				mr->att_hist); -+	} -+	p += sprintf(p, "\nTotal packet count::    ideal %d      " -+			"lookaround %d\n\n", -+			mi->packet_count - mi->sample_count, -+			mi->sample_count); -+	ms->len = p - ms->buf; -+ -+	return 0; -+} -+ -+static int -+minstrel_stats_read(struct file *file, char __user *buf, size_t len, loff_t *o) -+{ -+	struct minstrel_stats_info *ms; -+	char *src; -+ -+	ms = file->private_data; -+	src = ms->buf; -+ -+	len = min(len, ms->len); -+	if (len <= *o) -+		return 0; -+ -+	src += *o; -+	len -= *o; -+	*o += len; -+ -+	if (copy_to_user(buf, src, len)) -+		return -EFAULT; -+ -+	return len; -+} -+ -+static int -+minstrel_stats_release(struct inode *inode, struct file *file) -+{ -+	struct minstrel_stats_info *ms = file->private_data; -+ -+	kfree(ms); -+ -+	return 0; -+} -+ -+static struct file_operations minstrel_stat_fops = { -+	.owner = THIS_MODULE, -+	.open = minstrel_stats_open, -+	.read = minstrel_stats_read, -+	.release = minstrel_stats_release, -+}; -+ -+void -+minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir) -+{ -+	struct minstrel_sta_info *mi = priv_sta; -+ -+	mi->dbg_stats = debugfs_create_file("rc_stats", S_IRUGO, dir, mi, -+			&minstrel_stat_fops); -+} -+ -+void -+minstrel_remove_sta_debugfs(void *priv, void *priv_sta) -+{ -+	struct minstrel_sta_info *mi = priv_sta; -+ -+	debugfs_remove(mi->dbg_stats); -+} ---- a/net/mac80211/Kconfig -+++ b/net/mac80211/Kconfig -@@ -22,6 +22,11 @@ - 	  mac80211 that uses a PID controller to select the TX - 	  rate. -  -+config MAC80211_RC_MINSTREL -+	bool "Minstrel" -+	---help--- -+	  This option enables the 'minstrel' TX rate control algorithm -+ - choice - 	prompt "Default rate control algorithm" - 	default MAC80211_RC_DEFAULT_PID -@@ -39,11 +44,19 @@ - 	  default rate control algorithm. You should choose - 	  this unless you know what you are doing. -  -+config MAC80211_RC_DEFAULT_MINSTREL -+	bool "Minstrel" -+	depends on MAC80211_RC_MINSTREL -+	---help--- -+	  Select Minstrel as the default rate control algorithm. -+ -+ - endchoice -  - config MAC80211_RC_DEFAULT - 	string - 	default "pid" if MAC80211_RC_DEFAULT_PID -+	default "minstrel" if MAC80211_RC_DEFAULT_MINSTREL - 	default "" -  - endmenu diff --git a/package/mac80211/patches/300-minstrel_no_mrr.patch b/package/mac80211/patches/300-minstrel_no_mrr.patch new file mode 100644 index 000000000..d4c04c4d8 --- /dev/null +++ b/package/mac80211/patches/300-minstrel_no_mrr.patch @@ -0,0 +1,31 @@ +This fixes tx status processing for drivers that do not support mrr. +If the retry count is bigger than the maximum retry count configured in +the hardware, do not count the rate attempt as successful, the hardware +has probably switched to a lower rate. + +Signed-off-by: Felix Fietkau <nbd@openwrt.org> + +--- a/net/mac80211/rc80211_minstrel.c ++++ b/net/mac80211/rc80211_minstrel.c +@@ -171,6 +171,7 @@ minstrel_tx_status(void *priv, struct ie + 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + 	struct ieee80211_tx_altrate *ar = info->status.retries; + 	struct minstrel_priv *mp = priv; ++	struct ieee80211_local *local = hw_to_local(mp->hw); + 	int i, ndx, tries; + 	int success = 0; +  +@@ -180,6 +181,13 @@ minstrel_tx_status(void *priv, struct ie + 	if (!mp->has_mrr || (ar[0].rate_idx < 0)) { + 		ndx = rix_to_ndx(mi, info->tx_rate_idx); + 		tries = info->status.retry_count + 1; ++ ++		/* If the driver does not support the MRR API, but uses ++		 * a fallback rate, use the long retry limit as indication ++		 * that a rate switch has happened */ ++		if (!mp->has_mrr && (tries >= local->long_retry_limit)) ++			success = 0; ++ + 		mi->r[ndx].success += success; + 		mi->r[ndx].attempts += tries; + 		return; diff --git a/package/mac80211/patches/310-b43_txstatus.patch b/package/mac80211/patches/310-b43_txstatus.patch new file mode 100644 index 000000000..db731e584 --- /dev/null +++ b/package/mac80211/patches/310-b43_txstatus.patch @@ -0,0 +1,98 @@ +Fix the b43 tx status reporting. + +If the hardware uses RTS/CTS reporting and the actual RTS/CTS +handshake failed, it will switch to the fallback rate, even +though the main rate was never actually attempted. +Make sure that this does not screw up rate control statistics. + +Signed-off-by: Felix Fietkau <nbd@openwrt.org> + +--- a/drivers/net/wireless/b43/b43.h ++++ b/drivers/net/wireless/b43/b43.h +@@ -778,6 +778,9 @@ struct b43_wldev { + #ifdef CONFIG_B43_DEBUG + 	struct b43_dfsentry *dfsentry; + #endif ++ ++	/* necessary for figuring out the correct tx status */ ++	int short_retry; + }; +  + static inline struct b43_wl *hw_to_b43_wl(struct ieee80211_hw *hw) +--- a/drivers/net/wireless/b43/dma.c ++++ b/drivers/net/wireless/b43/dma.c +@@ -1393,7 +1393,7 @@ void b43_dma_handle_txstatus(struct b43_ + 			 * 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 +@@ -3892,6 +3892,7 @@ static void b43_set_retry_limits(struct  + 			short_retry); + 	b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT, + 			long_retry); ++	dev->short_retry = short_retry; + } +  + static void b43_set_synth_pu_delay(struct b43_wldev *dev, bool idle) +--- a/drivers/net/wireless/b43/pio.c ++++ b/drivers/net/wireless/b43/pio.c +@@ -589,7 +589,7 @@ void b43_pio_handle_txstatus(struct b43_ + 	info = IEEE80211_SKB_CB(pack->skb); + 	memset(&info->status, 0, sizeof(info->status)); +  +-	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 +@@ -687,7 +687,8 @@ 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; +@@ -706,8 +707,19 @@ bool b43_fill_txstatus_report(struct iee + 	if (status->frame_count == 0) { + 		/* The frame was not transmitted at all. */ + 		report->status.retry_count = 0; +-	} else ++	} else if (status->rts_count > dev->short_retry) { ++		/* ++		 * 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->tx_rate_idx = 0; ++		report->status.retry_count = 0; ++	} else { + 		report->status.retry_count = status->frame_count - 1; ++	} +  + 	return frame_success; + } +--- a/drivers/net/wireless/b43/xmit.h ++++ b/drivers/net/wireless/b43/xmit.h +@@ -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);  | 
