#ifndef __NET_PKT_SCHED_H
#define __NET_PKT_SCHED_H
+#define PSCHED_GETTIMEOFDAY 1
+#define PSCHED_JIFFIES 2
+#define PSCHED_CPU 3
+
+#define PSCHED_CLOCK_SOURCE PSCHED_JIFFIES
+
#include <linux/config.h>
#include <linux/netdevice.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/rtnetlink.h>
+#ifdef CONFIG_X86_TSC
+#include <asm/msr.h>
+#endif
+
+
struct rtattr;
struct Qdisc;
#define TCQ_F_BUILTIN 1
#define TCQ_F_THROTTLED 2
#define TCQ_F_INGRES 4
- int padded;
struct Qdisc_ops *ops;
+ struct Qdisc *next;
u32 handle;
atomic_t refcnt;
struct sk_buff_head q;
struct net_device *dev;
- struct list_head list;
struct tc_stats stats;
spinlock_t *stats_lock;
* and it will live until better solution will be invented.
*/
struct Qdisc *__parent;
-};
-
-#define QDISC_ALIGN 32
-#define QDISC_ALIGN_CONST (QDISC_ALIGN - 1)
-static inline void *qdisc_priv(struct Qdisc *q)
-{
- return (char *)q + ((sizeof(struct Qdisc) + QDISC_ALIGN_CONST)
- & ~QDISC_ALIGN_CONST);
-}
+ char data[0];
+};
struct qdisc_rate_table
{
int refcnt;
};
-extern void qdisc_lock_tree(struct net_device *dev);
-extern void qdisc_unlock_tree(struct net_device *dev);
+static inline void sch_tree_lock(struct Qdisc *q)
+{
+ write_lock(&qdisc_tree_lock);
+ spin_lock_bh(&q->dev->queue_lock);
+}
+
+static inline void sch_tree_unlock(struct Qdisc *q)
+{
+ spin_unlock_bh(&q->dev->queue_lock);
+ write_unlock(&qdisc_tree_lock);
+}
+
+static inline void tcf_tree_lock(struct tcf_proto *tp)
+{
+ write_lock(&qdisc_tree_lock);
+ spin_lock_bh(&tp->q->dev->queue_lock);
+}
+
+static inline void tcf_tree_unlock(struct tcf_proto *tp)
+{
+ spin_unlock_bh(&tp->q->dev->queue_lock);
+ write_unlock(&qdisc_tree_lock);
+}
+
+
+static inline unsigned long
+cls_set_class(struct tcf_proto *tp, unsigned long *clp, unsigned long cl)
+{
+ unsigned long old_cl;
-#define sch_tree_lock(q) qdisc_lock_tree((q)->dev)
-#define sch_tree_unlock(q) qdisc_unlock_tree((q)->dev)
-#define tcf_tree_lock(tp) qdisc_lock_tree((tp)->q->dev)
-#define tcf_tree_unlock(tp) qdisc_unlock_tree((tp)->q->dev)
+ tcf_tree_lock(tp);
+ old_cl = *clp;
+ *clp = cl;
+ tcf_tree_unlock(tp);
+ return old_cl;
+}
-#define cls_set_class(tp, clp, cl) tcf_set_class(tp, clp, cl)
static inline unsigned long
__cls_set_class(unsigned long *clp, unsigned long cl)
{
The reason is that, when it is not the same thing as
gettimeofday, it returns invalid timestamp, which is
not updated, when net_bh is active.
+
+ So, use PSCHED_CLOCK_SOURCE = PSCHED_CPU on alpha and pentiums
+ with rtdsc. And PSCHED_JIFFIES on all other architectures, including [34]86
+ and pentiums without rtdsc.
+ You can use PSCHED_GETTIMEOFDAY on another architectures,
+ which have fast and precise clock source, but it is too expensive.
*/
/* General note about internal clock.
Any clock source returns time intervals, measured in units
- close to 1usec. With source CONFIG_NET_SCH_CLK_GETTIMEOFDAY it is precisely
+ close to 1usec. With source PSCHED_GETTIMEOFDAY it is precisely
microseconds, otherwise something close but different chosen to minimize
arithmetic cost. Ratio usec/internal untis in form nominator/denominator
may be read from /proc/net/psched.
*/
-#ifdef CONFIG_NET_SCH_CLK_GETTIMEOFDAY
+#if PSCHED_CLOCK_SOURCE == PSCHED_GETTIMEOFDAY
typedef struct timeval psched_time_t;
typedef long psched_tdiff_t;
#define PSCHED_US2JIFFIE(usecs) (((usecs)+(1000000/HZ-1))/(1000000/HZ))
#define PSCHED_JIFFIE2US(delay) ((delay)*(1000000/HZ))
-#else /* !CONFIG_NET_SCH_CLK_GETTIMEOFDAY */
+#else /* PSCHED_CLOCK_SOURCE != PSCHED_GETTIMEOFDAY */
typedef u64 psched_time_t;
typedef long psched_tdiff_t;
-#ifdef CONFIG_NET_SCH_CLK_JIFFIES
+extern psched_time_t psched_time_base;
+
+#if PSCHED_CLOCK_SOURCE == PSCHED_JIFFIES
#if HZ < 96
#define PSCHED_JSCALE 14
#define PSCHED_US2JIFFIE(delay) (((delay)+(1<<PSCHED_JSCALE)-1)>>PSCHED_JSCALE)
#define PSCHED_JIFFIE2US(delay) ((delay)<<PSCHED_JSCALE)
-#endif /* CONFIG_NET_SCH_CLK_JIFFIES */
-#ifdef CONFIG_NET_SCH_CLK_CPU
-#include <asm/timex.h>
+#elif PSCHED_CLOCK_SOURCE == PSCHED_CPU
extern psched_tdiff_t psched_clock_per_hz;
extern int psched_clock_scale;
-extern psched_time_t psched_time_base;
-extern cycles_t psched_time_mark;
-
-#define PSCHED_GET_TIME(stamp) \
-do { \
- cycles_t cur = get_cycles(); \
- if (sizeof(cycles_t) == sizeof(u32)) { \
- if (cur <= psched_time_mark) \
- psched_time_base += 0x100000000ULL; \
- psched_time_mark = cur; \
- (stamp) = (psched_time_base + cur)>>psched_clock_scale; \
- } else { \
- (stamp) = cur>>psched_clock_scale; \
- } \
-} while (0)
+
#define PSCHED_US2JIFFIE(delay) (((delay)+psched_clock_per_hz-1)/psched_clock_per_hz)
#define PSCHED_JIFFIE2US(delay) ((delay)*psched_clock_per_hz)
-#endif /* CONFIG_NET_SCH_CLK_CPU */
+#ifdef CONFIG_X86_TSC
+
+#define PSCHED_GET_TIME(stamp) \
+({ u64 __cur; \
+ rdtscll(__cur); \
+ (stamp) = __cur>>psched_clock_scale; \
+})
+
+#elif defined (__alpha__)
+
+#define PSCHED_WATCHER u32
-#endif /* !CONFIG_NET_SCH_CLK_GETTIMEOFDAY */
+extern PSCHED_WATCHER psched_time_mark;
-#ifdef CONFIG_NET_SCH_CLK_GETTIMEOFDAY
+#define PSCHED_GET_TIME(stamp) \
+({ u32 __res; \
+ __asm__ __volatile__ ("rpcc %0" : "r="(__res)); \
+ if (__res <= psched_time_mark) psched_time_base += 0x100000000UL; \
+ psched_time_mark = __res; \
+ (stamp) = (psched_time_base + __res)>>psched_clock_scale; \
+})
+
+#else
+
+#error PSCHED_CLOCK_SOURCE=PSCHED_CPU is not supported on this arch.
+
+#endif /* ARCH */
+
+#endif /* PSCHED_CLOCK_SOURCE == PSCHED_JIFFIES */
+
+#endif /* PSCHED_CLOCK_SOURCE == PSCHED_GETTIMEOFDAY */
+
+#if PSCHED_CLOCK_SOURCE == PSCHED_GETTIMEOFDAY
#define PSCHED_TDIFF(tv1, tv2) \
({ \
int __delta_sec = (tv1).tv_sec - (tv2).tv_sec; \
#define PSCHED_AUDIT_TDIFF(t) ({ if ((t) > 2000000) (t) = 2000000; })
-#else /* !CONFIG_NET_SCH_CLK_GETTIMEOFDAY */
+#else
#define PSCHED_TDIFF(tv1, tv2) (long)((tv1) - (tv2))
#define PSCHED_TDIFF_SAFE(tv1, tv2, bound) \
#define PSCHED_IS_PASTPERFECT(t) ((t) == 0)
#define PSCHED_AUDIT_TDIFF(t)
-#endif /* !CONFIG_NET_SCH_CLK_GETTIMEOFDAY */
+#endif
struct tcf_police
{
extern int tcf_act_police(struct sk_buff **skb, struct tc_action *a);
#endif
-extern unsigned long tcf_set_class(struct tcf_proto *tp, unsigned long *clp,
- unsigned long cl);
extern int tcf_police(struct sk_buff *skb, struct tcf_police *p);
extern int qdisc_copy_stats(struct sk_buff *skb, struct tc_stats *st, spinlock_t *lock);
extern void tcf_police_destroy(struct tcf_police *p);
extern int qdisc_restart(struct net_device *dev);
+static inline void qdisc_run(struct net_device *dev)
+{
+ while (!netif_queue_stopped(dev) &&
+ qdisc_restart(dev)<0)
+ /* NOTHING */;
+}
+
/* Calculate maximal size of packet seen by hard_start_xmit
routine of this device.
*/