📄 minstrel.c.svn-base
字号:
{ ath_rate_ctl_reset(netdev_priv(ni->ni_ic->ic_dev), ni);}/* Reset the rate control state for each 802.11 state transition. */static voidath_rate_newstate(struct ieee80211vap *vap, enum ieee80211_state newstate){ struct ieee80211com *ic = vap->iv_ic; if (newstate == IEEE80211_S_RUN) { if (ic->ic_opmode != IEEE80211_M_STA) { /* Sync rates for associated stations and * neighbors. */ ieee80211_iterate_nodes(&ic->ic_sta, ath_rate_cb, NULL); } ath_rate_newassoc(netdev_priv(ic->ic_dev), ATH_NODE(vap->iv_bss), 1); }}static voidath_timer_function(unsigned long data){ struct minstrel_softc *ssc = (struct minstrel_softc *)data; struct ath_softc *sc = ssc->sc; struct ieee80211com *ic; struct net_device *dev = ssc->sc_dev; struct timer_list *timer; unsigned int interval = ath_timer_interval; if (dev == NULL) DPRINTF(sc, "%s: 'dev' is null in this timer \n", __func__); if (sc == NULL) DPRINTF(sc, "%s: 'sc' is null in this timer\n", __func__); ic = &sc->sc_ic; if (ssc->close_timer_now) return; if (dev->flags & IFF_RUNNING) { sc->sc_stats.ast_rate_calls++; if (ic->ic_opmode == IEEE80211_M_STA) { struct ieee80211vap *tmpvap; TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) { /* NB: no reference */ ath_rate_statistics(sc, tmpvap->iv_bss); } } else ieee80211_iterate_nodes(&ic->ic_sta, ath_rate_statistics, sc); } if (ic->ic_opmode == IEEE80211_M_STA) interval = ath_timer_interval >> 1; timer = &(ssc->timer); if (timer == NULL) DPRINTF(sc, "%s: timer is null - leave it\n", __func__); mod_timer(timer, jiffies + ((HZ * interval) / 1000));}static voidath_rate_statistics(void *arg, struct ieee80211_node *ni){ struct ath_node *an = (struct ath_node *)ni; struct ieee80211_rateset *rs = &ni->ni_rates; struct minstrel_node *rn = ATH_NODE_MINSTREL(an); unsigned int i; u_int32_t p; u_int32_t micro_secs; u_int32_t max_prob, index_max_prob; u_int32_t max_tp, index_max_tp, index_max_tp2; /* Calculate statistics for each date rate in the table */ /* 'micro_secs' is the time to transmit 1200 bytes, or 9600 bits. */ for (i = 0; i < rs->rs_nrates; i++) { micro_secs = rn->perfect_tx_time[i]; if (micro_secs == 0) micro_secs = ONE_SECOND; if (rn->rs_rateattempts[i] != 0) { p = (rn->rs_ratesuccess[i] * 18000) / rn->rs_rateattempts[i]; rn->rs_succ_hist[i] += rn->rs_ratesuccess[i]; rn->rs_att_hist[i] += rn->rs_rateattempts[i]; rn->rs_thisprob[i] = p; p = ((p * (100 - ath_ewma_level)) + (rn->rs_probability[i] * ath_ewma_level)) / 100; rn->rs_probability[i] = p; rn->rs_this_tp[i] = p * (ONE_SECOND / micro_secs); rn->rs_lastratesuccess[i] = rn->rs_ratesuccess[i]; rn->rs_lastrateattempts[i] = rn->rs_rateattempts[i]; rn->rs_ratesuccess[i] = 0; rn->rs_rateattempts[i] = 0; } else { rn->rs_lastratesuccess[i] = 0; rn->rs_lastrateattempts[i] = 0; } /* Sample less often below the 10% chance of success. * Sample less often above the 95% chance of success. * 'rn->rs_probability' has a scale of 0 (0%) to 18000 (100%), * which avoids rounding issues.*/ if ((rn->rs_probability[i] > 17100) || (rn->rs_probability[i] < 1800)) { rn->retry_adjusted_count[i] = rn->retry_count[i] >> 1; if (rn->retry_adjusted_count[i] > 2) rn->retry_adjusted_count[i] = 2; } else rn->retry_adjusted_count[i] = rn->retry_count[i]; if (rn->retry_adjusted_count[i] == 0) rn->retry_adjusted_count[i] = 1; } /* The High speed rates (e.g 54Mbps) is checked last. If * throughput is the same for two rates, we prefer the * lower rate, as this has a better chance of success. */ max_prob = 0; index_max_prob = 0; max_tp = 0; index_max_tp = 0; index_max_tp2 = 0; /* This code could have been moved up into the previous * loop. More readable to have it here */ for (i = 0; i < rs->rs_nrates; i++) { if (max_tp < rn->rs_this_tp[i]) { index_max_tp = i; max_tp = rn->rs_this_tp[i]; } if (max_prob < rn->rs_probability[i]) { index_max_prob = i; max_prob = rn->rs_probability[i]; } } max_tp = 0; for (i = 0; i < rs->rs_nrates; i++) { if ((i != index_max_tp) && (max_tp < rn->rs_this_tp[i])) { index_max_tp2 = i; max_tp = rn->rs_this_tp[i]; } } rn->max_tp_rate = index_max_tp; rn->max_tp_rate2 = index_max_tp2; rn->max_prob_rate = index_max_prob; rn->current_rate = index_max_tp;}static struct ath_ratectrl *ath_rate_attach(struct ath_softc *sc){ struct minstrel_softc *osc; DPRINTF(sc, "%s: %s\n", dev_info, __func__); _MOD_INC_USE(THIS_MODULE, return NULL); osc = kmalloc(sizeof(struct minstrel_softc), GFP_ATOMIC); if (osc == NULL) { _MOD_DEC_USE(THIS_MODULE); return NULL; } osc->arc.arc_space = sizeof(struct minstrel_node); osc->arc.arc_vap_space = 0; osc->close_timer_now = 0; init_timer(&osc->timer); osc->sc = sc; osc->sc_dev = sc->sc_dev; osc->timer.function = ath_timer_function; osc->timer.data = (unsigned long)osc; mod_timer(&osc->timer, jiffies + HZ); return &osc->arc;}static voidath_rate_detach(struct ath_ratectrl *arc){ struct minstrel_softc *osc = (struct minstrel_softc *)arc; osc->close_timer_now = 1; del_timer(&osc->timer); kfree(osc); _MOD_DEC_USE(THIS_MODULE);}#ifdef CONFIG_SYSCTLstatic intath_proc_read_nodes(struct ieee80211vap *vap, char *buf, int space){ char *p = buf; struct ieee80211_node *ni; struct minstrel_node *odst; struct ieee80211_node_table *nt = (struct ieee80211_node_table *)&vap->iv_ic->ic_sta; unsigned int x = 0; unsigned int this_tp, this_prob, this_eprob; struct ath_softc *sc = netdev_priv(vap->iv_ic->ic_dev); IEEE80211_NODE_TABLE_LOCK_IRQ(nt); TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { /* Assume each node needs 1500 bytes */ if ((buf + space) < (p + 1500)) { if ((buf + space) > (p + 100)) { p += sprintf(p, "out of room for node " MAC_FMT "\n\n", MAC_ADDR(ni->ni_macaddr)); break; } DPRINTF(sc, "%s: out of memeory to write " "all of the nodes\n", __func__); break; } odst = ATH_NODE_MINSTREL(ATH_NODE(ni)); /* Skip ourself */ if (IEEE80211_ADDR_EQ(vap->iv_myaddr, ni->ni_macaddr)) continue; p += sprintf(p, "rate data for node: " MAC_FMT "\n", MAC_ADDR(ni->ni_macaddr)); p += sprintf(p, " rate throughput EWMA prob this prob this " "succ/attempt success attempts\n"); for (x = 0; x < odst->num_rates; x++) { p += sprintf(p, "%c", (x == odst->current_rate) ? 'T' : ' '); p += sprintf(p, "%c", (x == odst->max_tp_rate2) ? 't' : ' '); p += sprintf(p, "%c", (x == odst->max_prob_rate) ? 'P' : ' '); p += sprintf(p, " %2u%s", odst->rates[x].rate / 2, (odst->rates[x].rate & 0x1) != 0 ? ".5" : " "); this_tp = ((odst->rs_this_tp[x] / 18000) * 96) >> 10; this_prob = odst->rs_thisprob[x] / 18; this_eprob = odst->rs_probability[x] / 18; p += sprintf(p, " %2u.%1u %2u.%1u %6u.%1u" " %3u(%3u) %8llu %8llu\n", this_tp / 10, this_tp % 10, this_eprob / 10, this_eprob % 10, this_prob / 10, this_prob % 10, odst->rs_lastratesuccess[x], odst->rs_lastrateattempts[x], (unsigned long long)odst->rs_succ_hist[x], (unsigned long long)odst->rs_att_hist[x]); } p += sprintf(p, "\n"); p += sprintf(p, "Total packet count:: ideal %d " "lookaround %d\n\n", odst->packet_count, odst->sample_count); } IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt); return (p - buf);}static intath_proc_ratesample_open(struct inode *inode, struct file *file){ struct proc_ieee80211_priv *pv = NULL; struct proc_dir_entry *dp = PDE(inode); struct ieee80211vap *vap = dp->data; if (!(file->private_data = kzalloc(sizeof(struct proc_ieee80211_priv), GFP_KERNEL))) return -ENOMEM; /* Initially allocate both read and write buffers */ pv = (struct proc_ieee80211_priv *)file->private_data; pv->rbuf = vmalloc(MAX_PROC_IEEE80211_SIZE); if (!pv->rbuf) { kfree(pv); return -ENOMEM; } pv->wbuf = vmalloc(MAX_PROC_IEEE80211_SIZE); if (!pv->wbuf) { vfree(pv->rbuf); kfree(pv); return -ENOMEM; } memset(pv->wbuf, 0, MAX_PROC_IEEE80211_SIZE); memset(pv->rbuf, 0, MAX_PROC_IEEE80211_SIZE); pv->max_wlen = MAX_PROC_IEEE80211_SIZE; pv->max_rlen = MAX_PROC_IEEE80211_SIZE; /* Now read the data into the buffer */ pv->rlen = ath_proc_read_nodes(vap, pv->rbuf, MAX_PROC_IEEE80211_SIZE); return 0;}static struct file_operations ath_proc_ratesample_ops = { .read = NULL, .write = NULL, .open = ath_proc_ratesample_open, .release = NULL,};static voidath_rate_dynamic_proc_register(struct ieee80211vap *vap){ /* Create proc entries for the rate control algorithm */ ieee80211_proc_vcreate(vap, &ath_proc_ratesample_ops, "rate_info");}#endif /* CONFIG_SYSCTL */static struct ieee80211_rate_ops ath_rate_ops = { .ratectl_id = IEEE80211_RATE_MINSTREL, .node_init = ath_rate_node_init, .node_cleanup = ath_rate_node_cleanup, .findrate = ath_rate_findrate, .get_mrr = ath_rate_get_mrr, .tx_complete = ath_rate_tx_complete, .newassoc = ath_rate_newassoc, .newstate = ath_rate_newstate, .attach = ath_rate_attach, .detach = ath_rate_detach, .dynamic_proc_register = ath_rate_dynamic_proc_register,};MODULE_AUTHOR("John Bicket/Derek Smithies");MODULE_DESCRIPTION("Minstrel Rate bit-rate selection algorithm for Atheros devices");#ifdef MODULE_VERSIONMODULE_VERSION(RELEASE_VERSION);#endif#ifdef MODULE_LICENSEMODULE_LICENSE("Dual BSD/GPL");#endifstatic int __init ath_rate_minstrel_init(void){/* Debugging output - disabled as noisy. */#if 0 printk(KERN_INFO "%s: look around rate set to %d%%\n", dev_info, ath_lookaround_rate); printk(KERN_INFO "%s: EWMA rolloff level set to %d%%\n", dev_info, ath_ewma_level); printk(KERN_INFO "%s: max segment size in the MRR set " "to %d us\n", dev_info, ath_segment_size);#endif return ieee80211_rate_register(&ath_rate_ops);}module_init(ath_rate_minstrel_init);static void __exit ath_rate_minstrel_exit(void){ ieee80211_rate_unregister(&ath_rate_ops);}module_exit(ath_rate_minstrel_exit);/* The comment below is magic for those who use emacs to edit this file. *//* With the comment below, the tab key does auto indent to 8 spaces. *//* * Local Variables: * mode:c * c-file-style:linux * c-basic-offset:8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -