/* allow Tegra qdisc to restrict tcp rx datarate */
#ifdef CONFIG_NET_SCH_TEGRA
uint tcp_window_divisor = 1;
+uint tcp_window_max = 0;
module_param(tcp_window_divisor, uint, 0644);
+module_param(tcp_window_max, uint, 0644);
#endif
/* People can turn this off for buggy TCP's found in printers etc. */
else
new_win = min(new_win, (65535U << tp->rx_opt.rcv_wscale));
+#ifdef CONFIG_NET_SCH_TEGRA
+ if ((tcp_window_max > 0) && (new_win > tcp_window_max)) {
+ pr_debug("%s: tcp_window_max %u: new_win %d -> %d\n",
+ __func__, tcp_window_max, new_win, tcp_window_max);
+ new_win = min(new_win, tcp_window_max);
+ }
+#endif
+
/* RFC1323 scaling applied */
new_win >>= tp->rx_opt.rcv_wscale;
return -ENOMEM;
for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
- dev_queue = netdev_get_tx_queue(dev, ntx);
#ifdef CONFIG_NET_SCH_TEGRA
extern struct Qdisc_ops sch_tegra_pfifo_fast_ops;
+#endif
+ dev_queue = netdev_get_tx_queue(dev, ntx);
+#ifdef CONFIG_NET_SCH_TEGRA
qdisc = qdisc_create_dflt(dev_queue, &sch_tegra_pfifo_fast_ops,
TC_H_MAKE(TC_H_MAJ(sch->handle),
TC_H_MIN(ntx + 1)));
#include <linux/rtnetlink.h>
#include <linux/moduleparam.h>
#include <linux/atomic.h>
+#include <linux/spinlock.h>
#include <net/pkt_sched.h>
#include <net/sch_generic.h>
static int sch_tegra_debug;
module_param(sch_tegra_debug, int, 0644);
-static int sch_tegra_enable = 1;
+static int sch_tegra_enable = 0;
module_param(sch_tegra_enable, int, 0644);
static unsigned long sch_tegra_pfifo_fast_dequeue_bits;
struct sk_buff_head q_highest_prio;
};
+static DEFINE_SPINLOCK(sch_tegra_datarate_lock);
+
static struct sk_buff *
sch_tegra_pfifo_fast_dequeue_datarate(struct sk_buff *skb)
{
+ unsigned long bits = skb ? skb->len * 8 : 0;
+ unsigned long flags;
unsigned long delta;
- if (skb)
- sch_tegra_pfifo_fast_dequeue_bits += skb->len * 8;
+ spin_lock_irqsave(&sch_tegra_datarate_lock, flags);
+ if (ULONG_MAX - bits < sch_tegra_pfifo_fast_dequeue_bits) {
+ sch_tegra_pfifo_fast_dequeue_bits
+ = bits;
+ sch_tegra_pfifo_fast_dequeue_jiffies0
+ = jiffies;
+ sch_tegra_pfifo_fast_dequeue_jiffies1
+ = sch_tegra_pfifo_fast_dequeue_jiffies0;
+ goto unlock;
+ }
+ sch_tegra_pfifo_fast_dequeue_bits += bits;
if (!sch_tegra_pfifo_fast_dequeue_jiffies0)
sch_tegra_pfifo_fast_dequeue_jiffies0 = jiffies;
sch_tegra_pfifo_fast_dequeue_jiffies1 = jiffies;
delta = sch_tegra_pfifo_fast_dequeue_jiffies1
- sch_tegra_pfifo_fast_dequeue_jiffies0;
- if (delta < 10)
- return skb;
+ if (delta < msecs_to_jiffies(100))
+ goto unlock;
if ((delta > msecs_to_jiffies(1000)) ||
(sch_tegra_pfifo_fast_dequeue_bits / (delta + 1)
> ULONG_MAX / HZ)) {
sch_tegra_pfifo_fast_dequeue_bits
- /= (delta + 1);
+ = bits;
sch_tegra_pfifo_fast_dequeue_jiffies0
= jiffies;
sch_tegra_pfifo_fast_dequeue_jiffies1
= sch_tegra_pfifo_fast_dequeue_jiffies0;
- delta = 0;
+ goto unlock;
}
sch_tegra_pfifo_fast_dequeue_bits_per_sec
= sch_tegra_pfifo_fast_dequeue_bits / (delta + 1) * HZ;
+unlock:
+ spin_unlock_irqrestore(&sch_tegra_datarate_lock, flags);
return skb;
}