diff options
author | nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2008-10-10 01:45:35 +0000 |
---|---|---|
committer | nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2008-10-10 01:45:35 +0000 |
commit | 57d7a45a015b3edab14f6427cbb7aea6f0cde749 (patch) | |
tree | 55a0da7136b9919ad4675101c3a3bf477e48a04d | |
parent | 647f6d6949bdb8e81b2d2b0cae5465a7b75b05d3 (diff) |
update to latest compat-wireless version and add some new minstrel/b43 fixes
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@12939 3c298f89-4303-0410-b956-a3cf2f4a3e73
-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); |