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