diff options
author | Felix Fietkau <nbd@openwrt.org> | 2008-10-10 01:45:35 +0000 |
---|---|---|
committer | Felix Fietkau <nbd@openwrt.org> | 2008-10-10 01:45:35 +0000 |
commit | 6e85059256a5b98637033ad7e803011c512771cf (patch) | |
tree | 340f8e3fbd72bafb6e16623dea02663c403ca100 /package/mac80211/patches/300-minstrel.patch | |
parent | beb83c1e59a87c8283791aa573f94906374de379 (diff) | |
download | upstream-6e85059256a5b98637033ad7e803011c512771cf.tar.gz upstream-6e85059256a5b98637033ad7e803011c512771cf.tar.bz2 upstream-6e85059256a5b98637033ad7e803011c512771cf.zip |
update to latest compat-wireless version and add some new minstrel/b43 fixes
SVN-Revision: 12939
Diffstat (limited to 'package/mac80211/patches/300-minstrel.patch')
-rw-r--r-- | package/mac80211/patches/300-minstrel.patch | 928 |
1 files changed, 0 insertions, 928 deletions
diff --git a/package/mac80211/patches/300-minstrel.patch b/package/mac80211/patches/300-minstrel.patch deleted file mode 100644 index ee1887a6ce..0000000000 --- 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 |