aboutsummaryrefslogtreecommitdiffstats
path: root/package/mac80211/patches/210-mrr.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/mac80211/patches/210-mrr.patch')
-rw-r--r--package/mac80211/patches/210-mrr.patch183
1 files changed, 183 insertions, 0 deletions
diff --git a/package/mac80211/patches/210-mrr.patch b/package/mac80211/patches/210-mrr.patch
new file mode 100644
index 0000000000..3894788245
--- /dev/null
+++ b/package/mac80211/patches/210-mrr.patch
@@ -0,0 +1,183 @@
+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);