aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/Makefile11
-rw-r--r--net/mac80211/rc80211_pid.h242
-rw-r--r--net/mac80211/rc80211_pid_algo.c (renamed from net/mac80211/rc80211_pid.c)149
-rw-r--r--net/mac80211/rc80211_pid_debugfs.c223
4 files changed, 508 insertions, 117 deletions
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index a375f0477da0..06aea8009cd4 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -1,10 +1,17 @@
1obj-$(CONFIG_MAC80211) += mac80211.o 1obj-$(CONFIG_MAC80211) += mac80211.o
2 2
3mac80211-objs-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o 3mac80211-objs-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o
4mac80211-objs-$(CONFIG_MAC80211_DEBUGFS) += debugfs.o debugfs_sta.o debugfs_netdev.o debugfs_key.o
5mac80211-objs-$(CONFIG_NET_SCHED) += wme.o 4mac80211-objs-$(CONFIG_NET_SCHED) += wme.o
6mac80211-objs-$(CONFIG_MAC80211_RC_SIMPLE) += rc80211_simple.o 5mac80211-objs-$(CONFIG_MAC80211_RC_SIMPLE) += rc80211_simple.o
7mac80211-objs-$(CONFIG_MAC80211_RC_PID) += rc80211_pid.o 6mac80211-objs-$(CONFIG_MAC80211_RC_PID) += rc80211_pid_algo.o
7
8mac80211-debugfs-objs-$(CONFIG_MAC80211_RC_PID) += rc80211_pid_debugfs.o
9mac80211-objs-$(CONFIG_MAC80211_DEBUGFS) += \
10 debugfs.o \
11 debugfs_sta.o \
12 debugfs_netdev.o \
13 debugfs_key.o \
14 $(mac80211-debugfs-objs-y)
8 15
9mac80211-objs := \ 16mac80211-objs := \
10 ieee80211.o \ 17 ieee80211.o \
diff --git a/net/mac80211/rc80211_pid.h b/net/mac80211/rc80211_pid.h
new file mode 100644
index 000000000000..5d0056c1513b
--- /dev/null
+++ b/net/mac80211/rc80211_pid.h
@@ -0,0 +1,242 @@
1/*
2 * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef RC80211_PID_H
10#define RC80211_PID_H
11
12/* Sampling period for measuring percentage of failed frames. */
13#define RC_PID_INTERVAL (HZ / 8)
14
15/* Exponential averaging smoothness (used for I part of PID controller) */
16#define RC_PID_SMOOTHING_SHIFT 3
17#define RC_PID_SMOOTHING (1 << RC_PID_SMOOTHING_SHIFT)
18
19/* Sharpening factor (used for D part of PID controller) */
20#define RC_PID_SHARPENING_FACTOR 0
21#define RC_PID_SHARPENING_DURATION 0
22
23/* Fixed point arithmetic shifting amount. */
24#define RC_PID_ARITH_SHIFT 8
25
26/* Fixed point arithmetic factor. */
27#define RC_PID_ARITH_FACTOR (1 << RC_PID_ARITH_SHIFT)
28
29/* Proportional PID component coefficient. */
30#define RC_PID_COEFF_P 15
31/* Integral PID component coefficient. */
32#define RC_PID_COEFF_I 9
33/* Derivative PID component coefficient. */
34#define RC_PID_COEFF_D 15
35
36/* Target failed frames rate for the PID controller. NB: This effectively gives
37 * maximum failed frames percentage we're willing to accept. If the wireless
38 * link quality is good, the controller will fail to adjust failed frames
39 * percentage to the target. This is intentional.
40 */
41#define RC_PID_TARGET_PF (11 << RC_PID_ARITH_SHIFT)
42
43/* Rate behaviour normalization quantity over time. */
44#define RC_PID_NORM_OFFSET 3
45
46/* Push high rates right after loading. */
47#define RC_PID_FAST_START 0
48
49/* Arithmetic right shift for positive and negative values for ISO C. */
50#define RC_PID_DO_ARITH_RIGHT_SHIFT(x, y) \
51 (x) < 0 ? -((-(x)) >> (y)) : (x) >> (y)
52
53enum rc_pid_event_type {
54 RC_PID_EVENT_TYPE_TX_STATUS,
55 RC_PID_EVENT_TYPE_RATE_CHANGE,
56 RC_PID_EVENT_TYPE_TX_RATE,
57 RC_PID_EVENT_TYPE_PF_SAMPLE,
58};
59
60union rc_pid_event_data {
61 /* RC_PID_EVENT_TX_STATUS */
62 struct {
63 struct ieee80211_tx_status tx_status;
64 };
65 /* RC_PID_EVENT_TYPE_RATE_CHANGE */
66 /* RC_PID_EVENT_TYPE_TX_RATE */
67 struct {
68 int index;
69 int rate;
70 };
71 /* RC_PID_EVENT_TYPE_PF_SAMPLE */
72 struct {
73 s32 pf_sample;
74 s32 prop_err;
75 s32 int_err;
76 s32 der_err;
77 };
78};
79
80struct rc_pid_event {
81 /* The time when the event occured */
82 unsigned long timestamp;
83
84 /* Event ID number */
85 unsigned int id;
86
87 /* Type of event */
88 enum rc_pid_event_type type;
89
90 /* type specific data */
91 union rc_pid_event_data data;
92};
93
94/* Size of the event ring buffer. */
95#define RC_PID_EVENT_RING_SIZE 32
96
97struct rc_pid_event_buffer {
98 /* Counter that generates event IDs */
99 unsigned int ev_count;
100
101 /* Ring buffer of events */
102 struct rc_pid_event ring[RC_PID_EVENT_RING_SIZE];
103
104 /* Index to the entry in events_buf to be reused */
105 unsigned int next_entry;
106
107 /* Lock that guards against concurrent access to this buffer struct */
108 spinlock_t lock;
109
110 /* Wait queue for poll/select and blocking I/O */
111 wait_queue_head_t waitqueue;
112};
113
114struct rc_pid_events_file_info {
115 /* The event buffer we read */
116 struct rc_pid_event_buffer *events;
117
118 /* The entry we have should read next */
119 unsigned int next_entry;
120};
121
122void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf,
123 struct ieee80211_tx_status *stat);
124
125void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf,
126 int index, int rate);
127
128void rate_control_pid_event_tx_rate(struct rc_pid_event_buffer *buf,
129 int index, int rate);
130
131void rate_control_pid_event_pf_sample(struct rc_pid_event_buffer *buf,
132 s32 pf_sample, s32 prop_err,
133 s32 int_err, s32 der_err);
134
135void rate_control_pid_add_sta_debugfs(void *priv, void *priv_sta,
136 struct dentry *dir);
137
138void rate_control_pid_remove_sta_debugfs(void *priv, void *priv_sta);
139
140struct rc_pid_sta_info {
141 unsigned long last_change;
142 unsigned long last_sample;
143
144 u32 tx_num_failed;
145 u32 tx_num_xmit;
146
147 /* Average failed frames percentage error (i.e. actual vs. target
148 * percentage), scaled by RC_PID_SMOOTHING. This value is computed
149 * using using an exponential weighted average technique:
150 *
151 * (RC_PID_SMOOTHING - 1) * err_avg_old + err
152 * err_avg = ------------------------------------------
153 * RC_PID_SMOOTHING
154 *
155 * where err_avg is the new approximation, err_avg_old the previous one
156 * and err is the error w.r.t. to the current failed frames percentage
157 * sample. Note that the bigger RC_PID_SMOOTHING the more weight is
158 * given to the previous estimate, resulting in smoother behavior (i.e.
159 * corresponding to a longer integration window).
160 *
161 * For computation, we actually don't use the above formula, but this
162 * one:
163 *
164 * err_avg_scaled = err_avg_old_scaled - err_avg_old + err
165 *
166 * where:
167 * err_avg_scaled = err * RC_PID_SMOOTHING
168 * err_avg_old_scaled = err_avg_old * RC_PID_SMOOTHING
169 *
170 * This avoids floating point numbers and the per_failed_old value can
171 * easily be obtained by shifting per_failed_old_scaled right by
172 * RC_PID_SMOOTHING_SHIFT.
173 */
174 s32 err_avg_sc;
175
176 /* Last framed failes percentage sample. */
177 u32 last_pf;
178
179 /* Sharpening needed. */
180 u8 sharp_cnt;
181
182#ifdef CONFIG_MAC80211_DEBUGFS
183 /* Event buffer */
184 struct rc_pid_event_buffer events;
185
186 /* Events debugfs file entry */
187 struct dentry *events_entry;
188#endif
189};
190
191/* Algorithm parameters. We keep them on a per-algorithm approach, so they can
192 * be tuned individually for each interface.
193 */
194struct rc_pid_rateinfo {
195
196 /* Map sorted rates to rates in ieee80211_hw_mode. */
197 int index;
198
199 /* Map rates in ieee80211_hw_mode to sorted rates. */
200 int rev_index;
201
202 /* Did we do any measurement on this rate? */
203 bool valid;
204
205 /* Comparison with the lowest rate. */
206 int diff;
207};
208
209struct rc_pid_info {
210
211 /* The failed frames percentage target. */
212 unsigned int target;
213
214 /* Rate at which failed frames percentage is sampled in 0.001s. */
215 unsigned int sampling_period;
216
217 /* P, I and D coefficients. */
218 int coeff_p;
219 int coeff_i;
220 int coeff_d;
221
222 /* Exponential averaging shift. */
223 unsigned int smoothing_shift;
224
225 /* Sharpening shift and duration. */
226 unsigned int sharpen_shift;
227 unsigned int sharpen_duration;
228
229 /* Normalization offset. */
230 unsigned int norm_offset;
231
232 /* Fast starst parameter. */
233 unsigned int fast_start;
234
235 /* Rates information. */
236 struct rc_pid_rateinfo *rinfo;
237
238 /* Index of the last used rate. */
239 int oldrate;
240};
241
242#endif /* RC80211_PID_H */
diff --git a/net/mac80211/rc80211_pid.c b/net/mac80211/rc80211_pid_algo.c
index 7f8cf27ad2f9..3fac3a5d7e00 100644
--- a/net/mac80211/rc80211_pid.c
+++ b/net/mac80211/rc80211_pid_algo.c
@@ -16,6 +16,8 @@
16#include <net/mac80211.h> 16#include <net/mac80211.h>
17#include "ieee80211_rate.h" 17#include "ieee80211_rate.h"
18 18
19#include "rc80211_pid.h"
20
19 21
20/* This is an implementation of a TX rate control algorithm that uses a PID 22/* This is an implementation of a TX rate control algorithm that uses a PID
21 * controller. Given a target failed frames rate, the controller decides about 23 * controller. Given a target failed frames rate, the controller decides about
@@ -61,121 +63,6 @@
61 * RC_PID_ARITH_SHIFT. 63 * RC_PID_ARITH_SHIFT.
62 */ 64 */
63 65
64/* Sampling period for measuring percentage of failed frames. */
65#define RC_PID_INTERVAL (HZ / 8)
66
67/* Exponential averaging smoothness (used for I part of PID controller) */
68#define RC_PID_SMOOTHING_SHIFT 3
69#define RC_PID_SMOOTHING (1 << RC_PID_SMOOTHING_SHIFT)
70
71/* Sharpening factor (used for D part of PID controller) */
72#define RC_PID_SHARPENING_FACTOR 0
73#define RC_PID_SHARPENING_DURATION 0
74
75/* Fixed point arithmetic shifting amount. */
76#define RC_PID_ARITH_SHIFT 8
77
78/* Fixed point arithmetic factor. */
79#define RC_PID_ARITH_FACTOR (1 << RC_PID_ARITH_SHIFT)
80
81/* Proportional PID component coefficient. */
82#define RC_PID_COEFF_P 15
83/* Integral PID component coefficient. */
84#define RC_PID_COEFF_I 9
85/* Derivative PID component coefficient. */
86#define RC_PID_COEFF_D 15
87
88/* Target failed frames rate for the PID controller. NB: This effectively gives
89 * maximum failed frames percentage we're willing to accept. If the wireless
90 * link quality is good, the controller will fail to adjust failed frames
91 * percentage to the target. This is intentional.
92 */
93#define RC_PID_TARGET_PF (11 << RC_PID_ARITH_SHIFT)
94
95/* Rate behaviour normalization quantity over time. */
96#define RC_PID_NORM_OFFSET 3
97
98/* Push high rates right after loading. */
99#define RC_PID_FAST_START 0
100
101/* Arithmetic right shift for positive and negative values for ISO C. */
102#define RC_PID_DO_ARITH_RIGHT_SHIFT(x, y) \
103 (x) < 0 ? -((-(x)) >> (y)) : (x) >> (y)
104
105struct rc_pid_sta_info {
106 unsigned long last_change;
107 unsigned long last_sample;
108
109 u32 tx_num_failed;
110 u32 tx_num_xmit;
111
112 /* Average failed frames percentage error (i.e. actual vs. target
113 * percentage), scaled by RC_PID_SMOOTHING. This value is computed
114 * using using an exponential weighted average technique:
115 *
116 * (RC_PID_SMOOTHING - 1) * err_avg_old + err
117 * err_avg = ------------------------------------------
118 * RC_PID_SMOOTHING
119 *
120 * where err_avg is the new approximation, err_avg_old the previous one
121 * and err is the error w.r.t. to the current failed frames percentage
122 * sample. Note that the bigger RC_PID_SMOOTHING the more weight is
123 * given to the previous estimate, resulting in smoother behavior (i.e.
124 * corresponding to a longer integration window).
125 *
126 * For computation, we actually don't use the above formula, but this
127 * one:
128 *
129 * err_avg_scaled = err_avg_old_scaled - err_avg_old + err
130 *
131 * where:
132 * err_avg_scaled = err * RC_PID_SMOOTHING
133 * err_avg_old_scaled = err_avg_old * RC_PID_SMOOTHING
134 *
135 * This avoids floating point numbers and the per_failed_old value can
136 * easily be obtained by shifting per_failed_old_scaled right by
137 * RC_PID_SMOOTHING_SHIFT.
138 */
139 s32 err_avg_sc;
140
141 /* Last framed failes percentage sample. */
142 u32 last_pf;
143
144 /* Sharpening needed. */
145 u8 sharp_cnt;
146};
147
148/* Algorithm parameters. We keep them on a per-algorithm approach, so they can
149 * be tuned individually for each interface.
150 */
151struct rc_pid_rateinfo {
152
153 /* Map sorted rates to rates in ieee80211_hw_mode. */
154 int index;
155
156 /* Map rates in ieee80211_hw_mode to sorted rates. */
157 int rev_index;
158
159 /* Comparison with the lowest rate. */
160 int diff;
161};
162
163struct rc_pid_info {
164
165 /* The failed frames percentage target. */
166 u32 target;
167
168 /* P, I and D coefficients. */
169 s32 coeff_p;
170 s32 coeff_i;
171 s32 coeff_d;
172
173 /* Rates information. */
174 struct rc_pid_rateinfo *rinfo;
175
176 /* Index of the last used rate. */
177 int oldrate;
178};
179 66
180/* Shift the adjustment so that we won't switch to a lower rate if it exhibited 67/* Shift the adjustment so that we won't switch to a lower rate if it exhibited
181 * a worse failed frames behaviour and we'll choose the highest rate whose 68 * a worse failed frames behaviour and we'll choose the highest rate whose
@@ -243,6 +130,12 @@ static void rate_control_pid_adjust_rate(struct ieee80211_local *local,
243 130
244 newidx += back; 131 newidx += back;
245 } 132 }
133
134#ifdef CONFIG_MAC80211_DEBUGFS
135 rate_control_pid_event_rate_change(
136 &((struct rc_pid_sta_info *)sta->rate_ctrl_priv)->events,
137 newidx, mode->rates[newidx].rate);
138#endif
246} 139}
247 140
248/* Normalize the failed frames per-rate differences. */ 141/* Normalize the failed frames per-rate differences. */
@@ -324,6 +217,11 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo,
324 if (spinfo->sharp_cnt) 217 if (spinfo->sharp_cnt)
325 spinfo->sharp_cnt--; 218 spinfo->sharp_cnt--;
326 219
220#ifdef CONFIG_MAC80211_DEBUGFS
221 rate_control_pid_event_pf_sample(&spinfo->events, pf, err_prop, err_int,
222 err_der);
223#endif
224
327 /* Compute the controller output. */ 225 /* Compute the controller output. */
328 adj = (err_prop * pinfo->coeff_p + err_int * pinfo->coeff_i 226 adj = (err_prop * pinfo->coeff_p + err_int * pinfo->coeff_i
329 + err_der * pinfo->coeff_d); 227 + err_der * pinfo->coeff_d);
@@ -357,6 +255,10 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
357 spinfo = sta->rate_ctrl_priv; 255 spinfo = sta->rate_ctrl_priv;
358 spinfo->tx_num_xmit++; 256 spinfo->tx_num_xmit++;
359 257
258#ifdef CONFIG_MAC80211_DEBUGFS
259 rate_control_pid_event_tx_status(&spinfo->events, status);
260#endif
261
360 /* We count frames that totally failed to be transmitted as two bad 262 /* We count frames that totally failed to be transmitted as two bad
361 * frames, those that made it out but had some retries as one good and 263 * frames, those that made it out but had some retries as one good and
362 * one bad frame. */ 264 * one bad frame. */
@@ -415,6 +317,12 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
415 sta_info_put(sta); 317 sta_info_put(sta);
416 318
417 sel->rate = &mode->rates[rateidx]; 319 sel->rate = &mode->rates[rateidx];
320
321#ifdef CONFIG_MAC80211_DEBUGFS
322 rate_control_pid_event_tx_rate(
323 &((struct rc_pid_sta_info *) sta->rate_ctrl_priv)->events,
324 rateidx, mode->rates[rateidx].rate);
325#endif
418} 326}
419 327
420static void rate_control_pid_rate_init(void *priv, void *priv_sta, 328static void rate_control_pid_rate_init(void *priv, void *priv_sta,
@@ -502,6 +410,13 @@ static void *rate_control_pid_alloc_sta(void *priv, gfp_t gfp)
502 struct rc_pid_sta_info *spinfo; 410 struct rc_pid_sta_info *spinfo;
503 411
504 spinfo = kzalloc(sizeof(*spinfo), gfp); 412 spinfo = kzalloc(sizeof(*spinfo), gfp);
413 if (spinfo == NULL)
414 return NULL;
415
416#ifdef CONFIG_MAC80211_DEBUGFS
417 spin_lock_init(&spinfo->events.lock);
418 init_waitqueue_head(&spinfo->events.waitqueue);
419#endif
505 420
506 return spinfo; 421 return spinfo;
507} 422}
@@ -522,4 +437,8 @@ struct rate_control_ops mac80211_rcpid = {
522 .free = rate_control_pid_free, 437 .free = rate_control_pid_free,
523 .alloc_sta = rate_control_pid_alloc_sta, 438 .alloc_sta = rate_control_pid_alloc_sta,
524 .free_sta = rate_control_pid_free_sta, 439 .free_sta = rate_control_pid_free_sta,
440#ifdef CONFIG_MAC80211_DEBUGFS
441 .add_sta_debugfs = rate_control_pid_add_sta_debugfs,
442 .remove_sta_debugfs = rate_control_pid_remove_sta_debugfs,
443#endif
525}; 444};
diff --git a/net/mac80211/rc80211_pid_debugfs.c b/net/mac80211/rc80211_pid_debugfs.c
new file mode 100644
index 000000000000..91818e4ff002
--- /dev/null
+++ b/net/mac80211/rc80211_pid_debugfs.c
@@ -0,0 +1,223 @@
1/*
2 * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include <linux/spinlock.h>
10#include <linux/poll.h>
11#include <linux/netdevice.h>
12#include <linux/types.h>
13#include <linux/skbuff.h>
14
15#include <net/mac80211.h>
16#include "ieee80211_rate.h"
17
18#include "rc80211_pid.h"
19
20static void rate_control_pid_event(struct rc_pid_event_buffer *buf,
21 enum rc_pid_event_type type,
22 union rc_pid_event_data *data)
23{
24 struct rc_pid_event *ev;
25 unsigned long status;
26
27 spin_lock_irqsave(&buf->lock, status);
28 ev = &(buf->ring[buf->next_entry]);
29 buf->next_entry = (buf->next_entry + 1) % RC_PID_EVENT_RING_SIZE;
30
31 ev->timestamp = jiffies;
32 ev->id = buf->ev_count++;
33 ev->type = type;
34 ev->data = *data;
35
36 spin_unlock_irqrestore(&buf->lock, status);
37
38 wake_up_all(&buf->waitqueue);
39}
40
41void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf,
42 struct ieee80211_tx_status *stat)
43{
44 union rc_pid_event_data evd;
45
46 memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_status));
47 rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_STATUS, &evd);
48}
49
50void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf,
51 int index, int rate)
52{
53 union rc_pid_event_data evd;
54
55 evd.index = index;
56 evd.rate = rate;
57 rate_control_pid_event(buf, RC_PID_EVENT_TYPE_RATE_CHANGE, &evd);
58}
59
60void rate_control_pid_event_tx_rate(struct rc_pid_event_buffer *buf,
61 int index, int rate)
62{
63 union rc_pid_event_data evd;
64
65 evd.index = index;
66 evd.rate = rate;
67 rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_RATE, &evd);
68}
69
70void rate_control_pid_event_pf_sample(struct rc_pid_event_buffer *buf,
71 s32 pf_sample, s32 prop_err,
72 s32 int_err, s32 der_err)
73{
74 union rc_pid_event_data evd;
75
76 evd.pf_sample = pf_sample;
77 evd.prop_err = prop_err;
78 evd.int_err = int_err;
79 evd.der_err = der_err;
80 rate_control_pid_event(buf, RC_PID_EVENT_TYPE_PF_SAMPLE, &evd);
81}
82
83static int rate_control_pid_events_open(struct inode *inode, struct file *file)
84{
85 struct rc_pid_sta_info *sinfo = inode->i_private;
86 struct rc_pid_event_buffer *events = &sinfo->events;
87 struct rc_pid_events_file_info *file_info;
88 unsigned int status;
89
90 /* Allocate a state struct */
91 file_info = kmalloc(sizeof(*file_info), GFP_KERNEL);
92 if (file_info == NULL)
93 return -ENOMEM;
94
95 spin_lock_irqsave(&events->lock, status);
96
97 file_info->next_entry = events->next_entry;
98 file_info->events = events;
99
100 spin_unlock_irqrestore(&events->lock, status);
101
102 file->private_data = file_info;
103
104 return 0;
105}
106
107static int rate_control_pid_events_release(struct inode *inode,
108 struct file *file)
109{
110 struct rc_pid_events_file_info *file_info = file->private_data;
111
112 kfree(file_info);
113
114 return 0;
115}
116
117static unsigned int rate_control_pid_events_poll(struct file *file,
118 poll_table *wait)
119{
120 struct rc_pid_events_file_info *file_info = file->private_data;
121
122 poll_wait(file, &file_info->events->waitqueue, wait);
123
124 return POLLIN | POLLRDNORM;
125}
126
127#define RC_PID_PRINT_BUF_SIZE 64
128
129static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf,
130 size_t length, loff_t *offset)
131{
132 struct rc_pid_events_file_info *file_info = file->private_data;
133 struct rc_pid_event_buffer *events = file_info->events;
134 struct rc_pid_event *ev;
135 char pb[RC_PID_PRINT_BUF_SIZE];
136 int ret;
137 int p;
138 unsigned int status;
139
140 /* Check if there is something to read. */
141 if (events->next_entry == file_info->next_entry) {
142 if (file->f_flags & O_NONBLOCK)
143 return -EAGAIN;
144
145 /* Wait */
146 ret = wait_event_interruptible(events->waitqueue,
147 events->next_entry != file_info->next_entry);
148
149 if (ret)
150 return ret;
151 }
152
153 /* Write out one event per call. I don't care whether it's a little
154 * inefficient, this is debugging code anyway. */
155 spin_lock_irqsave(&events->lock, status);
156
157 /* Get an event */
158 ev = &(events->ring[file_info->next_entry]);
159 file_info->next_entry = (file_info->next_entry + 1) %
160 RC_PID_EVENT_RING_SIZE;
161
162 /* Print information about the event. Note that userpace needs to
163 * provide large enough buffers. */
164 length = length < RC_PID_PRINT_BUF_SIZE ?
165 length : RC_PID_PRINT_BUF_SIZE;
166 p = snprintf(pb, length, "%u %lu ", ev->id, ev->timestamp);
167 switch (ev->type) {
168 case RC_PID_EVENT_TYPE_TX_STATUS:
169 p += snprintf(pb + p, length - p, "tx_status %u %u",
170 ev->data.tx_status.excessive_retries,
171 ev->data.tx_status.retry_count);
172 break;
173 case RC_PID_EVENT_TYPE_RATE_CHANGE:
174 p += snprintf(pb + p, length - p, "rate_change %d %d",
175 ev->data.index, ev->data.rate);
176 break;
177 case RC_PID_EVENT_TYPE_TX_RATE:
178 p += snprintf(pb + p, length - p, "tx_rate %d %d",
179 ev->data.index, ev->data.rate);
180 break;
181 case RC_PID_EVENT_TYPE_PF_SAMPLE:
182 p += snprintf(pb + p, length - p,
183 "pf_sample %d %d %d %d",
184 ev->data.pf_sample, ev->data.prop_err,
185 ev->data.int_err, ev->data.der_err);
186 break;
187 }
188 p += snprintf(pb + p, length - p, "\n");
189
190 spin_unlock_irqrestore(&events->lock, status);
191
192 if (copy_to_user(buf, pb, p))
193 return -EFAULT;
194
195 return p;
196}
197
198#undef RC_PID_PRINT_BUF_SIZE
199
200struct file_operations rc_pid_fop_events = {
201 .owner = THIS_MODULE,
202 .read = rate_control_pid_events_read,
203 .poll = rate_control_pid_events_poll,
204 .open = rate_control_pid_events_open,
205 .release = rate_control_pid_events_release,
206};
207
208void rate_control_pid_add_sta_debugfs(void *priv, void *priv_sta,
209 struct dentry *dir)
210{
211 struct rc_pid_sta_info *spinfo = priv_sta;
212
213 spinfo->events_entry = debugfs_create_file("rc_pid_events", S_IRUGO,
214 dir, spinfo,
215 &rc_pid_fop_events);
216}
217
218void rate_control_pid_remove_sta_debugfs(void *priv, void *priv_sta)
219{
220 struct rc_pid_sta_info *spinfo = priv_sta;
221
222 debugfs_remove(spinfo->events_entry);
223}