1 2/*- 3 * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com> 4 * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <sys/param.h> 20#include <sys/kernel.h> 21#include <sys/module.h> 22#include <sys/socket.h> 23#include <sys/sysctl.h> 24 25#include <net/if.h> 26#include <net/if_media.h> 27 28#include <net80211/ieee80211_var.h> 29 30#include <dev/rt2860/rt2860_amrr.h> 31 32/* 33 * Defines and macros 34 */ 35 36#define RT2860_AMRR_IS_SUCCESS(amrr_node) ((amrr_node)->retrycnt < (amrr_node)->txcnt / 10) 37 38#define RT2860_AMRR_IS_FAILURE(amrr_node) ((amrr_node)->retrycnt > (amrr_node)->txcnt / 3) 39 40#define RT2860_AMRR_IS_ENOUGH(amrr_node) ((amrr_node)->txcnt > 10) 41 42/* 43 * Static function prototypes 44 */ 45 46static int rt2860_amrr_update(struct rt2860_amrr *amrr, 47 struct rt2860_amrr_node *amrr_node, struct ieee80211_node *ni); 48 49/* 50 * rt2860_amrr_init 51 */ 52void rt2860_amrr_init(struct rt2860_amrr *amrr, struct ieee80211vap *vap, 53 int ntxpath, int min_success_threshold, int max_success_threshold, int msecs) 54{ 55 int t; 56 57 amrr->ntxpath = ntxpath; 58 59 amrr->min_success_threshold = min_success_threshold; 60 amrr->max_success_threshold = max_success_threshold; 61 62 if (msecs < 100) 63 msecs = 100; 64 65 t = msecs_to_ticks(msecs); 66 67 amrr->interval = (t < 1) ? 1 : t; 68} 69 70/* 71 * rt2860_amrr_cleanup 72 */ 73void rt2860_amrr_cleanup(struct rt2860_amrr *amrr) 74{ 75} 76 77/* 78 * rt2860_amrr_node_init 79 */ 80void rt2860_amrr_node_init(struct rt2860_amrr *amrr, 81 struct rt2860_amrr_node *amrr_node, struct ieee80211_node *ni) 82{ 83 const struct ieee80211_rateset *rs; 84 85 amrr_node->amrr = amrr; 86 amrr_node->success = 0; 87 amrr_node->recovery = 0; 88 amrr_node->txcnt = 0; 89 amrr_node->retrycnt = 0; 90 amrr_node->success_threshold = amrr->min_success_threshold; 91 92 if (ni->ni_flags & IEEE80211_NODE_HT) 93 { 94 rs = (const struct ieee80211_rateset *) &ni->ni_htrates; 95 96 for (amrr_node->rate_index = rs->rs_nrates - 1; 97 amrr_node->rate_index > 0 && (rs->rs_rates[amrr_node->rate_index] & IEEE80211_RATE_VAL) > 4; 98 amrr_node->rate_index--) ; 99 100 ni->ni_txrate = rs->rs_rates[amrr_node->rate_index] | IEEE80211_RATE_MCS; 101 } 102 else 103 { 104 rs = &ni->ni_rates; 105 106 for (amrr_node->rate_index = rs->rs_nrates - 1; 107 amrr_node->rate_index > 0 && (rs->rs_rates[amrr_node->rate_index] & IEEE80211_RATE_VAL) > 72; 108 amrr_node->rate_index--) ; 109 110 ni->ni_txrate = rs->rs_rates[amrr_node->rate_index] & IEEE80211_RATE_VAL; 111 } 112 113 amrr_node->ticks = ticks; 114} 115 116/* 117 * rt2860_amrr_choose 118 */ 119int rt2860_amrr_choose(struct ieee80211_node *ni, 120 struct rt2860_amrr_node *amrr_node) 121{ 122 struct rt2860_amrr *amrr; 123 int rate_index; 124 125 amrr = amrr_node->amrr; 126 127 if (RT2860_AMRR_IS_ENOUGH(amrr_node) && 128 (ticks - amrr_node->ticks) > amrr->interval) 129 { 130 rate_index = rt2860_amrr_update(amrr, amrr_node, ni); 131 if (rate_index != amrr_node->rate_index) 132 { 133 if (ni->ni_flags & IEEE80211_NODE_HT) 134 ni->ni_txrate = ni->ni_htrates.rs_rates[rate_index] | IEEE80211_RATE_MCS; 135 else 136 ni->ni_txrate = ni->ni_rates.rs_rates[rate_index] & IEEE80211_RATE_VAL; 137 138 amrr_node->rate_index = rate_index; 139 } 140 141 amrr_node->ticks = ticks; 142 } 143 else 144 { 145 rate_index = amrr_node->rate_index; 146 } 147 148 return rate_index; 149} 150 151/* 152 * rt2860_amrr_update 153 */ 154static int rt2860_amrr_update(struct rt2860_amrr *amrr, 155 struct rt2860_amrr_node *amrr_node, struct ieee80211_node *ni) 156{ 157 const struct ieee80211_rateset *rs; 158 int rate_index; 159 160 KASSERT(RT2860_AMRR_IS_ENOUGH(amrr_node), 161 ("not enough Tx count: txcnt=%d", 162 amrr_node->txcnt)); 163 164 if (ni->ni_flags & IEEE80211_NODE_HT) 165 rs = (const struct ieee80211_rateset *) &ni->ni_htrates; 166 else 167 rs = &ni->ni_rates; 168 169 rate_index = amrr_node->rate_index; 170 171 if (RT2860_AMRR_IS_SUCCESS(amrr_node)) 172 { 173 amrr_node->success++; 174 if ((amrr_node->success >= amrr_node->success_threshold) && 175 (rate_index + 1 < rs->rs_nrates) && 176 (!(ni->ni_flags & IEEE80211_NODE_HT) || (rs->rs_rates[rate_index + 1] & IEEE80211_RATE_VAL) < (amrr->ntxpath * 8))) 177 { 178 amrr_node->recovery = 1; 179 amrr_node->success = 0; 180 181 rate_index++; 182 } 183 else 184 { 185 amrr_node->recovery = 0; 186 } 187 } 188 else if (RT2860_AMRR_IS_FAILURE(amrr_node)) 189 { 190 amrr_node->success = 0; 191 192 if (rate_index > 0) 193 { 194 if (amrr_node->recovery) 195 { 196 amrr_node->success_threshold *= 2; 197 if (amrr_node->success_threshold > amrr->max_success_threshold) 198 amrr_node->success_threshold = amrr->max_success_threshold; 199 } 200 else 201 { 202 amrr_node->success_threshold = amrr->min_success_threshold; 203 } 204 205 rate_index--; 206 } 207 208 amrr_node->recovery = 0; 209 } 210 211 amrr_node->txcnt = 0; 212 amrr_node->retrycnt = 0; 213 214 return rate_index; 215} 216