Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v3.6-rc1 228 lines 6.1 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/sched.h> 10#include <linux/spinlock.h> 11#include <linux/poll.h> 12#include <linux/netdevice.h> 13#include <linux/types.h> 14#include <linux/skbuff.h> 15#include <linux/slab.h> 16#include <linux/export.h> 17 18#include <net/mac80211.h> 19#include "rate.h" 20 21#include "rc80211_pid.h" 22 23static void rate_control_pid_event(struct rc_pid_event_buffer *buf, 24 enum rc_pid_event_type type, 25 union rc_pid_event_data *data) 26{ 27 struct rc_pid_event *ev; 28 unsigned long status; 29 30 spin_lock_irqsave(&buf->lock, status); 31 ev = &(buf->ring[buf->next_entry]); 32 buf->next_entry = (buf->next_entry + 1) % RC_PID_EVENT_RING_SIZE; 33 34 ev->timestamp = jiffies; 35 ev->id = buf->ev_count++; 36 ev->type = type; 37 ev->data = *data; 38 39 spin_unlock_irqrestore(&buf->lock, status); 40 41 wake_up_all(&buf->waitqueue); 42} 43 44void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf, 45 struct ieee80211_tx_info *stat) 46{ 47 union rc_pid_event_data evd; 48 49 evd.flags = stat->flags; 50 memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_info)); 51 rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_STATUS, &evd); 52} 53 54void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf, 55 int index, int rate) 56{ 57 union rc_pid_event_data evd; 58 59 evd.index = index; 60 evd.rate = rate; 61 rate_control_pid_event(buf, RC_PID_EVENT_TYPE_RATE_CHANGE, &evd); 62} 63 64void rate_control_pid_event_tx_rate(struct rc_pid_event_buffer *buf, 65 int index, int rate) 66{ 67 union rc_pid_event_data evd; 68 69 evd.index = index; 70 evd.rate = rate; 71 rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_RATE, &evd); 72} 73 74void rate_control_pid_event_pf_sample(struct rc_pid_event_buffer *buf, 75 s32 pf_sample, s32 prop_err, 76 s32 int_err, s32 der_err) 77{ 78 union rc_pid_event_data evd; 79 80 evd.pf_sample = pf_sample; 81 evd.prop_err = prop_err; 82 evd.int_err = int_err; 83 evd.der_err = der_err; 84 rate_control_pid_event(buf, RC_PID_EVENT_TYPE_PF_SAMPLE, &evd); 85} 86 87static int rate_control_pid_events_open(struct inode *inode, struct file *file) 88{ 89 struct rc_pid_sta_info *sinfo = inode->i_private; 90 struct rc_pid_event_buffer *events = &sinfo->events; 91 struct rc_pid_events_file_info *file_info; 92 unsigned long status; 93 94 /* Allocate a state struct */ 95 file_info = kmalloc(sizeof(*file_info), GFP_KERNEL); 96 if (file_info == NULL) 97 return -ENOMEM; 98 99 spin_lock_irqsave(&events->lock, status); 100 101 file_info->next_entry = events->next_entry; 102 file_info->events = events; 103 104 spin_unlock_irqrestore(&events->lock, status); 105 106 file->private_data = file_info; 107 108 return 0; 109} 110 111static int rate_control_pid_events_release(struct inode *inode, 112 struct file *file) 113{ 114 struct rc_pid_events_file_info *file_info = file->private_data; 115 116 kfree(file_info); 117 118 return 0; 119} 120 121static unsigned int rate_control_pid_events_poll(struct file *file, 122 poll_table *wait) 123{ 124 struct rc_pid_events_file_info *file_info = file->private_data; 125 126 poll_wait(file, &file_info->events->waitqueue, wait); 127 128 return POLLIN | POLLRDNORM; 129} 130 131#define RC_PID_PRINT_BUF_SIZE 64 132 133static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf, 134 size_t length, loff_t *offset) 135{ 136 struct rc_pid_events_file_info *file_info = file->private_data; 137 struct rc_pid_event_buffer *events = file_info->events; 138 struct rc_pid_event *ev; 139 char pb[RC_PID_PRINT_BUF_SIZE]; 140 int ret; 141 int p; 142 unsigned long status; 143 144 /* Check if there is something to read. */ 145 if (events->next_entry == file_info->next_entry) { 146 if (file->f_flags & O_NONBLOCK) 147 return -EAGAIN; 148 149 /* Wait */ 150 ret = wait_event_interruptible(events->waitqueue, 151 events->next_entry != file_info->next_entry); 152 153 if (ret) 154 return ret; 155 } 156 157 /* Write out one event per call. I don't care whether it's a little 158 * inefficient, this is debugging code anyway. */ 159 spin_lock_irqsave(&events->lock, status); 160 161 /* Get an event */ 162 ev = &(events->ring[file_info->next_entry]); 163 file_info->next_entry = (file_info->next_entry + 1) % 164 RC_PID_EVENT_RING_SIZE; 165 166 /* Print information about the event. Note that userspace needs to 167 * provide large enough buffers. */ 168 length = length < RC_PID_PRINT_BUF_SIZE ? 169 length : RC_PID_PRINT_BUF_SIZE; 170 p = snprintf(pb, length, "%u %lu ", ev->id, ev->timestamp); 171 switch (ev->type) { 172 case RC_PID_EVENT_TYPE_TX_STATUS: 173 p += snprintf(pb + p, length - p, "tx_status %u %u", 174 !(ev->data.flags & IEEE80211_TX_STAT_ACK), 175 ev->data.tx_status.status.rates[0].idx); 176 break; 177 case RC_PID_EVENT_TYPE_RATE_CHANGE: 178 p += snprintf(pb + p, length - p, "rate_change %d %d", 179 ev->data.index, ev->data.rate); 180 break; 181 case RC_PID_EVENT_TYPE_TX_RATE: 182 p += snprintf(pb + p, length - p, "tx_rate %d %d", 183 ev->data.index, ev->data.rate); 184 break; 185 case RC_PID_EVENT_TYPE_PF_SAMPLE: 186 p += snprintf(pb + p, length - p, 187 "pf_sample %d %d %d %d", 188 ev->data.pf_sample, ev->data.prop_err, 189 ev->data.int_err, ev->data.der_err); 190 break; 191 } 192 p += snprintf(pb + p, length - p, "\n"); 193 194 spin_unlock_irqrestore(&events->lock, status); 195 196 if (copy_to_user(buf, pb, p)) 197 return -EFAULT; 198 199 return p; 200} 201 202#undef RC_PID_PRINT_BUF_SIZE 203 204static const struct file_operations rc_pid_fop_events = { 205 .owner = THIS_MODULE, 206 .read = rate_control_pid_events_read, 207 .poll = rate_control_pid_events_poll, 208 .open = rate_control_pid_events_open, 209 .release = rate_control_pid_events_release, 210 .llseek = noop_llseek, 211}; 212 213void rate_control_pid_add_sta_debugfs(void *priv, void *priv_sta, 214 struct dentry *dir) 215{ 216 struct rc_pid_sta_info *spinfo = priv_sta; 217 218 spinfo->events_entry = debugfs_create_file("rc_pid_events", S_IRUGO, 219 dir, spinfo, 220 &rc_pid_fop_events); 221} 222 223void rate_control_pid_remove_sta_debugfs(void *priv, void *priv_sta) 224{ 225 struct rc_pid_sta_info *spinfo = priv_sta; 226 227 debugfs_remove(spinfo->events_entry); 228}