xref: /onnv-gate/usr/src/uts/common/io/ath/ath_rate.c (revision 8033:142c11860489)
11000Sxc151355 /*
27249Sff224033  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
31000Sxc151355  * Use is subject to license terms.
41000Sxc151355  */
51000Sxc151355 
61000Sxc151355 /*
71000Sxc151355  * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
81000Sxc151355  * All rights reserved.
91000Sxc151355  *
101000Sxc151355  * Redistribution and use in source and binary forms, with or without
111000Sxc151355  * modification, are permitted provided that the following conditions
121000Sxc151355  * are met:
131000Sxc151355  * 1. Redistributions of source code must retain the above copyright
141000Sxc151355  * notice, this list of conditions and the following disclaimer,
151000Sxc151355  * without modification.
161000Sxc151355  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
171000Sxc151355  * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
181000Sxc151355  * redistribution must be conditioned upon including a substantially
191000Sxc151355  * similar Disclaimer requirement for further binary redistribution.
201000Sxc151355  * 3. Neither the names of the above-listed copyright holders nor the names
211000Sxc151355  * of any contributors may be used to endorse or promote products derived
221000Sxc151355  * from this software without specific prior written permission.
231000Sxc151355  *
241000Sxc151355  * NO WARRANTY
251000Sxc151355  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
261000Sxc151355  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
271000Sxc151355  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
281000Sxc151355  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
291000Sxc151355  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
301000Sxc151355  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
311000Sxc151355  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
321000Sxc151355  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
331000Sxc151355  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
341000Sxc151355  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
351000Sxc151355  * THE POSSIBILITY OF SUCH DAMAGES.
361000Sxc151355  */
371000Sxc151355 
381000Sxc151355 #include <sys/param.h>
391000Sxc151355 #include <sys/types.h>
401000Sxc151355 #include <sys/signal.h>
411000Sxc151355 #include <sys/stream.h>
421000Sxc151355 #include <sys/termio.h>
431000Sxc151355 #include <sys/errno.h>
441000Sxc151355 #include <sys/file.h>
451000Sxc151355 #include <sys/cmn_err.h>
461000Sxc151355 #include <sys/stropts.h>
471000Sxc151355 #include <sys/strsubr.h>
481000Sxc151355 #include <sys/strtty.h>
491000Sxc151355 #include <sys/kbio.h>
501000Sxc151355 #include <sys/cred.h>
511000Sxc151355 #include <sys/stat.h>
521000Sxc151355 #include <sys/consdev.h>
531000Sxc151355 #include <sys/kmem.h>
541000Sxc151355 #include <sys/modctl.h>
551000Sxc151355 #include <sys/ddi.h>
561000Sxc151355 #include <sys/sunddi.h>
571000Sxc151355 #include <sys/pci.h>
581000Sxc151355 #include <sys/errno.h>
591000Sxc151355 #include <sys/dlpi.h>
601000Sxc151355 #include <sys/ethernet.h>
611000Sxc151355 #include <sys/list.h>
621000Sxc151355 #include <sys/byteorder.h>
631000Sxc151355 #include <sys/strsun.h>
641000Sxc151355 #include <inet/common.h>
651000Sxc151355 #include <inet/nd.h>
661000Sxc151355 #include <inet/mi.h>
671000Sxc151355 #include <inet/wifi_ioctl.h>
681000Sxc151355 #include "ath_hal.h"
691000Sxc151355 #include "ath_impl.h"
703147Sxc151355 #include "ath_rate.h"
711000Sxc151355 
721000Sxc151355 void
ath_rate_update(ath_t * asc,struct ieee80211_node * in,int32_t rate)731000Sxc151355 ath_rate_update(ath_t *asc, struct ieee80211_node *in, int32_t rate)
741000Sxc151355 {
751000Sxc151355 	struct ath_node *an = ATH_NODE(in);
761000Sxc151355 	const HAL_RATE_TABLE *rt = asc->asc_currates;
771000Sxc151355 	uint8_t rix;
781000Sxc151355 
79*8033SWang.Lin@Sun.COM 	ASSERT(rt != NULL);
80*8033SWang.Lin@Sun.COM 
811000Sxc151355 	in->in_txrate = rate;
82*8033SWang.Lin@Sun.COM 
831000Sxc151355 	/* management/control frames always go at the lowest speed */
841000Sxc151355 	an->an_tx_mgtrate = rt->info[0].rateCode;
851000Sxc151355 	an->an_tx_mgtratesp = an->an_tx_mgtrate | rt->info[0].shortPreamble;
861000Sxc151355 	ATH_DEBUG((ATH_DBG_RATE, "ath: ath_rate_update(): "
871000Sxc151355 	    "mgtrate=%d mgtratesp=%d\n",
881000Sxc151355 	    an->an_tx_mgtrate, an->an_tx_mgtratesp));
891000Sxc151355 	/*
901000Sxc151355 	 * Before associating a node has no rate set setup
911000Sxc151355 	 * so we can't calculate any transmit codes to use.
921000Sxc151355 	 * This is ok since we should never be sending anything
931000Sxc151355 	 * but management frames and those always go at the
941000Sxc151355 	 * lowest hardware rate.
951000Sxc151355 	 */
961000Sxc151355 	if (in->in_rates.ir_nrates == 0)
971000Sxc151355 		goto done;
981000Sxc151355 	an->an_tx_rix0 = asc->asc_rixmap[
991000Sxc151355 	    in->in_rates.ir_rates[rate] & IEEE80211_RATE_VAL];
1001000Sxc151355 	an->an_tx_rate0 = rt->info[an->an_tx_rix0].rateCode;
1011000Sxc151355 	an->an_tx_rate0sp = an->an_tx_rate0 |
1021000Sxc151355 	    rt->info[an->an_tx_rix0].shortPreamble;
1031000Sxc151355 	if (asc->asc_mrretry) {
1041000Sxc151355 		/*
1051000Sxc151355 		 * Hardware supports multi-rate retry; setup two
1061000Sxc151355 		 * step-down retry rates and make the lowest rate
1071000Sxc151355 		 * be the ``last chance''.  We use 4, 2, 2, 2 tries
1081000Sxc151355 		 * respectively (4 is set here, the rest are fixed
1091000Sxc151355 		 * in the xmit routine).
1101000Sxc151355 		 */
1111000Sxc151355 		an->an_tx_try0 = 1 + 3;		/* 4 tries at rate 0 */
1121000Sxc151355 		if (--rate >= 0) {
1131000Sxc151355 			rix = asc->asc_rixmap[
1141000Sxc151355 			    in->in_rates.ir_rates[rate]&IEEE80211_RATE_VAL];
1151000Sxc151355 			an->an_tx_rate1 = rt->info[rix].rateCode;
1161000Sxc151355 			an->an_tx_rate1sp = an->an_tx_rate1 |
1171000Sxc151355 			    rt->info[rix].shortPreamble;
1181000Sxc151355 		} else {
1191000Sxc151355 			an->an_tx_rate1 = an->an_tx_rate1sp = 0;
1201000Sxc151355 		}
1211000Sxc151355 		if (--rate >= 0) {
1221000Sxc151355 			rix = asc->asc_rixmap[
1231000Sxc151355 			    in->in_rates.ir_rates[rate]&IEEE80211_RATE_VAL];
1241000Sxc151355 			an->an_tx_rate2 = rt->info[rix].rateCode;
1251000Sxc151355 			an->an_tx_rate2sp = an->an_tx_rate2 |
1261000Sxc151355 			    rt->info[rix].shortPreamble;
1271000Sxc151355 		} else {
1281000Sxc151355 			an->an_tx_rate2 = an->an_tx_rate2sp = 0;
1291000Sxc151355 		}
1301000Sxc151355 		if (rate > 0) {
1311000Sxc151355 			an->an_tx_rate3 = rt->info[0].rateCode;
1321000Sxc151355 			an->an_tx_rate3sp =
1331000Sxc151355 			    an->an_tx_mgtrate | rt->info[0].shortPreamble;
1341000Sxc151355 		} else {
1351000Sxc151355 			an->an_tx_rate3 = an->an_tx_rate3sp = 0;
1361000Sxc151355 		}
1371000Sxc151355 	} else {
1381000Sxc151355 		an->an_tx_try0 = ATH_TXMAXTRY;  /* max tries at rate 0 */
1391000Sxc151355 		an->an_tx_rate1 = an->an_tx_rate1sp = 0;
1401000Sxc151355 		an->an_tx_rate2 = an->an_tx_rate2sp = 0;
1411000Sxc151355 		an->an_tx_rate3 = an->an_tx_rate3sp = 0;
1421000Sxc151355 	}
1431000Sxc151355 done:
1441000Sxc151355 	an->an_tx_ok = an->an_tx_err = an->an_tx_retr = an->an_tx_upper = 0;
1451000Sxc151355 }
1461000Sxc151355 
1471000Sxc151355 
1481000Sxc151355 /*
1491000Sxc151355  * Set the starting transmit rate for a node.
1501000Sxc151355  */
1511000Sxc151355 void
ath_rate_ctl_start(ath_t * asc,struct ieee80211_node * in)1521000Sxc151355 ath_rate_ctl_start(ath_t *asc, struct ieee80211_node *in)
1531000Sxc151355 {
1543147Sxc151355 	ieee80211com_t *ic = (ieee80211com_t *)asc;
1551000Sxc151355 	int32_t srate;
1561000Sxc151355 
1573147Sxc151355 	if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) {
1581000Sxc151355 		/*
1591000Sxc151355 		 * No fixed rate is requested. For 11b start with
1601000Sxc151355 		 * the highest negotiated rate; otherwise, for 11g
1611000Sxc151355 		 * and 11a, we start "in the middle" at 24Mb or 36Mb.
1621000Sxc151355 		 */
1631000Sxc151355 		srate = in->in_rates.ir_nrates - 1;
1641000Sxc151355 		if (asc->asc_curmode != IEEE80211_MODE_11B) {
1651000Sxc151355 			/*
1661000Sxc151355 			 * Scan the negotiated rate set to find the
1671000Sxc151355 			 * closest rate.
1681000Sxc151355 			 */
1691000Sxc151355 			/* NB: the rate set is assumed sorted */
1701000Sxc151355 			for (; srate >= 0 && IEEE80211_RATE(srate) > 72;
1717249Sff224033 			    srate--) {}
1721000Sxc151355 		}
1731000Sxc151355 	} else {
1741000Sxc151355 		/*
1753147Sxc151355 		 * A fixed rate is to be used; We know the rate is
1763147Sxc151355 		 * there because the rate set is checked when the
1773147Sxc151355 		 * station associates.
1781000Sxc151355 		 */
1791000Sxc151355 		/* NB: the rate set is assumed sorted */
1801000Sxc151355 		srate = in->in_rates.ir_nrates - 1;
1813147Sxc151355 		for (; srate >= 0 && IEEE80211_RATE(srate) != ic->ic_fixed_rate;
1827249Sff224033 		    srate--) {}
1831000Sxc151355 	}
1841000Sxc151355 	ATH_DEBUG((ATH_DBG_RATE, "ath: ath_rate_ctl_start(): "
1851000Sxc151355 	    "srate=%d rate=%d\n", srate, IEEE80211_RATE(srate)));
1861000Sxc151355 	ath_rate_update(asc, in, srate);
1871000Sxc151355 }
1881000Sxc151355 
1893147Sxc151355 void
ath_rate_cb(void * arg,struct ieee80211_node * in)1903147Sxc151355 ath_rate_cb(void *arg, struct ieee80211_node *in)
1913147Sxc151355 {
1923147Sxc151355 	ath_rate_update((ath_t *)arg, in, 0);
1933147Sxc151355 }
1941000Sxc151355 
1951000Sxc151355 /*
1961000Sxc151355  * Reset the rate control state for each 802.11 state transition.
1971000Sxc151355  */
1981000Sxc151355 void
ath_rate_ctl_reset(ath_t * asc,enum ieee80211_state state)1991000Sxc151355 ath_rate_ctl_reset(ath_t *asc, enum ieee80211_state state)
2001000Sxc151355 {
2013147Sxc151355 	ieee80211com_t *ic = (ieee80211com_t *)asc;
2021000Sxc151355 	struct ieee80211_node *in;
2031000Sxc151355 
2043147Sxc151355 	if (ic->ic_opmode == IEEE80211_M_STA) {
2051000Sxc151355 		/*
2061000Sxc151355 		 * Reset local xmit state; this is really only
2071000Sxc151355 		 * meaningful when operating in station mode.
2081000Sxc151355 		 */
2093147Sxc151355 		in = (struct ieee80211_node *)ic->ic_bss;
2101000Sxc151355 		if (state == IEEE80211_S_RUN) {
2111000Sxc151355 			ath_rate_ctl_start(asc, in);
2121000Sxc151355 		} else {
2131000Sxc151355 			ath_rate_update(asc, in, 0);
2141000Sxc151355 		}
2151000Sxc151355 	} else {
2161000Sxc151355 		/*
2171000Sxc151355 		 * When operating as a station the node table holds
2181000Sxc151355 		 * the AP's that were discovered during scanning.
2191000Sxc151355 		 * For any other operating mode we want to reset the
2201000Sxc151355 		 * tx rate state of each node.
2211000Sxc151355 		 */
2223147Sxc151355 		ieee80211_iterate_nodes(&ic->ic_sta, ath_rate_cb, asc);
2233147Sxc151355 		ath_rate_update(asc, ic->ic_bss, 0);
2241000Sxc151355 	}
2251000Sxc151355 }
2261000Sxc151355 
2271000Sxc151355 
2281000Sxc151355 /*
2291000Sxc151355  * Examine and potentially adjust the transmit rate.
2301000Sxc151355  */
2311000Sxc151355 void
ath_rate_ctl(void * arg,struct ieee80211_node * in)232*8033SWang.Lin@Sun.COM ath_rate_ctl(void *arg, struct ieee80211_node *in)
2331000Sxc151355 {
234*8033SWang.Lin@Sun.COM 	ath_t *asc = arg;
2351000Sxc151355 	struct ath_node *an = ATH_NODE(in);
2361000Sxc151355 	struct ieee80211_rateset *rs = &in->in_rates;
2371000Sxc151355 	int32_t mod = 0, nrate, enough;
2381000Sxc151355 
2391000Sxc151355 	/*
2401000Sxc151355 	 * Rate control(very primitive version).
2411000Sxc151355 	 */
2421000Sxc151355 	asc->asc_stats.ast_rate_calls++;
2431000Sxc151355 
2441000Sxc151355 	enough = (an->an_tx_ok + an->an_tx_err >= 10);
2451000Sxc151355 
2461000Sxc151355 	/* no packet reached -> down */
2471000Sxc151355 	if (an->an_tx_err > 0 && an->an_tx_ok == 0)
2481000Sxc151355 		mod = -1;
2491000Sxc151355 
2501000Sxc151355 	/* all packets needs retry in average -> down */
2511000Sxc151355 	if (enough && an->an_tx_ok < an->an_tx_retr)
2521000Sxc151355 		mod = -1;
2531000Sxc151355 
2541000Sxc151355 	/* no error and less than 10% of packets needs retry -> up */
2551000Sxc151355 	if (enough && an->an_tx_err == 0 && an->an_tx_ok > an->an_tx_retr * 10)
2561000Sxc151355 		mod = 1;
2571000Sxc151355 
2581000Sxc151355 	nrate = in->in_txrate;
2591000Sxc151355 	switch (mod) {
2601000Sxc151355 	case 0:
2611000Sxc151355 		if (enough && an->an_tx_upper > 0)
2621000Sxc151355 			an->an_tx_upper--;
2631000Sxc151355 		break;
2641000Sxc151355 	case -1:
2651000Sxc151355 		if (nrate > 0) {
2661000Sxc151355 			nrate--;
2671000Sxc151355 			asc->asc_stats.ast_rate_drop++;
2681000Sxc151355 		}
2691000Sxc151355 		an->an_tx_upper = 0;
2701000Sxc151355 		break;
2711000Sxc151355 	case 1:
2721000Sxc151355 		if (++an->an_tx_upper < 10)
2731000Sxc151355 			break;
2741000Sxc151355 		an->an_tx_upper = 0;
2751000Sxc151355 		if (nrate + 1 < rs->ir_nrates) {
2761000Sxc151355 			nrate++;
2771000Sxc151355 			asc->asc_stats.ast_rate_raise++;
2781000Sxc151355 		}
2791000Sxc151355 		break;
2801000Sxc151355 	}
2811000Sxc151355 
2821000Sxc151355 	if (nrate != in->in_txrate) {
2831000Sxc151355 		ATH_DEBUG((ATH_DBG_RATE, "ath: ath_rate_ctl(): %dM -> %dM "
2841000Sxc151355 		    "(%d ok, %d err, %d retr)\n",
2851000Sxc151355 		    (rs->ir_rates[in->in_txrate] & IEEE80211_RATE_VAL) / 2,
2861000Sxc151355 		    (rs->ir_rates[nrate] & IEEE80211_RATE_VAL) / 2,
2871000Sxc151355 		    an->an_tx_ok, an->an_tx_err, an->an_tx_retr));
2881000Sxc151355 		ath_rate_update(asc, in, nrate);
2891000Sxc151355 	} else if (enough)
2901000Sxc151355 		an->an_tx_ok = an->an_tx_err = an->an_tx_retr = 0;
2911000Sxc151355 }
2921000Sxc151355 
2931000Sxc151355 
2941000Sxc151355 /*
2951000Sxc151355  * Read rate table from the HAL, and then
2961000Sxc151355  * copy the table to the driver's data structure.
2971000Sxc151355  */
2981000Sxc151355 void
ath_rate_setup(ath_t * asc,uint32_t mode)2991000Sxc151355 ath_rate_setup(ath_t *asc, uint32_t mode)
3001000Sxc151355 {
3017249Sff224033 	int32_t i;
3027249Sff224033 	uint8_t maxrates;
3031000Sxc151355 	struct ieee80211_rateset *rs;
3041000Sxc151355 	struct ath_hal *ah = asc->asc_ah;
3053147Sxc151355 	ieee80211com_t *ic = (ieee80211com_t *)asc;
3061000Sxc151355 	const HAL_RATE_TABLE *rt;
3071000Sxc151355 
3081000Sxc151355 	switch (mode) {
3091000Sxc151355 	case IEEE80211_MODE_11A:
3101000Sxc151355 		asc->asc_rates[mode] = ATH_HAL_GETRATETABLE(ah, HAL_MODE_11A);
3111000Sxc151355 		break;
3121000Sxc151355 	case IEEE80211_MODE_11B:
3131000Sxc151355 		asc->asc_rates[mode] = ATH_HAL_GETRATETABLE(ah, HAL_MODE_11B);
3141000Sxc151355 		break;
3151000Sxc151355 	case IEEE80211_MODE_11G:
3161000Sxc151355 		asc->asc_rates[mode] = ATH_HAL_GETRATETABLE(ah, HAL_MODE_11G);
3171000Sxc151355 		break;
3183147Sxc151355 	case IEEE80211_MODE_TURBO_A:
3191000Sxc151355 		asc->asc_rates[mode] = ATH_HAL_GETRATETABLE(ah, HAL_MODE_TURBO);
3201000Sxc151355 		break;
3213147Sxc151355 	case IEEE80211_MODE_TURBO_G:
3223147Sxc151355 		asc->asc_rates[mode] = ATH_HAL_GETRATETABLE(ah, HAL_MODE_108G);
3233147Sxc151355 		break;
3241000Sxc151355 	default:
3251000Sxc151355 		ATH_DEBUG((ATH_DBG_RATE, "ath: ath_rate_setup(): "
3261000Sxc151355 		    "invalid mode %u\n", mode));
3271000Sxc151355 		return;
3281000Sxc151355 	}
3291000Sxc151355 
3301000Sxc151355 	rt = asc->asc_rates[mode];
3311000Sxc151355 	if (rt == NULL)
3321000Sxc151355 		return;
3331000Sxc151355 	if (rt->rateCount > IEEE80211_RATE_MAXSIZE) {
3341000Sxc151355 		ATH_DEBUG((ATH_DBG_RATE, "ath: ath_rate_setup(): "
3351000Sxc151355 		    "rate table too small (%u > %u)\n",
3361000Sxc151355 		    rt->rateCount, IEEE80211_RATE_MAXSIZE));
3371000Sxc151355 		maxrates = IEEE80211_RATE_MAXSIZE;
3381000Sxc151355 	} else
3391000Sxc151355 		maxrates = rt->rateCount;
3403147Sxc151355 	rs = &ic->ic_sup_rates[mode];
3411000Sxc151355 	for (i = 0; i < maxrates; i++)
3421000Sxc151355 		rs->ir_rates[i] = rt->info[i].dot11Rate;
3431000Sxc151355 	rs->ir_nrates = maxrates;
3441000Sxc151355 }
345