xref: /illumos-gate/usr/src/uts/common/io/ath/ath_rate.c (revision f808c858)
1 /*
2  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer,
15  * without modification.
16  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
17  * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
18  * redistribution must be conditioned upon including a substantially
19  * similar Disclaimer requirement for further binary redistribution.
20  * 3. Neither the names of the above-listed copyright holders nor the names
21  * of any contributors may be used to endorse or promote products derived
22  * from this software without specific prior written permission.
23  *
24  * NO WARRANTY
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
28  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
29  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
30  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
33  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
35  * THE POSSIBILITY OF SUCH DAMAGES.
36  */
37 
38 #pragma ident	"%Z%%M%	%I%	%E% SMI"
39 
40 #include <sys/param.h>
41 #include <sys/types.h>
42 #include <sys/signal.h>
43 #include <sys/stream.h>
44 #include <sys/termio.h>
45 #include <sys/errno.h>
46 #include <sys/file.h>
47 #include <sys/cmn_err.h>
48 #include <sys/stropts.h>
49 #include <sys/strsubr.h>
50 #include <sys/strtty.h>
51 #include <sys/kbio.h>
52 #include <sys/cred.h>
53 #include <sys/stat.h>
54 #include <sys/consdev.h>
55 #include <sys/kmem.h>
56 #include <sys/modctl.h>
57 #include <sys/ddi.h>
58 #include <sys/sunddi.h>
59 #include <sys/pci.h>
60 #include <sys/errno.h>
61 #include <sys/gld.h>
62 #include <sys/dlpi.h>
63 #include <sys/ethernet.h>
64 #include <sys/list.h>
65 #include <sys/byteorder.h>
66 #include <sys/strsun.h>
67 #include <inet/common.h>
68 #include <inet/nd.h>
69 #include <inet/mi.h>
70 #include <inet/wifi_ioctl.h>
71 #include "ath_hal.h"
72 #include "ath_impl.h"
73 #include "ath_ieee80211.h"
74 
75 void
76 ath_rate_update(ath_t *asc, struct ieee80211_node *in, int32_t rate)
77 {
78 	struct ath_node *an = ATH_NODE(in);
79 	const HAL_RATE_TABLE *rt = asc->asc_currates;
80 	uint8_t rix;
81 
82 	in->in_txrate = rate;
83 	/* management/control frames always go at the lowest speed */
84 	an->an_tx_mgtrate = rt->info[0].rateCode;
85 	an->an_tx_mgtratesp = an->an_tx_mgtrate | rt->info[0].shortPreamble;
86 	ATH_DEBUG((ATH_DBG_RATE, "ath: ath_rate_update(): "
87 	    "mgtrate=%d mgtratesp=%d\n",
88 	    an->an_tx_mgtrate, an->an_tx_mgtratesp));
89 	/*
90 	 * Before associating a node has no rate set setup
91 	 * so we can't calculate any transmit codes to use.
92 	 * This is ok since we should never be sending anything
93 	 * but management frames and those always go at the
94 	 * lowest hardware rate.
95 	 */
96 	if (in->in_rates.ir_nrates == 0)
97 		goto done;
98 	an->an_tx_rix0 = asc->asc_rixmap[
99 	    in->in_rates.ir_rates[rate] & IEEE80211_RATE_VAL];
100 	an->an_tx_rate0 = rt->info[an->an_tx_rix0].rateCode;
101 	an->an_tx_rate0sp = an->an_tx_rate0 |
102 	    rt->info[an->an_tx_rix0].shortPreamble;
103 	if (asc->asc_mrretry) {
104 		/*
105 		 * Hardware supports multi-rate retry; setup two
106 		 * step-down retry rates and make the lowest rate
107 		 * be the ``last chance''.  We use 4, 2, 2, 2 tries
108 		 * respectively (4 is set here, the rest are fixed
109 		 * in the xmit routine).
110 		 */
111 		an->an_tx_try0 = 1 + 3;		/* 4 tries at rate 0 */
112 		if (--rate >= 0) {
113 			rix = asc->asc_rixmap[
114 			    in->in_rates.ir_rates[rate]&IEEE80211_RATE_VAL];
115 			an->an_tx_rate1 = rt->info[rix].rateCode;
116 			an->an_tx_rate1sp = an->an_tx_rate1 |
117 			    rt->info[rix].shortPreamble;
118 		} else {
119 			an->an_tx_rate1 = an->an_tx_rate1sp = 0;
120 		}
121 		if (--rate >= 0) {
122 			rix = asc->asc_rixmap[
123 			    in->in_rates.ir_rates[rate]&IEEE80211_RATE_VAL];
124 			an->an_tx_rate2 = rt->info[rix].rateCode;
125 			an->an_tx_rate2sp = an->an_tx_rate2 |
126 			    rt->info[rix].shortPreamble;
127 		} else {
128 			an->an_tx_rate2 = an->an_tx_rate2sp = 0;
129 		}
130 		if (rate > 0) {
131 			an->an_tx_rate3 = rt->info[0].rateCode;
132 			an->an_tx_rate3sp =
133 			    an->an_tx_mgtrate | rt->info[0].shortPreamble;
134 		} else {
135 			an->an_tx_rate3 = an->an_tx_rate3sp = 0;
136 		}
137 	} else {
138 		an->an_tx_try0 = ATH_TXMAXTRY;  /* max tries at rate 0 */
139 		an->an_tx_rate1 = an->an_tx_rate1sp = 0;
140 		an->an_tx_rate2 = an->an_tx_rate2sp = 0;
141 		an->an_tx_rate3 = an->an_tx_rate3sp = 0;
142 	}
143 done:
144 	an->an_tx_ok = an->an_tx_err = an->an_tx_retr = an->an_tx_upper = 0;
145 }
146 
147 
148 /*
149  * Set the starting transmit rate for a node.
150  */
151 void
152 ath_rate_ctl_start(ath_t *asc, struct ieee80211_node *in)
153 {
154 	ieee80211com_t *isc = (ieee80211com_t *)asc;
155 	int32_t srate;
156 
157 	if (isc->isc_fixed_rate == -1) {
158 		/*
159 		 * No fixed rate is requested. For 11b start with
160 		 * the highest negotiated rate; otherwise, for 11g
161 		 * and 11a, we start "in the middle" at 24Mb or 36Mb.
162 		 */
163 		srate = in->in_rates.ir_nrates - 1;
164 		if (asc->asc_curmode != IEEE80211_MODE_11B) {
165 			/*
166 			 * Scan the negotiated rate set to find the
167 			 * closest rate.
168 			 */
169 			/* NB: the rate set is assumed sorted */
170 			for (; srate >= 0 && IEEE80211_RATE(srate) > 72;
171 			    srate--);
172 		}
173 	} else {
174 		/*
175 		 * A fixed rate is to be used; ic_fixed_rate is an
176 		 * index into the supported rate set.  Convert this
177 		 * to the index into the negotiated rate set for
178 		 * the node.  We know the rate is there because the
179 		 * rate set is checked when the station associates.
180 		 */
181 		const struct ieee80211_rateset *rs =
182 		    &isc->isc_sup_rates[isc->isc_curmode];
183 		int32_t r = rs->ir_rates[isc->isc_fixed_rate] &
184 		    IEEE80211_RATE_VAL;
185 		/* NB: the rate set is assumed sorted */
186 		srate = in->in_rates.ir_nrates - 1;
187 		for (; srate >= 0 && IEEE80211_RATE(srate) != r; srate--);
188 	}
189 	ATH_DEBUG((ATH_DBG_RATE, "ath: ath_rate_ctl_start(): "
190 	    "srate=%d rate=%d\n", srate, IEEE80211_RATE(srate)));
191 	ath_rate_update(asc, in, srate);
192 }
193 
194 
195 /*
196  * Reset the rate control state for each 802.11 state transition.
197  */
198 void
199 ath_rate_ctl_reset(ath_t *asc, enum ieee80211_state state)
200 {
201 	ieee80211com_t *isc = (ieee80211com_t *)asc;
202 	struct ieee80211_node *in;
203 
204 	if (isc->isc_opmode == IEEE80211_M_STA) {
205 		/*
206 		 * Reset local xmit state; this is really only
207 		 * meaningful when operating in station mode.
208 		 */
209 		in = (struct ieee80211_node *)isc->isc_bss;
210 		if (state == IEEE80211_S_RUN) {
211 			ath_rate_ctl_start(asc, in);
212 		} else {
213 			ath_rate_update(asc, in, 0);
214 		}
215 	} else {
216 		/*
217 		 * When operating as a station the node table holds
218 		 * the AP's that were discovered during scanning.
219 		 * For any other operating mode we want to reset the
220 		 * tx rate state of each node.
221 		 */
222 		in = list_head(&isc->isc_in_list);
223 		while (in != NULL) {
224 			ath_rate_update(asc, in, 0);
225 			in = list_next(&isc->isc_in_list, in);
226 		}
227 		ath_rate_update(asc, isc->isc_bss, 0);
228 	}
229 }
230 
231 
232 /*
233  * Examine and potentially adjust the transmit rate.
234  */
235 void
236 ath_rate_ctl(ieee80211com_t *isc, struct ieee80211_node *in)
237 {
238 	ath_t *asc = (ath_t *)isc;
239 	struct ath_node *an = ATH_NODE(in);
240 	struct ieee80211_rateset *rs = &in->in_rates;
241 	int32_t mod = 0, nrate, enough;
242 
243 	/*
244 	 * Rate control(very primitive version).
245 	 */
246 	asc->asc_stats.ast_rate_calls++;
247 
248 	enough = (an->an_tx_ok + an->an_tx_err >= 10);
249 
250 	/* no packet reached -> down */
251 	if (an->an_tx_err > 0 && an->an_tx_ok == 0)
252 		mod = -1;
253 
254 	/* all packets needs retry in average -> down */
255 	if (enough && an->an_tx_ok < an->an_tx_retr)
256 		mod = -1;
257 
258 	/* no error and less than 10% of packets needs retry -> up */
259 	if (enough && an->an_tx_err == 0 && an->an_tx_ok > an->an_tx_retr * 10)
260 		mod = 1;
261 
262 	nrate = in->in_txrate;
263 	switch (mod) {
264 	case 0:
265 		if (enough && an->an_tx_upper > 0)
266 			an->an_tx_upper--;
267 		break;
268 	case -1:
269 		if (nrate > 0) {
270 			nrate--;
271 			asc->asc_stats.ast_rate_drop++;
272 		}
273 		an->an_tx_upper = 0;
274 		break;
275 	case 1:
276 		if (++an->an_tx_upper < 10)
277 			break;
278 		an->an_tx_upper = 0;
279 		if (nrate + 1 < rs->ir_nrates) {
280 			nrate++;
281 			asc->asc_stats.ast_rate_raise++;
282 		}
283 		break;
284 	}
285 
286 	if (nrate != in->in_txrate) {
287 		ATH_DEBUG((ATH_DBG_RATE, "ath: ath_rate_ctl(): %dM -> %dM "
288 		    "(%d ok, %d err, %d retr)\n",
289 		    (rs->ir_rates[in->in_txrate] & IEEE80211_RATE_VAL) / 2,
290 		    (rs->ir_rates[nrate] & IEEE80211_RATE_VAL) / 2,
291 		    an->an_tx_ok, an->an_tx_err, an->an_tx_retr));
292 		ath_rate_update(asc, in, nrate);
293 	} else if (enough)
294 		an->an_tx_ok = an->an_tx_err = an->an_tx_retr = 0;
295 }
296 
297 
298 /*
299  * Read rate table from the HAL, and then
300  * copy the table to the driver's data structure.
301  */
302 void
303 ath_rate_setup(ath_t *asc, uint32_t mode)
304 {
305 	int32_t i, maxrates;
306 	struct ieee80211_rateset *rs;
307 	struct ath_hal *ah = asc->asc_ah;
308 	ieee80211com_t *isc = (ieee80211com_t *)asc;
309 	const HAL_RATE_TABLE *rt;
310 
311 	switch (mode) {
312 	case IEEE80211_MODE_11A:
313 		asc->asc_rates[mode] = ATH_HAL_GETRATETABLE(ah, HAL_MODE_11A);
314 		break;
315 	case IEEE80211_MODE_11B:
316 		asc->asc_rates[mode] = ATH_HAL_GETRATETABLE(ah, HAL_MODE_11B);
317 		break;
318 	case IEEE80211_MODE_11G:
319 		asc->asc_rates[mode] = ATH_HAL_GETRATETABLE(ah, HAL_MODE_11G);
320 		break;
321 	case IEEE80211_MODE_TURBO:
322 		asc->asc_rates[mode] = ATH_HAL_GETRATETABLE(ah, HAL_MODE_TURBO);
323 		break;
324 	default:
325 		ATH_DEBUG((ATH_DBG_RATE, "ath: ath_rate_setup(): "
326 		    "invalid mode %u\n", mode));
327 		return;
328 	}
329 
330 	rt = asc->asc_rates[mode];
331 	if (rt == NULL)
332 		return;
333 	if (rt->rateCount > IEEE80211_RATE_MAXSIZE) {
334 		ATH_DEBUG((ATH_DBG_RATE, "ath: ath_rate_setup(): "
335 		    "rate table too small (%u > %u)\n",
336 		    rt->rateCount, IEEE80211_RATE_MAXSIZE));
337 		maxrates = IEEE80211_RATE_MAXSIZE;
338 	} else
339 		maxrates = rt->rateCount;
340 	rs = &isc->isc_sup_rates[mode];
341 	for (i = 0; i < maxrates; i++)
342 		rs->ir_rates[i] = rt->info[i].dot11Rate;
343 	rs->ir_nrates = maxrates;
344 }
345