aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/rc80211_pid_debugfs.c
diff options
context:
space:
mode:
authorMattias Nissler <mattias.nissler@gmx.de>2007-12-18 19:27:18 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:59:44 -0500
commit12446c67fea1e5bc74c58e43ef53eea308cdda61 (patch)
tree597ab96b5a7827d53ba676e78530646f842b4bde /net/mac80211/rc80211_pid_debugfs.c
parent1dc4d1e6a1e81fee0d488cec4fcd39269ec51318 (diff)
rc80211-pid: add debugging
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. Signed-off-by: Mattias Nissler <mattias.nissler@gmx.de> Signed-off-by: Stefano Brivio <stefano.brivio@polimi.it> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mac80211/rc80211_pid_debugfs.c')
-rw-r--r--net/mac80211/rc80211_pid_debugfs.c223
1 files changed, 223 insertions, 0 deletions
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}