1*e07d9cb8Szf162725 /* 2*e07d9cb8Szf162725 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 3*e07d9cb8Szf162725 * Use is subject to license terms. 4*e07d9cb8Szf162725 */ 5*e07d9cb8Szf162725 6*e07d9cb8Szf162725 /* 7*e07d9cb8Szf162725 * Copyright (c) 2003, 2004 David Young. All rights reserved. 8*e07d9cb8Szf162725 * 9*e07d9cb8Szf162725 * Redistribution and use in source and binary forms, with or 10*e07d9cb8Szf162725 * without modification, are permitted provided that the following 11*e07d9cb8Szf162725 * conditions are met: 12*e07d9cb8Szf162725 * 1. Redistributions of source code must retain the above copyright 13*e07d9cb8Szf162725 * notice, this list of conditions and the following disclaimer. 14*e07d9cb8Szf162725 * 2. Redistributions in binary form must reproduce the above 15*e07d9cb8Szf162725 * copyright notice, this list of conditions and the following 16*e07d9cb8Szf162725 * disclaimer in the documentation and/or other materials provided 17*e07d9cb8Szf162725 * with the distribution. 18*e07d9cb8Szf162725 * 3. The name of David Young may not be used to endorse or promote 19*e07d9cb8Szf162725 * products derived from this software without specific prior 20*e07d9cb8Szf162725 * written permission. 21*e07d9cb8Szf162725 * 22*e07d9cb8Szf162725 * THIS SOFTWARE IS PROVIDED BY David Young ``AS IS'' AND ANY 23*e07d9cb8Szf162725 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 24*e07d9cb8Szf162725 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 25*e07d9cb8Szf162725 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David 26*e07d9cb8Szf162725 * Young BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 27*e07d9cb8Szf162725 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 28*e07d9cb8Szf162725 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29*e07d9cb8Szf162725 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30*e07d9cb8Szf162725 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31*e07d9cb8Szf162725 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32*e07d9cb8Szf162725 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 33*e07d9cb8Szf162725 * OF SUCH DAMAGE. 34*e07d9cb8Szf162725 */ 35*e07d9cb8Szf162725 36*e07d9cb8Szf162725 #pragma ident "%Z%%M% %I% %E% SMI" 37*e07d9cb8Szf162725 38*e07d9cb8Szf162725 #include <sys/types.h> 39*e07d9cb8Szf162725 #include <sys/byteorder.h> 40*e07d9cb8Szf162725 #include <sys/conf.h> 41*e07d9cb8Szf162725 #include <sys/cmn_err.h> 42*e07d9cb8Szf162725 #include <sys/ddi.h> 43*e07d9cb8Szf162725 #include <sys/sunddi.h> 44*e07d9cb8Szf162725 #include <sys/stream.h> 45*e07d9cb8Szf162725 #include <sys/strsun.h> 46*e07d9cb8Szf162725 #include <sys/modctl.h> 47*e07d9cb8Szf162725 #include <sys/devops.h> 48*e07d9cb8Szf162725 #include <sys/dlpi.h> 49*e07d9cb8Szf162725 #include <sys/gld.h> 50*e07d9cb8Szf162725 #include <sys/varargs.h> 51*e07d9cb8Szf162725 #include <sys/pci.h> 52*e07d9cb8Szf162725 #include <sys/net80211.h> 53*e07d9cb8Szf162725 54*e07d9cb8Szf162725 #include "ral_rate.h" 55*e07d9cb8Szf162725 56*e07d9cb8Szf162725 #define MAX(a, b) ((a) > (b) ? (a) : (b)) 57*e07d9cb8Szf162725 58*e07d9cb8Szf162725 #ifdef interpolate 59*e07d9cb8Szf162725 #undef interpolate 60*e07d9cb8Szf162725 #endif 61*e07d9cb8Szf162725 #define interpolate(parm, old, new) \ 62*e07d9cb8Szf162725 ((parm##_old * (old) + \ 63*e07d9cb8Szf162725 (parm##_denom - parm##_old) * (new)) / \ 64*e07d9cb8Szf162725 parm##_denom) 65*e07d9cb8Szf162725 66*e07d9cb8Szf162725 static struct ral_rssadapt_expavgctl master_expavgctl; 67*e07d9cb8Szf162725 68*e07d9cb8Szf162725 void 69*e07d9cb8Szf162725 ral_rate_init(void) 70*e07d9cb8Szf162725 { 71*e07d9cb8Szf162725 master_expavgctl.rc_decay_denom = 16; 72*e07d9cb8Szf162725 master_expavgctl.rc_decay_old = 15; 73*e07d9cb8Szf162725 master_expavgctl.rc_thresh_denom = 8; 74*e07d9cb8Szf162725 master_expavgctl.rc_thresh_old = 4; 75*e07d9cb8Szf162725 master_expavgctl.rc_avgrssi_denom = 8; 76*e07d9cb8Szf162725 master_expavgctl.rc_avgrssi_old = 4; 77*e07d9cb8Szf162725 } 78*e07d9cb8Szf162725 79*e07d9cb8Szf162725 /* ARGSUSED */ 80*e07d9cb8Szf162725 int 81*e07d9cb8Szf162725 ral_rssadapt_choose(struct ral_rssadapt *ra, struct ieee80211_rateset *rs, 82*e07d9cb8Szf162725 struct ieee80211_frame *wh, uint32_t len, 83*e07d9cb8Szf162725 const char *dvname, int do_not_adapt) 84*e07d9cb8Szf162725 { 85*e07d9cb8Szf162725 uint16_t (*thrs)[IEEE80211_RATE_SIZE]; 86*e07d9cb8Szf162725 int flags = 0, i, rateidx = 0, thridx, top; 87*e07d9cb8Szf162725 88*e07d9cb8Szf162725 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) 89*e07d9cb8Szf162725 flags |= IEEE80211_RATE_BASIC; 90*e07d9cb8Szf162725 91*e07d9cb8Szf162725 for (i = 0, top = RAL_RSSADAPT_BKT0; 92*e07d9cb8Szf162725 i < RAL_RSSADAPT_BKTS; 93*e07d9cb8Szf162725 i++, top <<= RAL_RSSADAPT_BKTPOWER) { 94*e07d9cb8Szf162725 thridx = i; 95*e07d9cb8Szf162725 if (len <= top) 96*e07d9cb8Szf162725 break; 97*e07d9cb8Szf162725 } 98*e07d9cb8Szf162725 99*e07d9cb8Szf162725 thrs = &ra->ra_rate_thresh[thridx]; 100*e07d9cb8Szf162725 101*e07d9cb8Szf162725 i = rs->ir_nrates; 102*e07d9cb8Szf162725 while (--i >= 0) { 103*e07d9cb8Szf162725 rateidx = i; 104*e07d9cb8Szf162725 if ((rs->ir_rates[i] & flags) != flags) 105*e07d9cb8Szf162725 continue; 106*e07d9cb8Szf162725 if (do_not_adapt) 107*e07d9cb8Szf162725 break; 108*e07d9cb8Szf162725 if ((*thrs)[i] < ra->ra_avg_rssi) 109*e07d9cb8Szf162725 break; 110*e07d9cb8Szf162725 } 111*e07d9cb8Szf162725 112*e07d9cb8Szf162725 return (rateidx); 113*e07d9cb8Szf162725 } 114*e07d9cb8Szf162725 115*e07d9cb8Szf162725 void 116*e07d9cb8Szf162725 ral_rssadapt_updatestats(struct ral_rssadapt *ra) 117*e07d9cb8Szf162725 { 118*e07d9cb8Szf162725 long interval; 119*e07d9cb8Szf162725 120*e07d9cb8Szf162725 ra->ra_pktrate = 121*e07d9cb8Szf162725 (ra->ra_pktrate + 10 * (ra->ra_nfail + ra->ra_nok)) / 2; 122*e07d9cb8Szf162725 ra->ra_nfail = ra->ra_nok = 0; 123*e07d9cb8Szf162725 124*e07d9cb8Szf162725 /* 125*e07d9cb8Szf162725 * a node is eligible for its rate to be raised every 1/10 to 10 126*e07d9cb8Szf162725 * seconds, more eligible in proportion to recent packet rates. 127*e07d9cb8Szf162725 */ 128*e07d9cb8Szf162725 interval = MAX(100000, 10000000 / MAX(1, 10 * ra->ra_pktrate)); 129*e07d9cb8Szf162725 ra->ra_raise_interval.tv_sec = interval / (1000 * 1000); 130*e07d9cb8Szf162725 ra->ra_raise_interval.tv_usec = interval % (1000 * 1000); 131*e07d9cb8Szf162725 } 132*e07d9cb8Szf162725 133*e07d9cb8Szf162725 /* ARGSUSED */ 134*e07d9cb8Szf162725 void 135*e07d9cb8Szf162725 ral_rssadapt_input(struct ieee80211com *ic, struct ieee80211_node *ni, 136*e07d9cb8Szf162725 struct ral_rssadapt *ra, int rssi) 137*e07d9cb8Szf162725 { 138*e07d9cb8Szf162725 ra->ra_avg_rssi = interpolate(master_expavgctl.rc_avgrssi, 139*e07d9cb8Szf162725 ra->ra_avg_rssi, (rssi << 8)); 140*e07d9cb8Szf162725 } 141*e07d9cb8Szf162725 142*e07d9cb8Szf162725 /* 143*e07d9cb8Szf162725 * Adapt the data rate to suit the conditions. When a transmitted 144*e07d9cb8Szf162725 * packet is dropped after RAL_RSSADAPT_RETRY_LIMIT retransmissions, 145*e07d9cb8Szf162725 * raise the RSS threshold for transmitting packets of similar length at 146*e07d9cb8Szf162725 * the same data rate. 147*e07d9cb8Szf162725 */ 148*e07d9cb8Szf162725 /* ARGSUSED */ 149*e07d9cb8Szf162725 void 150*e07d9cb8Szf162725 ral_rssadapt_lower_rate(struct ieee80211com *ic, struct ieee80211_node *ni, 151*e07d9cb8Szf162725 struct ral_rssadapt *ra, struct ral_rssdesc *id) 152*e07d9cb8Szf162725 { 153*e07d9cb8Szf162725 struct ieee80211_rateset *rs = &ni->in_rates; 154*e07d9cb8Szf162725 uint16_t last_thr; 155*e07d9cb8Szf162725 uint32_t i, thridx, top; 156*e07d9cb8Szf162725 157*e07d9cb8Szf162725 ra->ra_nfail++; 158*e07d9cb8Szf162725 159*e07d9cb8Szf162725 if (id->id_rateidx >= rs->ir_nrates) 160*e07d9cb8Szf162725 return; 161*e07d9cb8Szf162725 162*e07d9cb8Szf162725 for (i = 0, top = RAL_RSSADAPT_BKT0; 163*e07d9cb8Szf162725 i < RAL_RSSADAPT_BKTS; 164*e07d9cb8Szf162725 i++, top <<= RAL_RSSADAPT_BKTPOWER) { 165*e07d9cb8Szf162725 thridx = i; 166*e07d9cb8Szf162725 if (id->id_len <= top) 167*e07d9cb8Szf162725 break; 168*e07d9cb8Szf162725 } 169*e07d9cb8Szf162725 170*e07d9cb8Szf162725 last_thr = ra->ra_rate_thresh[thridx][id->id_rateidx]; 171*e07d9cb8Szf162725 ra->ra_rate_thresh[thridx][id->id_rateidx] = 172*e07d9cb8Szf162725 interpolate(master_expavgctl.rc_thresh, last_thr, 173*e07d9cb8Szf162725 (id->id_rssi << 8)); 174*e07d9cb8Szf162725 } 175*e07d9cb8Szf162725 176*e07d9cb8Szf162725 /* ARGSUSED */ 177*e07d9cb8Szf162725 void 178*e07d9cb8Szf162725 ral_rssadapt_raise_rate(struct ieee80211com *ic, struct ral_rssadapt *ra, 179*e07d9cb8Szf162725 struct ral_rssdesc *id) 180*e07d9cb8Szf162725 { 181*e07d9cb8Szf162725 uint16_t (*thrs)[IEEE80211_RATE_SIZE], newthr, oldthr; 182*e07d9cb8Szf162725 struct ieee80211_node *ni = id->id_node; 183*e07d9cb8Szf162725 struct ieee80211_rateset *rs = &ni->in_rates; 184*e07d9cb8Szf162725 int i, top; 185*e07d9cb8Szf162725 186*e07d9cb8Szf162725 ra->ra_nok++; 187*e07d9cb8Szf162725 188*e07d9cb8Szf162725 for (i = 0, top = RAL_RSSADAPT_BKT0; 189*e07d9cb8Szf162725 i < RAL_RSSADAPT_BKTS; 190*e07d9cb8Szf162725 i++, top <<= RAL_RSSADAPT_BKTPOWER) { 191*e07d9cb8Szf162725 thrs = &ra->ra_rate_thresh[i]; 192*e07d9cb8Szf162725 if (id->id_len <= top) 193*e07d9cb8Szf162725 break; 194*e07d9cb8Szf162725 } 195*e07d9cb8Szf162725 196*e07d9cb8Szf162725 if (id->id_rateidx + 1 < rs->ir_nrates && 197*e07d9cb8Szf162725 (*thrs)[id->id_rateidx + 1] > (*thrs)[id->id_rateidx]) { 198*e07d9cb8Szf162725 oldthr = (*thrs)[id->id_rateidx + 1]; 199*e07d9cb8Szf162725 if ((*thrs)[id->id_rateidx] == 0) 200*e07d9cb8Szf162725 newthr = ra->ra_avg_rssi; 201*e07d9cb8Szf162725 else 202*e07d9cb8Szf162725 newthr = (*thrs)[id->id_rateidx]; 203*e07d9cb8Szf162725 (*thrs)[id->id_rateidx + 1] = 204*e07d9cb8Szf162725 interpolate(master_expavgctl.rc_decay, oldthr, newthr); 205*e07d9cb8Szf162725 } 206*e07d9cb8Szf162725 } 207