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