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#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}
 229
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.