URL
https://opencores.org/ocsvn/test_project/test_project/trunk
Subversion Repositories test_project
[/] [test_project/] [trunk/] [linux_sd_driver/] [net/] [mac80211/] [rc80211_simple.c] - Rev 62
Compare with Previous | Blame | View Log
/* * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005, Devicescape Software, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include <linux/init.h> #include <linux/netdevice.h> #include <linux/types.h> #include <linux/slab.h> #include <linux/skbuff.h> #include <linux/compiler.h> #include <net/mac80211.h> #include "ieee80211_i.h" #include "ieee80211_rate.h" #include "debugfs.h" /* This is a minimal implementation of TX rate controlling that can be used * as the default when no improved mechanisms are available. */ #define RATE_CONTROL_EMERG_DEC 2 #define RATE_CONTROL_INTERVAL (HZ / 20) #define RATE_CONTROL_MIN_TX 10 static void rate_control_rate_inc(struct ieee80211_local *local, struct sta_info *sta) { struct ieee80211_sub_if_data *sdata; struct ieee80211_hw_mode *mode; int i = sta->txrate; int maxrate; sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { /* forced unicast rate - do not change STA rate */ return; } mode = local->oper_hw_mode; maxrate = sdata->bss ? sdata->bss->max_ratectrl_rateidx : -1; if (i > mode->num_rates) i = mode->num_rates - 2; while (i + 1 < mode->num_rates) { i++; if (sta->supp_rates & BIT(i) && mode->rates[i].flags & IEEE80211_RATE_SUPPORTED && (maxrate < 0 || i <= maxrate)) { sta->txrate = i; break; } } } static void rate_control_rate_dec(struct ieee80211_local *local, struct sta_info *sta) { struct ieee80211_sub_if_data *sdata; struct ieee80211_hw_mode *mode; int i = sta->txrate; sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { /* forced unicast rate - do not change STA rate */ return; } mode = local->oper_hw_mode; if (i > mode->num_rates) i = mode->num_rates; while (i > 0) { i--; if (sta->supp_rates & BIT(i) && mode->rates[i].flags & IEEE80211_RATE_SUPPORTED) { sta->txrate = i; break; } } } static struct ieee80211_rate * rate_control_lowest_rate(struct ieee80211_local *local, struct ieee80211_hw_mode *mode) { int i; for (i = 0; i < mode->num_rates; i++) { struct ieee80211_rate *rate = &mode->rates[i]; if (rate->flags & IEEE80211_RATE_SUPPORTED) return rate; } printk(KERN_DEBUG "rate_control_lowest_rate - no supported rates " "found\n"); return &mode->rates[0]; } struct global_rate_control { int dummy; }; struct sta_rate_control { unsigned long last_rate_change; u32 tx_num_failures; u32 tx_num_xmit; unsigned long avg_rate_update; u32 tx_avg_rate_sum; u32 tx_avg_rate_num; #ifdef CONFIG_MAC80211_DEBUGFS struct dentry *tx_avg_rate_sum_dentry; struct dentry *tx_avg_rate_num_dentry; #endif }; static void rate_control_simple_tx_status(void *priv, struct net_device *dev, struct sk_buff *skb, struct ieee80211_tx_status *status) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct sta_info *sta; struct sta_rate_control *srctrl; sta = sta_info_get(local, hdr->addr1); if (!sta) return; srctrl = sta->rate_ctrl_priv; srctrl->tx_num_xmit++; if (status->excessive_retries) { srctrl->tx_num_failures++; sta->tx_retry_failed++; sta->tx_num_consecutive_failures++; sta->tx_num_mpdu_fail++; } else { sta->last_ack_rssi[0] = sta->last_ack_rssi[1]; sta->last_ack_rssi[1] = sta->last_ack_rssi[2]; sta->last_ack_rssi[2] = status->ack_signal; sta->tx_num_consecutive_failures = 0; sta->tx_num_mpdu_ok++; } sta->tx_retry_count += status->retry_count; sta->tx_num_mpdu_fail += status->retry_count; if (time_after(jiffies, srctrl->last_rate_change + RATE_CONTROL_INTERVAL) && srctrl->tx_num_xmit > RATE_CONTROL_MIN_TX) { u32 per_failed; srctrl->last_rate_change = jiffies; per_failed = (100 * sta->tx_num_mpdu_fail) / (sta->tx_num_mpdu_fail + sta->tx_num_mpdu_ok); /* TODO: calculate average per_failed to make adjusting * parameters easier */ #if 0 if (net_ratelimit()) { printk(KERN_DEBUG "MPDU fail=%d ok=%d per_failed=%d\n", sta->tx_num_mpdu_fail, sta->tx_num_mpdu_ok, per_failed); } #endif /* * XXX: Make these configurable once we have an * interface to the rate control algorithms */ if (per_failed > RATE_CONTROL_NUM_DOWN) { rate_control_rate_dec(local, sta); } else if (per_failed < RATE_CONTROL_NUM_UP) { rate_control_rate_inc(local, sta); } srctrl->tx_avg_rate_sum += status->control.rate->rate; srctrl->tx_avg_rate_num++; srctrl->tx_num_failures = 0; srctrl->tx_num_xmit = 0; } else if (sta->tx_num_consecutive_failures >= RATE_CONTROL_EMERG_DEC) { rate_control_rate_dec(local, sta); } if (srctrl->avg_rate_update + 60 * HZ < jiffies) { srctrl->avg_rate_update = jiffies; if (srctrl->tx_avg_rate_num > 0) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "%s: STA %s Average rate: " "%d (%d/%d)\n", dev->name, print_mac(mac, sta->addr), srctrl->tx_avg_rate_sum / srctrl->tx_avg_rate_num, srctrl->tx_avg_rate_sum, srctrl->tx_avg_rate_num); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ srctrl->tx_avg_rate_sum = 0; srctrl->tx_avg_rate_num = 0; } } sta_info_put(sta); } static struct ieee80211_rate * rate_control_simple_get_rate(void *priv, struct net_device *dev, struct sk_buff *skb, struct rate_control_extra *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_hw_mode *mode = extra->mode; struct sta_info *sta; int rateidx, nonerp_idx; u16 fc; memset(extra, 0, sizeof(*extra)); fc = le16_to_cpu(hdr->frame_control); if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || (hdr->addr1[0] & 0x01)) { /* Send management frames and broadcast/multicast data using * lowest rate. */ /* TODO: this could probably be improved.. */ return rate_control_lowest_rate(local, mode); } sta = sta_info_get(local, hdr->addr1); if (!sta) return rate_control_lowest_rate(local, mode); sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) sta->txrate = sdata->bss->force_unicast_rateidx; rateidx = sta->txrate; if (rateidx >= mode->num_rates) rateidx = mode->num_rates - 1; sta->last_txrate = rateidx; nonerp_idx = rateidx; while (nonerp_idx > 0 && ((mode->rates[nonerp_idx].flags & IEEE80211_RATE_ERP) || !(mode->rates[nonerp_idx].flags & IEEE80211_RATE_SUPPORTED) || !(sta->supp_rates & BIT(nonerp_idx)))) nonerp_idx--; extra->nonerp = &mode->rates[nonerp_idx]; sta_info_put(sta); return &mode->rates[rateidx]; } static void rate_control_simple_rate_init(void *priv, void *priv_sta, struct ieee80211_local *local, struct sta_info *sta) { struct ieee80211_hw_mode *mode; int i; sta->txrate = 0; mode = local->oper_hw_mode; /* TODO: This routine should consider using RSSI from previous packets * as we need to have IEEE 802.1X auth succeed immediately after assoc.. * Until that method is implemented, we will use the lowest supported rate * as a workaround, */ for (i = 0; i < mode->num_rates; i++) { if ((sta->supp_rates & BIT(i)) && (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED)) { sta->txrate = i; break; } } } static void * rate_control_simple_alloc(struct ieee80211_local *local) { struct global_rate_control *rctrl; rctrl = kzalloc(sizeof(*rctrl), GFP_ATOMIC); return rctrl; } static void rate_control_simple_free(void *priv) { struct global_rate_control *rctrl = priv; kfree(rctrl); } static void rate_control_simple_clear(void *priv) { } static void * rate_control_simple_alloc_sta(void *priv, gfp_t gfp) { struct sta_rate_control *rctrl; rctrl = kzalloc(sizeof(*rctrl), gfp); return rctrl; } static void rate_control_simple_free_sta(void *priv, void *priv_sta) { struct sta_rate_control *rctrl = priv_sta; kfree(rctrl); } #ifdef CONFIG_MAC80211_DEBUGFS static int open_file_generic(struct inode *inode, struct file *file) { file->private_data = inode->i_private; return 0; } static ssize_t sta_tx_avg_rate_sum_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct sta_rate_control *srctrl = file->private_data; char buf[20]; sprintf(buf, "%d\n", srctrl->tx_avg_rate_sum); return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); } static const struct file_operations sta_tx_avg_rate_sum_ops = { .read = sta_tx_avg_rate_sum_read, .open = open_file_generic, }; static ssize_t sta_tx_avg_rate_num_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct sta_rate_control *srctrl = file->private_data; char buf[20]; sprintf(buf, "%d\n", srctrl->tx_avg_rate_num); return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); } static const struct file_operations sta_tx_avg_rate_num_ops = { .read = sta_tx_avg_rate_num_read, .open = open_file_generic, }; static void rate_control_simple_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir) { struct sta_rate_control *srctrl = priv_sta; srctrl->tx_avg_rate_num_dentry = debugfs_create_file("rc_simple_sta_tx_avg_rate_num", 0400, dir, srctrl, &sta_tx_avg_rate_num_ops); srctrl->tx_avg_rate_sum_dentry = debugfs_create_file("rc_simple_sta_tx_avg_rate_sum", 0400, dir, srctrl, &sta_tx_avg_rate_sum_ops); } static void rate_control_simple_remove_sta_debugfs(void *priv, void *priv_sta) { struct sta_rate_control *srctrl = priv_sta; debugfs_remove(srctrl->tx_avg_rate_sum_dentry); debugfs_remove(srctrl->tx_avg_rate_num_dentry); } #endif struct rate_control_ops mac80211_rcsimple = { .name = "simple", .tx_status = rate_control_simple_tx_status, .get_rate = rate_control_simple_get_rate, .rate_init = rate_control_simple_rate_init, .clear = rate_control_simple_clear, .alloc = rate_control_simple_alloc, .free = rate_control_simple_free, .alloc_sta = rate_control_simple_alloc_sta, .free_sta = rate_control_simple_free_sta, #ifdef CONFIG_MAC80211_DEBUGFS .add_sta_debugfs = rate_control_simple_add_sta_debugfs, .remove_sta_debugfs = rate_control_simple_remove_sta_debugfs, #endif };