Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.28-rc6 223 lines 5.9 kB view raw
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 "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_info *stat) 43{ 44 union rc_pid_event_data evd; 45 46 memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_info)); 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 long 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 long 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.status.excessive_retries, 171 ev->data.tx_status.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 200static struct 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}