Skip to contentSkip to conversation

mac80211: clean up rate selection

PATCH Superseded Stefano Brivio 6 participants 24 messages Dec 19, 2007 – Dec 29, 2007 1 message not in the archive

Subsystems (10)
lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

#1 lore raw

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
Index: wireless-2.6/net/mac80211/ieee80211.c
===================================================================
@@ -860,10 +860,8 @@ void ieee80211_tx_status(struct ieee8021
 			sta_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
Index: wireless-2.6/net/mac80211/ieee80211_sta.c
===================================================================
@@ -2467,9 +2467,8 @@ static int ieee80211_sta_join_ibss(struc
 	struct 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
maintainer
#2 lore raw
Quoted 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

#3 lore raw

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
Index: wireless-2.6/net/mac80211/ieee80211.c
===================================================================
@@ -860,10 +860,8 @@ void ieee80211_tx_status(struct ieee8021
 			sta_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
Index: wireless-2.6/net/mac80211/ieee80211_sta.c
===================================================================
@@ -2467,9 +2467,8 @@ static int ieee80211_sta_join_ibss(struc
 	struct 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
#4 lore raw

PATCH v3 2/8 mac80211: add PID controller based rate control algorithm

In reply to a message not in the archive

From: 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
Index: wireless-2.6/net/mac80211/Kconfig
===================================================================
@@ -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
Index: wireless-2.6/net/mac80211/Makefile
===================================================================
@@ -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
Index: wireless-2.6/net/mac80211/ieee80211.c
===================================================================
@@ -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
Index: wireless-2.6/net/mac80211/ieee80211_rate.h
===================================================================
@@ -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
#5 lore raw

PATCH v3 3/8 mac80211: make PID rate control algorithm the default

In reply to a message not in the archive

This 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
Index: wireless-2.6/net/mac80211/Kconfig
===================================================================
@@ -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
Index: wireless-2.6/net/mac80211/Makefile
===================================================================
@@ -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
Index: wireless-2.6/net/mac80211/ieee80211.c
===================================================================
@@ -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
Index: wireless-2.6/net/mac80211/ieee80211_rate.c
===================================================================
@@ -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 cha
 	struct 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
Index: wireless-2.6/net/mac80211/ieee80211_rate.h
===================================================================
@@ -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
Index: wireless-2.6/Documentation/feature-removal-schedule.txt
===================================================================
@@ -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
#6 lore raw

PATCH v3 4/8 rc80211-pid: add rate behaviour learning algorithm

In reply to a message not in the archive

This 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
Index: wireless-2.6/net/mac80211/rc80211_pid.c
===================================================================
@@ -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(v
 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;
 }
@@ -330,6 +470,7 @@ static void *rate_control_pid_alloc(stru
 static void rate_control_pid_free(void *priv)
 {
 	struct rc_pid_info *pinfo = priv;
+	kfree(pinfo->rinfo);
 	kfree(pinfo);
 }
 
Signature · 2 lines
Ciao
Stefano
#7 lore raw

PATCH v3 5/8 rc80211-pid: add sharpening factor

In reply to a message not in the archive

This 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
Index: wireless-2.6/net/mac80211/rc80211_pid.c
===================================================================
@@ -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
#8 lore raw

PATCH v3 6/8 rc80211-pid: add debugging

In reply to a message not in the archive

From: 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
Index: wireless-2.6/net/mac80211/rc80211_pid.c
===================================================================
@@ -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
Index: wireless-2.6/net/mac80211/Makefile
===================================================================
@@ -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
#9 lore raw

PATCH v3 7/8 debugfs: allow access to signed values

In reply to a message not in the archive

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]>

---
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
Index: wireless-2.6/fs/debugfs/file.c
===================================================================
@@ -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
Index: wireless-2.6/fs/libfs.c
===================================================================
@@ -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
Index: wireless-2.6/include/linux/debugfs.h
===================================================================
@@ -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_cre
 	return 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
#10 lore raw

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

---
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

#11 lore raw

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]>

---
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:

to the patch.

Thanks. I'm going to resend the patch to John with your Signed-off-by -- in case.

--
Ciao
Stefano

#12 lore raw

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]
#13 lore raw

PATCH v4 7/8 debugfs: allow access to signed values

In reply to Stefano Brivio

Add 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
Index: wireless-2.6/fs/debugfs/file.c
===================================================================
@@ -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
Index: wireless-2.6/fs/libfs.c
===================================================================
@@ -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
Index: wireless-2.6/include/linux/debugfs.h
===================================================================
@@ -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_cre
 	return 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
maintainer
#14 lore raw

Re: [PATCH v3 7/8] debugfs: allow access to signed values

In reply to Stefano Brivio

fs/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

#15 lore raw

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
Index: wireless-2.6/fs/debugfs/file.c
===================================================================
@@ -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
Index: wireless-2.6/fs/libfs.c
===================================================================
@@ -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, v
 					continue;
 
 				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
Index: wireless-2.6/include/linux/debugfs.h
===================================================================
@@ -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_cre
 	return 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
Index: wireless-2.6/include/linux/fs.h
===================================================================
@@ -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 inod
 static 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
Index: wireless-2.6/lib/fault-inject.c
===================================================================
@@ -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
#16 lore raw

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_open prototype 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]>

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 <><
#17 lore raw

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=14962

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.

maintainer
#18 lore raw

Re: [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

#19 lore raw

Re: [PATCH v4 7/8] debugfs: allow access to signed values

In reply to Christoph Hellwig
Quoted 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
#20 lore raw

PATCH v5 7/8 debugfs: allow access to signed values

In reply to Johannes Berg

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. 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
Index: wireless-2.6/fs/debugfs/file.c
===================================================================
@@ -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
Index: wireless-2.6/fs/libfs.c
===================================================================
@@ -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, v
 					continue;
 
 				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
Index: wireless-2.6/include/linux/debugfs.h
===================================================================
@@ -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_cre
 	return 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
Index: wireless-2.6/include/linux/fs.h
===================================================================
@@ -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 inod
 static 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
Index: wireless-2.6/lib/fault-inject.c
===================================================================
@@ -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
#21 lore raw

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_open prototype 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]
#22 lore raw

PATCH v3 8/8 rc80211-pid: export tuning parameters through debugfs

In reply to a message not in the archive

From: 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
Index: wireless-2.6/net/mac80211/rc80211_pid_algo.c
===================================================================
@@ -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(stru
 	s32 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(v
 	struct 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(stru
 	struct 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(stru
 	for (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
Index: wireless-2.6/net/mac80211/rc80211_pid.h
===================================================================
@@ -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
maintainer
#23 lore raw

Re: [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

#24 lore raw

PATCH v4 8/8 rc80211-pid: export tuning parameters through debugfs

In reply to Stefano Brivio

From: 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
Index: wireless-2.6/net/mac80211/rc80211_pid_algo.c
===================================================================
@@ -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(stru
 	struct 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(v
 	struct 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(stru
 	struct 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(stru
 	for (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
Index: wireless-2.6/net/mac80211/rc80211_pid.h
===================================================================
@@ -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