| #ifndef __NET_PKT_SCHED_H |
| #define __NET_PKT_SCHED_H |
| |
| #include <linux/jiffies.h> |
| #include <net/sch_generic.h> |
| |
| struct qdisc_walker |
| { |
| int stop; |
| int skip; |
| int count; |
| int (*fn)(struct Qdisc *, unsigned long cl, struct qdisc_walker *); |
| }; |
| |
| extern rwlock_t qdisc_tree_lock; |
| |
| #define QDISC_ALIGNTO 32 |
| #define QDISC_ALIGN(len) (((len) + QDISC_ALIGNTO-1) & ~(QDISC_ALIGNTO-1)) |
| |
| static inline void *qdisc_priv(struct Qdisc *q) |
| { |
| return (char *) q + QDISC_ALIGN(sizeof(struct Qdisc)); |
| } |
| |
| /* |
| Timer resolution MUST BE < 10% of min_schedulable_packet_size/bandwidth |
| |
| Normal IP packet size ~ 512byte, hence: |
| |
| 0.5Kbyte/1Mbyte/sec = 0.5msec, so that we need 50usec timer for |
| 10Mbit ethernet. |
| |
| 10msec resolution -> <50Kbit/sec. |
| |
| The result: [34]86 is not good choice for QoS router :-( |
| |
| The things are not so bad, because we may use artifical |
| clock evaluated by integration of network data flow |
| in the most critical places. |
| |
| Note: we do not use fastgettimeofday. |
| 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. |
| */ |
| |
| /* 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 |
| 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 |
| |
| typedef struct timeval psched_time_t; |
| typedef long psched_tdiff_t; |
| |
| #define PSCHED_GET_TIME(stamp) do_gettimeofday(&(stamp)) |
| #define PSCHED_US2JIFFIE(usecs) usecs_to_jiffies(usecs) |
| #define PSCHED_JIFFIE2US(delay) jiffies_to_usecs(delay) |
| |
| #else /* !CONFIG_NET_SCH_CLK_GETTIMEOFDAY */ |
| |
| typedef u64 psched_time_t; |
| typedef long psched_tdiff_t; |
| |
| #ifdef CONFIG_NET_SCH_CLK_JIFFIES |
| |
| #if HZ < 96 |
| #define PSCHED_JSCALE 14 |
| #elif HZ >= 96 && HZ < 192 |
| #define PSCHED_JSCALE 13 |
| #elif HZ >= 192 && HZ < 384 |
| #define PSCHED_JSCALE 12 |
| #elif HZ >= 384 && HZ < 768 |
| #define PSCHED_JSCALE 11 |
| #elif HZ >= 768 |
| #define PSCHED_JSCALE 10 |
| #endif |
| |
| #define PSCHED_GET_TIME(stamp) ((stamp) = (get_jiffies_64()<<PSCHED_JSCALE)) |
| #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> |
| |
| 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 */ |
| |
| #endif /* !CONFIG_NET_SCH_CLK_GETTIMEOFDAY */ |
| |
| #ifdef CONFIG_NET_SCH_CLK_GETTIMEOFDAY |
| #define PSCHED_TDIFF(tv1, tv2) \ |
| ({ \ |
| int __delta_sec = (tv1).tv_sec - (tv2).tv_sec; \ |
| int __delta = (tv1).tv_usec - (tv2).tv_usec; \ |
| if (__delta_sec) { \ |
| switch (__delta_sec) { \ |
| default: \ |
| __delta = 0; \ |
| case 2: \ |
| __delta += USEC_PER_SEC; \ |
| case 1: \ |
| __delta += USEC_PER_SEC; \ |
| } \ |
| } \ |
| __delta; \ |
| }) |
| |
| static inline int |
| psched_tod_diff(int delta_sec, int bound) |
| { |
| int delta; |
| |
| if (bound <= USEC_PER_SEC || delta_sec > (0x7FFFFFFF/USEC_PER_SEC)-1) |
| return bound; |
| delta = delta_sec * USEC_PER_SEC; |
| if (delta > bound || delta < 0) |
| delta = bound; |
| return delta; |
| } |
| |
| #define PSCHED_TDIFF_SAFE(tv1, tv2, bound) \ |
| ({ \ |
| int __delta_sec = (tv1).tv_sec - (tv2).tv_sec; \ |
| int __delta = (tv1).tv_usec - (tv2).tv_usec; \ |
| switch (__delta_sec) { \ |
| default: \ |
| __delta = psched_tod_diff(__delta_sec, bound); break; \ |
| case 2: \ |
| __delta += USEC_PER_SEC; \ |
| case 1: \ |
| __delta += USEC_PER_SEC; \ |
| case 0: \ |
| if (__delta > bound || __delta < 0) \ |
| __delta = bound; \ |
| } \ |
| __delta; \ |
| }) |
| |
| #define PSCHED_TLESS(tv1, tv2) (((tv1).tv_usec < (tv2).tv_usec && \ |
| (tv1).tv_sec <= (tv2).tv_sec) || \ |
| (tv1).tv_sec < (tv2).tv_sec) |
| |
| #define PSCHED_TADD2(tv, delta, tv_res) \ |
| ({ \ |
| int __delta = (delta); \ |
| (tv_res) = (tv); \ |
| while(__delta >= USEC_PER_SEC){ \ |
| (tv_res).tv_sec++; \ |
| __delta -= USEC_PER_SEC; \ |
| } \ |
| (tv_res).tv_usec = __delta; \ |
| }) |
| |
| #define PSCHED_TADD(tv, delta) \ |
| ({ \ |
| int __delta = (delta); \ |
| while(__delta >= USEC_PER_SEC){ \ |
| (tv).tv_sec++; \ |
| __delta -= USEC_PER_SEC; \ |
| } \ |
| (tv).tv_usec = __delta; \ |
| }) |
| |
| /* Set/check that time is in the "past perfect"; |
| it depends on concrete representation of system time |
| */ |
| |
| #define PSCHED_SET_PASTPERFECT(t) ((t).tv_sec = 0) |
| #define PSCHED_IS_PASTPERFECT(t) ((t).tv_sec == 0) |
| |
| #define PSCHED_AUDIT_TDIFF(t) ({ if ((t) > 2000000) (t) = 2000000; }) |
| |
| #else /* !CONFIG_NET_SCH_CLK_GETTIMEOFDAY */ |
| |
| #define PSCHED_TDIFF(tv1, tv2) (long)((tv1) - (tv2)) |
| #define PSCHED_TDIFF_SAFE(tv1, tv2, bound) \ |
| min_t(long long, (tv1) - (tv2), bound) |
| |
| |
| #define PSCHED_TLESS(tv1, tv2) ((tv1) < (tv2)) |
| #define PSCHED_TADD2(tv, delta, tv_res) ((tv_res) = (tv) + (delta)) |
| #define PSCHED_TADD(tv, delta) ((tv) += (delta)) |
| #define PSCHED_SET_PASTPERFECT(t) ((t) = 0) |
| #define PSCHED_IS_PASTPERFECT(t) ((t) == 0) |
| #define PSCHED_AUDIT_TDIFF(t) |
| |
| #endif /* !CONFIG_NET_SCH_CLK_GETTIMEOFDAY */ |
| |
| extern struct Qdisc_ops pfifo_qdisc_ops; |
| extern struct Qdisc_ops bfifo_qdisc_ops; |
| |
| extern int register_qdisc(struct Qdisc_ops *qops); |
| extern int unregister_qdisc(struct Qdisc_ops *qops); |
| extern struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle); |
| extern struct Qdisc *qdisc_lookup_class(struct net_device *dev, u32 handle); |
| extern struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, |
| struct rtattr *tab); |
| extern void qdisc_put_rtab(struct qdisc_rate_table *tab); |
| |
| extern void __qdisc_run(struct net_device *dev); |
| |
| static inline void qdisc_run(struct net_device *dev) |
| { |
| if (!netif_queue_stopped(dev) && |
| !test_and_set_bit(__LINK_STATE_QDISC_RUNNING, &dev->state)) |
| __qdisc_run(dev); |
| } |
| |
| extern int tc_classify(struct sk_buff *skb, struct tcf_proto *tp, |
| struct tcf_result *res); |
| |
| /* Calculate maximal size of packet seen by hard_start_xmit |
| routine of this device. |
| */ |
| static inline unsigned psched_mtu(struct net_device *dev) |
| { |
| unsigned mtu = dev->mtu; |
| return dev->hard_header ? mtu + dev->hard_header_len : mtu; |
| } |
| |
| #endif |