17a1306a7Sxc151355 /* 2ff3124efSff224033 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 37a1306a7Sxc151355 * Use is subject to license terms. 47a1306a7Sxc151355 */ 57a1306a7Sxc151355 67a1306a7Sxc151355 /* 77a1306a7Sxc151355 * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting 87a1306a7Sxc151355 * All rights reserved. 97a1306a7Sxc151355 * 107a1306a7Sxc151355 * Redistribution and use in source and binary forms, with or without 117a1306a7Sxc151355 * modification, are permitted provided that the following conditions 127a1306a7Sxc151355 * are met: 137a1306a7Sxc151355 * 1. Redistributions of source code must retain the above copyright 147a1306a7Sxc151355 * notice, this list of conditions and the following disclaimer, 157a1306a7Sxc151355 * without modification. 167a1306a7Sxc151355 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 177a1306a7Sxc151355 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 187a1306a7Sxc151355 * redistribution must be conditioned upon including a substantially 197a1306a7Sxc151355 * similar Disclaimer requirement for further binary redistribution. 207a1306a7Sxc151355 * 3. Neither the names of the above-listed copyright holders nor the names 217a1306a7Sxc151355 * of any contributors may be used to endorse or promote products derived 227a1306a7Sxc151355 * from this software without specific prior written permission. 237a1306a7Sxc151355 * 247a1306a7Sxc151355 * NO WARRANTY 257a1306a7Sxc151355 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 267a1306a7Sxc151355 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 277a1306a7Sxc151355 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 287a1306a7Sxc151355 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 297a1306a7Sxc151355 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 307a1306a7Sxc151355 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 317a1306a7Sxc151355 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 327a1306a7Sxc151355 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 337a1306a7Sxc151355 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 347a1306a7Sxc151355 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 357a1306a7Sxc151355 * THE POSSIBILITY OF SUCH DAMAGES. 367a1306a7Sxc151355 */ 377a1306a7Sxc151355 387a1306a7Sxc151355 #include <sys/param.h> 397a1306a7Sxc151355 #include <sys/types.h> 407a1306a7Sxc151355 #include <sys/signal.h> 417a1306a7Sxc151355 #include <sys/stream.h> 427a1306a7Sxc151355 #include <sys/termio.h> 437a1306a7Sxc151355 #include <sys/errno.h> 447a1306a7Sxc151355 #include <sys/file.h> 457a1306a7Sxc151355 #include <sys/cmn_err.h> 467a1306a7Sxc151355 #include <sys/stropts.h> 477a1306a7Sxc151355 #include <sys/strsubr.h> 487a1306a7Sxc151355 #include <sys/strtty.h> 497a1306a7Sxc151355 #include <sys/kbio.h> 507a1306a7Sxc151355 #include <sys/cred.h> 517a1306a7Sxc151355 #include <sys/stat.h> 527a1306a7Sxc151355 #include <sys/consdev.h> 537a1306a7Sxc151355 #include <sys/kmem.h> 547a1306a7Sxc151355 #include <sys/modctl.h> 557a1306a7Sxc151355 #include <sys/ddi.h> 567a1306a7Sxc151355 #include <sys/sunddi.h> 577a1306a7Sxc151355 #include <sys/pci.h> 587a1306a7Sxc151355 #include <sys/errno.h> 597a1306a7Sxc151355 #include <sys/dlpi.h> 607a1306a7Sxc151355 #include <sys/ethernet.h> 617a1306a7Sxc151355 #include <sys/list.h> 627a1306a7Sxc151355 #include <sys/byteorder.h> 637a1306a7Sxc151355 #include <sys/strsun.h> 647a1306a7Sxc151355 #include <inet/common.h> 657a1306a7Sxc151355 #include <inet/nd.h> 667a1306a7Sxc151355 #include <inet/mi.h> 677a1306a7Sxc151355 #include <inet/wifi_ioctl.h> 687a1306a7Sxc151355 #include "ath_hal.h" 697a1306a7Sxc151355 #include "ath_impl.h" 700ba2cbe9Sxc151355 #include "ath_rate.h" 717a1306a7Sxc151355 727a1306a7Sxc151355 void 737a1306a7Sxc151355 ath_rate_update(ath_t *asc, struct ieee80211_node *in, int32_t rate) 747a1306a7Sxc151355 { 757a1306a7Sxc151355 struct ath_node *an = ATH_NODE(in); 767a1306a7Sxc151355 const HAL_RATE_TABLE *rt = asc->asc_currates; 777a1306a7Sxc151355 uint8_t rix; 787a1306a7Sxc151355 79*129d67acSlin wang - Sun Microsystems - Beijing China ASSERT(rt != NULL); 80*129d67acSlin wang - Sun Microsystems - Beijing China 817a1306a7Sxc151355 in->in_txrate = rate; 82*129d67acSlin wang - Sun Microsystems - Beijing China 837a1306a7Sxc151355 /* management/control frames always go at the lowest speed */ 847a1306a7Sxc151355 an->an_tx_mgtrate = rt->info[0].rateCode; 857a1306a7Sxc151355 an->an_tx_mgtratesp = an->an_tx_mgtrate | rt->info[0].shortPreamble; 867a1306a7Sxc151355 ATH_DEBUG((ATH_DBG_RATE, "ath: ath_rate_update(): " 877a1306a7Sxc151355 "mgtrate=%d mgtratesp=%d\n", 887a1306a7Sxc151355 an->an_tx_mgtrate, an->an_tx_mgtratesp)); 897a1306a7Sxc151355 /* 907a1306a7Sxc151355 * Before associating a node has no rate set setup 917a1306a7Sxc151355 * so we can't calculate any transmit codes to use. 927a1306a7Sxc151355 * This is ok since we should never be sending anything 937a1306a7Sxc151355 * but management frames and those always go at the 947a1306a7Sxc151355 * lowest hardware rate. 957a1306a7Sxc151355 */ 967a1306a7Sxc151355 if (in->in_rates.ir_nrates == 0) 977a1306a7Sxc151355 goto done; 987a1306a7Sxc151355 an->an_tx_rix0 = asc->asc_rixmap[ 997a1306a7Sxc151355 in->in_rates.ir_rates[rate] & IEEE80211_RATE_VAL]; 1007a1306a7Sxc151355 an->an_tx_rate0 = rt->info[an->an_tx_rix0].rateCode; 1017a1306a7Sxc151355 an->an_tx_rate0sp = an->an_tx_rate0 | 1027a1306a7Sxc151355 rt->info[an->an_tx_rix0].shortPreamble; 1037a1306a7Sxc151355 if (asc->asc_mrretry) { 1047a1306a7Sxc151355 /* 1057a1306a7Sxc151355 * Hardware supports multi-rate retry; setup two 1067a1306a7Sxc151355 * step-down retry rates and make the lowest rate 1077a1306a7Sxc151355 * be the ``last chance''. We use 4, 2, 2, 2 tries 1087a1306a7Sxc151355 * respectively (4 is set here, the rest are fixed 1097a1306a7Sxc151355 * in the xmit routine). 1107a1306a7Sxc151355 */ 1117a1306a7Sxc151355 an->an_tx_try0 = 1 + 3; /* 4 tries at rate 0 */ 1127a1306a7Sxc151355 if (--rate >= 0) { 1137a1306a7Sxc151355 rix = asc->asc_rixmap[ 1147a1306a7Sxc151355 in->in_rates.ir_rates[rate]&IEEE80211_RATE_VAL]; 1157a1306a7Sxc151355 an->an_tx_rate1 = rt->info[rix].rateCode; 1167a1306a7Sxc151355 an->an_tx_rate1sp = an->an_tx_rate1 | 1177a1306a7Sxc151355 rt->info[rix].shortPreamble; 1187a1306a7Sxc151355 } else { 1197a1306a7Sxc151355 an->an_tx_rate1 = an->an_tx_rate1sp = 0; 1207a1306a7Sxc151355 } 1217a1306a7Sxc151355 if (--rate >= 0) { 1227a1306a7Sxc151355 rix = asc->asc_rixmap[ 1237a1306a7Sxc151355 in->in_rates.ir_rates[rate]&IEEE80211_RATE_VAL]; 1247a1306a7Sxc151355 an->an_tx_rate2 = rt->info[rix].rateCode; 1257a1306a7Sxc151355 an->an_tx_rate2sp = an->an_tx_rate2 | 1267a1306a7Sxc151355 rt->info[rix].shortPreamble; 1277a1306a7Sxc151355 } else { 1287a1306a7Sxc151355 an->an_tx_rate2 = an->an_tx_rate2sp = 0; 1297a1306a7Sxc151355 } 1307a1306a7Sxc151355 if (rate > 0) { 1317a1306a7Sxc151355 an->an_tx_rate3 = rt->info[0].rateCode; 1327a1306a7Sxc151355 an->an_tx_rate3sp = 1337a1306a7Sxc151355 an->an_tx_mgtrate | rt->info[0].shortPreamble; 1347a1306a7Sxc151355 } else { 1357a1306a7Sxc151355 an->an_tx_rate3 = an->an_tx_rate3sp = 0; 1367a1306a7Sxc151355 } 1377a1306a7Sxc151355 } else { 1387a1306a7Sxc151355 an->an_tx_try0 = ATH_TXMAXTRY; /* max tries at rate 0 */ 1397a1306a7Sxc151355 an->an_tx_rate1 = an->an_tx_rate1sp = 0; 1407a1306a7Sxc151355 an->an_tx_rate2 = an->an_tx_rate2sp = 0; 1417a1306a7Sxc151355 an->an_tx_rate3 = an->an_tx_rate3sp = 0; 1427a1306a7Sxc151355 } 1437a1306a7Sxc151355 done: 1447a1306a7Sxc151355 an->an_tx_ok = an->an_tx_err = an->an_tx_retr = an->an_tx_upper = 0; 1457a1306a7Sxc151355 } 1467a1306a7Sxc151355 1477a1306a7Sxc151355 1487a1306a7Sxc151355 /* 1497a1306a7Sxc151355 * Set the starting transmit rate for a node. 1507a1306a7Sxc151355 */ 1517a1306a7Sxc151355 void 1527a1306a7Sxc151355 ath_rate_ctl_start(ath_t *asc, struct ieee80211_node *in) 1537a1306a7Sxc151355 { 1540ba2cbe9Sxc151355 ieee80211com_t *ic = (ieee80211com_t *)asc; 1557a1306a7Sxc151355 int32_t srate; 1567a1306a7Sxc151355 1570ba2cbe9Sxc151355 if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) { 1587a1306a7Sxc151355 /* 1597a1306a7Sxc151355 * No fixed rate is requested. For 11b start with 1607a1306a7Sxc151355 * the highest negotiated rate; otherwise, for 11g 1617a1306a7Sxc151355 * and 11a, we start "in the middle" at 24Mb or 36Mb. 1627a1306a7Sxc151355 */ 1637a1306a7Sxc151355 srate = in->in_rates.ir_nrates - 1; 1647a1306a7Sxc151355 if (asc->asc_curmode != IEEE80211_MODE_11B) { 1657a1306a7Sxc151355 /* 1667a1306a7Sxc151355 * Scan the negotiated rate set to find the 1677a1306a7Sxc151355 * closest rate. 1687a1306a7Sxc151355 */ 1697a1306a7Sxc151355 /* NB: the rate set is assumed sorted */ 1707a1306a7Sxc151355 for (; srate >= 0 && IEEE80211_RATE(srate) > 72; 171ff3124efSff224033 srate--) {} 1727a1306a7Sxc151355 } 1737a1306a7Sxc151355 } else { 1747a1306a7Sxc151355 /* 1750ba2cbe9Sxc151355 * A fixed rate is to be used; We know the rate is 1760ba2cbe9Sxc151355 * there because the rate set is checked when the 1770ba2cbe9Sxc151355 * station associates. 1787a1306a7Sxc151355 */ 1797a1306a7Sxc151355 /* NB: the rate set is assumed sorted */ 1807a1306a7Sxc151355 srate = in->in_rates.ir_nrates - 1; 1810ba2cbe9Sxc151355 for (; srate >= 0 && IEEE80211_RATE(srate) != ic->ic_fixed_rate; 182ff3124efSff224033 srate--) {} 1837a1306a7Sxc151355 } 1847a1306a7Sxc151355 ATH_DEBUG((ATH_DBG_RATE, "ath: ath_rate_ctl_start(): " 1857a1306a7Sxc151355 "srate=%d rate=%d\n", srate, IEEE80211_RATE(srate))); 1867a1306a7Sxc151355 ath_rate_update(asc, in, srate); 1877a1306a7Sxc151355 } 1887a1306a7Sxc151355 1890ba2cbe9Sxc151355 void 1900ba2cbe9Sxc151355 ath_rate_cb(void *arg, struct ieee80211_node *in) 1910ba2cbe9Sxc151355 { 1920ba2cbe9Sxc151355 ath_rate_update((ath_t *)arg, in, 0); 1930ba2cbe9Sxc151355 } 1947a1306a7Sxc151355 1957a1306a7Sxc151355 /* 1967a1306a7Sxc151355 * Reset the rate control state for each 802.11 state transition. 1977a1306a7Sxc151355 */ 1987a1306a7Sxc151355 void 1997a1306a7Sxc151355 ath_rate_ctl_reset(ath_t *asc, enum ieee80211_state state) 2007a1306a7Sxc151355 { 2010ba2cbe9Sxc151355 ieee80211com_t *ic = (ieee80211com_t *)asc; 2027a1306a7Sxc151355 struct ieee80211_node *in; 2037a1306a7Sxc151355 2040ba2cbe9Sxc151355 if (ic->ic_opmode == IEEE80211_M_STA) { 2057a1306a7Sxc151355 /* 2067a1306a7Sxc151355 * Reset local xmit state; this is really only 2077a1306a7Sxc151355 * meaningful when operating in station mode. 2087a1306a7Sxc151355 */ 2090ba2cbe9Sxc151355 in = (struct ieee80211_node *)ic->ic_bss; 2107a1306a7Sxc151355 if (state == IEEE80211_S_RUN) { 2117a1306a7Sxc151355 ath_rate_ctl_start(asc, in); 2127a1306a7Sxc151355 } else { 2137a1306a7Sxc151355 ath_rate_update(asc, in, 0); 2147a1306a7Sxc151355 } 2157a1306a7Sxc151355 } else { 2167a1306a7Sxc151355 /* 2177a1306a7Sxc151355 * When operating as a station the node table holds 2187a1306a7Sxc151355 * the AP's that were discovered during scanning. 2197a1306a7Sxc151355 * For any other operating mode we want to reset the 2207a1306a7Sxc151355 * tx rate state of each node. 2217a1306a7Sxc151355 */ 2220ba2cbe9Sxc151355 ieee80211_iterate_nodes(&ic->ic_sta, ath_rate_cb, asc); 2230ba2cbe9Sxc151355 ath_rate_update(asc, ic->ic_bss, 0); 2247a1306a7Sxc151355 } 2257a1306a7Sxc151355 } 2267a1306a7Sxc151355 2277a1306a7Sxc151355 2287a1306a7Sxc151355 /* 2297a1306a7Sxc151355 * Examine and potentially adjust the transmit rate. 2307a1306a7Sxc151355 */ 2317a1306a7Sxc151355 void 232*129d67acSlin wang - Sun Microsystems - Beijing China ath_rate_ctl(void *arg, struct ieee80211_node *in) 2337a1306a7Sxc151355 { 234*129d67acSlin wang - Sun Microsystems - Beijing China ath_t *asc = arg; 2357a1306a7Sxc151355 struct ath_node *an = ATH_NODE(in); 2367a1306a7Sxc151355 struct ieee80211_rateset *rs = &in->in_rates; 2377a1306a7Sxc151355 int32_t mod = 0, nrate, enough; 2387a1306a7Sxc151355 2397a1306a7Sxc151355 /* 2407a1306a7Sxc151355 * Rate control(very primitive version). 2417a1306a7Sxc151355 */ 2427a1306a7Sxc151355 asc->asc_stats.ast_rate_calls++; 2437a1306a7Sxc151355 2447a1306a7Sxc151355 enough = (an->an_tx_ok + an->an_tx_err >= 10); 2457a1306a7Sxc151355 2467a1306a7Sxc151355 /* no packet reached -> down */ 2477a1306a7Sxc151355 if (an->an_tx_err > 0 && an->an_tx_ok == 0) 2487a1306a7Sxc151355 mod = -1; 2497a1306a7Sxc151355 2507a1306a7Sxc151355 /* all packets needs retry in average -> down */ 2517a1306a7Sxc151355 if (enough && an->an_tx_ok < an->an_tx_retr) 2527a1306a7Sxc151355 mod = -1; 2537a1306a7Sxc151355 2547a1306a7Sxc151355 /* no error and less than 10% of packets needs retry -> up */ 2557a1306a7Sxc151355 if (enough && an->an_tx_err == 0 && an->an_tx_ok > an->an_tx_retr * 10) 2567a1306a7Sxc151355 mod = 1; 2577a1306a7Sxc151355 2587a1306a7Sxc151355 nrate = in->in_txrate; 2597a1306a7Sxc151355 switch (mod) { 2607a1306a7Sxc151355 case 0: 2617a1306a7Sxc151355 if (enough && an->an_tx_upper > 0) 2627a1306a7Sxc151355 an->an_tx_upper--; 2637a1306a7Sxc151355 break; 2647a1306a7Sxc151355 case -1: 2657a1306a7Sxc151355 if (nrate > 0) { 2667a1306a7Sxc151355 nrate--; 2677a1306a7Sxc151355 asc->asc_stats.ast_rate_drop++; 2687a1306a7Sxc151355 } 2697a1306a7Sxc151355 an->an_tx_upper = 0; 2707a1306a7Sxc151355 break; 2717a1306a7Sxc151355 case 1: 2727a1306a7Sxc151355 if (++an->an_tx_upper < 10) 2737a1306a7Sxc151355 break; 2747a1306a7Sxc151355 an->an_tx_upper = 0; 2757a1306a7Sxc151355 if (nrate + 1 < rs->ir_nrates) { 2767a1306a7Sxc151355 nrate++; 2777a1306a7Sxc151355 asc->asc_stats.ast_rate_raise++; 2787a1306a7Sxc151355 } 2797a1306a7Sxc151355 break; 2807a1306a7Sxc151355 } 2817a1306a7Sxc151355 2827a1306a7Sxc151355 if (nrate != in->in_txrate) { 2837a1306a7Sxc151355 ATH_DEBUG((ATH_DBG_RATE, "ath: ath_rate_ctl(): %dM -> %dM " 2847a1306a7Sxc151355 "(%d ok, %d err, %d retr)\n", 2857a1306a7Sxc151355 (rs->ir_rates[in->in_txrate] & IEEE80211_RATE_VAL) / 2, 2867a1306a7Sxc151355 (rs->ir_rates[nrate] & IEEE80211_RATE_VAL) / 2, 2877a1306a7Sxc151355 an->an_tx_ok, an->an_tx_err, an->an_tx_retr)); 2887a1306a7Sxc151355 ath_rate_update(asc, in, nrate); 2897a1306a7Sxc151355 } else if (enough) 2907a1306a7Sxc151355 an->an_tx_ok = an->an_tx_err = an->an_tx_retr = 0; 2917a1306a7Sxc151355 } 2927a1306a7Sxc151355 2937a1306a7Sxc151355 2947a1306a7Sxc151355 /* 2957a1306a7Sxc151355 * Read rate table from the HAL, and then 2967a1306a7Sxc151355 * copy the table to the driver's data structure. 2977a1306a7Sxc151355 */ 2987a1306a7Sxc151355 void 2997a1306a7Sxc151355 ath_rate_setup(ath_t *asc, uint32_t mode) 3007a1306a7Sxc151355 { 301ff3124efSff224033 int32_t i; 302ff3124efSff224033 uint8_t maxrates; 3037a1306a7Sxc151355 struct ieee80211_rateset *rs; 3047a1306a7Sxc151355 struct ath_hal *ah = asc->asc_ah; 3050ba2cbe9Sxc151355 ieee80211com_t *ic = (ieee80211com_t *)asc; 3067a1306a7Sxc151355 const HAL_RATE_TABLE *rt; 3077a1306a7Sxc151355 3087a1306a7Sxc151355 switch (mode) { 3097a1306a7Sxc151355 case IEEE80211_MODE_11A: 3107a1306a7Sxc151355 asc->asc_rates[mode] = ATH_HAL_GETRATETABLE(ah, HAL_MODE_11A); 3117a1306a7Sxc151355 break; 3127a1306a7Sxc151355 case IEEE80211_MODE_11B: 3137a1306a7Sxc151355 asc->asc_rates[mode] = ATH_HAL_GETRATETABLE(ah, HAL_MODE_11B); 3147a1306a7Sxc151355 break; 3157a1306a7Sxc151355 case IEEE80211_MODE_11G: 3167a1306a7Sxc151355 asc->asc_rates[mode] = ATH_HAL_GETRATETABLE(ah, HAL_MODE_11G); 3177a1306a7Sxc151355 break; 3180ba2cbe9Sxc151355 case IEEE80211_MODE_TURBO_A: 3197a1306a7Sxc151355 asc->asc_rates[mode] = ATH_HAL_GETRATETABLE(ah, HAL_MODE_TURBO); 3207a1306a7Sxc151355 break; 3210ba2cbe9Sxc151355 case IEEE80211_MODE_TURBO_G: 3220ba2cbe9Sxc151355 asc->asc_rates[mode] = ATH_HAL_GETRATETABLE(ah, HAL_MODE_108G); 3230ba2cbe9Sxc151355 break; 3247a1306a7Sxc151355 default: 3257a1306a7Sxc151355 ATH_DEBUG((ATH_DBG_RATE, "ath: ath_rate_setup(): " 3267a1306a7Sxc151355 "invalid mode %u\n", mode)); 3277a1306a7Sxc151355 return; 3287a1306a7Sxc151355 } 3297a1306a7Sxc151355 3307a1306a7Sxc151355 rt = asc->asc_rates[mode]; 3317a1306a7Sxc151355 if (rt == NULL) 3327a1306a7Sxc151355 return; 3337a1306a7Sxc151355 if (rt->rateCount > IEEE80211_RATE_MAXSIZE) { 3347a1306a7Sxc151355 ATH_DEBUG((ATH_DBG_RATE, "ath: ath_rate_setup(): " 3357a1306a7Sxc151355 "rate table too small (%u > %u)\n", 3367a1306a7Sxc151355 rt->rateCount, IEEE80211_RATE_MAXSIZE)); 3377a1306a7Sxc151355 maxrates = IEEE80211_RATE_MAXSIZE; 3387a1306a7Sxc151355 } else 3397a1306a7Sxc151355 maxrates = rt->rateCount; 3400ba2cbe9Sxc151355 rs = &ic->ic_sup_rates[mode]; 3417a1306a7Sxc151355 for (i = 0; i < maxrates; i++) 3427a1306a7Sxc151355 rs->ir_rates[i] = rt->info[i].dot11Rate; 3437a1306a7Sxc151355 rs->ir_nrates = maxrates; 3447a1306a7Sxc151355 } 345