mac80211: clean up rate selection
Subsystems (10)
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH v3 1/8 mac80211: clean up rate selection
From: Mattias Nissler <[email protected]>
Move some code out of rc80211_simple since it's probably needed for all rate selection algorithms, and fix iwlwifi accordingly. While at it, clean up the rate_control_get_rate() interface.
--- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 44 ++--------------- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 47 +++--------------- net/mac80211/ieee80211.c | 6 -- net/mac80211/ieee80211_rate.c | 47 ++++++++++++++++++ net/mac80211/ieee80211_rate.h | 73 ++++++++++++++++++----------- net/mac80211/ieee80211_sta.c | 13 +---- net/mac80211/rc80211_simple.c | 64 ++++--------------------- net/mac80211/tx.c | 42 +++++++--------- 8 files changed, 146 insertions(+), 190 deletions(-)
net/mac80211/ieee80211.c +2 -4
@@ -860,10 +860,8 @@ void ieee80211_tx_status(struct ieee8021sta_info_put (sta);return ; } - }else { -/* FIXME: STUPID to call this with both local and local->mdev */ -rate_control_tx_status (local, local->mdev, skb, status); - } + }else +rate_control_tx_status (local->mdev, skb, status);ieee80211_led_tx (local,0 );
net/mac80211/ieee80211_rate.c +47 -0
53 lines not on this page · raw message
net/mac80211/ieee80211_rate.h +46 -27
108 lines not on this page · raw message
net/mac80211/ieee80211_sta.c +5 -8
@@ -2467,9 +2467,8 @@ static int ieee80211_sta_join_ibss(strucstruct sk_buff *skb;struct ieee80211_mgmt *mgmt;struct ieee80211_tx_control control; -struct ieee80211_rate *rate;struct ieee80211_hw_mode *mode; -struct rate_control_extra extra; +struct rate_selection ratesel;u8 *pos;struct ieee80211_sub_if_data *sdata;
@@ -2554,18 +2553,16 @@ static int ieee80211_sta_join_ibss(struc }memset (&control,0 ,sizeof (control)); -memset (&extra,0 ,sizeof (extra)); - extra.mode = local->oper_hw_mode; - rate =rate_control_get_rate (local, dev, skb, &extra); -if (!rate) { +rate_control_get_rate (dev, local->oper_hw_mode, skb, &ratesel); +if (!ratesel.rate) {printk (KERN_DEBUG "%s: Failed to determine TX rate " "for IBSS beacon\n" , dev->name);break ; } control.tx_rate = ((sdata->flags &IEEE80211_SDATA_SHORT_PREAMBLE ) && - (rate->flags &IEEE80211_RATE_PREAMBLE2 )) ? - rate->val2 : rate->val; + (ratesel.rate->flags &IEEE80211_RATE_PREAMBLE2 )) ? + ratesel.rate->val2 : ratesel.rate->val; control.antenna_sel_tx = local->hw.conf.antenna_sel_tx; control.power_level = local->hw.conf.power_level; control.flags |=IEEE80211_TXCTL_NO_ACK ;
net/mac80211/rc80211_simple.c +11 -53
99 lines not on this page · raw message
net/mac80211/tx.c +18 -24
83 lines not on this page · raw message
drivers/net/wireless/iwlwifi/iwl-3945-rs.c +7 -37
78 lines not on this page · raw message
drivers/net/wireless/iwlwifi/iwl-4965-rs.c +10 -37
77 lines not on this page · raw message
Signature · 2 lines
Ciao Stefano
Johannes Berg
maintainerQuoted 7 lines
net/mac80211/ieee80211_rate.h +6
-0+static inline int +rate_lowest_index (struct ieee80211_local *local,struct ieee80211_hw_mode *mode, +struct sta_info *sta) +{ +int i; +
net/mac80211/ieee80211_rate.h static inline void rate_control_remove_s · line 155
Quoted 10 lines
net/mac80211/ieee80211_rate.h +10
-0+for (i =0 ; i < mode->num_rates; i++) { +if (rate_supported (sta, mode, i)) +return i; + } + +/* warn when we cannot find a rate. */ +WARN_ON (i ==0 ); + +return 0 ; +}
That doesn't look right. Shouldn't it be WARN_ON(1)? Not that it can ever happen with proper drivers...
Other than that, looks ok to me.
johannes
PATCH v4 1/8 mac80211: clean up rate selection
From: Mattias Nissler <[email protected]>
Move some code out of rc80211_simple since it's probably needed for all rate selection algorithms, and fix iwlwifi accordingly. While at it, clean up the rate_control_get_rate() interface.
--- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 44 ++--------------- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 47 +++--------------- net/mac80211/ieee80211.c | 6 -- net/mac80211/ieee80211_rate.c | 47 ++++++++++++++++++ net/mac80211/ieee80211_rate.h | 73 ++++++++++++++++++----------- net/mac80211/ieee80211_sta.c | 13 +---- net/mac80211/rc80211_simple.c | 64 ++++--------------------- net/mac80211/tx.c | 42 +++++++--------- 8 files changed, 146 insertions(+), 190 deletions(-)
net/mac80211/ieee80211.c +2 -4
@@ -860,10 +860,8 @@ void ieee80211_tx_status(struct ieee8021sta_info_put (sta);return ; } - }else { -/* FIXME: STUPID to call this with both local and local->mdev */ -rate_control_tx_status (local, local->mdev, skb, status); - } + }else +rate_control_tx_status (local->mdev, skb, status);ieee80211_led_tx (local,0 );
net/mac80211/ieee80211_rate.c +47 -0
53 lines not on this page · raw message
net/mac80211/ieee80211_rate.h +46 -27
108 lines not on this page · raw message
net/mac80211/ieee80211_sta.c +5 -8
@@ -2467,9 +2467,8 @@ static int ieee80211_sta_join_ibss(strucstruct sk_buff *skb;struct ieee80211_mgmt *mgmt;struct ieee80211_tx_control control; -struct ieee80211_rate *rate;struct ieee80211_hw_mode *mode; -struct rate_control_extra extra; +struct rate_selection ratesel;u8 *pos;struct ieee80211_sub_if_data *sdata;
@@ -2554,18 +2553,16 @@ static int ieee80211_sta_join_ibss(struc }memset (&control,0 ,sizeof (control)); -memset (&extra,0 ,sizeof (extra)); - extra.mode = local->oper_hw_mode; - rate =rate_control_get_rate (local, dev, skb, &extra); -if (!rate) { +rate_control_get_rate (dev, local->oper_hw_mode, skb, &ratesel); +if (!ratesel.rate) {printk (KERN_DEBUG "%s: Failed to determine TX rate " "for IBSS beacon\n" , dev->name);break ; } control.tx_rate = ((sdata->flags &IEEE80211_SDATA_SHORT_PREAMBLE ) && - (rate->flags &IEEE80211_RATE_PREAMBLE2 )) ? - rate->val2 : rate->val; + (ratesel.rate->flags &IEEE80211_RATE_PREAMBLE2 )) ? + ratesel.rate->val2 : ratesel.rate->val; control.antenna_sel_tx = local->hw.conf.antenna_sel_tx; control.power_level = local->hw.conf.power_level; control.flags |=IEEE80211_TXCTL_NO_ACK ;
net/mac80211/rc80211_simple.c +11 -53
99 lines not on this page · raw message
net/mac80211/tx.c +18 -24
83 lines not on this page · raw message
drivers/net/wireless/iwlwifi/iwl-3945-rs.c +7 -37
78 lines not on this page · raw message
drivers/net/wireless/iwlwifi/iwl-4965-rs.c +10 -37
77 lines not on this page · raw message
Signature · 2 lines
Ciao Stefano
PATCH v3 2/8 mac80211: add PID controller based rate control algorithm
In reply to a message not in the archiveFrom: Mattias Nissler <[email protected]>
Add a new rate control algorithm based on a PID controller. It samples the percentage of failed frames over time, feeds the result into the controller and uses its output to control the TX rate.
--- Kconfig | 12 + Makefile | 1 ieee80211.c | 27 +++- ieee80211_rate.h | 3 rc80211_pid.c | 365 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 403 insertions(+), 5 deletions(-)
net/mac80211/Kconfig +12 -0
@@ -25,6 +25,18 @@ config MAC80211_RCSIMPLE Say Y unless you know you will have another algorithm available. +config MAC80211_RCPID + bool "'PID' rate control algorithm" if EMBEDDED + default y + depends on MAC80211 + help + This option enables a TX rate control algorithm for + mac80211 that uses a PID controller to select the TX + rate. + + Say Y unless you're sure you want to use a different + rate control algorithm. + config MAC80211_LEDS bool "Enable LED triggers" depends on MAC80211 && LEDS_TRIGGERS
net/mac80211/Makefile +1 -0
@@ -4,6 +4,7 @@ mac80211-objs-$(CONFIG_MAC80211_LEDS) += mac80211-objs-$(CONFIG_MAC80211_DEBUGFS) += debugfs.o debugfs_sta.o debugfs_netdev.o debugfs_key.o mac80211-objs-$(CONFIG_NET_SCHED) += wme.o mac80211-objs-$(CONFIG_MAC80211_RCSIMPLE) += rc80211_simple.o +mac80211-objs-$(CONFIG_MAC80211_RCPID) += rc80211_pid.o mac80211-objs := \ ieee80211.o \
net/mac80211/ieee80211.c +22 -5
@@ -1316,23 +1316,37 @@ static int __init ieee80211_init(void)#ifdef CONFIG_MAC80211_RCSIMPLE ret =ieee80211_rate_control_register (&mac80211_rcsimple);if (ret) -return ret; + goto fail; +#endif + +#ifdef CONFIG_MAC80211_RCPID + ret =ieee80211_rate_control_register (&mac80211_rcpid); +if (ret) + goto fail;#endif ret =ieee80211_wme_register ();if (ret) { -#ifdef CONFIG_MAC80211_RCSIMPLE -ieee80211_rate_control_unregister (&mac80211_rcsimple); -#endif printk (KERN_DEBUG "ieee80211_init: failed to " "initialize WME (err=%d)\n" , ret); -return ret; + goto fail; }ieee80211_debugfs_netdev_init ();ieee80211_regdomain_init ();return 0 ; + +fail: + +#ifdef CONFIG_MAC80211_RCSIMPLE +ieee80211_rate_control_unregister (&mac80211_rcsimple); +#endif +#ifdef CONFIG_MAC80211_RCPID +ieee80211_rate_control_unregister (&mac80211_rcpid); +#endif + +return ret; } static void __exit ieee80211_exit(void)
@@ -1340,6 +1354,9 @@ static void __exit ieee80211_exit(void)#ifdef CONFIG_MAC80211_RCSIMPLE ieee80211_rate_control_unregister (&mac80211_rcsimple);#endif +#ifdef CONFIG_MAC80211_RCPID +ieee80211_rate_control_unregister (&mac80211_rcpid); +#endif ieee80211_wme_unregister ();ieee80211_debugfs_netdev_exit ();
net/mac80211/ieee80211_rate.h +3 -0
@@ -61,6 +61,9 @@ struct rate_control_ref {/* default 'simple' algorithm */ extern struct rate_control_ops mac80211_rcsimple; +/* 'PID' algorithm */ +extern struct rate_control_ops mac80211_rcpid; +int ieee80211_rate_control_register (struct rate_control_ops *ops);void ieee80211_rate_control_unregister (struct rate_control_ops *ops);
net/mac80211/rc80211_pid.c new file +365 -0
365 lines not on this page · raw message
Signature · 2 lines
Ciao Stefano
PATCH v3 3/8 mac80211: make PID rate control algorithm the default
In reply to a message not in the archiveThis makes the new PID TX rate control algorithm the default instead of the rc80211_simple rate control algorithm. The simple algorithm was flawed in several ways: it wasn't responsive at all and didn't age the information it was relying on properly. The PID algorithm allows us to tune characteristics such as responsiveness by adjusting parameters and was found to generally behave better.
Two separate modules are created, however we force users to build rc80211-simple into mac80211 if rc80211-pid isn't built-in, so that this won't break for users who disable module autoloading. The default algorithm can be set through a modparam. While at it, mark rc80211-simple as deprecated, and schedule it for removal.
--- Documentation/feature-removal-schedule.txt | 8 +++ net/mac80211/Kconfig | 61 +++++++++++++++++++++++------ net/mac80211/Makefile | 10 +++- net/mac80211/ieee80211.c | 32 --------------- net/mac80211/ieee80211_rate.c | 12 +++++ net/mac80211/ieee80211_rate.h | 6 -- 6 files changed, 77 insertions(+), 52 deletions(-)
net/mac80211/Kconfig +49 -12
@@ -13,20 +13,45 @@ config MAC80211 This option enables the hardware independent IEEE 802.11 networking stack. -config MAC80211_RCSIMPLE - bool "'simple' rate control algorithm" if EMBEDDED - default y +choice + prompt "Default rate control algorithm" + default MAC80211_RC_DEFAULT_PID + depends on MAC80211 + help + This option selects the default rate control algorithm + mac80211 will use. Note that this default can still be + overriden through the ieee80211_default_rc_algo module + parameter. + +config MAC80211_RC_DEFAULT_PID + bool "PID controller based rate control algorithm" + depends on MAC80211 + select MAC80211_RC_PID + help + Select the PID controller based rate control as the + default rate control algorithm. You should choose + this unless you know what you are doing. + +config MAC80211_RC_DEFAULT_SIMPLE + bool "Simple rate control algorithm" depends on MAC80211 + select MAC80211_RC_SIMPLE help - This option allows you to turn off the 'simple' rate - control algorithm in mac80211. If you do turn it off, - you absolutely need another rate control algorithm. + Select the simple rate control as the default rate + control algorithm. Note that this is a non-responsive, + dumb algorithm. You should choose the PID rate control + instead. - Say Y unless you know you will have another algorithm - available. +endchoice -config MAC80211_RCPID - bool "'PID' rate control algorithm" if EMBEDDED +config MAC80211_RC_DEFAULT + string + depends on MAC80211 + default "pid" if MAC80211_RC_DEFAULT_PID + default "simple" if MAC80211_RC_DEFAULT_SIMPLE + +config MAC80211_RC_PID + tristate "PID controller based rate control algorithm" default y depends on MAC80211 help
@@ -34,8 +59,20 @@ config MAC80211_RCPID mac80211 that uses a PID controller to select the TX rate. - Say Y unless you're sure you want to use a different - rate control algorithm. + Say Y or M unless you're sure you want to use a + different rate control algorithm. + +config MAC80211_RC_SIMPLE + tristate "Simple rate control algorithm (DEPRECATED)" + default n + depends on MAC80211 + help + This option enables a very simple, non-responsive TX + rate control algorithm. This algorithm is deprecated + and will be removed from the kernel in near future. + It has been replaced by the PID algorithm. + + Say N unless you know what you are doing. config MAC80211_LEDS bool "Enable LED triggers"
net/mac80211/Makefile +8 -2
@@ -1,10 +1,12 @@ obj-$(CONFIG_MAC80211) += mac80211.o +obj-$(CONFIG_MAC80211_RC_PID) += rc80211_pid.o +ifeq ($(CONFIG_MAC80211_RC_PID),y) + obj-$(CONFIG_MAC80211_RC_SIMPLE) += rc80211_simple.o +endif mac80211-objs-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o mac80211-objs-$(CONFIG_MAC80211_DEBUGFS) += debugfs.o debugfs_sta.o debugfs_netdev.o debugfs_key.o mac80211-objs-$(CONFIG_NET_SCHED) += wme.o -mac80211-objs-$(CONFIG_MAC80211_RCSIMPLE) += rc80211_simple.o -mac80211-objs-$(CONFIG_MAC80211_RCPID) += rc80211_pid.o mac80211-objs := \ ieee80211.o \
@@ -26,3 +28,7 @@ mac80211-objs := \ util.o \ event.o \ $(mac80211-objs-y) + +ifneq ($(CONFIG_MAC80211_RC_PID),y) + mac80211-objs += rc80211_simple.o +endif
net/mac80211/ieee80211.c +1 -31
@@ -1313,51 +1313,21 @@ static int __init ieee80211_init(void)BUILD_BUG_ON (sizeof (struct ieee80211_tx_packet_data ) >sizeof (skb->cb)); -#ifdef CONFIG_MAC80211_RCSIMPLE - ret =ieee80211_rate_control_register (&mac80211_rcsimple); -if (ret) - goto fail; -#endif - -#ifdef CONFIG_MAC80211_RCPID - ret =ieee80211_rate_control_register (&mac80211_rcpid); -if (ret) - goto fail; -#endif - ret =ieee80211_wme_register ();if (ret) {printk (KERN_DEBUG "ieee80211_init: failed to " "initialize WME (err=%d)\n" , ret); - goto fail; +return ret; }ieee80211_debugfs_netdev_init ();ieee80211_regdomain_init ();return 0 ; - -fail: - -#ifdef CONFIG_MAC80211_RCSIMPLE -ieee80211_rate_control_unregister (&mac80211_rcsimple); -#endif -#ifdef CONFIG_MAC80211_RCPID -ieee80211_rate_control_unregister (&mac80211_rcpid); -#endif - -return ret; } static void __exit ieee80211_exit(void) { -#ifdef CONFIG_MAC80211_RCSIMPLE -ieee80211_rate_control_unregister (&mac80211_rcsimple); -#endif -#ifdef CONFIG_MAC80211_RCPID -ieee80211_rate_control_unregister (&mac80211_rcpid); -#endif -ieee80211_wme_unregister ();ieee80211_debugfs_netdev_exit (); }
net/mac80211/ieee80211_rate.c +11 -1
@@ -21,6 +21,11 @@ struct rate_control_alg {static LIST_HEAD (rate_ctrl_algs);static DEFINE_MUTEX (rate_ctrl_mutex); +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" ); +int ieee80211_rate_control_register (struct rate_control_ops *ops) {struct rate_control_alg *alg;
@@ -97,13 +102,17 @@ ieee80211_rate_control_ops_get(const chastruct rate_control_ops *ops;if (!name) - name ="simple" ; + name = ieee80211_default_rc_algo; ops =ieee80211_try_rate_control_ops_get (name);if (!ops) {request_module ("rc80211_%s" , name); ops =ieee80211_try_rate_control_ops_get (name); } +if (!ops) +/* If we get here, rc80211_simple must be built into mac80211. */ + ops =ieee80211_try_rate_control_ops_get ("simple" ); +return ops; }
@@ -244,3 +253,4 @@ void rate_control_deinitialize(struct ie local->rate_ctrl =NULL ;rate_control_put (ref); } +
net/mac80211/ieee80211_rate.h +0 -6
@@ -58,12 +58,6 @@ struct rate_control_ref {struct kref kref; }; -/* default 'simple' algorithm */ -extern struct rate_control_ops mac80211_rcsimple; - -/* 'PID' algorithm */ -extern struct rate_control_ops mac80211_rcpid; -int ieee80211_rate_control_register (struct rate_control_ops *ops);void ieee80211_rate_control_unregister (struct rate_control_ops *ops);
Documentation/feature-removal-schedule.txt +8 -0
@@ -350,3 +350,11 @@ Why: No in-kernel drivers will depend on Who: John W. Linville <[email protected]> --------------------------- + +What: rc80211-simple rate control algorithm for mac80211 +When: 2.6.26 +Files: net/mac80211/rc80211-simple.c +Why: This algorithm was provided for reference but always exhibited bad + responsiveness and performance and has some serious flaws. It has been + replaced by rc80211-pid. +Who: Stefano Brivio <[email protected]>
Signature · 2 lines
Ciao Stefano
PATCH v3 4/8 rc80211-pid: add rate behaviour learning algorithm
In reply to a message not in the archiveThis patch introduces a learning algorithm in order for the PID controller to learn how to map adjustment values to rates. This is better described in code comments.
--- rc80211_pid.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 161 insertions(+), 20 deletions(-)
net/mac80211/rc80211_pid.c +161 -20
@@ -2,6 +2,7 @@* Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005, Devicescape Software, Inc. * Copyright 2007, Mattias Nissler <[email protected]> +* Copyright 2007, Stefano Brivio <[email protected]> * * 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
@@ -39,12 +40,18 @@* an actual sliding window. The advantage is that we don't need to keep an * array of the last N error values and computation is easier. * -* Once we have the adj value, we need to map it to a TX rate to be selected. -* For now, we depend on the rates to be ordered in a way such that more robust -* rates (i.e. such that exhibit a lower framed failed percentage) come first. -* E.g. for the 802.11b/g case, we first have the b rates in ascending order, -* then the g rates. The adj simply decides the index of the TX rate in the list -* to switch to (relative to the current TX rate entry). +* Once we have the adj value, we map it to a rate by means of a learning +* algorithm. This algorithm keeps the state of the percentual failed frames +* difference between rates. The behaviour of the lowest available rate is kept +* as a reference value, and every time we switch between two rates, we compute +* the difference between the failed frames each rate exhibited. By doing so, +* we compare behaviours which different rates exhibited in adjacent timeslices, +* thus the comparison is minimally affected by external conditions. This +* difference gets propagated to the whole set of measurements, so that the +* reference is always the same. Periodically, we normalize this set so that +* recent events weigh the most. By comparing the adj value with this set, we +* avoid pejorative switches to lower rates and allow for switches to higher +* rates if they behaved well. * * Note that for the computations we use a fixed-point representation to avoid * floating point arithmetic. Hence, all values are shifted left by
@@ -78,6 +85,16 @@*/ #define RC_PID_TARGET_PF (11 << RC_PID_ARITH_SHIFT) +/* Rate behaviour normalization quantity over time. */ +#define RC_PID_NORM_OFFSET 3 + +/* Push high rates right after loading. */ +#define RC_PID_FAST_START 0 + +/* Arithmetic right shift for positive and negative values for ISO C. */ +#define RC_PID_DO_ARITH_RIGHT_SHIFT (x, y) \ + (x) < 0 ? -((-(x)) >> (y)) : (x) >> (y) +struct rc_pid_sta_info {unsigned long last_change;unsigned long last_sample;
@@ -121,6 +138,18 @@ struct rc_pid_sta_info {/* Algorithm parameters. We keep them on a per-algorithm approach, so they can * be tuned individually for each interface. */ +struct rc_pid_rateinfo { + +/* Map sorted rates to rates in ieee80211_hw_mode. */ +int index; + +/* Map rates in ieee80211_hw_mode to sorted rates. */ +int rev_index; + +/* Comparison with the lowest rate. */ +int diff; +}; +struct rc_pid_info {/* The failed frames percentage target. */
@@ -130,15 +159,56 @@ struct rc_pid_info {s32 coeff_p;s32 coeff_i;s32 coeff_d; + +/* Rates information. */ +struct rc_pid_rateinfo *rinfo; + +/* Index of the last used rate. */ +int oldrate; }; +/* Shift the adjustment so that we won't switch to a lower rate if it exhibited +* a worse failed frames behaviour and we'll choose the highest rate whose +* failed frames behaviour is not worse than the one of the original rate +* target. While at it, check that the adjustment is within the ranges. Then, +* provide the new rate index. */ +static int rate_control_pid_shift_adjust (struct rc_pid_rateinfo *r, +int adj,int cur,int l) +{ +int i, j, k, tmp; + +if (cur + adj <0 ) +return 0 ; +if (cur + adj >= l) +return l -1 ; + + i = r[cur + adj].rev_index; + + j = r[cur].rev_index; + +if (adj <0 ) { + tmp = i; +for (k = j; k >= i; k--) +if (r[k].diff <= r[j].diff) + tmp = k; +return r[tmp].index; + }else if (adj >0 ) { + tmp = i; +for (k = i +1 ; k + i < l; k++) +if (r[k].diff <= r[i].diff) + tmp = k; +return r[tmp].index; + } +return cur + adj; +}static void rate_control_pid_adjust_rate (struct ieee80211_local *local, -struct sta_info *sta,int adj) +struct sta_info *sta,int adj, +struct rc_pid_rateinfo *rinfo) {struct ieee80211_sub_if_data *sdata;struct ieee80211_hw_mode *mode; -int newidx = sta->txrate + adj; +int newidx;int maxrate;int back = (adj >0 ) ?1 :-1 ;
@@ -151,10 +221,8 @@ static void rate_control_pid_adjust_rate mode = local->oper_hw_mode; maxrate = sdata->bss ? sdata->bss->max_ratectrl_rateidx :-1 ; -if (newidx <0 ) - newidx =0 ; -else if (newidx >= mode->num_rates) - newidx = mode->num_rates -1 ; + newidx =rate_control_pid_shift_adjust (rinfo, adj, sta->txrate, + mode->num_rates);while (newidx != sta->txrate) { if (rate_supported(sta, mode, newidx) &&
@@ -167,18 +235,37 @@ static void rate_control_pid_adjust_rate } } +/* Normalize the failed frames per-rate differences. */ +static void rate_control_pid_normalize (struct rc_pid_rateinfo *r,int l) +{ +int i; + +if (r[0 ].diff >RC_PID_NORM_OFFSET ) + r[0 ].diff -=RC_PID_NORM_OFFSET ; +else if (r[0 ].diff < -RC_PID_NORM_OFFSET ) + r[0 ].diff +=RC_PID_NORM_OFFSET ; +for (i =0 ; i < l -1 ; i++) +if (r[i +1 ].diff > r[i].diff +RC_PID_NORM_OFFSET ) + r[i +1 ].diff -=RC_PID_NORM_OFFSET ; +else if (r[i +1 ].diff <= r[i].diff) + r[i +1 ].diff +=RC_PID_NORM_OFFSET ; +} +static void rate_control_pid_sample (struct rc_pid_info *pinfo,struct ieee80211_local *local,struct sta_info *sta) {struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv; +struct rc_pid_rateinfo *rinfo = pinfo->rinfo; +struct ieee80211_hw_mode *mode;u32 pf;s32 err_avg;s32 err_prop;s32 err_int;s32 err_der; -int adj; +int adj, i, j, tmp; + mode = local->oper_hw_mode; spinfo = sta->rate_ctrl_priv; spinfo->last_sample = jiffies;
@@ -194,6 +281,20 @@ static void rate_control_pid_sample(stru spinfo->tx_num_failed =0 ; } +/* If we just switched rate, update the rate behaviour info. */ +if (pinfo->oldrate != sta->txrate) { + + i = rinfo[pinfo->oldrate].rev_index; + j = rinfo[sta->txrate].rev_index; + + tmp = (pf - spinfo->last_pf); + tmp =RC_PID_DO_ARITH_RIGHT_SHIFT (tmp,RC_PID_ARITH_SHIFT ); + + rinfo[j].diff = rinfo[i].diff + tmp; + pinfo->oldrate = sta->txrate; + } +rate_control_pid_normalize (rinfo, mode->num_rates); +/* Compute the proportional, integral and derivative errors. */ err_prop =RC_PID_TARGET_PF - pf;
@@ -207,16 +308,11 @@ static void rate_control_pid_sample(stru/* Compute the controller output. */ adj = (err_prop * pinfo->coeff_p + err_int * pinfo->coeff_i + err_der * pinfo->coeff_d); - -/* We need to do an arithmetic right shift. ISO C says this is -* implementation defined for negative left operands. Hence, be -* careful to get it right, also for negative values. */ - adj = (adj <0 ) ? -((-adj) >> (2 *RC_PID_ARITH_SHIFT )) : - adj >> (2 *RC_PID_ARITH_SHIFT ); + adj =RC_PID_DO_ARITH_RIGHT_SHIFT (adj,2 *RC_PID_ARITH_SHIFT );/* Change rate. */ if (adj) -rate_control_pid_adjust_rate (local, sta, adj); +rate_control_pid_adjust_rate (local, sta, adj, rinfo); } static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
@@ -316,13 +412,57 @@ static void rate_control_pid_rate_init(vstatic void *rate_control_pid_alloc (struct ieee80211_local *local) {struct rc_pid_info *pinfo; +struct rc_pid_rateinfo *rinfo; +struct ieee80211_hw_mode *mode; +int i, j, tmp; +bool s; pinfo =kmalloc (sizeof (*pinfo),GFP_ATOMIC ); +if (!pinfo) +return NULL ; + +/* We can safely assume that oper_hw_mode won't change unless we get +* reinitialized. */ + mode = local->oper_hw_mode; + rinfo =kmalloc (sizeof (*rinfo) * mode->num_rates,GFP_ATOMIC ); +if (!rinfo) { +kfree (pinfo); +return NULL ; + } + +/* Sort the rates. This is optimized for the most common case (i.e. +* almost-sorted CCK+OFDM rates). Kind of bubble-sort with reversed +* mapping too. */ +for (i =0 ; i < mode->num_rates; i++) { + rinfo[i].index = i; + rinfo[i].rev_index = i; +if (RC_PID_FAST_START ) + rinfo[i].diff =0 ; +else + rinfo[i].diff = i *RC_PID_NORM_OFFSET ; + } +for (i =1 ; i < mode->num_rates; i++) { + s =0 ; +for (j =0 ; j < mode->num_rates - i; j++) +if (unlikely (mode->rates[rinfo[j].index].rate > + mode->rates[rinfo[j +1 ].index].rate)) { + tmp = rinfo[j].index; + rinfo[j].index = rinfo[j +1 ].index; + rinfo[j +1 ].index = tmp; + rinfo[rinfo[j].index].rev_index = j; + rinfo[rinfo[j +1 ].index].rev_index = j +1 ; + s =1 ; + } +if (!s) +break ; + } pinfo->target =RC_PID_TARGET_PF ; pinfo->coeff_p =RC_PID_COEFF_P ; pinfo->coeff_i =RC_PID_COEFF_I ; pinfo->coeff_d =RC_PID_COEFF_D ; + pinfo->rinfo = rinfo; + pinfo->oldrate =0 ;return pinfo; }
@@ -330,6 +470,7 @@ static void *rate_control_pid_alloc(strustatic void rate_control_pid_free (void *priv) {struct rc_pid_info *pinfo = priv; +kfree (pinfo->rinfo);kfree (pinfo); }
Signature · 2 lines
Ciao Stefano
PATCH v3 5/8 rc80211-pid: add sharpening factor
In reply to a message not in the archiveThis patch introduces a PID sharpening factor for faster response after association and low activity events.
--- rc80211_pid.c | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-)
net/mac80211/rc80211_pid.c +27 -8
@@ -23,13 +23,16 @@* * The controller basically computes the following: * -* adj = CP * err + CI * err_avg + CD * (err - last_err) +* adj = CP * err + CI * err_avg + CD * (err - last_err) * (1 + sharpening) * * where * adj adjustment value that is used to switch TX rate (see below) * err current error: target vs. current failed frames percentage * last_err last error * err_avg average (i.e. poor man's integral) of recent errors +* sharpening non-zero when fast response is needed (i.e. right after +* association or no frames sent for a long time), heading +* to zero over time * CP Proportional coefficient * CI Integral coefficient * CD Derivative coefficient
@@ -65,6 +68,10 @@#define RC_PID_SMOOTHING_SHIFT 3#define RC_PID_SMOOTHING (1 << RC_PID_SMOOTHING_SHIFT) +/* Sharpening factor (used for D part of PID controller) */ +#define RC_PID_SHARPENING_FACTOR 0 +#define RC_PID_SHARPENING_DURATION 0 +/* Fixed point arithmetic shifting amount. */ #define RC_PID_ARITH_SHIFT 8
@@ -131,8 +138,11 @@ struct rc_pid_sta_info {*/ s32 err_avg_sc; -/* Last framed failes percentage sample */ +/* Last framed failes percentage sample. */ u32 last_pf; + +/* Sharpening needed. */ +u8 sharp_cnt; };/* Algorithm parameters. We keep them on a per-algorithm approach, so they can
@@ -267,20 +277,26 @@ static void rate_control_pid_sample(stru mode = local->oper_hw_mode; spinfo = sta->rate_ctrl_priv; + +/* In case nothing happened during the previous control interval, turn +* the sharpening factor on. */ +if (jiffies - spinfo->last_sample >2 *RC_PID_INTERVAL ) + spinfo->sharp_cnt =RC_PID_SHARPENING_DURATION ; + spinfo->last_sample = jiffies; -/* If no frames were transmitted, we assume the old sample is +/* This should never happen, but in case, we assume the old sample is * still a good measurement and copy it. */ -if (spinfo->tx_num_xmit ==0 ) +if (unlikely (spinfo->tx_num_xmit ==0 )) pf = spinfo->last_pf;else { pf = spinfo->tx_num_failed *100 / spinfo->tx_num_xmit; pf <<=RC_PID_ARITH_SHIFT ; - - spinfo->tx_num_xmit =0 ; - spinfo->tx_num_failed =0 ; } + spinfo->tx_num_xmit =0 ; + spinfo->tx_num_failed =0 ; +/* If we just switched rate, update the rate behaviour info. */ if (pinfo->oldrate != sta->txrate) {
@@ -302,8 +318,11 @@ static void rate_control_pid_sample(stru spinfo->err_avg_sc = spinfo->err_avg_sc - err_avg + err_prop; err_int = spinfo->err_avg_sc >>RC_PID_SMOOTHING_SHIFT ; - err_der = pf - spinfo->last_pf; + err_der = pf - spinfo->last_pf + * (1 +RC_PID_SHARPENING_FACTOR * spinfo->sharp_cnt); spinfo->last_pf = pf; +if (spinfo->sharp_cnt) + spinfo->sharp_cnt--;/* Compute the controller output. */ adj = (err_prop * pinfo->coeff_p + err_int * pinfo->coeff_i
Signature · 2 lines
Ciao Stefano
PATCH v3 6/8 rc80211-pid: add debugging
In reply to a message not in the archiveFrom: Mattias Nissler <[email protected]>
This adds a new debugfs file from which rate control relevant events can be read one event per line. The output includes the current time, so graphs can be created showing the rate control parameters. This helps in evaluating and tuning rate control parameters. While at it, we split headers and code for better readability.
--- net/mac80211/rc80211_pid.c | 525 ------------------------ wireless-2.6/net/mac80211/Makefile | 7 wireless-2.6/net/mac80211/rc80211_pid.h | 242 +++++++++++ wireless-2.6/net/mac80211/rc80211_pid_algo.c | 444 ++++++++++++++++++++ wireless-2.6/net/mac80211/rc80211_pid_debugfs.c | 223 ++++++++++ 5 files changed, 916 insertions(+), 525 deletions(-)
net/mac80211/rc80211_pid.c deleted +0 -525
@@ -1,525 +0,0 @@ -/* -* Copyright 2002-2005, Instant802 Networks, Inc. -* Copyright 2005, Devicescape Software, Inc. -* Copyright 2007, Mattias Nissler <[email protected]> -* Copyright 2007, Stefano Brivio <[email protected]> -* -* 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/netdevice.h> -#include <linux/types.h> -#include <linux/skbuff.h> - -#include <net/mac80211.h> -#include "ieee80211_rate.h" - - -/* This is an implementation of a TX rate control algorithm that uses a PID -* controller. Given a target failed frames rate, the controller decides about -* TX rate changes to meet the target failed frames rate. -* -* The controller basically computes the following: -* -* adj = CP * err + CI * err_avg + CD * (err - last_err) * (1 + sharpening) -* -* where -* adj adjustment value that is used to switch TX rate (see below) -* err current error: target vs. current failed frames percentage -* last_err last error -* err_avg average (i.e. poor man's integral) of recent errors -* sharpening non-zero when fast response is needed (i.e. right after -* association or no frames sent for a long time), heading -* to zero over time -* CP Proportional coefficient -* CI Integral coefficient -* CD Derivative coefficient -* -* CP, CI, CD are subject to careful tuning. -* -* The integral component uses a exponential moving average approach instead of -* an actual sliding window. The advantage is that we don't need to keep an -* array of the last N error values and computation is easier. -* -* Once we have the adj value, we map it to a rate by means of a learning -* algorithm. This algorithm keeps the state of the percentual failed frames -* difference between rates. The behaviour of the lowest available rate is kept -* as a reference value, and every time we switch between two rates, we compute -* the difference between the failed frames each rate exhibited. By doing so, -* we compare behaviours which different rates exhibited in adjacent timeslices, -* thus the comparison is minimally affected by external conditions. This -* difference gets propagated to the whole set of measurements, so that the -* reference is always the same. Periodically, we normalize this set so that -* recent events weigh the most. By comparing the adj value with this set, we -* avoid pejorative switches to lower rates and allow for switches to higher -* rates if they behaved well. -* -* Note that for the computations we use a fixed-point representation to avoid -* floating point arithmetic. Hence, all values are shifted left by -* RC_PID_ARITH_SHIFT. -*/ - -/* Sampling period for measuring percentage of failed frames. */ -#define RC_PID_INTERVAL (HZ / 8) - -/* Exponential averaging smoothness (used for I part of PID controller) */ -#define RC_PID_SMOOTHING_SHIFT 3 -#define RC_PID_SMOOTHING (1 << RC_PID_SMOOTHING_SHIFT) - -/* Sharpening factor (used for D part of PID controller) */ -#define RC_PID_SHARPENING_FACTOR 0 -#define RC_PID_SHARPENING_DURATION 0 - -/* Fixed point arithmetic shifting amount. */ -#define RC_PID_ARITH_SHIFT 8 - -/* Fixed point arithmetic factor. */ -#define RC_PID_ARITH_FACTOR (1 << RC_PID_ARITH_SHIFT) - -/* Proportional PID component coefficient. */ -#define RC_PID_COEFF_P 15 -/* Integral PID component coefficient. */ -#define RC_PID_COEFF_I 9 -/* Derivative PID component coefficient. */ -#define RC_PID_COEFF_D 15 - -/* Target failed frames rate for the PID controller. NB: This effectively gives -* maximum failed frames percentage we're willing to accept. If the wireless -* link quality is good, the controller will fail to adjust failed frames -* percentage to the target. This is intentional. -*/ -#define RC_PID_TARGET_PF (11 << RC_PID_ARITH_SHIFT) - -/* Rate behaviour normalization quantity over time. */ -#define RC_PID_NORM_OFFSET 3 - -/* Push high rates right after loading. */ -#define RC_PID_FAST_START 0 - -/* Arithmetic right shift for positive and negative values for ISO C. */ -#define RC_PID_DO_ARITH_RIGHT_SHIFT (x, y) \ - (x) < 0 ? -((-(x)) >> (y)) : (x) >> (y) - -struct rc_pid_sta_info { -unsigned long last_change; -unsigned long last_sample; - -u32 tx_num_failed; -u32 tx_num_xmit; - -/* Average failed frames percentage error (i.e. actual vs. target -* percentage), scaled by RC_PID_SMOOTHING. This value is computed -* using using an exponential weighted average technique: -* -* (RC_PID_SMOOTHING - 1) * err_avg_old + err -* err_avg = ------------------------------------------ -* RC_PID_SMOOTHING -* -* where err_avg is the new approximation, err_avg_old the previous one -* and err is the error w.r.t. to the current failed frames percentage -* sample. Note that the bigger RC_PID_SMOOTHING the more weight is -* given to the previous estimate, resulting in smoother behavior (i.e. -* corresponding to a longer integration window). -* -* For computation, we actually don't use the above formula, but this -* one: -* -* err_avg_scaled = err_avg_old_scaled - err_avg_old + err -* -* where: -* err_avg_scaled = err * RC_PID_SMOOTHING -* err_avg_old_scaled = err_avg_old * RC_PID_SMOOTHING -* -* This avoids floating point numbers and the per_failed_old value can -* easily be obtained by shifting per_failed_old_scaled right by -* RC_PID_SMOOTHING_SHIFT. -*/ -s32 err_avg_sc; - -/* Last framed failes percentage sample. */ -u32 last_pf; - -/* Sharpening needed. */ -u8 sharp_cnt; -}; - -/* Algorithm parameters. We keep them on a per-algorithm approach, so they can -* be tuned individually for each interface. -*/ -struct rc_pid_rateinfo { - -/* Map sorted rates to rates in ieee80211_hw_mode. */ -int index; - -/* Map rates in ieee80211_hw_mode to sorted rates. */ -int rev_index; - -/* Comparison with the lowest rate. */ -int diff; -}; - -struct rc_pid_info { - -/* The failed frames percentage target. */ -u32 target; - -/* P, I and D coefficients. */ -s32 coeff_p; -s32 coeff_i; -s32 coeff_d; - -/* Rates information. */ -struct rc_pid_rateinfo *rinfo; - -/* Index of the last used rate. */ -int oldrate; -}; - -/* Shift the adjustment so that we won't switch to a lower rate if it exhibited -* a worse failed frames behaviour and we'll choose the highest rate whose -* failed frames behaviour is not worse than the one of the original rate -* target. While at it, check that the adjustment is within the ranges. Then, -* provide the new rate index. */ -static int rate_control_pid_shift_adjust (struct rc_pid_rateinfo *r, -int adj,int cur,int l) -{ -int i, j, k, tmp; - -if (cur + adj <0 ) -return 0 ; -if (cur + adj >= l) -return l -1 ; - - i = r[cur + adj].rev_index; - - j = r[cur].rev_index; - -if (adj <0 ) { - tmp = i; -for (k = j; k >= i; k--) -if (r[k].diff <= r[j].diff) - tmp = k; -return r[tmp].index; - }else if (adj >0 ) { - tmp = i; -for (k = i +1 ; k + i < l; k++) -if (r[k].diff <= r[i].diff) - tmp = k; -return r[tmp].index; - } -return cur + adj; -} - -static void rate_control_pid_adjust_rate (struct ieee80211_local *local, -struct sta_info *sta,int adj, -struct rc_pid_rateinfo *rinfo) -{ -struct ieee80211_sub_if_data *sdata; -struct ieee80211_hw_mode *mode; -int newidx; -int maxrate; -int back = (adj >0 ) ?1 :-1 ; - - 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 ; - - newidx =rate_control_pid_shift_adjust (rinfo, adj, sta->txrate, - mode->num_rates); - -while (newidx != sta->txrate) { -if (rate_supported (sta, mode, newidx) && - (maxrate <0 || newidx <= maxrate)) { - sta->txrate = newidx; -break ; - } - - newidx += back; - } -} - -/* Normalize the failed frames per-rate differences. */ -static void rate_control_pid_normalize (struct rc_pid_rateinfo *r,int l) -{ -int i; - -if (r[0 ].diff >RC_PID_NORM_OFFSET ) - r[0 ].diff -=RC_PID_NORM_OFFSET ; -else if (r[0 ].diff < -RC_PID_NORM_OFFSET ) - r[0 ].diff +=RC_PID_NORM_OFFSET ; -for (i =0 ; i < l -1 ; i++) -if (r[i +1 ].diff > r[i].diff +RC_PID_NORM_OFFSET ) - r[i +1 ].diff -=RC_PID_NORM_OFFSET ; -else if (r[i +1 ].diff <= r[i].diff) - r[i +1 ].diff +=RC_PID_NORM_OFFSET ; -} - -static void rate_control_pid_sample (struct rc_pid_info *pinfo, -struct ieee80211_local *local, -struct sta_info *sta) -{ -struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv; -struct rc_pid_rateinfo *rinfo = pinfo->rinfo; -struct ieee80211_hw_mode *mode; -u32 pf; -s32 err_avg; -s32 err_prop; -s32 err_int; -s32 err_der; -int adj, i, j, tmp; - - mode = local->oper_hw_mode; - spinfo = sta->rate_ctrl_priv; - -/* In case nothing happened during the previous control interval, turn -* the sharpening factor on. */ -if (jiffies - spinfo->last_sample >2 *RC_PID_INTERVAL ) - spinfo->sharp_cnt =RC_PID_SHARPENING_DURATION ; - - spinfo->last_sample = jiffies; - -/* This should never happen, but in case, we assume the old sample is -* still a good measurement and copy it. */ -if (unlikely (spinfo->tx_num_xmit ==0 )) - pf = spinfo->last_pf; -else { - pf = spinfo->tx_num_failed *100 / spinfo->tx_num_xmit; - pf <<=RC_PID_ARITH_SHIFT ; - } - - spinfo->tx_num_xmit =0 ; - spinfo->tx_num_failed =0 ; - -/* If we just switched rate, update the rate behaviour info. */ -if (pinfo->oldrate != sta->txrate) { - - i = rinfo[pinfo->oldrate].rev_index; - j = rinfo[sta->txrate].rev_index; - - tmp = (pf - spinfo->last_pf); - tmp =RC_PID_DO_ARITH_RIGHT_SHIFT (tmp,RC_PID_ARITH_SHIFT ); - - rinfo[j].diff = rinfo[i].diff + tmp; - pinfo->oldrate = sta->txrate; - } -rate_control_pid_normalize (rinfo, mode->num_rates); - -/* Compute the proportional, integral and derivative errors. */ - err_prop =RC_PID_TARGET_PF - pf; - - err_avg = spinfo->err_avg_sc >>RC_PID_SMOOTHING_SHIFT ; - spinfo->err_avg_sc = spinfo->err_avg_sc - err_avg + err_prop; - err_int = spinfo->err_avg_sc >>RC_PID_SMOOTHING_SHIFT ; - - err_der = pf - spinfo->last_pf - * (1 +RC_PID_SHARPENING_FACTOR * spinfo->sharp_cnt); - spinfo->last_pf = pf; -if (spinfo->sharp_cnt) - spinfo->sharp_cnt--; - -/* Compute the controller output. */ - adj = (err_prop * pinfo->coeff_p + err_int * pinfo->coeff_i - + err_der * pinfo->coeff_d); - adj =RC_PID_DO_ARITH_RIGHT_SHIFT (adj,2 *RC_PID_ARITH_SHIFT ); - -/* Change rate. */ -if (adj) -rate_control_pid_adjust_rate (local, sta, adj, rinfo); -} - -static void rate_control_pid_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 rc_pid_info *pinfo = priv; -struct sta_info *sta; -struct rc_pid_sta_info *spinfo; - - sta =sta_info_get (local, hdr->addr1); - -if (!sta) -return ; - -/* Ignore all frames that were sent with a different rate than the rate -* we currently advise mac80211 to use. */ -if (status->control.rate != &local->oper_hw_mode->rates[sta->txrate]) -return ; - - spinfo = sta->rate_ctrl_priv; - spinfo->tx_num_xmit++; - -/* We count frames that totally failed to be transmitted as two bad -* frames, those that made it out but had some retries as one good and -* one bad frame. */ -if (status->excessive_retries) { - spinfo->tx_num_failed +=2 ; - spinfo->tx_num_xmit++; - }else if (status->retry_count) { - spinfo->tx_num_failed++; - spinfo->tx_num_xmit++; - } - -if (status->excessive_retries) { - 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; - -/* Update PID controller state. */ -if (time_after (jiffies, spinfo->last_sample +RC_PID_INTERVAL )) -rate_control_pid_sample (pinfo, local, sta); - -sta_info_put (sta); -} - -static void rate_control_pid_get_rate (void *priv,struct net_device *dev, -struct ieee80211_hw_mode *mode, -struct sk_buff *skb, -struct rate_selection *sel) -{ -struct ieee80211_local *local =wdev_priv (dev->ieee80211_ptr); -struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; -struct sta_info *sta; -int rateidx; - - sta =sta_info_get (local, hdr->addr1); - -if (!sta) { - sel->rate =rate_lowest (local, mode,NULL ); -sta_info_put (sta); -return ; - } - - rateidx = sta->txrate; - -if (rateidx >= mode->num_rates) - rateidx = mode->num_rates -1 ; - -sta_info_put (sta); - - sel->rate = &mode->rates[rateidx]; -} - -static void rate_control_pid_rate_init (void *priv,void *priv_sta, -struct ieee80211_local *local, -struct sta_info *sta) -{ -/* 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. */ - sta->txrate =rate_lowest_index (local, local->oper_hw_mode, sta); -} - -static void *rate_control_pid_alloc (struct ieee80211_local *local) -{ -struct rc_pid_info *pinfo; -struct rc_pid_rateinfo *rinfo; -struct ieee80211_hw_mode *mode; -int i, j, tmp; -bool s; - - pinfo =kmalloc (sizeof (*pinfo),GFP_ATOMIC ); -if (!pinfo) -return NULL ; - -/* We can safely assume that oper_hw_mode won't change unless we get -* reinitialized. */ - mode = local->oper_hw_mode; - rinfo =kmalloc (sizeof (*rinfo) * mode->num_rates,GFP_ATOMIC ); -if (!rinfo) { -kfree (pinfo); -return NULL ; - } - -/* Sort the rates. This is optimized for the most common case (i.e. -* almost-sorted CCK+OFDM rates). Kind of bubble-sort with reversed -* mapping too. */ -for (i =0 ; i < mode->num_rates; i++) { - rinfo[i].index = i; - rinfo[i].rev_index = i; -if (RC_PID_FAST_START ) - rinfo[i].diff =0 ; -else - rinfo[i].diff = i *RC_PID_NORM_OFFSET ; - } -for (i =1 ; i < mode->num_rates; i++) { - s =0 ; -for (j =0 ; j < mode->num_rates - i; j++) -if (unlikely (mode->rates[rinfo[j].index].rate > - mode->rates[rinfo[j +1 ].index].rate)) { - tmp = rinfo[j].index; - rinfo[j].index = rinfo[j +1 ].index; - rinfo[j +1 ].index = tmp; - rinfo[rinfo[j].index].rev_index = j; - rinfo[rinfo[j +1 ].index].rev_index = j +1 ; - s =1 ; - } -if (!s) -break ; - } - - pinfo->target =RC_PID_TARGET_PF ; - pinfo->coeff_p =RC_PID_COEFF_P ; - pinfo->coeff_i =RC_PID_COEFF_I ; - pinfo->coeff_d =RC_PID_COEFF_D ; - pinfo->rinfo = rinfo; - pinfo->oldrate =0 ; - -return pinfo; -} - -static void rate_control_pid_free (void *priv) -{ -struct rc_pid_info *pinfo = priv; -kfree (pinfo->rinfo); -kfree (pinfo); -} - -static void rate_control_pid_clear (void *priv) -{ -} - -static void *rate_control_pid_alloc_sta (void *priv,gfp_t gfp) -{ -struct rc_pid_sta_info *spinfo; - - spinfo =kzalloc (sizeof (*spinfo), gfp); - -return spinfo; -} - -static void rate_control_pid_free_sta (void *priv,void *priv_sta) -{ -struct rc_pid_sta_info *spinfo = priv_sta; -kfree (spinfo); -} - -struct rate_control_ops mac80211_rcpid = { - .name ="pid" , - .tx_status = rate_control_pid_tx_status, - .get_rate = rate_control_pid_get_rate, - .rate_init = rate_control_pid_rate_init, - .clear = rate_control_pid_clear, - .alloc = rate_control_pid_alloc, - .free = rate_control_pid_free, - .alloc_sta = rate_control_pid_alloc_sta, - .free_sta = rate_control_pid_free_sta, -};
net/mac80211/rc80211_pid_debugfs.c new file +223 -0
223 lines not on this page · raw message
net/mac80211/rc80211_pid.h new file +242 -0
242 lines not on this page · raw message
net/mac80211/Makefile +7 -0
@@ -32,3 +33,10 @@ mac80211-objs := \ ifneq ($(CONFIG_MAC80211_RC_PID),y) mac80211-objs += rc80211_simple.o endif + + +rc80211_pid-objs-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o + +rc80211_pid-objs := \ + rc80211_pid_algo.o \ + $(rc80211_pid-objs-y)
net/mac80211/rc80211_pid_algo.c new file +444 -0
444 lines not on this page · raw message
Signature · 2 lines
Ciao Stefano
PATCH v3 7/8 debugfs: allow access to signed values
In reply to a message not in the archiveAdd debugfs_create_s{8,16,32,64}. For these to work properly, we need to remove a cast in libfs.
Cc: Johannes Berg <[email protected]>
To: Greg Kroah-Hartman <[email protected]>
---
Greg,
here comes an implementation of debugfs_create_s{8,16,32,64} which avoids code duplication, suggested by Johannes Berg. We would need this to be merged to 2.6.25, as we need those functions to be available for rc80211-pid, the new mac80211 rate control algorithm.
--- fs/debugfs/file.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/libfs.c | 4 - include/linux/debugfs.h | 30 ++++++++ 3 files changed, 197 insertions(+), 3 deletions(-)
fs/debugfs/file.c +166 -0
@@ -221,6 +221,172 @@ struct dentry *debugfs_create_u64(const }EXPORT_SYMBOL_GPL (debugfs_create_u64); + +static void debugfs_s8_set (void *data,u64 val) +{ + *(s8 *)data = val; +} +static u64 debugfs_s8_get (void *data) +{ +return *(s8 *)data; +} +DEFINE_SIMPLE_ATTRIBUTE (fops_s8, debugfs_s8_get, debugfs_s8_set,"%lld\n" ); + +/** +* debugfs_create_s8 - create a debugfs file that is used to read and write a signed 8-bit value +* @name: a pointer to a string containing the name of the file to create. +* @mode: the permission that the file should have +* @parent: a pointer to the parent dentry for this file. This should be a +* directory dentry if set. If this parameter is %NULL, then the +* file will be created in the root of the debugfs filesystem. +* @value: a pointer to the variable that the file should read to and write +* from. +* +* This function creates a file in debugfs with the given name that +* contains the value of the variable @value. If the @mode variable is so +* set, it can be read from, and written to. +* +* This function will return a pointer to a dentry if it succeeds. This +* pointer must be passed to the debugfs_remove() function when the file is +* to be removed (no automatic cleanup happens if your module is unloaded, +* you are responsible here.) If an error occurs, %NULL will be returned. +* +* If debugfs is not enabled in the kernel, the value -%ENODEV will be +* returned. It is not wise to check for this value, but rather, check for +* %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling +* code. +*/ +struct dentry *debugfs_create_s8 (const char *name,mode_t mode, +struct dentry *parent,s8 *value) +{ +return debugfs_create_file (name, mode, parent, value, &fops_s8); +} +EXPORT_SYMBOL_GPL (debugfs_create_s8); + +static void debugfs_s16_set (void *data,u64 val) +{ + *(s16 *)data = val; +} +static u64 debugfs_s16_get (void *data) +{ +return *(s16 *)data; +} +DEFINE_SIMPLE_ATTRIBUTE (fops_s16, debugfs_s16_get, debugfs_s16_set,"%lld\n" ); + +/** +* debugfs_create_s16 - create a debugfs file that is used to read and write a signed 16-bit value +* @name: a pointer to a string containing the name of the file to create. +* @mode: the permission that the file should have +* @parent: a pointer to the parent dentry for this file. This should be a +* directory dentry if set. If this parameter is %NULL, then the +* file will be created in the root of the debugfs filesystem. +* @value: a pointer to the variable that the file should read to and write +* from. +* +* This function creates a file in debugfs with the given name that +* contains the value of the variable @value. If the @mode variable is so +* set, it can be read from, and written to. +* +* This function will return a pointer to a dentry if it succeeds. This +* pointer must be passed to the debugfs_remove() function when the file is +* to be removed (no automatic cleanup happens if your module is unloaded, +* you are responsible here.) If an error occurs, %NULL will be returned. +* +* If debugfs is not enabled in the kernel, the value -%ENODEV will be +* returned. It is not wise to check for this value, but rather, check for +* %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling +* code. +*/ +struct dentry *debugfs_create_s16 (const char *name,mode_t mode, +struct dentry *parent,s16 *value) +{ +return debugfs_create_file (name, mode, parent, value, &fops_s16); +} +EXPORT_SYMBOL_GPL (debugfs_create_s16); + +static void debugfs_s32_set (void *data,u64 val) +{ + *(s32 *)data = val; +} +static u64 debugfs_s32_get (void *data) +{ +return *(s32 *)data; +} +DEFINE_SIMPLE_ATTRIBUTE (fops_s32, debugfs_s32_get, debugfs_s32_set,"%lld\n" ); + +/** +* debugfs_create_s32 - create a debugfs file that is used to read and write a signed 32-bit value +* @name: a pointer to a string containing the name of the file to create. +* @mode: the permission that the file should have +* @parent: a pointer to the parent dentry for this file. This should be a +* directory dentry if set. If this parameter is %NULL, then the +* file will be created in the root of the debugfs filesystem. +* @value: a pointer to the variable that the file should read to and write +* from. +* +* This function creates a file in debugfs with the given name that +* contains the value of the variable @value. If the @mode variable is so +* set, it can be read from, and written to. +* +* This function will return a pointer to a dentry if it succeeds. This +* pointer must be passed to the debugfs_remove() function when the file is +* to be removed (no automatic cleanup happens if your module is unloaded, +* you are responsible here.) If an error occurs, %NULL will be returned. +* +* If debugfs is not enabled in the kernel, the value -%ENODEV will be +* returned. It is not wise to check for this value, but rather, check for +* %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling +* code. +*/ +struct dentry *debugfs_create_s32 (const char *name,mode_t mode, +struct dentry *parent,s32 *value) +{ +return debugfs_create_file (name, mode, parent, value, &fops_s32); +} +EXPORT_SYMBOL_GPL (debugfs_create_s32); + +static void debugfs_s64_set (void *data,u64 val) +{ + *(s64 *)data = val; +} + +static u64 debugfs_s64_get (void *data) +{ +return *(s64 *)data; +} +DEFINE_SIMPLE_ATTRIBUTE (fops_s64, debugfs_s64_get, debugfs_s64_set,"%lld\n" ); + +/** +* debugfs_create_s64 - create a debugfs file that is used to read and write a signed 64-bit value +* @name: a pointer to a string containing the name of the file to create. +* @mode: the permission that the file should have +* @parent: a pointer to the parent dentry for this file. This should be a +* directory dentry if set. If this parameter is %NULL, then the +* file will be created in the root of the debugfs filesystem. +* @value: a pointer to the variable that the file should read to and write +* from. +* +* This function creates a file in debugfs with the given name that +* contains the value of the variable @value. If the @mode variable is so +* set, it can be read from, and written to. +* +* This function will return a pointer to a dentry if it succeeds. This +* pointer must be passed to the debugfs_remove() function when the file is +* to be removed (no automatic cleanup happens if your module is unloaded, +* you are responsible here.) If an error occurs, %NULL will be returned. +* +* If debugfs is not enabled in the kernel, the value -%ENODEV will be +* returned. It is not wise to check for this value, but rather, check for +* %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling +* code. +*/ +struct dentry *debugfs_create_s64 (const char *name,mode_t mode, +struct dentry *parent,u64 *value) +{ +return debugfs_create_file (name, mode, parent, value, &fops_s64); +} +EXPORT_SYMBOL_GPL (debugfs_create_s64); +DEFINE_SIMPLE_ATTRIBUTE (fops_x8, debugfs_u8_get, debugfs_u8_set,"0x%02llx\n" );DEFINE_SIMPLE_ATTRIBUTE (fops_x16, debugfs_u16_get, debugfs_u16_set,"0x%04llx\n" );
fs/libfs.c +2 -2
@@ -586,7 +586,7 @@ int simple_transaction_release(struct in/* Simple attribute files */ struct simple_attr { -u64 (*get)(void *); +unsigned long long (*get)(void *);void (*set)(void *,u64 );char get_buf[24 ];/* enough to store a u64 and "\n\0" */ char set_buf[24 ];
@@ -643,7 +643,7 @@ ssize_t simple_attr_read(struct file *fi else /* first read */ size =scnprintf (attr->get_buf,sizeof (attr->get_buf), attr->fmt, - (unsigned long long )attr->get (attr->data)); + attr->get (attr->data)); ret =simple_read_from_buffer (buf, len, ppos, attr->get_buf, size);mutex_unlock (&attr->mutex);
include/linux/debugfs.h +29 -1
@@ -65,7 +65,7 @@ struct dentry *debugfs_create_blob(const#include <linux/err.h> -/* +/* * We do not return NULL from these functions if CONFIG_DEBUG_FS is not enabled * so users have a chance to detect if there was a real error or not. We don't * want to duplicate the design decision mistakes of procfs and devfs again.
@@ -128,6 +128,34 @@ static inline struct dentry *debugfs_crereturn ERR_PTR (-ENODEV ); } +static inline struct dentry *debugfs_create_s8 (const char *name,mode_t mode, +struct dentry *parent, +u8 *value) +{ +return ERR_PTR (-ENODEV ); +} + +static inline struct dentry *debugfs_create_s16 (const char *name,mode_t mode, +struct dentry *parent, +s16 *value) +{ +return ERR_PTR (-ENODEV ); +} + +static inline struct dentry *debugfs_create_s32 (const char *name,mode_t mode, +struct dentry *parent, +s32 *value) +{ +return ERR_PTR (-ENODEV ); +} + +static inline struct dentry *debugfs_create_s64 (const char *name,mode_t mode, +struct dentry *parent, +s64 *value) +{ +return ERR_PTR (-ENODEV ); +} +static inline struct dentry *debugfs_create_x8 (const char *name,mode_t mode,struct dentry *parent,u8 *value)
Signature · 2 lines
Ciao Stefano
Re: [PATCH v3 7/8] debugfs: allow access to signed values
Quoted 5 lines · Stefano Brivio
Add debugfs_create_s{8,16,32,64}. For these to work properly, we need to remove a cast in libfs.
Cc: Johannes Berg <[email protected]>
To: Greg Kroah-Hartman <[email protected]>
Quoted 8 lines
Signed-off-by Stefano Brivio <[email protected]>---
Greg,here comes an implementation of debugfs_create_s{8,16,32,64} which avoids code duplication, suggested by Johannes Berg. We would need this to be merged to 2.6.25, as we need those functions to be available for rc80211-pid, the new mac80211 rate control algorithm.
Looks good to me, do you want me to add this to my tree and send it to Linus when 2.6.25 opens up, or do you want this to go through the wireless tree as you have patches relying on it?
Whatever works the best for you is fine for me. If the wireless tree, feel free to add:
to the patch.
thanks,
greg k-h
Re: [PATCH v3 7/8] debugfs: allow access to signed values
Quoted 10 lines · On Tue, 18 Dec 2007 22:45:10 -0800 Greg KH <[email protected]> wrote:
Quoted 9 lines · Stefano Brivio
Add debugfs_create_s{8,16,32,64}. For these to work properly, we need to remove a cast in libfs.
Cc: Johannes Berg <[email protected]>
To: Greg Kroah-Hartman <[email protected]>Signed-off-by Stefano Brivio <[email protected]>---
Greg,
Quoted 8 lines
Quoted 4 lines
here comes an implementation of debugfs_create_s{8,16,32,64} which avoids code duplication, suggested by Johannes Berg. We would need this to be merged to 2.6.25, as we need those functions to be available for rc80211-pid, the new mac80211 rate control algorithm.
Looks good to me, do you want me to add this to my tree and send it to Linus when 2.6.25 opens up, or do you want this to go through the wireless tree as you have patches relying on it?
I have one patch (rate control rework, 8/8) relying on it. Let's ask John. John, what's the best for you?
Quoted 4 lines
Whatever works the best for you is fine for me. If the wireless tree, feel free to add:
Signed-off-by Greg Kroah-Hartman <[email protected]>to the patch.
Thanks. I'm going to resend the patch to John with your Signed-off-by -- in case.
--
Ciao
Stefano
Re: [PATCH v3 7/8] debugfs: allow access to signed values
Quoted 10 lines · Stefano Brivio
Quoted 7 lines · On Tue, 18 Dec 2007 22:45:10 -0800 Greg KH <[email protected]> wrote:
Quoted 4 lines · Stefano Brivio
here comes an implementation of debugfs_create_s{8,16,32,64} which avoids code duplication, suggested by Johannes Berg. We would need this to be merged to 2.6.25, as we need those functions to be available for rc80211-pid, the new mac80211 rate control algorithm.
Quoted 6 lines
Quoted 3 lines
Looks good to me, do you want me to add this to my tree and send it to Linus when 2.6.25 opens up, or do you want this to go through the wireless tree as you have patches relying on it?
I have one patch (rate control rework, 8/8) relying on it. Let's ask John. John, what's the best for you?
Since Greg approves, I'll take it through wireless-2.6 to avoid any staging problems for patch 8/8.
Thanks,
John
Signature · 2 lines
John W. Linville [email protected]
PATCH v4 7/8 debugfs: allow access to signed values
In reply to Stefano BrivioAdd debugfs_create_s{8,16,32,64}. For these to work properly, we need to remove a cast in libfs.
--- fs/debugfs/file.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/libfs.c | 4 - include/linux/debugfs.h | 30 ++++++++ 3 files changed, 197 insertions(+), 3 deletions(-)
fs/debugfs/file.c +166 -0
@@ -221,6 +221,172 @@ struct dentry *debugfs_create_u64(const }EXPORT_SYMBOL_GPL (debugfs_create_u64); + +static void debugfs_s8_set (void *data,u64 val) +{ + *(s8 *)data = val; +} +static u64 debugfs_s8_get (void *data) +{ +return *(s8 *)data; +} +DEFINE_SIMPLE_ATTRIBUTE (fops_s8, debugfs_s8_get, debugfs_s8_set,"%lld\n" ); + +/** +* debugfs_create_s8 - create a debugfs file that is used to read and write a signed 8-bit value +* @name: a pointer to a string containing the name of the file to create. +* @mode: the permission that the file should have +* @parent: a pointer to the parent dentry for this file. This should be a +* directory dentry if set. If this parameter is %NULL, then the +* file will be created in the root of the debugfs filesystem. +* @value: a pointer to the variable that the file should read to and write +* from. +* +* This function creates a file in debugfs with the given name that +* contains the value of the variable @value. If the @mode variable is so +* set, it can be read from, and written to. +* +* This function will return a pointer to a dentry if it succeeds. This +* pointer must be passed to the debugfs_remove() function when the file is +* to be removed (no automatic cleanup happens if your module is unloaded, +* you are responsible here.) If an error occurs, %NULL will be returned. +* +* If debugfs is not enabled in the kernel, the value -%ENODEV will be +* returned. It is not wise to check for this value, but rather, check for +* %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling +* code. +*/ +struct dentry *debugfs_create_s8 (const char *name,mode_t mode, +struct dentry *parent,s8 *value) +{ +return debugfs_create_file (name, mode, parent, value, &fops_s8); +} +EXPORT_SYMBOL_GPL (debugfs_create_s8); + +static void debugfs_s16_set (void *data,u64 val) +{ + *(s16 *)data = val; +} +static u64 debugfs_s16_get (void *data) +{ +return *(s16 *)data; +} +DEFINE_SIMPLE_ATTRIBUTE (fops_s16, debugfs_s16_get, debugfs_s16_set,"%lld\n" ); + +/** +* debugfs_create_s16 - create a debugfs file that is used to read and write a signed 16-bit value +* @name: a pointer to a string containing the name of the file to create. +* @mode: the permission that the file should have +* @parent: a pointer to the parent dentry for this file. This should be a +* directory dentry if set. If this parameter is %NULL, then the +* file will be created in the root of the debugfs filesystem. +* @value: a pointer to the variable that the file should read to and write +* from. +* +* This function creates a file in debugfs with the given name that +* contains the value of the variable @value. If the @mode variable is so +* set, it can be read from, and written to. +* +* This function will return a pointer to a dentry if it succeeds. This +* pointer must be passed to the debugfs_remove() function when the file is +* to be removed (no automatic cleanup happens if your module is unloaded, +* you are responsible here.) If an error occurs, %NULL will be returned. +* +* If debugfs is not enabled in the kernel, the value -%ENODEV will be +* returned. It is not wise to check for this value, but rather, check for +* %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling +* code. +*/ +struct dentry *debugfs_create_s16 (const char *name,mode_t mode, +struct dentry *parent,s16 *value) +{ +return debugfs_create_file (name, mode, parent, value, &fops_s16); +} +EXPORT_SYMBOL_GPL (debugfs_create_s16); + +static void debugfs_s32_set (void *data,u64 val) +{ + *(s32 *)data = val; +} +static u64 debugfs_s32_get (void *data) +{ +return *(s32 *)data; +} +DEFINE_SIMPLE_ATTRIBUTE (fops_s32, debugfs_s32_get, debugfs_s32_set,"%lld\n" ); + +/** +* debugfs_create_s32 - create a debugfs file that is used to read and write a signed 32-bit value +* @name: a pointer to a string containing the name of the file to create. +* @mode: the permission that the file should have +* @parent: a pointer to the parent dentry for this file. This should be a +* directory dentry if set. If this parameter is %NULL, then the +* file will be created in the root of the debugfs filesystem. +* @value: a pointer to the variable that the file should read to and write +* from. +* +* This function creates a file in debugfs with the given name that +* contains the value of the variable @value. If the @mode variable is so +* set, it can be read from, and written to. +* +* This function will return a pointer to a dentry if it succeeds. This +* pointer must be passed to the debugfs_remove() function when the file is +* to be removed (no automatic cleanup happens if your module is unloaded, +* you are responsible here.) If an error occurs, %NULL will be returned. +* +* If debugfs is not enabled in the kernel, the value -%ENODEV will be +* returned. It is not wise to check for this value, but rather, check for +* %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling +* code. +*/ +struct dentry *debugfs_create_s32 (const char *name,mode_t mode, +struct dentry *parent,s32 *value) +{ +return debugfs_create_file (name, mode, parent, value, &fops_s32); +} +EXPORT_SYMBOL_GPL (debugfs_create_s32); + +static void debugfs_s64_set (void *data,u64 val) +{ + *(s64 *)data = val; +} + +static u64 debugfs_s64_get (void *data) +{ +return *(s64 *)data; +} +DEFINE_SIMPLE_ATTRIBUTE (fops_s64, debugfs_s64_get, debugfs_s64_set,"%lld\n" ); + +/** +* debugfs_create_s64 - create a debugfs file that is used to read and write a signed 64-bit value +* @name: a pointer to a string containing the name of the file to create. +* @mode: the permission that the file should have +* @parent: a pointer to the parent dentry for this file. This should be a +* directory dentry if set. If this parameter is %NULL, then the +* file will be created in the root of the debugfs filesystem. +* @value: a pointer to the variable that the file should read to and write +* from. +* +* This function creates a file in debugfs with the given name that +* contains the value of the variable @value. If the @mode variable is so +* set, it can be read from, and written to. +* +* This function will return a pointer to a dentry if it succeeds. This +* pointer must be passed to the debugfs_remove() function when the file is +* to be removed (no automatic cleanup happens if your module is unloaded, +* you are responsible here.) If an error occurs, %NULL will be returned. +* +* If debugfs is not enabled in the kernel, the value -%ENODEV will be +* returned. It is not wise to check for this value, but rather, check for +* %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling +* code. +*/ +struct dentry *debugfs_create_s64 (const char *name,mode_t mode, +struct dentry *parent,u64 *value) +{ +return debugfs_create_file (name, mode, parent, value, &fops_s64); +} +EXPORT_SYMBOL_GPL (debugfs_create_s64); +DEFINE_SIMPLE_ATTRIBUTE (fops_x8, debugfs_u8_get, debugfs_u8_set,"0x%02llx\n" );DEFINE_SIMPLE_ATTRIBUTE (fops_x16, debugfs_u16_get, debugfs_u16_set,"0x%04llx\n" );
fs/libfs.c +2 -2
@@ -586,7 +586,7 @@ int simple_transaction_release(struct in/* Simple attribute files */ struct simple_attr { -u64 (*get)(void *); +unsigned long long (*get)(void *);void (*set)(void *,u64 );char get_buf[24 ];/* enough to store a u64 and "\n\0" */ char set_buf[24 ];
@@ -643,7 +643,7 @@ ssize_t simple_attr_read(struct file *fi else /* first read */ size =scnprintf (attr->get_buf,sizeof (attr->get_buf), attr->fmt, - (unsigned long long )attr->get (attr->data)); + attr->get (attr->data)); ret =simple_read_from_buffer (buf, len, ppos, attr->get_buf, size);mutex_unlock (&attr->mutex);
include/linux/debugfs.h +29 -1
@@ -65,7 +65,7 @@ struct dentry *debugfs_create_blob(const#include <linux/err.h> -/* +/* * We do not return NULL from these functions if CONFIG_DEBUG_FS is not enabled * so users have a chance to detect if there was a real error or not. We don't * want to duplicate the design decision mistakes of procfs and devfs again.
@@ -128,6 +128,34 @@ static inline struct dentry *debugfs_crereturn ERR_PTR (-ENODEV ); } +static inline struct dentry *debugfs_create_s8 (const char *name,mode_t mode, +struct dentry *parent, +u8 *value) +{ +return ERR_PTR (-ENODEV ); +} + +static inline struct dentry *debugfs_create_s16 (const char *name,mode_t mode, +struct dentry *parent, +s16 *value) +{ +return ERR_PTR (-ENODEV ); +} + +static inline struct dentry *debugfs_create_s32 (const char *name,mode_t mode, +struct dentry *parent, +s32 *value) +{ +return ERR_PTR (-ENODEV ); +} + +static inline struct dentry *debugfs_create_s64 (const char *name,mode_t mode, +struct dentry *parent, +s64 *value) +{ +return ERR_PTR (-ENODEV ); +} +static inline struct dentry *debugfs_create_x8 (const char *name,mode_t mode,struct dentry *parent,u8 *value)
Signature · 2 lines
Ciao Stefano
Johannes Berg
maintainerRe: [PATCH v3 7/8] debugfs: allow access to signed values
In reply to Stefano Briviofs/libfs.c int simple_transaction_release(struct in · line 589
Quoted 7 lines
fs/libfs.c +2
-1+static u64 debugfs_s8_get (void *data) struct simple_attr { -u64 (*get)(void *); +unsigned long long (*get)(void *);
That seems wrong. Wouldn't you have to declare all the _get functions with unsigned long long too now to avoid trouble on systems where u64 != unsigned long long?
johannes
PATCH v4 7/8 debugfs: allow access to signed values
debugfs: allow access to signed values
Add debugfs_create_s{8,16,32,64}. For these to work properly, we need to remove a cast in libfs, change the simple_attr_open prototype and thus fix the users as well.
Cc: Johannes Berg <[email protected]>
Cc: Mattias Nissler <[email protected]>
To: Greg Kroah-Hartman <[email protected]>
To: Arnd Bergmann <[email protected]>
To: Akinobu Mita <[email protected]>
---
This version addresses last Johannes' concerns.
--- arch/powerpc/platforms/cell/spufs/file.c | 48 ++++---- fs/debugfs/file.c | 186 +++++++++++++++++++++++++++++-- fs/libfs.c | 23 ++- include/linux/debugfs.h | 38 ++++++ include/linux/fs.h | 25 ++-- lib/fault-inject.c | 11 + 6 files changed, 268 insertions(+), 63 deletions(-)
fs/debugfs/file.c +176 -10
@@ -56,11 +56,11 @@ const struct inode_operations debugfs_li .follow_link = debugfs_follow_link, }; -static void debugfs_u8_set (void *data,u64 val) +static void debugfs_u8_set (void *data,unsigned long long val) { *(u8 *)data = val; } -static u64 debugfs_u8_get (void *data) +static unsigned long long debugfs_u8_get (void *data) {return *(u8 *)data; }
@@ -97,11 +97,11 @@ struct dentry *debugfs_create_u8(const c }EXPORT_SYMBOL_GPL (debugfs_create_u8); -static void debugfs_u16_set (void *data,u64 val) +static void debugfs_u16_set (void *data,unsigned long long val) { *(u16 *)data = val; } -static u64 debugfs_u16_get (void *data) +static unsigned long long debugfs_u16_get (void *data) {return *(u16 *)data; }
@@ -138,11 +138,11 @@ struct dentry *debugfs_create_u16(const }EXPORT_SYMBOL_GPL (debugfs_create_u16); -static void debugfs_u32_set (void *data,u64 val) +static void debugfs_u32_set (void *data,unsigned long long val) { *(u32 *)data = val; } -static u64 debugfs_u32_get (void *data) +static unsigned long long debugfs_u32_get (void *data) {return *(u32 *)data; }
@@ -179,12 +179,12 @@ struct dentry *debugfs_create_u32(const }EXPORT_SYMBOL_GPL (debugfs_create_u32); -static void debugfs_u64_set (void *data,u64 val) +static void debugfs_u64_set (void *data,unsigned long long val) { *(u64 *)data = val; } -static u64 debugfs_u64_get (void *data) +static unsigned long long debugfs_u64_get (void *data) {return *(u64 *)data; }
@@ -221,6 +221,172 @@ struct dentry *debugfs_create_u64(const }EXPORT_SYMBOL_GPL (debugfs_create_u64); + +static void debugfs_s8_set (void *data,unsigned long long val) +{ + *(s8 *)data = val; +} +static unsigned long long debugfs_s8_get (void *data) +{ +return *(s8 *)data; +} +DEFINE_SIMPLE_ATTRIBUTE (fops_s8, debugfs_s8_get, debugfs_s8_set,"%lld\n" ); + +/** +* debugfs_create_s8 - create a debugfs file that is used to read and write a signed 8-bit value +* @name: a pointer to a string containing the name of the file to create. +* @mode: the permission that the file should have +* @parent: a pointer to the parent dentry for this file. This should be a +* directory dentry if set. If this parameter is %NULL, then the +* file will be created in the root of the debugfs filesystem. +* @value: a pointer to the variable that the file should read to and write +* from. +* +* This function creates a file in debugfs with the given name that +* contains the value of the variable @value. If the @mode variable is so +* set, it can be read from, and written to. +* +* This function will return a pointer to a dentry if it succeeds. This +* pointer must be passed to the debugfs_remove() function when the file is +* to be removed (no automatic cleanup happens if your module is unloaded, +* you are responsible here.) If an error occurs, %NULL will be returned. +* +* If debugfs is not enabled in the kernel, the value -%ENODEV will be +* returned. It is not wise to check for this value, but rather, check for +* %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling +* code. +*/ +struct dentry *debugfs_create_s8 (const char *name,mode_t mode, +struct dentry *parent,s8 *value) +{ +return debugfs_create_file (name, mode, parent, value, &fops_s8); +} +EXPORT_SYMBOL_GPL (debugfs_create_s8); + +static void debugfs_s16_set (void *data,unsigned long long val) +{ + *(s16 *)data = val; +} +static unsigned long long debugfs_s16_get (void *data) +{ +return *(s16 *)data; +} +DEFINE_SIMPLE_ATTRIBUTE (fops_s16, debugfs_s16_get, debugfs_s16_set,"%lld\n" ); + +/** +* debugfs_create_s16 - create a debugfs file that is used to read and write a signed 16-bit value +* @name: a pointer to a string containing the name of the file to create. +* @mode: the permission that the file should have +* @parent: a pointer to the parent dentry for this file. This should be a +* directory dentry if set. If this parameter is %NULL, then the +* file will be created in the root of the debugfs filesystem. +* @value: a pointer to the variable that the file should read to and write +* from. +* +* This function creates a file in debugfs with the given name that +* contains the value of the variable @value. If the @mode variable is so +* set, it can be read from, and written to. +* +* This function will return a pointer to a dentry if it succeeds. This +* pointer must be passed to the debugfs_remove() function when the file is +* to be removed (no automatic cleanup happens if your module is unloaded, +* you are responsible here.) If an error occurs, %NULL will be returned. +* +* If debugfs is not enabled in the kernel, the value -%ENODEV will be +* returned. It is not wise to check for this value, but rather, check for +* %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling +* code. +*/ +struct dentry *debugfs_create_s16 (const char *name,mode_t mode, +struct dentry *parent,s16 *value) +{ +return debugfs_create_file (name, mode, parent, value, &fops_s16); +} +EXPORT_SYMBOL_GPL (debugfs_create_s16); + +static void debugfs_s32_set (void *data,unsigned long long val) +{ + *(s32 *)data = val; +} +static unsigned long long debugfs_s32_get (void *data) +{ +return *(s32 *)data; +} +DEFINE_SIMPLE_ATTRIBUTE (fops_s32, debugfs_s32_get, debugfs_s32_set,"%lld\n" ); + +/** +* debugfs_create_s32 - create a debugfs file that is used to read and write a signed 32-bit value +* @name: a pointer to a string containing the name of the file to create. +* @mode: the permission that the file should have +* @parent: a pointer to the parent dentry for this file. This should be a +* directory dentry if set. If this parameter is %NULL, then the +* file will be created in the root of the debugfs filesystem. +* @value: a pointer to the variable that the file should read to and write +* from. +* +* This function creates a file in debugfs with the given name that +* contains the value of the variable @value. If the @mode variable is so +* set, it can be read from, and written to. +* +* This function will return a pointer to a dentry if it succeeds. This +* pointer must be passed to the debugfs_remove() function when the file is +* to be removed (no automatic cleanup happens if your module is unloaded, +* you are responsible here.) If an error occurs, %NULL will be returned. +* +* If debugfs is not enabled in the kernel, the value -%ENODEV will be +* returned. It is not wise to check for this value, but rather, check for +* %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling +* code. +*/ +struct dentry *debugfs_create_s32 (const char *name,mode_t mode, +struct dentry *parent,s32 *value) +{ +return debugfs_create_file (name, mode, parent, value, &fops_s32); +} +EXPORT_SYMBOL_GPL (debugfs_create_s32); + +static void debugfs_s64_set (void *data,unsigned long long val) +{ + *(s64 *)data = val; +} + +static unsigned long long debugfs_s64_get (void *data) +{ +return *(s64 *)data; +} +DEFINE_SIMPLE_ATTRIBUTE (fops_s64, debugfs_s64_get, debugfs_s64_set,"%lld\n" ); + +/** +* debugfs_create_s64 - create a debugfs file that is used to read and write a signed 64-bit value +* @name: a pointer to a string containing the name of the file to create. +* @mode: the permission that the file should have +* @parent: a pointer to the parent dentry for this file. This should be a +* directory dentry if set. If this parameter is %NULL, then the +* file will be created in the root of the debugfs filesystem. +* @value: a pointer to the variable that the file should read to and write +* from. +* +* This function creates a file in debugfs with the given name that +* contains the value of the variable @value. If the @mode variable is so +* set, it can be read from, and written to. +* +* This function will return a pointer to a dentry if it succeeds. This +* pointer must be passed to the debugfs_remove() function when the file is +* to be removed (no automatic cleanup happens if your module is unloaded, +* you are responsible here.) If an error occurs, %NULL will be returned. +* +* If debugfs is not enabled in the kernel, the value -%ENODEV will be +* returned. It is not wise to check for this value, but rather, check for +* %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling +* code. +*/ +struct dentry *debugfs_create_s64 (const char *name,mode_t mode, +struct dentry *parent,s64 *value) +{ +return debugfs_create_file (name, mode, parent, value, &fops_s64); +} +EXPORT_SYMBOL_GPL (debugfs_create_s64); +DEFINE_SIMPLE_ATTRIBUTE (fops_x8, debugfs_u8_get, debugfs_u8_set,"0x%02llx\n" );DEFINE_SIMPLE_ATTRIBUTE (fops_x16, debugfs_u16_get, debugfs_u16_set,"0x%04llx\n" );
@@ -291,7 +457,7 @@ static ssize_t read_file_bool(struct fil {char buf[3 ];u32 *val = file->private_data; - +if (*val) buf[0 ] ='Y' ;else
@@ -324,7 +490,7 @@ static ssize_t write_file_bool(struct fi *val =0 ;break ; } - +return count; }
fs/libfs.c +12 -11
@@ -59,7 +59,7 @@ int simple_sync_file(struct file * file, {return 0 ; } - +int dcache_dir_open (struct inode *inode,struct file *file) {static struct qstr cursor_name = {.len =1 , .name ="." };
@@ -160,9 +160,9 @@ int dcache_readdir(struct file * filp, vcontinue ;spin_unlock (&dcache_lock); -if (filldir (dirent, next->d_name.name, - next->d_name.len, filp->f_pos, - next->d_inode->i_ino, +if (filldir (dirent, next->d_name.name, + next->d_name.len, filp->f_pos, + next->d_inode->i_ino,dt_type (next->d_inode)) <0 )return 0 ;spin_lock (&dcache_lock);
@@ -586,10 +586,10 @@ int simple_transaction_release(struct in/* Simple attribute files */ struct simple_attr { -u64 (*get)(void *); -void (*set)(void *,u64 ); -char get_buf[24 ];/* enough to store a u64 and "\n\0" */ -char set_buf[24 ]; +unsigned long long (*get)(void *); +void (*set)(void *,unsigned long long ); +char get_buf[sizeof (unsigned long long ) +2 ];/* ULL + "\n\0" */ +char set_buf[sizeof (unsigned long long ) +2 ];void *data;const char *fmt;/* format for read operation */ struct mutex mutex;/* protects access to these buffers */
@@ -598,7 +598,8 @@ struct simple_attr {/* simple_attr_open is called by an actual attribute open file operation * to set the attribute specific access operations. */ int simple_attr_open (struct inode *inode,struct file *file, -u64 (*get)(void *),void (*set)(void *,u64 ), +unsigned long long (*get)(void *), +void (*set)(void *,unsigned long long ),const char *fmt) {struct simple_attr *attr;
@@ -643,7 +644,7 @@ ssize_t simple_attr_read(struct file *fi else /* first read */ size =scnprintf (attr->get_buf,sizeof (attr->get_buf), attr->fmt, - (unsigned long long )attr->get (attr->data)); + attr->get (attr->data)); ret =simple_read_from_buffer (buf, len, ppos, attr->get_buf, size);mutex_unlock (&attr->mutex);
@@ -655,7 +656,7 @@ ssize_t simple_attr_write(struct file *f size_t len, loff_t *ppos) { struct simple_attr *attr; -u64 val; +unsigned long long val;size_t size;ssize_t ret;
include/linux/debugfs.h +37 -1
@@ -49,6 +49,14 @@ struct dentry *debugfs_create_u32(const struct dentry *parent, u32 *value);struct dentry *debugfs_create_u64 (const char *name,mode_t mode,struct dentry *parent,u64 *value); +struct dentry *debugfs_create_s8 (const char *name,mode_t mode, +struct dentry *parent,s8 *value); +struct dentry *debugfs_create_s16 (const char *name,mode_t mode, +struct dentry *parent,s16 *value); +struct dentry *debugfs_create_s32 (const char *name,mode_t mode, +struct dentry *parent,s32 *value); +struct dentry *debugfs_create_s64 (const char *name,mode_t mode, +struct dentry *parent,s64 *value);struct dentry *debugfs_create_x8 (const char *name,mode_t mode,struct dentry *parent,u8 *value); struct dentry *debugfs_create_x16(const char *name, mode_t mode,
@@ -65,7 +73,7 @@ struct dentry *debugfs_create_blob(const#include <linux/err.h> -/* +/* * We do not return NULL from these functions if CONFIG_DEBUG_FS is not enabled * so users have a chance to detect if there was a real error or not. We don't * want to duplicate the design decision mistakes of procfs and devfs again.
@@ -128,6 +136,34 @@ static inline struct dentry *debugfs_crereturn ERR_PTR (-ENODEV ); } +static inline struct dentry *debugfs_create_s8 (const char *name,mode_t mode, +struct dentry *parent, +u8 *value) +{ +return ERR_PTR (-ENODEV ); +} + +static inline struct dentry *debugfs_create_s16 (const char *name,mode_t mode, +struct dentry *parent, +s16 *value) +{ +return ERR_PTR (-ENODEV ); +} + +static inline struct dentry *debugfs_create_s32 (const char *name,mode_t mode, +struct dentry *parent, +s32 *value) +{ +return ERR_PTR (-ENODEV ); +} + +static inline struct dentry *debugfs_create_s64 (const char *name,mode_t mode, +struct dentry *parent, +s64 *value) +{ +return ERR_PTR (-ENODEV ); +} +static inline struct dentry *debugfs_create_x8 (const char *name,mode_t mode,struct dentry *parent,u8 *value)
arch/powerpc/platforms/cell/spufs/file.c +24 -24
183 lines not on this page · raw message
include/linux/fs.h +13 -12
@@ -15,8 +15,8 @@* nr_file rlimit, so it's safe to set up a ridiculously high absolute * upper limit on files-per-process. * -* Some programs (notably those using select()) may have to be -* recompiled to take full advantage of the new limits.. +* Some programs (notably those using select()) may have to be +* recompiled to take full advantage of the new limits.. */ /* Fixed constants first: */
@@ -90,7 +90,7 @@ extern int dir_notify_enable;#define SEL_EX 4/* public flags for file_system_type */ -#define FS_REQUIRES_DEV 1 +#define FS_REQUIRES_DEV 1#define FS_BINARY_MOUNTDATA 2#define FS_HAS_SUBTYPE 4#define FS_REVAL_DOT 16384/* Check the paths ".", ".." for staleness */
@@ -365,7 +365,7 @@ struct iattr {*/ #include <linux/quota.h> -/** +/** * enum positive_aop_returns - aop return codes with specific semantics * * @AOP_WRITEPAGE_ACTIVATE: Informs the caller that page writeback has
@@ -375,7 +375,7 @@ struct iattr {* be a candidate for writeback again in the near * future. Other callers must be careful to unlock * the page if they get this return. Returned by -* writepage(); +* writepage(); * * @AOP_TRUNCATED_PAGE: The AOP method that was handed a locked page has * unlocked it and the page might have been truncated.
@@ -818,10 +818,10 @@ extern spinlock_t files_lock;#define MAX_NON_LFS ((1UL<<31) - 1) -/* Page cache limit. The filesystems should put that into their s_maxbytes -limits, otherwise bad things can happen in VM. */ +/* Page cache limit. The filesystems should put that into their s_maxbytes +limits, otherwise bad things can happen in VM. */ #if BITS_PER_LONG ==32 -#define MAX_LFS_FILESIZE (((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1) +#define MAX_LFS_FILESIZE (((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1)#elif BITS_PER_LONG ==64 #define MAX_LFS_FILESIZE 0x7fffffffffffffffUL#endif
@@ -1240,7 +1240,7 @@ struct super_operations {void (*destroy_inode)(struct inode *);void (*read_inode) (struct inode *); - +void (*dirty_inode) (struct inode *);int (*write_inode) (struct inode *,int );void (*put_inode) (struct inode *);
@@ -1719,7 +1719,7 @@ extern int may_open(struct nameidata *,extern int kernel_read (struct file *,unsigned long ,char *,unsigned long );extern struct file *open_exec (const char *); - +/* fs/dcache.c -- generic fs support functions */ extern int is_subdir (struct dentry *,struct dentry *);extern ino_t find_inode_number (struct dentry *,struct qstr *);
@@ -1753,7 +1753,7 @@ extern void unlock_new_inode(struct inodstatic inline struct inode *iget (struct super_block *sb,unsigned long ino) {struct inode *inode =iget_locked (sb, ino); - +if (inode && (inode->i_state &I_NEW )) { sb->s_op->read_inode (inode);unlock_new_inode (inode);
@@ -2062,7 +2062,8 @@ __simple_attr_check_format(const char *f }int simple_attr_open (struct inode *inode,struct file *file, -u64 (*get)(void *),void (*set)(void *,u64 ), +unsigned long long (*get)(void *), +void (*set)(void *,unsigned long long ),const char *fmt);int simple_attr_close (struct inode *inode,struct file *file); ssize_t simple_attr_read(struct file *file, char __user *buf,
lib/fault-inject.c +6 -5
@@ -134,13 +134,14 @@ bool should_fail(struct fault_attr *attr #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS -static void debugfs_ul_set(void *data, u64 val) +static void debugfs_ul_set(void *data, unsigned long long val) { *(unsigned long *)data = val; } #ifdef CONFIG_FAULT_INJECTION_STACKTRACE_FILTER -static void debugfs_ul_set_MAX_STACK_TRACE_DEPTH(void *data, u64 val) +static void debugfs_ul_set_MAX_STACK_TRACE_DEPTH(void *data, + unsigned long long val) { *(unsigned long *)data = val < MAX_STACK_TRACE_DEPTH ?
@@ -148,7 +149,7 @@ static void debugfs_ul_set_MAX_STACK_TRA }#endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */ -static u64 debugfs_ul_get (void *data) +static unsigned long long debugfs_ul_get (void *data) {return *(unsigned long *)data; }
@@ -174,12 +175,12 @@ static struct dentry *debugfs_create_ul_ }#endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */ -static void debugfs_atomic_t_set (void *data,u64 val) +static void debugfs_atomic_t_set (void *data,unsigned long long val) {atomic_set ((atomic_t *)data, val); } -static u64 debugfs_atomic_t_get (void *data) +static unsigned long long debugfs_atomic_t_get (void *data) {return atomic_read ((atomic_t *)data); }
Signature · 2 lines
Ciao Stefano
Re: [PATCH v4 7/8] debugfs: allow access to signed values
Quoted 6 lines · Stefano Brivio
debugfs: allow access to signed values
Add debugfs_create_s{8,16,32,64}. For these to work properly, we need to remove a cast in libfs, change the
simple_attr_openprototype and thus fix the users as well.
Quoted 6 lines
Cc: Johannes Berg <[email protected]>
Cc: Mattias Nissler <[email protected]>
To: Greg Kroah-Hartman <[email protected]>
To: Arnd Bergmann <[email protected]>
To: Akinobu Mita <[email protected]>Signed-off-by Stefano Brivio <[email protected]>
Have you checked that spufs still builds? I would guess that you need to do the same interface changes there.
Also, Christoph has recently posted a suggestion for how to improve the interface to allow the 'get' operation to return an error:
http://patchwork.ozlabs.org/cbe-oss-dev/patch?id=14962
I'd suggest consolidating the two changes in order to avoid merge conflicts.
Arnd <><
Re: [PATCH v4 7/8] debugfs: allow access to signed values
Quoted 6 lines · Arnd Bergmann
Also, Christoph has recently posted a suggestion for how to improve the interface to allow the 'get' operation to return an error:
http://patchwork.ozlabs.org/cbe-oss-dev/patch?id=14962I'd suggest consolidating the two changes in order to avoid merge conflicts.
Stefano, I couldn't find your complete patch series. Where are the
other 7 patches for that series? Anyway, I'll post my series with
the simple attribute chanegs ASAP and I'll Cc you. If you send me the latest version of your patches I'll port it ontop of my patches.
Johannes Berg
maintainerRe: [PATCH v4 7/8] debugfs: allow access to signed values
Quoted 5 lines · Christoph Hellwig
Quoted 4 lines · Arnd Bergmann
Also, Christoph has recently posted a suggestion for how to improve the interface to allow the 'get' operation to return an error:
http://patchwork.ozlabs.org/cbe-oss-dev/patch?id=14962
Quoted 7 lines
Quoted 2 lines
I'd suggest consolidating the two changes in order to avoid merge conflicts.
Stefano, I couldn't find your complete patch series. Where are the
other 7 patches for that series? Anyway, I'll post my series with
the simple attribute chanegs ASAP and I'll Cc you. If you send me the latest version of your patches I'll port it ontop of my patches.
There was only one, the seven other patches are plain wireless patches.
johannes
Re: [PATCH v4 7/8] debugfs: allow access to signed values
In reply to Christoph HellwigQuoted 5 lines · On Fri, 28 Dec 2007 19:58:32 +0100 Christoph Hellwig <[email protected]> wrote:
Quoted 4 lines · Arnd Bergmann
Also, Christoph has recently posted a suggestion for how to improve the interface to allow the 'get' operation to return an error:
http://patchwork.ozlabs.org/cbe-oss-dev/patch?id=14962
Quoted 7 lines
Quoted 2 lines
I'd suggest consolidating the two changes in order to avoid merge conflicts.
Stefano, I couldn't find your complete patch series. Where are the
other 7 patches for that series? Anyway, I'll post my series with
the simple attribute chanegs ASAP and I'll Cc you. If you send me the latest version of your patches I'll port it ontop of my patches.
Sorry for the late reply. As Johannes said, the other patches have nothing to do with this anyway. I had to put this patch within my patchset because I originally wanted to send a patch which would export signed values to debugfs, but then I solved the issue in a different fashion, and I'm not that interested in it at the moment.
BTW, the patch I sent was just meant to allow exporting signed values through debugfs, but in order to do that I had to change some users as well. And being spufs an user, I don't feel that much like sending a patch without testing on ppc64 in advance.
Signature · 2 lines
Ciao Stefano
PATCH v5 7/8 debugfs: allow access to signed values
In reply to Johannes Bergdebugfs: allow access to signed values
Add debugfs_create_s{8,16,32,64}. For these to work properly, we need to remove a cast in libfs, change the simple_attr_open prototype and thus fix the users as well.
Cc: Johannes Berg <[email protected]>
Cc: Mattias Nissler <[email protected]>
To: Greg Kroah-Hartman <[email protected]>
To: Arnd Bergmann <[email protected]>
To: Akinobu Mita <[email protected]>
---
This version addresses last Johannes' concerns. Please just discard v4.
--- arch/powerpc/platforms/cell/spufs/file.c | 48 ++++---- fs/debugfs/file.c | 186 +++++++++++++++++++++++++++++-- fs/libfs.c | 21 +-- include/linux/debugfs.h | 38 ++++++ include/linux/fs.h | 25 ++-- lib/fault-inject.c | 11 + 6 files changed, 267 insertions(+), 62 deletions(-)
fs/debugfs/file.c +176 -10
@@ -56,11 +56,11 @@ const struct inode_operations debugfs_li .follow_link = debugfs_follow_link, }; -static void debugfs_u8_set (void *data,u64 val) +static void debugfs_u8_set (void *data,unsigned long long val) { *(u8 *)data = val; } -static u64 debugfs_u8_get (void *data) +static unsigned long long debugfs_u8_get (void *data) {return *(u8 *)data; }
@@ -97,11 +97,11 @@ struct dentry *debugfs_create_u8(const c }EXPORT_SYMBOL_GPL (debugfs_create_u8); -static void debugfs_u16_set (void *data,u64 val) +static void debugfs_u16_set (void *data,unsigned long long val) { *(u16 *)data = val; } -static u64 debugfs_u16_get (void *data) +static unsigned long long debugfs_u16_get (void *data) {return *(u16 *)data; }
@@ -138,11 +138,11 @@ struct dentry *debugfs_create_u16(const }EXPORT_SYMBOL_GPL (debugfs_create_u16); -static void debugfs_u32_set (void *data,u64 val) +static void debugfs_u32_set (void *data,unsigned long long val) { *(u32 *)data = val; } -static u64 debugfs_u32_get (void *data) +static unsigned long long debugfs_u32_get (void *data) {return *(u32 *)data; }
@@ -179,12 +179,12 @@ struct dentry *debugfs_create_u32(const }EXPORT_SYMBOL_GPL (debugfs_create_u32); -static void debugfs_u64_set (void *data,u64 val) +static void debugfs_u64_set (void *data,unsigned long long val) { *(u64 *)data = val; } -static u64 debugfs_u64_get (void *data) +static unsigned long long debugfs_u64_get (void *data) {return *(u64 *)data; }
@@ -221,6 +221,172 @@ struct dentry *debugfs_create_u64(const }EXPORT_SYMBOL_GPL (debugfs_create_u64); + +static void debugfs_s8_set (void *data,unsigned long long val) +{ + *(s8 *)data = val; +} +static unsigned long long debugfs_s8_get (void *data) +{ +return *(s8 *)data; +} +DEFINE_SIMPLE_ATTRIBUTE (fops_s8, debugfs_s8_get, debugfs_s8_set,"%lld\n" ); + +/** +* debugfs_create_s8 - create a debugfs file that is used to read and write a signed 8-bit value +* @name: a pointer to a string containing the name of the file to create. +* @mode: the permission that the file should have +* @parent: a pointer to the parent dentry for this file. This should be a +* directory dentry if set. If this parameter is %NULL, then the +* file will be created in the root of the debugfs filesystem. +* @value: a pointer to the variable that the file should read to and write +* from. +* +* This function creates a file in debugfs with the given name that +* contains the value of the variable @value. If the @mode variable is so +* set, it can be read from, and written to. +* +* This function will return a pointer to a dentry if it succeeds. This +* pointer must be passed to the debugfs_remove() function when the file is +* to be removed (no automatic cleanup happens if your module is unloaded, +* you are responsible here.) If an error occurs, %NULL will be returned. +* +* If debugfs is not enabled in the kernel, the value -%ENODEV will be +* returned. It is not wise to check for this value, but rather, check for +* %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling +* code. +*/ +struct dentry *debugfs_create_s8 (const char *name,mode_t mode, +struct dentry *parent,s8 *value) +{ +return debugfs_create_file (name, mode, parent, value, &fops_s8); +} +EXPORT_SYMBOL_GPL (debugfs_create_s8); + +static void debugfs_s16_set (void *data,unsigned long long val) +{ + *(s16 *)data = val; +} +static unsigned long long debugfs_s16_get (void *data) +{ +return *(s16 *)data; +} +DEFINE_SIMPLE_ATTRIBUTE (fops_s16, debugfs_s16_get, debugfs_s16_set,"%lld\n" ); + +/** +* debugfs_create_s16 - create a debugfs file that is used to read and write a signed 16-bit value +* @name: a pointer to a string containing the name of the file to create. +* @mode: the permission that the file should have +* @parent: a pointer to the parent dentry for this file. This should be a +* directory dentry if set. If this parameter is %NULL, then the +* file will be created in the root of the debugfs filesystem. +* @value: a pointer to the variable that the file should read to and write +* from. +* +* This function creates a file in debugfs with the given name that +* contains the value of the variable @value. If the @mode variable is so +* set, it can be read from, and written to. +* +* This function will return a pointer to a dentry if it succeeds. This +* pointer must be passed to the debugfs_remove() function when the file is +* to be removed (no automatic cleanup happens if your module is unloaded, +* you are responsible here.) If an error occurs, %NULL will be returned. +* +* If debugfs is not enabled in the kernel, the value -%ENODEV will be +* returned. It is not wise to check for this value, but rather, check for +* %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling +* code. +*/ +struct dentry *debugfs_create_s16 (const char *name,mode_t mode, +struct dentry *parent,s16 *value) +{ +return debugfs_create_file (name, mode, parent, value, &fops_s16); +} +EXPORT_SYMBOL_GPL (debugfs_create_s16); + +static void debugfs_s32_set (void *data,unsigned long long val) +{ + *(s32 *)data = val; +} +static unsigned long long debugfs_s32_get (void *data) +{ +return *(s32 *)data; +} +DEFINE_SIMPLE_ATTRIBUTE (fops_s32, debugfs_s32_get, debugfs_s32_set,"%lld\n" ); + +/** +* debugfs_create_s32 - create a debugfs file that is used to read and write a signed 32-bit value +* @name: a pointer to a string containing the name of the file to create. +* @mode: the permission that the file should have +* @parent: a pointer to the parent dentry for this file. This should be a +* directory dentry if set. If this parameter is %NULL, then the +* file will be created in the root of the debugfs filesystem. +* @value: a pointer to the variable that the file should read to and write +* from. +* +* This function creates a file in debugfs with the given name that +* contains the value of the variable @value. If the @mode variable is so +* set, it can be read from, and written to. +* +* This function will return a pointer to a dentry if it succeeds. This +* pointer must be passed to the debugfs_remove() function when the file is +* to be removed (no automatic cleanup happens if your module is unloaded, +* you are responsible here.) If an error occurs, %NULL will be returned. +* +* If debugfs is not enabled in the kernel, the value -%ENODEV will be +* returned. It is not wise to check for this value, but rather, check for +* %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling +* code. +*/ +struct dentry *debugfs_create_s32 (const char *name,mode_t mode, +struct dentry *parent,s32 *value) +{ +return debugfs_create_file (name, mode, parent, value, &fops_s32); +} +EXPORT_SYMBOL_GPL (debugfs_create_s32); + +static void debugfs_s64_set (void *data,unsigned long long val) +{ + *(s64 *)data = val; +} + +static unsigned long long debugfs_s64_get (void *data) +{ +return *(s64 *)data; +} +DEFINE_SIMPLE_ATTRIBUTE (fops_s64, debugfs_s64_get, debugfs_s64_set,"%lld\n" ); + +/** +* debugfs_create_s64 - create a debugfs file that is used to read and write a signed 64-bit value +* @name: a pointer to a string containing the name of the file to create. +* @mode: the permission that the file should have +* @parent: a pointer to the parent dentry for this file. This should be a +* directory dentry if set. If this parameter is %NULL, then the +* file will be created in the root of the debugfs filesystem. +* @value: a pointer to the variable that the file should read to and write +* from. +* +* This function creates a file in debugfs with the given name that +* contains the value of the variable @value. If the @mode variable is so +* set, it can be read from, and written to. +* +* This function will return a pointer to a dentry if it succeeds. This +* pointer must be passed to the debugfs_remove() function when the file is +* to be removed (no automatic cleanup happens if your module is unloaded, +* you are responsible here.) If an error occurs, %NULL will be returned. +* +* If debugfs is not enabled in the kernel, the value -%ENODEV will be +* returned. It is not wise to check for this value, but rather, check for +* %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling +* code. +*/ +struct dentry *debugfs_create_s64 (const char *name,mode_t mode, +struct dentry *parent,s64 *value) +{ +return debugfs_create_file (name, mode, parent, value, &fops_s64); +} +EXPORT_SYMBOL_GPL (debugfs_create_s64); +DEFINE_SIMPLE_ATTRIBUTE (fops_x8, debugfs_u8_get, debugfs_u8_set,"0x%02llx\n" );DEFINE_SIMPLE_ATTRIBUTE (fops_x16, debugfs_u16_get, debugfs_u16_set,"0x%04llx\n" );
@@ -291,7 +457,7 @@ static ssize_t read_file_bool(struct fil {char buf[3 ];u32 *val = file->private_data; - +if (*val) buf[0 ] ='Y' ;else
@@ -324,7 +490,7 @@ static ssize_t write_file_bool(struct fi *val =0 ;break ; } - +return count; }
fs/libfs.c +11 -10
@@ -59,7 +59,7 @@ int simple_sync_file(struct file * file, {return 0 ; } - +int dcache_dir_open (struct inode *inode,struct file *file) {static struct qstr cursor_name = {.len =1 , .name ="." };
@@ -160,9 +160,9 @@ int dcache_readdir(struct file * filp, vcontinue ;spin_unlock (&dcache_lock); -if (filldir (dirent, next->d_name.name, - next->d_name.len, filp->f_pos, - next->d_inode->i_ino, +if (filldir (dirent, next->d_name.name, + next->d_name.len, filp->f_pos, + next->d_inode->i_ino,dt_type (next->d_inode)) <0 )return 0 ;spin_lock (&dcache_lock);
@@ -586,9 +586,9 @@ int simple_transaction_release(struct in/* Simple attribute files */ struct simple_attr { -u64 (*get)(void *); -void (*set)(void *,u64 ); -char get_buf[24 ];/* enough to store a u64 and "\n\0" */ +unsigned long long (*get)(void *); +void (*set)(void *,unsigned long long ); +char get_buf[24 ];/* enough to store an ULL and "\n\0" */ char set_buf[24 ];void *data;const char *fmt;/* format for read operation */
@@ -598,7 +598,8 @@ struct simple_attr {/* simple_attr_open is called by an actual attribute open file operation * to set the attribute specific access operations. */ int simple_attr_open (struct inode *inode,struct file *file, -u64 (*get)(void *),void (*set)(void *,u64 ), +unsigned long long (*get)(void *), +void (*set)(void *,unsigned long long ),const char *fmt) {struct simple_attr *attr;
@@ -643,7 +644,7 @@ ssize_t simple_attr_read(struct file *fi else /* first read */ size =scnprintf (attr->get_buf,sizeof (attr->get_buf), attr->fmt, - (unsigned long long )attr->get (attr->data)); + attr->get (attr->data)); ret =simple_read_from_buffer (buf, len, ppos, attr->get_buf, size);mutex_unlock (&attr->mutex);
@@ -655,7 +656,7 @@ ssize_t simple_attr_write(struct file *f size_t len, loff_t *ppos) { struct simple_attr *attr; -u64 val; +unsigned long long val;size_t size;ssize_t ret;
include/linux/debugfs.h +37 -1
@@ -49,6 +49,14 @@ struct dentry *debugfs_create_u32(const struct dentry *parent, u32 *value);struct dentry *debugfs_create_u64 (const char *name,mode_t mode,struct dentry *parent,u64 *value); +struct dentry *debugfs_create_s8 (const char *name,mode_t mode, +struct dentry *parent,s8 *value); +struct dentry *debugfs_create_s16 (const char *name,mode_t mode, +struct dentry *parent,s16 *value); +struct dentry *debugfs_create_s32 (const char *name,mode_t mode, +struct dentry *parent,s32 *value); +struct dentry *debugfs_create_s64 (const char *name,mode_t mode, +struct dentry *parent,s64 *value);struct dentry *debugfs_create_x8 (const char *name,mode_t mode,struct dentry *parent,u8 *value); struct dentry *debugfs_create_x16(const char *name, mode_t mode,
@@ -65,7 +73,7 @@ struct dentry *debugfs_create_blob(const#include <linux/err.h> -/* +/* * We do not return NULL from these functions if CONFIG_DEBUG_FS is not enabled * so users have a chance to detect if there was a real error or not. We don't * want to duplicate the design decision mistakes of procfs and devfs again.
@@ -128,6 +136,34 @@ static inline struct dentry *debugfs_crereturn ERR_PTR (-ENODEV ); } +static inline struct dentry *debugfs_create_s8 (const char *name,mode_t mode, +struct dentry *parent, +u8 *value) +{ +return ERR_PTR (-ENODEV ); +} + +static inline struct dentry *debugfs_create_s16 (const char *name,mode_t mode, +struct dentry *parent, +s16 *value) +{ +return ERR_PTR (-ENODEV ); +} + +static inline struct dentry *debugfs_create_s32 (const char *name,mode_t mode, +struct dentry *parent, +s32 *value) +{ +return ERR_PTR (-ENODEV ); +} + +static inline struct dentry *debugfs_create_s64 (const char *name,mode_t mode, +struct dentry *parent, +s64 *value) +{ +return ERR_PTR (-ENODEV ); +} +static inline struct dentry *debugfs_create_x8 (const char *name,mode_t mode,struct dentry *parent,u8 *value)
arch/powerpc/platforms/cell/spufs/file.c +24 -24
183 lines not on this page · raw message
include/linux/fs.h +13 -12
@@ -15,8 +15,8 @@* nr_file rlimit, so it's safe to set up a ridiculously high absolute * upper limit on files-per-process. * -* Some programs (notably those using select()) may have to be -* recompiled to take full advantage of the new limits.. +* Some programs (notably those using select()) may have to be +* recompiled to take full advantage of the new limits.. */ /* Fixed constants first: */
@@ -90,7 +90,7 @@ extern int dir_notify_enable;#define SEL_EX 4/* public flags for file_system_type */ -#define FS_REQUIRES_DEV 1 +#define FS_REQUIRES_DEV 1#define FS_BINARY_MOUNTDATA 2#define FS_HAS_SUBTYPE 4#define FS_REVAL_DOT 16384/* Check the paths ".", ".." for staleness */
@@ -365,7 +365,7 @@ struct iattr {*/ #include <linux/quota.h> -/** +/** * enum positive_aop_returns - aop return codes with specific semantics * * @AOP_WRITEPAGE_ACTIVATE: Informs the caller that page writeback has
@@ -375,7 +375,7 @@ struct iattr {* be a candidate for writeback again in the near * future. Other callers must be careful to unlock * the page if they get this return. Returned by -* writepage(); +* writepage(); * * @AOP_TRUNCATED_PAGE: The AOP method that was handed a locked page has * unlocked it and the page might have been truncated.
@@ -818,10 +818,10 @@ extern spinlock_t files_lock;#define MAX_NON_LFS ((1UL<<31) - 1) -/* Page cache limit. The filesystems should put that into their s_maxbytes -limits, otherwise bad things can happen in VM. */ +/* Page cache limit. The filesystems should put that into their s_maxbytes +limits, otherwise bad things can happen in VM. */ #if BITS_PER_LONG ==32 -#define MAX_LFS_FILESIZE (((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1) +#define MAX_LFS_FILESIZE (((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1)#elif BITS_PER_LONG ==64 #define MAX_LFS_FILESIZE 0x7fffffffffffffffUL#endif
@@ -1240,7 +1240,7 @@ struct super_operations {void (*destroy_inode)(struct inode *);void (*read_inode) (struct inode *); - +void (*dirty_inode) (struct inode *);int (*write_inode) (struct inode *,int );void (*put_inode) (struct inode *);
@@ -1719,7 +1719,7 @@ extern int may_open(struct nameidata *,extern int kernel_read (struct file *,unsigned long ,char *,unsigned long );extern struct file *open_exec (const char *); - +/* fs/dcache.c -- generic fs support functions */ extern int is_subdir (struct dentry *,struct dentry *);extern ino_t find_inode_number (struct dentry *,struct qstr *);
@@ -1753,7 +1753,7 @@ extern void unlock_new_inode(struct inodstatic inline struct inode *iget (struct super_block *sb,unsigned long ino) {struct inode *inode =iget_locked (sb, ino); - +if (inode && (inode->i_state &I_NEW )) { sb->s_op->read_inode (inode);unlock_new_inode (inode);
@@ -2062,7 +2062,8 @@ __simple_attr_check_format(const char *f }int simple_attr_open (struct inode *inode,struct file *file, -u64 (*get)(void *),void (*set)(void *,u64 ), +unsigned long long (*get)(void *), +void (*set)(void *,unsigned long long ),const char *fmt);int simple_attr_close (struct inode *inode,struct file *file); ssize_t simple_attr_read(struct file *file, char __user *buf,
lib/fault-inject.c +6 -5
@@ -134,13 +134,14 @@ bool should_fail(struct fault_attr *attr #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS -static void debugfs_ul_set(void *data, u64 val) +static void debugfs_ul_set(void *data, unsigned long long val) { *(unsigned long *)data = val; } #ifdef CONFIG_FAULT_INJECTION_STACKTRACE_FILTER -static void debugfs_ul_set_MAX_STACK_TRACE_DEPTH(void *data, u64 val) +static void debugfs_ul_set_MAX_STACK_TRACE_DEPTH(void *data, + unsigned long long val) { *(unsigned long *)data = val < MAX_STACK_TRACE_DEPTH ?
@@ -148,7 +149,7 @@ static void debugfs_ul_set_MAX_STACK_TRA }#endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */ -static u64 debugfs_ul_get (void *data) +static unsigned long long debugfs_ul_get (void *data) {return *(unsigned long *)data; }
@@ -174,12 +175,12 @@ static struct dentry *debugfs_create_ul_ }#endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */ -static void debugfs_atomic_t_set (void *data,u64 val) +static void debugfs_atomic_t_set (void *data,unsigned long long val) {atomic_set ((atomic_t *)data, val); } -static u64 debugfs_atomic_t_get (void *data) +static unsigned long long debugfs_atomic_t_get (void *data) {return atomic_read ((atomic_t *)data); }
Signature · 2 lines
Ciao Stefano
Re: [PATCH v5 7/8] debugfs: allow access to signed values
Quoted 5 lines · Stefano Brivio
debugfs: allow access to signed values
Add debugfs_create_s{8,16,32,64}. For these to work properly, we need to remove a cast in libfs, change the
simple_attr_openprototype and thus fix the users as well.
Looks like Stefano is going to cooperate w/ hch on this, so I'm dropping this from wireless-2.6 for now...FYI
John
Signature · 2 lines
John W. Linville [email protected]
PATCH v3 8/8 rc80211-pid: export tuning parameters through debugfs
In reply to a message not in the archiveFrom: Mattias Nissler <[email protected]>
This adds all the tunable parameters used by rc80211_pid to debugfs for easy testing and tuning.
--- rc80211_pid.h | 23 ++++++++++- rc80211_pid_algo.c | 106 +++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 107 insertions(+), 22 deletions(-)
net/mac80211/rc80211_pid_algo.c +86 -20
@@ -139,19 +139,20 @@ static void rate_control_pid_adjust_rate }/* Normalize the failed frames per-rate differences. */ -static void rate_control_pid_normalize (struct rc_pid_rateinfo *r,int l) +static void rate_control_pid_normalize (struct rc_pid_info *pinfo,int l) { -int i; +int i, norm_offset = pinfo->norm_offset; +struct rc_pid_rateinfo *r = pinfo->rinfo; -if (r[0 ].diff >RC_PID_NORM_OFFSET ) - r[0 ].diff -=RC_PID_NORM_OFFSET ; -else if (r[0 ].diff < -RC_PID_NORM_OFFSET ) - r[0 ].diff +=RC_PID_NORM_OFFSET ; +if (r[0 ].diff > norm_offset) + r[0 ].diff -= norm_offset; +else if (r[0 ].diff < -norm_offset) + r[0 ].diff += norm_offset;for (i =0 ; i < l -1 ; i++) -if (r[i +1 ].diff > r[i].diff +RC_PID_NORM_OFFSET ) - r[i +1 ].diff -=RC_PID_NORM_OFFSET ; +if (r[i +1 ].diff > r[i].diff + norm_offset) + r[i +1 ].diff -= norm_offset;else if (r[i +1 ].diff <= r[i].diff) - r[i +1 ].diff +=RC_PID_NORM_OFFSET ; + r[i +1 ].diff += norm_offset; } static void rate_control_pid_sample(struct rc_pid_info *pinfo,
@@ -167,14 +168,18 @@ static void rate_control_pid_sample(strus32 err_int;s32 err_der;int adj, i, j, tmp; +unsigned long period; mode = local->oper_hw_mode; spinfo = sta->rate_ctrl_priv;/* In case nothing happened during the previous control interval, turn * the sharpening factor on. */ -if (jiffies - spinfo->last_sample >2 *RC_PID_INTERVAL ) - spinfo->sharp_cnt =RC_PID_SHARPENING_DURATION ; + period = (HZ * pinfo->sampling_period +500 ) /1000 ; +if (!period) + period =1 ; +if (jiffies - spinfo->last_sample >2 * period) + spinfo->sharp_cnt = pinfo->sharpen_duration; spinfo->last_sample = jiffies;
@@ -202,17 +207,17 @@ static void rate_control_pid_sample(stru rinfo[j].diff = rinfo[i].diff + tmp; pinfo->oldrate = sta->txrate; } -rate_control_pid_normalize (rinfo, mode->num_rates); +rate_control_pid_normalize (pinfo, mode->num_rates);/* Compute the proportional, integral and derivative errors. */ - err_prop =RC_PID_TARGET_PF - pf; + err_prop = pinfo->target - pf; - err_avg = spinfo->err_avg_sc >>RC_PID_SMOOTHING_SHIFT ; + err_avg = spinfo->err_avg_sc >> pinfo->smoothing_shift; spinfo->err_avg_sc = spinfo->err_avg_sc - err_avg + err_prop; - err_int = spinfo->err_avg_sc >>RC_PID_SMOOTHING_SHIFT ; + err_int = spinfo->err_avg_sc >> pinfo->smoothing_shift; - err_der = pf - spinfo->last_pf - * (1 +RC_PID_SHARPENING_FACTOR * spinfo->sharp_cnt); + err_der = (pf - spinfo->last_pf) * + (1 + pinfo->sharpen_factor * spinfo->sharp_cnt); spinfo->last_pf = pf;if (spinfo->sharp_cnt) spinfo->sharp_cnt--;
@@ -241,6 +246,7 @@ static void rate_control_pid_tx_status(vstruct rc_pid_info *pinfo = priv;struct sta_info *sta;struct rc_pid_sta_info *spinfo; +unsigned long period; sta =sta_info_get (local, hdr->addr1);
@@ -285,7 +291,10 @@ static void rate_control_pid_tx_status(v sta->tx_num_mpdu_fail += status->retry_count;/* Update PID controller state. */ -if (time_after (jiffies, spinfo->last_sample +RC_PID_INTERVAL )) + period = (HZ * pinfo->sampling_period +500 ) /1000 ; +if (!period) + period =1 ; +if (time_after (jiffies, spinfo->last_sample + period))rate_control_pid_sample (pinfo, local, sta);sta_info_put (sta);
@@ -343,6 +352,9 @@ static void *rate_control_pid_alloc(strustruct ieee80211_hw_mode *mode;int i, j, tmp;bool s; +#ifdef CONFIG_MAC80211_DEBUGFS +struct rc_pid_debugfs_entries *de; +#endif pinfo =kmalloc (sizeof (*pinfo),GFP_ATOMIC );if (!pinfo)
@@ -363,10 +375,10 @@ static void *rate_control_pid_alloc(strufor (i =0 ; i < mode->num_rates; i++) { rinfo[i].index = i; rinfo[i].rev_index = i; -if (RC_PID_FAST_START ) +if (pinfo->fast_start) rinfo[i].diff =0 ;else - rinfo[i].diff = i *RC_PID_NORM_OFFSET ; + rinfo[i].diff = i * pinfo->norm_offset; }for (i =1 ; i < mode->num_rates; i++) { s =0 ;
@@ -385,18 +397,72 @@ static void *rate_control_pid_alloc(stru } pinfo->target =RC_PID_TARGET_PF ; + pinfo->sampling_period =RC_PID_INTERVAL ; pinfo->coeff_p =RC_PID_COEFF_P ; pinfo->coeff_i =RC_PID_COEFF_I ; pinfo->coeff_d =RC_PID_COEFF_D ; + pinfo->smoothing_shift =RC_PID_SMOOTHING_SHIFT ; + pinfo->sharpen_factor =RC_PID_SHARPENING_FACTOR ; + pinfo->sharpen_duration =RC_PID_SHARPENING_DURATION ; + pinfo->norm_offset =RC_PID_NORM_OFFSET ; + pinfo->fast_start =RC_PID_FAST_START ; pinfo->rinfo = rinfo; pinfo->oldrate =0 ; +#ifdef CONFIG_MAC80211_DEBUGFS + de = &pinfo->dentries; + de->dir =debugfs_create_dir ("rc80211_pid" , + local->hw.wiphy->debugfsdir); + de->target =debugfs_create_u32 ("target_pf" ,S_IRUSR |S_IWUSR , + de->dir, &pinfo->target); + de->sampling_period =debugfs_create_u32 ("sampling_period" , +S_IRUSR |S_IWUSR , de->dir, + &pinfo->sampling_period); + de->coeff_p =debugfs_create_s32 ("coeff_p" ,S_IRUSR |S_IWUSR , + de->dir, &pinfo->coeff_p); + de->coeff_i =debugfs_create_s32 ("coeff_i" ,S_IRUSR |S_IWUSR , + de->dir, &pinfo->coeff_i); + de->coeff_d =debugfs_create_s32 ("coeff_d" ,S_IRUSR |S_IWUSR , + de->dir, &pinfo->coeff_d); + de->smoothing_shift =debugfs_create_u32 ("smoothing_shift" , +S_IRUSR |S_IWUSR , de->dir, + &pinfo->smoothing_shift); + de->sharpen_factor =debugfs_create_u32 ("sharpen_factor" , +S_IRUSR |S_IWUSR , de->dir, + &pinfo->sharpen_factor); + de->sharpen_duration =debugfs_create_u32 ("sharpen_duration" , +S_IRUSR |S_IWUSR , de->dir, + &pinfo->sharpen_duration); + de->norm_offset =debugfs_create_u32 ("norm_offset" , +S_IRUSR |S_IWUSR , de->dir, + &pinfo->norm_offset); + de->fast_start =debugfs_create_bool ("fast_start" , +S_IRUSR |S_IWUSR , de->dir, + &pinfo->fast_start); +#endif +return pinfo; }static void rate_control_pid_free (void *priv) {struct rc_pid_info *pinfo = priv; +#ifdef CONFIG_MAC80211_DEBUGFS +struct rc_pid_debugfs_entries *de = &pinfo->dentries; + +debugfs_remove (de->fast_start); +debugfs_remove (de->norm_offset); +debugfs_remove (de->sharpen_duration); +debugfs_remove (de->sharpen_factor); +debugfs_remove (de->smoothing_shift); +debugfs_remove (de->coeff_d); +debugfs_remove (de->coeff_i); +debugfs_remove (de->coeff_p); +debugfs_remove (de->sampling_period); +debugfs_remove (de->target); +debugfs_remove (de->dir); +#endif +kfree (pinfo->rinfo);kfree (pinfo); }
net/mac80211/rc80211_pid.h +21 -2
@@ -119,6 +119,20 @@ struct rc_pid_events_file_info {unsigned int next_entry; }; +struct rc_pid_debugfs_entries { +struct dentry *dir; +struct dentry *target; +struct dentry *sampling_period; +struct dentry *coeff_p; +struct dentry *coeff_i; +struct dentry *coeff_d; +struct dentry *smoothing_shift; +struct dentry *sharpen_factor; +struct dentry *sharpen_duration; +struct dentry *norm_offset; +struct dentry *fast_start; +}; +void rate_control_pid_event_tx_status (struct rc_pid_event_buffer *buf,struct ieee80211_tx_status *stat);
@@ -222,8 +236,8 @@ struct rc_pid_info {/* Exponential averaging shift. */ unsigned int smoothing_shift; -/* Sharpening shift and duration. */ -unsigned int sharpen_shift; +/* Sharpening factor and duration. */ +unsigned int sharpen_factor;unsigned int sharpen_duration;/* Normalization offset. */
@@ -237,6 +251,11 @@ struct rc_pid_info {/* Index of the last used rate. */ int oldrate; + +#ifdef CONFIG_MAC80211_DEBUGFS +/* Debugfs entries created for the parameters above. */ +struct rc_pid_debugfs_entries dentries; +#endif };#endif /* RC80211_PID_H */
Signature · 2 lines
Ciao Stefano
Johannes Berg
maintainerRe: [PATCH v3 8/8] rc80211-pid: export tuning parameters through debugfs
Ok, I already commented on patch 4 and just on patch 1 as well, other than that the series looks fine. I haven't really done a detailed review of the new code though, you get to be blamed if it breaks.
johannes
PATCH v4 8/8 rc80211-pid: export tuning parameters through debugfs
In reply to Stefano BrivioFrom: Mattias Nissler <[email protected]>
This adds all the tunable parameters used by rc80211_pid to debugfs for easy testing and tuning.
---
John,
this is an amended version of patch v3 8/8 which doesn't rely on patch 7/8, so that there are more chances that this makes into 2.6.25.
--- rc80211_pid.h | 23 +++++++++- rc80211_pid_algo.c | 112 ++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 110 insertions(+), 25 deletions(-)
net/mac80211/rc80211_pid_algo.c +89 -23
@@ -139,19 +139,20 @@ static void rate_control_pid_adjust_rate }/* Normalize the failed frames per-rate differences. */ -static void rate_control_pid_normalize (struct rc_pid_rateinfo *r,int l) +static void rate_control_pid_normalize (struct rc_pid_info *pinfo,int l) { -int i; +int i, norm_offset = pinfo->norm_offset; +struct rc_pid_rateinfo *r = pinfo->rinfo; -if (r[0 ].diff >RC_PID_NORM_OFFSET ) - r[0 ].diff -=RC_PID_NORM_OFFSET ; -else if (r[0 ].diff < -RC_PID_NORM_OFFSET ) - r[0 ].diff +=RC_PID_NORM_OFFSET ; +if (r[0 ].diff > norm_offset) + r[0 ].diff -= norm_offset; +else if (r[0 ].diff < -norm_offset) + r[0 ].diff += norm_offset;for (i =0 ; i < l -1 ; i++) -if (r[i +1 ].diff > r[i].diff +RC_PID_NORM_OFFSET ) - r[i +1 ].diff -=RC_PID_NORM_OFFSET ; +if (r[i +1 ].diff > r[i].diff + norm_offset) + r[i +1 ].diff -= norm_offset;else if (r[i +1 ].diff <= r[i].diff) - r[i +1 ].diff +=RC_PID_NORM_OFFSET ; + r[i +1 ].diff += norm_offset; } static void rate_control_pid_sample(struct rc_pid_info *pinfo,
@@ -163,18 +164,22 @@ static void rate_control_pid_sample(strustruct ieee80211_hw_mode *mode;u32 pf;s32 err_avg; -s32 err_prop; -s32 err_int; -s32 err_der; +u32 err_prop; +u32 err_int; +u32 err_der;int adj, i, j, tmp; +unsigned long period; mode = local->oper_hw_mode; spinfo = sta->rate_ctrl_priv;/* In case nothing happened during the previous control interval, turn * the sharpening factor on. */ -if (jiffies - spinfo->last_sample >2 *RC_PID_INTERVAL ) - spinfo->sharp_cnt =RC_PID_SHARPENING_DURATION ; + period = (HZ * pinfo->sampling_period +500 ) /1000 ; +if (!period) + period =1 ; +if (jiffies - spinfo->last_sample >2 * period) + spinfo->sharp_cnt = pinfo->sharpen_duration; spinfo->last_sample = jiffies;
@@ -202,17 +207,17 @@ static void rate_control_pid_sample(stru rinfo[j].diff = rinfo[i].diff + tmp; pinfo->oldrate = sta->txrate; } -rate_control_pid_normalize (rinfo, mode->num_rates); +rate_control_pid_normalize (pinfo, mode->num_rates);/* Compute the proportional, integral and derivative errors. */ - err_prop =RC_PID_TARGET_PF - pf; + err_prop = pinfo->target - pf; - err_avg = spinfo->err_avg_sc >>RC_PID_SMOOTHING_SHIFT ; + err_avg = spinfo->err_avg_sc >> pinfo->smoothing_shift; spinfo->err_avg_sc = spinfo->err_avg_sc - err_avg + err_prop; - err_int = spinfo->err_avg_sc >>RC_PID_SMOOTHING_SHIFT ; + err_int = spinfo->err_avg_sc >> pinfo->smoothing_shift; - err_der = pf - spinfo->last_pf - * (1 +RC_PID_SHARPENING_FACTOR * spinfo->sharp_cnt); + err_der = (pf - spinfo->last_pf) * + (1 + pinfo->sharpen_factor * spinfo->sharp_cnt); spinfo->last_pf = pf;if (spinfo->sharp_cnt) spinfo->sharp_cnt--;
@@ -241,6 +246,7 @@ static void rate_control_pid_tx_status(vstruct rc_pid_info *pinfo = priv;struct sta_info *sta;struct rc_pid_sta_info *spinfo; +unsigned long period; sta =sta_info_get (local, hdr->addr1);
@@ -285,7 +291,10 @@ static void rate_control_pid_tx_status(v sta->tx_num_mpdu_fail += status->retry_count;/* Update PID controller state. */ -if (time_after (jiffies, spinfo->last_sample +RC_PID_INTERVAL )) + period = (HZ * pinfo->sampling_period +500 ) /1000 ; +if (!period) + period =1 ; +if (time_after (jiffies, spinfo->last_sample + period))rate_control_pid_sample (pinfo, local, sta);sta_info_put (sta);
@@ -343,6 +352,9 @@ static void *rate_control_pid_alloc(strustruct ieee80211_hw_mode *mode;int i, j, tmp;bool s; +#ifdef CONFIG_MAC80211_DEBUGFS +struct rc_pid_debugfs_entries *de; +#endif pinfo =kmalloc (sizeof (*pinfo),GFP_ATOMIC );if (!pinfo)
@@ -363,10 +375,10 @@ static void *rate_control_pid_alloc(strufor (i =0 ; i < mode->num_rates; i++) { rinfo[i].index = i; rinfo[i].rev_index = i; -if (RC_PID_FAST_START ) +if (pinfo->fast_start) rinfo[i].diff =0 ;else - rinfo[i].diff = i *RC_PID_NORM_OFFSET ; + rinfo[i].diff = i * pinfo->norm_offset; }for (i =1 ; i < mode->num_rates; i++) { s =0 ;
@@ -385,18 +397,72 @@ static void *rate_control_pid_alloc(stru } pinfo->target =RC_PID_TARGET_PF ; + pinfo->sampling_period =RC_PID_INTERVAL ; pinfo->coeff_p =RC_PID_COEFF_P ; pinfo->coeff_i =RC_PID_COEFF_I ; pinfo->coeff_d =RC_PID_COEFF_D ; + pinfo->smoothing_shift =RC_PID_SMOOTHING_SHIFT ; + pinfo->sharpen_factor =RC_PID_SHARPENING_FACTOR ; + pinfo->sharpen_duration =RC_PID_SHARPENING_DURATION ; + pinfo->norm_offset =RC_PID_NORM_OFFSET ; + pinfo->fast_start =RC_PID_FAST_START ; pinfo->rinfo = rinfo; pinfo->oldrate =0 ; +#ifdef CONFIG_MAC80211_DEBUGFS + de = &pinfo->dentries; + de->dir =debugfs_create_dir ("rc80211_pid" , + local->hw.wiphy->debugfsdir); + de->target =debugfs_create_u32 ("target_pf" ,S_IRUSR |S_IWUSR , + de->dir, &pinfo->target); + de->sampling_period =debugfs_create_u32 ("sampling_period" , +S_IRUSR |S_IWUSR , de->dir, + &pinfo->sampling_period); + de->coeff_p =debugfs_create_u32 ("coeff_p" ,S_IRUSR |S_IWUSR , + de->dir, &pinfo->coeff_p); + de->coeff_i =debugfs_create_u32 ("coeff_i" ,S_IRUSR |S_IWUSR , + de->dir, &pinfo->coeff_i); + de->coeff_d =debugfs_create_u32 ("coeff_d" ,S_IRUSR |S_IWUSR , + de->dir, &pinfo->coeff_d); + de->smoothing_shift =debugfs_create_u32 ("smoothing_shift" , +S_IRUSR |S_IWUSR , de->dir, + &pinfo->smoothing_shift); + de->sharpen_factor =debugfs_create_u32 ("sharpen_factor" , +S_IRUSR |S_IWUSR , de->dir, + &pinfo->sharpen_factor); + de->sharpen_duration =debugfs_create_u32 ("sharpen_duration" , +S_IRUSR |S_IWUSR , de->dir, + &pinfo->sharpen_duration); + de->norm_offset =debugfs_create_u32 ("norm_offset" , +S_IRUSR |S_IWUSR , de->dir, + &pinfo->norm_offset); + de->fast_start =debugfs_create_bool ("fast_start" , +S_IRUSR |S_IWUSR , de->dir, + &pinfo->fast_start); +#endif +return pinfo; }static void rate_control_pid_free (void *priv) {struct rc_pid_info *pinfo = priv; +#ifdef CONFIG_MAC80211_DEBUGFS +struct rc_pid_debugfs_entries *de = &pinfo->dentries; + +debugfs_remove (de->fast_start); +debugfs_remove (de->norm_offset); +debugfs_remove (de->sharpen_duration); +debugfs_remove (de->sharpen_factor); +debugfs_remove (de->smoothing_shift); +debugfs_remove (de->coeff_d); +debugfs_remove (de->coeff_i); +debugfs_remove (de->coeff_p); +debugfs_remove (de->sampling_period); +debugfs_remove (de->target); +debugfs_remove (de->dir); +#endif +kfree (pinfo->rinfo);kfree (pinfo); }
net/mac80211/rc80211_pid.h +21 -2
@@ -119,6 +119,20 @@ struct rc_pid_events_file_info {unsigned int next_entry; }; +struct rc_pid_debugfs_entries { +struct dentry *dir; +struct dentry *target; +struct dentry *sampling_period; +struct dentry *coeff_p; +struct dentry *coeff_i; +struct dentry *coeff_d; +struct dentry *smoothing_shift; +struct dentry *sharpen_factor; +struct dentry *sharpen_duration; +struct dentry *norm_offset; +struct dentry *fast_start; +}; +void rate_control_pid_event_tx_status (struct rc_pid_event_buffer *buf,struct ieee80211_tx_status *stat);
@@ -222,8 +236,8 @@ struct rc_pid_info {/* Exponential averaging shift. */ unsigned int smoothing_shift; -/* Sharpening shift and duration. */ -unsigned int sharpen_shift; +/* Sharpening factor and duration. */ +unsigned int sharpen_factor;unsigned int sharpen_duration;/* Normalization offset. */
@@ -237,6 +251,11 @@ struct rc_pid_info {/* Index of the last used rate. */ int oldrate; + +#ifdef CONFIG_MAC80211_DEBUGFS +/* Debugfs entries created for the parameters above. */ +struct rc_pid_debugfs_entries dentries; +#endif };#endif /* RC80211_PID_H */
Signature · 2 lines
Ciao Stefano