| .. | .. |
|---|
| 70 | 70 | } |
|---|
| 71 | 71 | |
|---|
| 72 | 72 | /* return current EMWA throughput */ |
|---|
| 73 | | -int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_ewma) |
|---|
| 73 | +int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_avg) |
|---|
| 74 | 74 | { |
|---|
| 75 | 75 | int usecs; |
|---|
| 76 | 76 | |
|---|
| .. | .. |
|---|
| 79 | 79 | usecs = 1000000; |
|---|
| 80 | 80 | |
|---|
| 81 | 81 | /* reset thr. below 10% success */ |
|---|
| 82 | | - if (mr->stats.prob_ewma < MINSTREL_FRAC(10, 100)) |
|---|
| 82 | + if (mr->stats.prob_avg < MINSTREL_FRAC(10, 100)) |
|---|
| 83 | 83 | return 0; |
|---|
| 84 | 84 | |
|---|
| 85 | | - if (prob_ewma > MINSTREL_FRAC(90, 100)) |
|---|
| 85 | + if (prob_avg > MINSTREL_FRAC(90, 100)) |
|---|
| 86 | 86 | return MINSTREL_TRUNC(100000 * (MINSTREL_FRAC(90, 100) / usecs)); |
|---|
| 87 | 87 | else |
|---|
| 88 | | - return MINSTREL_TRUNC(100000 * (prob_ewma / usecs)); |
|---|
| 88 | + return MINSTREL_TRUNC(100000 * (prob_avg / usecs)); |
|---|
| 89 | 89 | } |
|---|
| 90 | 90 | |
|---|
| 91 | 91 | /* find & sort topmost throughput rates */ |
|---|
| .. | .. |
|---|
| 98 | 98 | |
|---|
| 99 | 99 | for (j = MAX_THR_RATES; j > 0; --j) { |
|---|
| 100 | 100 | tmp_mrs = &mi->r[tp_list[j - 1]].stats; |
|---|
| 101 | | - if (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_ewma) <= |
|---|
| 102 | | - minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_ewma)) |
|---|
| 101 | + if (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_avg) <= |
|---|
| 102 | + minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_avg)) |
|---|
| 103 | 103 | break; |
|---|
| 104 | 104 | } |
|---|
| 105 | 105 | |
|---|
| .. | .. |
|---|
| 157 | 157 | * Recalculate statistics and counters of a given rate |
|---|
| 158 | 158 | */ |
|---|
| 159 | 159 | void |
|---|
| 160 | | -minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs) |
|---|
| 160 | +minstrel_calc_rate_stats(struct minstrel_priv *mp, |
|---|
| 161 | + struct minstrel_rate_stats *mrs) |
|---|
| 161 | 162 | { |
|---|
| 162 | 163 | unsigned int cur_prob; |
|---|
| 163 | 164 | |
|---|
| 164 | 165 | if (unlikely(mrs->attempts > 0)) { |
|---|
| 165 | 166 | mrs->sample_skipped = 0; |
|---|
| 166 | 167 | cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts); |
|---|
| 167 | | - if (unlikely(!mrs->att_hist)) { |
|---|
| 168 | | - mrs->prob_ewma = cur_prob; |
|---|
| 168 | + if (mp->new_avg) { |
|---|
| 169 | + minstrel_filter_avg_add(&mrs->prob_avg, |
|---|
| 170 | + &mrs->prob_avg_1, cur_prob); |
|---|
| 171 | + } else if (unlikely(!mrs->att_hist)) { |
|---|
| 172 | + mrs->prob_avg = cur_prob; |
|---|
| 169 | 173 | } else { |
|---|
| 170 | | - /* update exponential weighted moving variance */ |
|---|
| 171 | | - mrs->prob_ewmv = minstrel_ewmv(mrs->prob_ewmv, |
|---|
| 172 | | - cur_prob, |
|---|
| 173 | | - mrs->prob_ewma, |
|---|
| 174 | | - EWMA_LEVEL); |
|---|
| 175 | | - |
|---|
| 176 | 174 | /*update exponential weighted moving avarage */ |
|---|
| 177 | | - mrs->prob_ewma = minstrel_ewma(mrs->prob_ewma, |
|---|
| 178 | | - cur_prob, |
|---|
| 179 | | - EWMA_LEVEL); |
|---|
| 175 | + mrs->prob_avg = minstrel_ewma(mrs->prob_avg, |
|---|
| 176 | + cur_prob, |
|---|
| 177 | + EWMA_LEVEL); |
|---|
| 180 | 178 | } |
|---|
| 181 | 179 | mrs->att_hist += mrs->attempts; |
|---|
| 182 | 180 | mrs->succ_hist += mrs->success; |
|---|
| .. | .. |
|---|
| 206 | 204 | struct minstrel_rate_stats *tmp_mrs = &mi->r[tmp_prob_rate].stats; |
|---|
| 207 | 205 | |
|---|
| 208 | 206 | /* Update statistics of success probability per rate */ |
|---|
| 209 | | - minstrel_calc_rate_stats(mrs); |
|---|
| 207 | + minstrel_calc_rate_stats(mp, mrs); |
|---|
| 210 | 208 | |
|---|
| 211 | 209 | /* Sample less often below the 10% chance of success. |
|---|
| 212 | 210 | * Sample less often above the 95% chance of success. */ |
|---|
| 213 | | - if (mrs->prob_ewma > MINSTREL_FRAC(95, 100) || |
|---|
| 214 | | - mrs->prob_ewma < MINSTREL_FRAC(10, 100)) { |
|---|
| 211 | + if (mrs->prob_avg > MINSTREL_FRAC(95, 100) || |
|---|
| 212 | + mrs->prob_avg < MINSTREL_FRAC(10, 100)) { |
|---|
| 215 | 213 | mr->adjusted_retry_count = mrs->retry_count >> 1; |
|---|
| 216 | 214 | if (mr->adjusted_retry_count > 2) |
|---|
| 217 | 215 | mr->adjusted_retry_count = 2; |
|---|
| .. | .. |
|---|
| 231 | 229 | * choose the maximum throughput rate as max_prob_rate |
|---|
| 232 | 230 | * (2) if all success probabilities < 95%, the rate with |
|---|
| 233 | 231 | * highest success probability is chosen as max_prob_rate */ |
|---|
| 234 | | - if (mrs->prob_ewma >= MINSTREL_FRAC(95, 100)) { |
|---|
| 235 | | - tmp_cur_tp = minstrel_get_tp_avg(mr, mrs->prob_ewma); |
|---|
| 232 | + if (mrs->prob_avg >= MINSTREL_FRAC(95, 100)) { |
|---|
| 233 | + tmp_cur_tp = minstrel_get_tp_avg(mr, mrs->prob_avg); |
|---|
| 236 | 234 | tmp_prob_tp = minstrel_get_tp_avg(&mi->r[tmp_prob_rate], |
|---|
| 237 | | - tmp_mrs->prob_ewma); |
|---|
| 235 | + tmp_mrs->prob_avg); |
|---|
| 238 | 236 | if (tmp_cur_tp >= tmp_prob_tp) |
|---|
| 239 | 237 | tmp_prob_rate = i; |
|---|
| 240 | 238 | } else { |
|---|
| 241 | | - if (mrs->prob_ewma >= tmp_mrs->prob_ewma) |
|---|
| 239 | + if (mrs->prob_avg >= tmp_mrs->prob_avg) |
|---|
| 242 | 240 | tmp_prob_rate = i; |
|---|
| 243 | 241 | } |
|---|
| 244 | 242 | } |
|---|
| .. | .. |
|---|
| 290 | 288 | } |
|---|
| 291 | 289 | |
|---|
| 292 | 290 | if (time_after(jiffies, mi->last_stats_update + |
|---|
| 293 | | - (mp->update_interval * HZ) / 1000)) |
|---|
| 291 | + mp->update_interval / (mp->new_avg ? 2 : 1))) |
|---|
| 294 | 292 | minstrel_update_stats(mp, mi); |
|---|
| 295 | 293 | } |
|---|
| 296 | 294 | |
|---|
| .. | .. |
|---|
| 339 | 337 | bool prev_sample; |
|---|
| 340 | 338 | int delta; |
|---|
| 341 | 339 | int sampling_ratio; |
|---|
| 342 | | - |
|---|
| 343 | | - /* management/no-ack frames do not use rate control */ |
|---|
| 344 | | - if (rate_control_send_low(sta, priv_sta, txrc)) |
|---|
| 345 | | - return; |
|---|
| 346 | 340 | |
|---|
| 347 | 341 | /* check multi-rate-retry capabilities & adjust lookaround_rate */ |
|---|
| 348 | 342 | mrr_capable = mp->has_mrr && |
|---|
| .. | .. |
|---|
| 414 | 408 | * has a probability of >95%, we shouldn't be attempting |
|---|
| 415 | 409 | * to use it, as this only wastes precious airtime */ |
|---|
| 416 | 410 | if (!mrr_capable && |
|---|
| 417 | | - (mi->r[ndx].stats.prob_ewma > MINSTREL_FRAC(95, 100))) |
|---|
| 411 | + (mi->r[ndx].stats.prob_avg > MINSTREL_FRAC(95, 100))) |
|---|
| 418 | 412 | return; |
|---|
| 419 | 413 | |
|---|
| 420 | 414 | mi->prev_sample = true; |
|---|
| .. | .. |
|---|
| 555 | 549 | minstrel_update_rates(mp, mi); |
|---|
| 556 | 550 | } |
|---|
| 557 | 551 | |
|---|
| 558 | | -static void * |
|---|
| 559 | | -minstrel_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) |
|---|
| 560 | | -{ |
|---|
| 561 | | - struct ieee80211_supported_band *sband; |
|---|
| 562 | | - struct minstrel_sta_info *mi; |
|---|
| 563 | | - struct minstrel_priv *mp = priv; |
|---|
| 564 | | - struct ieee80211_hw *hw = mp->hw; |
|---|
| 565 | | - int max_rates = 0; |
|---|
| 566 | | - int i; |
|---|
| 567 | | - |
|---|
| 568 | | - mi = kzalloc(sizeof(struct minstrel_sta_info), gfp); |
|---|
| 569 | | - if (!mi) |
|---|
| 570 | | - return NULL; |
|---|
| 571 | | - |
|---|
| 572 | | - for (i = 0; i < NUM_NL80211_BANDS; i++) { |
|---|
| 573 | | - sband = hw->wiphy->bands[i]; |
|---|
| 574 | | - if (sband && sband->n_bitrates > max_rates) |
|---|
| 575 | | - max_rates = sband->n_bitrates; |
|---|
| 576 | | - } |
|---|
| 577 | | - |
|---|
| 578 | | - mi->r = kcalloc(max_rates, sizeof(struct minstrel_rate), gfp); |
|---|
| 579 | | - if (!mi->r) |
|---|
| 580 | | - goto error; |
|---|
| 581 | | - |
|---|
| 582 | | - mi->sample_table = kmalloc_array(max_rates, SAMPLE_COLUMNS, gfp); |
|---|
| 583 | | - if (!mi->sample_table) |
|---|
| 584 | | - goto error1; |
|---|
| 585 | | - |
|---|
| 586 | | - mi->last_stats_update = jiffies; |
|---|
| 587 | | - return mi; |
|---|
| 588 | | - |
|---|
| 589 | | -error1: |
|---|
| 590 | | - kfree(mi->r); |
|---|
| 591 | | -error: |
|---|
| 592 | | - kfree(mi); |
|---|
| 593 | | - return NULL; |
|---|
| 594 | | -} |
|---|
| 595 | | - |
|---|
| 596 | | -static void |
|---|
| 597 | | -minstrel_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta) |
|---|
| 598 | | -{ |
|---|
| 599 | | - struct minstrel_sta_info *mi = priv_sta; |
|---|
| 600 | | - |
|---|
| 601 | | - kfree(mi->sample_table); |
|---|
| 602 | | - kfree(mi->r); |
|---|
| 603 | | - kfree(mi); |
|---|
| 604 | | -} |
|---|
| 605 | | - |
|---|
| 606 | | -static void |
|---|
| 607 | | -minstrel_init_cck_rates(struct minstrel_priv *mp) |
|---|
| 608 | | -{ |
|---|
| 609 | | - static const int bitrates[4] = { 10, 20, 55, 110 }; |
|---|
| 610 | | - struct ieee80211_supported_band *sband; |
|---|
| 611 | | - u32 rate_flags = ieee80211_chandef_rate_flags(&mp->hw->conf.chandef); |
|---|
| 612 | | - int i, j; |
|---|
| 613 | | - |
|---|
| 614 | | - sband = mp->hw->wiphy->bands[NL80211_BAND_2GHZ]; |
|---|
| 615 | | - if (!sband) |
|---|
| 616 | | - return; |
|---|
| 617 | | - |
|---|
| 618 | | - for (i = 0, j = 0; i < sband->n_bitrates; i++) { |
|---|
| 619 | | - struct ieee80211_rate *rate = &sband->bitrates[i]; |
|---|
| 620 | | - |
|---|
| 621 | | - if (rate->flags & IEEE80211_RATE_ERP_G) |
|---|
| 622 | | - continue; |
|---|
| 623 | | - |
|---|
| 624 | | - if ((rate_flags & sband->bitrates[i].flags) != rate_flags) |
|---|
| 625 | | - continue; |
|---|
| 626 | | - |
|---|
| 627 | | - for (j = 0; j < ARRAY_SIZE(bitrates); j++) { |
|---|
| 628 | | - if (rate->bitrate != bitrates[j]) |
|---|
| 629 | | - continue; |
|---|
| 630 | | - |
|---|
| 631 | | - mp->cck_rates[j] = i; |
|---|
| 632 | | - break; |
|---|
| 633 | | - } |
|---|
| 634 | | - } |
|---|
| 635 | | -} |
|---|
| 636 | | - |
|---|
| 637 | | -static void * |
|---|
| 638 | | -minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) |
|---|
| 639 | | -{ |
|---|
| 640 | | - struct minstrel_priv *mp; |
|---|
| 641 | | - |
|---|
| 642 | | - mp = kzalloc(sizeof(struct minstrel_priv), GFP_ATOMIC); |
|---|
| 643 | | - if (!mp) |
|---|
| 644 | | - return NULL; |
|---|
| 645 | | - |
|---|
| 646 | | - /* contention window settings |
|---|
| 647 | | - * Just an approximation. Using the per-queue values would complicate |
|---|
| 648 | | - * the calculations and is probably unnecessary */ |
|---|
| 649 | | - mp->cw_min = 15; |
|---|
| 650 | | - mp->cw_max = 1023; |
|---|
| 651 | | - |
|---|
| 652 | | - /* number of packets (in %) to use for sampling other rates |
|---|
| 653 | | - * sample less often for non-mrr packets, because the overhead |
|---|
| 654 | | - * is much higher than with mrr */ |
|---|
| 655 | | - mp->lookaround_rate = 5; |
|---|
| 656 | | - mp->lookaround_rate_mrr = 10; |
|---|
| 657 | | - |
|---|
| 658 | | - /* maximum time that the hw is allowed to stay in one MRR segment */ |
|---|
| 659 | | - mp->segment_size = 6000; |
|---|
| 660 | | - |
|---|
| 661 | | - if (hw->max_rate_tries > 0) |
|---|
| 662 | | - mp->max_retry = hw->max_rate_tries; |
|---|
| 663 | | - else |
|---|
| 664 | | - /* safe default, does not necessarily have to match hw properties */ |
|---|
| 665 | | - mp->max_retry = 7; |
|---|
| 666 | | - |
|---|
| 667 | | - if (hw->max_rates >= 4) |
|---|
| 668 | | - mp->has_mrr = true; |
|---|
| 669 | | - |
|---|
| 670 | | - mp->hw = hw; |
|---|
| 671 | | - mp->update_interval = 100; |
|---|
| 672 | | - |
|---|
| 673 | | -#ifdef CONFIG_MAC80211_DEBUGFS |
|---|
| 674 | | - mp->fixed_rate_idx = (u32) -1; |
|---|
| 675 | | - mp->dbg_fixed_rate = debugfs_create_u32("fixed_rate_idx", |
|---|
| 676 | | - 0666, debugfsdir, &mp->fixed_rate_idx); |
|---|
| 677 | | -#endif |
|---|
| 678 | | - |
|---|
| 679 | | - minstrel_init_cck_rates(mp); |
|---|
| 680 | | - |
|---|
| 681 | | - return mp; |
|---|
| 682 | | -} |
|---|
| 683 | | - |
|---|
| 684 | | -static void |
|---|
| 685 | | -minstrel_free(void *priv) |
|---|
| 686 | | -{ |
|---|
| 687 | | -#ifdef CONFIG_MAC80211_DEBUGFS |
|---|
| 688 | | - debugfs_remove(((struct minstrel_priv *)priv)->dbg_fixed_rate); |
|---|
| 689 | | -#endif |
|---|
| 690 | | - kfree(priv); |
|---|
| 691 | | -} |
|---|
| 692 | | - |
|---|
| 693 | 552 | static u32 minstrel_get_expected_throughput(void *priv_sta) |
|---|
| 694 | 553 | { |
|---|
| 695 | 554 | struct minstrel_sta_info *mi = priv_sta; |
|---|
| .. | .. |
|---|
| 701 | 560 | * computing cur_tp |
|---|
| 702 | 561 | */ |
|---|
| 703 | 562 | tmp_mrs = &mi->r[idx].stats; |
|---|
| 704 | | - tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_ewma) * 10; |
|---|
| 563 | + tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_avg) * 10; |
|---|
| 705 | 564 | tmp_cur_tp = tmp_cur_tp * 1200 * 8 / 1024; |
|---|
| 706 | 565 | |
|---|
| 707 | 566 | return tmp_cur_tp; |
|---|
| 708 | 567 | } |
|---|
| 709 | 568 | |
|---|
| 710 | 569 | const struct rate_control_ops mac80211_minstrel = { |
|---|
| 711 | | - .name = "minstrel", |
|---|
| 712 | 570 | .tx_status_ext = minstrel_tx_status, |
|---|
| 713 | 571 | .get_rate = minstrel_get_rate, |
|---|
| 714 | 572 | .rate_init = minstrel_rate_init, |
|---|
| 715 | | - .alloc = minstrel_alloc, |
|---|
| 716 | | - .free = minstrel_free, |
|---|
| 717 | | - .alloc_sta = minstrel_alloc_sta, |
|---|
| 718 | | - .free_sta = minstrel_free_sta, |
|---|
| 719 | | -#ifdef CONFIG_MAC80211_DEBUGFS |
|---|
| 720 | | - .add_sta_debugfs = minstrel_add_sta_debugfs, |
|---|
| 721 | | - .remove_sta_debugfs = minstrel_remove_sta_debugfs, |
|---|
| 722 | | -#endif |
|---|
| 723 | 573 | .get_expected_throughput = minstrel_get_expected_throughput, |
|---|
| 724 | 574 | }; |
|---|
| 725 | | - |
|---|
| 726 | | -int __init |
|---|
| 727 | | -rc80211_minstrel_init(void) |
|---|
| 728 | | -{ |
|---|
| 729 | | - return ieee80211_rate_control_register(&mac80211_minstrel); |
|---|
| 730 | | -} |
|---|
| 731 | | - |
|---|
| 732 | | -void |
|---|
| 733 | | -rc80211_minstrel_exit(void) |
|---|
| 734 | | -{ |
|---|
| 735 | | - ieee80211_rate_control_unregister(&mac80211_minstrel); |
|---|
| 736 | | -} |
|---|