blob: e59cdc1cfab0cb943cc52621d36bf361d314c39d [file] [log] [blame]
/*
* Copyright 2010 Kshitij Kulshreshtha <kkhere.geo@gmail.com>
* Copyright 2012 Luis R. Rodriguez <mcgrof@do-not-panic.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Backport functionality introduced in Linux 2.6.35.
*/
#include <linux/compat.h>
#include <linux/ctype.h>
#include <linux/netdevice.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <net/sch_generic.h>
/*
* Routine to help set real_num_tx_queues. To avoid skbs mapped to queues
* greater then real_num_tx_queues stale skbs on the qdisc must be flushed.
*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27))
int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
{
unsigned int real_num = dev->real_num_tx_queues;
if (unlikely(txq > dev->num_tx_queues))
return -EINVAL;
else if (txq > real_num)
dev->real_num_tx_queues = txq;
else if (txq < real_num) {
dev->real_num_tx_queues = txq;
qdisc_reset_all_tx_gt(dev, txq);
}
return 0;
}
#else
int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
{
dev->egress_subqueue_count = txq;
/* XXX: consider qdisc reset for older kernels */
return 0;
}
#endif
EXPORT_SYMBOL_GPL(netif_set_real_num_tx_queues);
/**
* hex_to_bin - convert a hex digit to its real value
* @ch: ascii character represents hex digit
*
* hex_to_bin() converts one hex digit to its actual value or -1 in case of bad
* input.
*/
int hex_to_bin(char ch)
{
if ((ch >= '0') && (ch <= '9'))
return ch - '0';
ch = tolower(ch);
if ((ch >= 'a') && (ch <= 'f'))
return ch - 'a' + 10;
return -1;
}
EXPORT_SYMBOL_GPL(hex_to_bin);
/**
* noop_llseek - No Operation Performed llseek implementation
* @file: file structure to seek on
* @offset: file offset to seek to
* @origin: type of seek
*
* This is an implementation of ->llseek useable for the rare special case when
* userspace expects the seek to succeed but the (device) file is actually not
* able to perform the seek. In this case you use noop_llseek() instead of
* falling back to the default implementation of ->llseek.
*/
loff_t noop_llseek(struct file *file, loff_t offset, int origin)
{
return file->f_pos;
}
EXPORT_SYMBOL_GPL(noop_llseek);
/**
* simple_write_to_buffer - copy data from user space to the buffer
* @to: the buffer to write to
* @available: the size of the buffer
* @ppos: the current position in the buffer
* @from: the user space buffer to read from
* @count: the maximum number of bytes to read
*
* The simple_write_to_buffer() function reads up to @count bytes from the user
* space address starting at @from into the buffer @to at offset @ppos.
*
* On success, the number of bytes written is returned and the offset @ppos is
* advanced by this number, or negative value is returned on error.
**/
ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
const void __user *from, size_t count)
{
loff_t pos = *ppos;
size_t res;
if (pos < 0)
return -EINVAL;
if (pos >= available || !count)
return 0;
if (count > available - pos)
count = available - pos;
res = copy_from_user(to + pos, from, count);
if (res == count)
return -EFAULT;
count -= res;
*ppos = pos + count;
return count;
}
EXPORT_SYMBOL_GPL(simple_write_to_buffer);