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