2007-05-05 11:45:53 -07:00
/*
* Copyright 2002 - 2005 , Instant802 Networks , Inc .
* Copyright 2005 - 2006 , Devicescape Software , Inc .
* Copyright ( c ) 2006 Jiri Benc < jbenc @ suse . cz >
*
* 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/kernel.h>
2007-07-27 15:43:23 +02:00
# include <linux/rtnetlink.h>
2008-04-08 15:14:40 -04:00
# include "rate.h"
2007-05-05 11:45:53 -07:00
# include "ieee80211_i.h"
2008-09-18 18:14:18 +02:00
# include "debugfs.h"
2007-05-05 11:45:53 -07:00
struct rate_control_alg {
struct list_head list ;
struct rate_control_ops * ops ;
} ;
static LIST_HEAD ( rate_ctrl_algs ) ;
static DEFINE_MUTEX ( rate_ctrl_mutex ) ;
2007-12-19 01:26:16 +01:00
static char * ieee80211_default_rc_algo = CONFIG_MAC80211_RC_DEFAULT ;
module_param ( ieee80211_default_rc_algo , charp , 0644 ) ;
MODULE_PARM_DESC ( ieee80211_default_rc_algo ,
" Default rate control algorithm for mac80211 to use " ) ;
2007-05-05 11:45:53 -07:00
int ieee80211_rate_control_register ( struct rate_control_ops * ops )
{
struct rate_control_alg * alg ;
2007-10-28 14:17:44 +01:00
if ( ! ops - > name )
return - EINVAL ;
2007-10-28 14:49:33 +01:00
mutex_lock ( & rate_ctrl_mutex ) ;
list_for_each_entry ( alg , & rate_ctrl_algs , list ) {
if ( ! strcmp ( alg - > ops - > name , ops - > name ) ) {
/* don't register an algorithm twice */
WARN_ON ( 1 ) ;
2007-12-13 15:52:11 -08:00
mutex_unlock ( & rate_ctrl_mutex ) ;
2007-10-28 14:49:33 +01:00
return - EALREADY ;
}
}
some kmalloc/memset ->kzalloc (tree wide)
Transform some calls to kmalloc/memset to a single kzalloc (or kcalloc).
Here is a short excerpt of the semantic patch performing
this transformation:
@@
type T2;
expression x;
identifier f,fld;
expression E;
expression E1,E2;
expression e1,e2,e3,y;
statement S;
@@
x =
- kmalloc
+ kzalloc
(E1,E2)
... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\)
- memset((T2)x,0,E1);
@@
expression E1,E2,E3;
@@
- kzalloc(E1 * E2,E3)
+ kcalloc(E1,E2,E3)
[akpm@linux-foundation.org: get kcalloc args the right way around]
Signed-off-by: Yoann Padioleau <padator@wanadoo.fr>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Acked-by: Russell King <rmk@arm.linux.org.uk>
Cc: Bryan Wu <bryan.wu@analog.com>
Acked-by: Jiri Slaby <jirislaby@gmail.com>
Cc: Dave Airlie <airlied@linux.ie>
Acked-by: Roland Dreier <rolandd@cisco.com>
Cc: Jiri Kosina <jkosina@suse.cz>
Acked-by: Dmitry Torokhov <dtor@mail.ru>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Acked-by: Pierre Ossman <drzeus-list@drzeus.cx>
Cc: Jeff Garzik <jeff@garzik.org>
Cc: "David S. Miller" <davem@davemloft.net>
Acked-by: Greg KH <greg@kroah.com>
Cc: James Bottomley <James.Bottomley@steeleye.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-19 01:49:03 -07:00
alg = kzalloc ( sizeof ( * alg ) , GFP_KERNEL ) ;
2007-05-05 11:45:53 -07:00
if ( alg = = NULL ) {
2007-10-28 14:49:33 +01:00
mutex_unlock ( & rate_ctrl_mutex ) ;
2007-05-05 11:45:53 -07:00
return - ENOMEM ;
}
alg - > ops = ops ;
list_add_tail ( & alg - > list , & rate_ctrl_algs ) ;
mutex_unlock ( & rate_ctrl_mutex ) ;
return 0 ;
}
EXPORT_SYMBOL ( ieee80211_rate_control_register ) ;
void ieee80211_rate_control_unregister ( struct rate_control_ops * ops )
{
struct rate_control_alg * alg ;
mutex_lock ( & rate_ctrl_mutex ) ;
list_for_each_entry ( alg , & rate_ctrl_algs , list ) {
if ( alg - > ops = = ops ) {
list_del ( & alg - > list ) ;
2007-12-13 16:17:03 -08:00
kfree ( alg ) ;
2007-05-05 11:45:53 -07:00
break ;
}
}
mutex_unlock ( & rate_ctrl_mutex ) ;
}
EXPORT_SYMBOL ( ieee80211_rate_control_unregister ) ;
static struct rate_control_ops *
ieee80211_try_rate_control_ops_get ( const char * name )
{
struct rate_control_alg * alg ;
struct rate_control_ops * ops = NULL ;
2007-10-28 14:17:44 +01:00
if ( ! name )
return NULL ;
2007-05-05 11:45:53 -07:00
mutex_lock ( & rate_ctrl_mutex ) ;
list_for_each_entry ( alg , & rate_ctrl_algs , list ) {
2007-10-28 14:17:44 +01:00
if ( ! strcmp ( alg - > ops - > name , name ) )
2007-05-05 11:45:53 -07:00
if ( try_module_get ( alg - > ops - > module ) ) {
ops = alg - > ops ;
break ;
}
}
mutex_unlock ( & rate_ctrl_mutex ) ;
return ops ;
}
2007-12-19 01:26:16 +01:00
/* Get the rate control algorithm. */
2007-05-05 11:45:53 -07:00
static struct rate_control_ops *
ieee80211_rate_control_ops_get ( const char * name )
{
struct rate_control_ops * ops ;
2007-12-19 01:26:16 +01:00
const char * alg_name ;
2007-05-05 11:45:53 -07:00
2007-10-28 14:17:44 +01:00
if ( ! name )
2007-12-19 01:26:16 +01:00
alg_name = ieee80211_default_rc_algo ;
else
alg_name = name ;
2007-10-28 14:17:44 +01:00
2007-12-19 01:26:16 +01:00
ops = ieee80211_try_rate_control_ops_get ( alg_name ) ;
2007-05-05 11:45:53 -07:00
if ( ! ops ) {
2007-12-19 01:26:16 +01:00
request_module ( " rc80211_%s " , alg_name ) ;
ops = ieee80211_try_rate_control_ops_get ( alg_name ) ;
2007-05-05 11:45:53 -07:00
}
2007-12-19 01:26:16 +01:00
if ( ! ops & & name )
/* try default if specific alg requested but not found */
ops = ieee80211_try_rate_control_ops_get ( ieee80211_default_rc_algo ) ;
2008-01-02 15:17:03 +01:00
/* try built-in one if specific alg requested but not found */
if ( ! ops & & strlen ( CONFIG_MAC80211_RC_DEFAULT ) )
ops = ieee80211_try_rate_control_ops_get ( CONFIG_MAC80211_RC_DEFAULT ) ;
2007-05-05 11:45:53 -07:00
return ops ;
}
static void ieee80211_rate_control_ops_put ( struct rate_control_ops * ops )
{
module_put ( ops - > module ) ;
}
2008-09-18 18:14:18 +02:00
# ifdef CONFIG_MAC80211_DEBUGFS
static ssize_t rcname_read ( struct file * file , char __user * userbuf ,
size_t count , loff_t * ppos )
{
struct rate_control_ref * ref = file - > private_data ;
int len = strlen ( ref - > ops - > name ) ;
return simple_read_from_buffer ( userbuf , count , ppos ,
ref - > ops - > name , len ) ;
}
static const struct file_operations rcname_ops = {
. read = rcname_read ,
. open = mac80211_open_file_generic ,
} ;
# endif
2007-05-05 11:45:53 -07:00
struct rate_control_ref * rate_control_alloc ( const char * name ,
struct ieee80211_local * local )
{
2008-09-18 18:14:18 +02:00
struct dentry * debugfsdir = NULL ;
2007-05-05 11:45:53 -07:00
struct rate_control_ref * ref ;
ref = kmalloc ( sizeof ( struct rate_control_ref ) , GFP_KERNEL ) ;
if ( ! ref )
goto fail_ref ;
kref_init ( & ref - > kref ) ;
2008-09-18 18:14:18 +02:00
ref - > local = local ;
2007-05-05 11:45:53 -07:00
ref - > ops = ieee80211_rate_control_ops_get ( name ) ;
if ( ! ref - > ops )
goto fail_ops ;
2008-09-18 18:14:18 +02:00
# ifdef CONFIG_MAC80211_DEBUGFS
debugfsdir = debugfs_create_dir ( " rc " , local - > hw . wiphy - > debugfsdir ) ;
local - > debugfs . rcdir = debugfsdir ;
2009-10-27 12:59:03 +01:00
debugfs_create_file ( " name " , 0400 , debugfsdir , ref , & rcname_ops ) ;
2008-09-18 18:14:18 +02:00
# endif
ref - > priv = ref - > ops - > alloc ( & local - > hw , debugfsdir ) ;
2007-05-05 11:45:53 -07:00
if ( ! ref - > priv )
goto fail_priv ;
return ref ;
fail_priv :
ieee80211_rate_control_ops_put ( ref - > ops ) ;
fail_ops :
kfree ( ref ) ;
fail_ref :
return NULL ;
}
static void rate_control_release ( struct kref * kref )
{
struct rate_control_ref * ctrl_ref ;
ctrl_ref = container_of ( kref , struct rate_control_ref , kref ) ;
ctrl_ref - > ops - > free ( ctrl_ref - > priv ) ;
2008-09-18 18:14:18 +02:00
# ifdef CONFIG_MAC80211_DEBUGFS
2009-10-27 12:59:03 +01:00
debugfs_remove_recursive ( ctrl_ref - > local - > debugfs . rcdir ) ;
2008-09-18 18:14:18 +02:00
ctrl_ref - > local - > debugfs . rcdir = NULL ;
# endif
2007-05-05 11:45:53 -07:00
ieee80211_rate_control_ops_put ( ctrl_ref - > ops ) ;
kfree ( ctrl_ref ) ;
}
2009-07-16 10:05:41 -07:00
static bool rc_no_data_or_no_ack ( struct ieee80211_tx_rate_control * txrc )
{
struct sk_buff * skb = txrc - > skb ;
struct ieee80211_hdr * hdr = ( struct ieee80211_hdr * ) skb - > data ;
struct ieee80211_tx_info * info = IEEE80211_SKB_CB ( skb ) ;
__le16 fc ;
fc = hdr - > frame_control ;
return ( ( info - > flags & IEEE80211_TX_CTL_NO_ACK ) | | ! ieee80211_is_data ( fc ) ) ;
}
bool rate_control_send_low ( struct ieee80211_sta * sta ,
void * priv_sta ,
struct ieee80211_tx_rate_control * txrc )
{
struct ieee80211_tx_info * info = IEEE80211_SKB_CB ( txrc - > skb ) ;
if ( ! sta | | ! priv_sta | | rc_no_data_or_no_ack ( txrc ) ) {
info - > control . rates [ 0 ] . idx = rate_lowest_index ( txrc - > sband , sta ) ;
info - > control . rates [ 0 ] . count =
( info - > flags & IEEE80211_TX_CTL_NO_ACK ) ?
1 : txrc - > hw - > max_rate_tries ;
return true ;
}
return false ;
}
EXPORT_SYMBOL ( rate_control_send_low ) ;
2008-09-18 18:14:18 +02:00
void rate_control_get_rate ( struct ieee80211_sub_if_data * sdata ,
2008-10-21 12:40:02 +02:00
struct sta_info * sta ,
struct ieee80211_tx_rate_control * txrc )
2007-12-20 13:50:07 +01:00
{
2008-09-18 18:14:18 +02:00
struct rate_control_ref * ref = sdata - > local - > rate_ctrl ;
void * priv_sta = NULL ;
struct ieee80211_sta * ista = NULL ;
2008-10-21 12:40:02 +02:00
struct ieee80211_tx_info * info = IEEE80211_SKB_CB ( txrc - > skb ) ;
2007-12-20 13:50:07 +01:00
int i ;
2008-09-18 18:14:18 +02:00
if ( sta ) {
ista = & sta - > sta ;
priv_sta = sta - > rate_ctrl_priv ;
}
2008-10-21 12:40:02 +02:00
for ( i = 0 ; i < IEEE80211_TX_MAX_RATES ; i + + ) {
info - > control . rates [ i ] . idx = - 1 ;
info - > control . rates [ i ] . flags = 0 ;
info - > control . rates [ i ] . count = 1 ;
}
2009-03-23 14:10:22 +01:00
if ( sta & & sdata - > force_unicast_rateidx > - 1 ) {
2008-10-21 12:40:02 +02:00
info - > control . rates [ 0 ] . idx = sdata - > force_unicast_rateidx ;
2009-03-23 14:10:22 +01:00
} else {
2008-10-21 12:40:02 +02:00
ref - > ops - > get_rate ( ref - > priv , ista , priv_sta , txrc ) ;
2009-03-23 14:10:22 +01:00
info - > flags | = IEEE80211_TX_INTFL_RCALGO ;
}
2008-10-21 12:40:02 +02:00
/*
* try to enforce the maximum rate the user wanted
*/
if ( sdata - > max_ratectrl_rateidx > - 1 )
for ( i = 0 ; i < IEEE80211_TX_MAX_RATES ; i + + ) {
if ( info - > control . rates [ i ] . flags & IEEE80211_TX_RC_MCS )
continue ;
info - > control . rates [ i ] . idx =
min_t ( s8 , info - > control . rates [ i ] . idx ,
sdata - > max_ratectrl_rateidx ) ;
2007-12-20 13:50:07 +01:00
}
2008-10-21 12:40:02 +02:00
BUG_ON ( info - > control . rates [ 0 ] . idx < 0 ) ;
2007-12-20 13:50:07 +01:00
}
2007-05-05 11:45:53 -07:00
struct rate_control_ref * rate_control_get ( struct rate_control_ref * ref )
{
kref_get ( & ref - > kref ) ;
return ref ;
}
void rate_control_put ( struct rate_control_ref * ref )
{
kref_put ( & ref - > kref , rate_control_release ) ;
}
2007-07-27 15:43:23 +02:00
int ieee80211_init_rate_ctrl_alg ( struct ieee80211_local * local ,
const char * name )
{
struct rate_control_ref * ref , * old ;
ASSERT_RTNL ( ) ;
2009-06-17 17:43:56 +02:00
if ( local - > open_count )
2007-07-27 15:43:23 +02:00
return - EBUSY ;
ref = rate_control_alloc ( name , local ) ;
if ( ! ref ) {
printk ( KERN_WARNING " %s: Failed to select rate control "
2007-09-18 17:29:20 -04:00
" algorithm \n " , wiphy_name ( local - > hw . wiphy ) ) ;
2007-07-27 15:43:23 +02:00
return - ENOENT ;
}
old = local - > rate_ctrl ;
local - > rate_ctrl = ref ;
if ( old ) {
rate_control_put ( old ) ;
sta_info_flush ( local , NULL ) ;
}
printk ( KERN_DEBUG " %s: Selected rate control "
2007-09-18 17:29:20 -04:00
" algorithm '%s' \n " , wiphy_name ( local - > hw . wiphy ) ,
2007-07-27 15:43:23 +02:00
ref - > ops - > name ) ;
return 0 ;
}
void rate_control_deinitialize ( struct ieee80211_local * local )
{
struct rate_control_ref * ref ;
ref = local - > rate_ctrl ;
local - > rate_ctrl = NULL ;
rate_control_put ( ref ) ;
}
2007-12-19 01:26:16 +01:00