diff options
-rw-r--r-- | drivers/net/Kconfig | 79 | ||||
-rw-r--r-- | include/linux/netdevice.h | 4 | ||||
-rw-r--r-- | include/net/sch_generic.h | 43 | ||||
-rw-r--r-- | net/core/dev.c | 26 | ||||
-rw-r--r-- | net/sched/sch_prio.c | 60 |
5 files changed, 211 insertions, 1 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index b2f3a62..8d3dc1df 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -67,6 +67,85 @@ config ASF_IPV6 This option compiles the ASF for IPV6 Firewall and IPsec. +config ASF_QOS + default y + bool "ASF QoS Support" + depends on AS_FASTPATH + select NETFILTER_XT_TARGET_DSCP + select NET_SCHED + select NET_SCH_PRIO + select NET_SCH_TBF + select NET_SCH_DRR + select NET_CLS + select NET_CLS_BASIC + select NET_CLS_U32 + select NET_CLS_FLOW + select NET_SCH_FIFO + select IP_NF_MANGLE + select IP6_NF_MANGLE + +config ASF_EGRESS_QOS + default y + bool + depends on ASF_QOS + +config ASF_INGRESS_MARKER + default y + bool "DSCP Marking Support" + depends on ASF_QOS && ASF_EGRESS_QOS + ---help--- + Choose this option if you wish to utilize ASF Marking support. + Currently only DSCP marking is supported. + +config ASF_EGRESS_SCH + default y + bool "S/W Scheduler Support" + depends on ASF_QOS && ASF_EGRESS_QOS && !DPA_ETH + ---help--- + Choose this option if you wish to utilize ASF S/W based Strict Priority + Scheduler support. + +config ASF_EGRESS_SHAPER + default y + bool "S/W Shaper Support" + depends on ASF_QOS && ASF_EGRESS_QOS && !DPA_ETH + + ---help--- + Choose this option if you wish to utilize ASF S/W based Shaping support. + This shaper will be configured at each scheduler queue. + +config ASF_HW_SCH + default n + bool "ASF H/W Scheduler Support" + depends on ASF_QOS && ASF_EGRESS_QOS && !ASF_EGRESS_SCH + ---help--- + Choose this option if you wish to utilize eTSEC(NON-DPAA) TX Scheduler. +choice + prompt "Select Scheduling Algorithm" + depends on ASF_HW_SCH && !DPA_ETH + default ASF_SCH_PRIO + +config ASF_SCH_PRIO + bool "Strict Priority (PRIO)" + ---help--- + This option compiles the ASF to utilize eTSEC(NON-DPAA) + H/W Scheduler with PRIORITY algorithm. + +config ASF_SCH_MWRR + bool "Modified Weighted Round-Robin (MWRR)" + ---help--- + This option compiles the ASF to utilize eTSEC(NON-DPAA) + H/W Scheduler with Modified Weighted Round-Robin algorithm. + +endchoice + +config ASF_HW_SHAPER + default y + bool "ASF H/W Shaper Support" + depends on ASF_QOS && ASF_EGRESS_QOS && DPA_ETH + ---help--- + Choose this option if you wish to utilize DPAA TX Shaper. + config NET_CORE default y bool "Network core driver support" diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 041bc5b..c4e30cd 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1214,7 +1214,9 @@ struct net_device { /* root qdisc from userspace point of view */ struct Qdisc *qdisc; - +#ifdef CONFIG_ASF_EGRESS_QOS + void *asf_qdisc; +#endif unsigned long tx_queue_len; /* Max frames per queue allowed */ spinlock_t tx_global_lock; diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 1540f9c..97dddf2 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -679,4 +679,47 @@ static inline struct sk_buff *skb_act_clone(struct sk_buff *skb, gfp_t gfp_mask, } #endif +#if defined(CONFIG_ASF_EGRESS_SCH) || defined(CONFIG_ASF_HW_SCH) +typedef int prio_add_hook( + struct net_device *dev, + uint32_t handle, + uint32_t parent, + uint32_t bands); +typedef int prio_flush_hook( + struct net_device *dev, + uint32_t handle, + uint32_t parent); + +void prio_hook_fn_register(prio_add_hook *add, + prio_flush_hook *flush); +#endif + +#ifdef CONFIG_ASF_EGRESS_SHAPER +struct tbf_opt { + struct net_device *dev; + uint32_t handle; + uint32_t parent; + uint32_t rate; + uint32_t limit; + uint32_t buffer; + uint16_t mpu; +}; + +typedef int tbf_add_hook(struct tbf_opt *opt); +typedef int tbf_del_hook( + struct net_device *dev, + uint32_t handle, + uint32_t parent); + +void tbf_hook_fn_register(tbf_add_hook *add, + tbf_del_hook *del); +#endif + +#ifdef CONFIG_ASF_EGRESS_QOS +typedef int asf_qos_fn_hook(struct sk_buff *skb); + +void asf_qos_fn_register(asf_qos_fn_hook *fn); +void asf_qos_fn_unregister(void); +#endif + #endif diff --git a/net/core/dev.c b/net/core/dev.c index 29aab09..68dd7f8 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2617,6 +2617,24 @@ static void skb_update_prio(struct sk_buff *skb) static DEFINE_PER_CPU(int, xmit_recursion); #define RECURSION_LIMIT 10 +#ifdef CONFIG_ASF_EGRESS_QOS +/* Linux QoS hook to tranfer all packet to ASF QoS */ +static asf_qos_fn_hook *asf_qos_fn; + +void asf_qos_fn_register(asf_qos_fn_hook *fn) +{ + asf_qos_fn = fn; +} +EXPORT_SYMBOL(asf_qos_fn_register); + +void asf_qos_fn_unregister(void) +{ + asf_qos_fn = NULL; +} +EXPORT_SYMBOL(asf_qos_fn_unregister); +#endif + + /** * dev_loopback_xmit - loop back @skb * @skb: buffer to transmit @@ -2686,6 +2704,14 @@ int dev_queue_xmit(struct sk_buff *skb) #ifdef CONFIG_NET_CLS_ACT skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_EGRESS); #endif + +#ifdef CONFIG_ASF_EGRESS_QOS + if (asf_qos_fn) { + rc = asf_qos_fn(skb); + goto out; + } +#endif + trace_net_dev_queue(skb); if (q->enqueue) { rc = __dev_xmit_skb(skb, q, dev, txq); diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 79359b6..868ab9a 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -22,6 +22,16 @@ #include <net/pkt_sched.h> +#if defined(CONFIG_ASF_EGRESS_SCH) || defined(CONFIG_ASF_HW_SCH) +static inline void _prio_add_hook(struct Qdisc *sch, + uint32_t bands); +static inline void _prio_flush_hook(struct Qdisc *sch); + +/* Define ADD/DELETE Hooks */ +static prio_add_hook *prio_add_fn; +static prio_flush_hook *prio_flush_fn; +#endif + struct prio_sched_data { int bands; struct tcf_proto *filter_list; @@ -161,6 +171,11 @@ prio_destroy(struct Qdisc *sch) tcf_destroy_chain(&q->filter_list); for (prio = 0; prio < q->bands; prio++) qdisc_destroy(q->queues[prio]); + +#if defined(CONFIG_ASF_EGRESS_SCH) || defined(CONFIG_ASF_HW_SCH) + /* Invoke PRIO Qdisc Deletiion */ + _prio_flush_hook(sch); +#endif } static int prio_tune(struct Qdisc *sch, struct nlattr *opt) @@ -234,6 +249,12 @@ static int prio_init(struct Qdisc *sch, struct nlattr *opt) if ((err = prio_tune(sch, opt)) != 0) return err; + +#if defined(CONFIG_ASF_EGRESS_SCH) || defined(CONFIG_ASF_HW_SCH) + /* PRIO Qdisc creation is complete, now safe to offload */ + _prio_add_hook(sch, q->bands); +#endif + } return 0; } @@ -360,6 +381,45 @@ static struct tcf_proto **prio_find_tcf(struct Qdisc *sch, unsigned long cl) return &q->filter_list; } +#if defined(CONFIG_ASF_EGRESS_SCH) || defined(CONFIG_ASF_HW_SCH) +static inline void _prio_add_hook( + struct Qdisc *sch, + uint32_t bands) +{ + if (prio_add_fn) { + struct net_device *dev = qdisc_dev(sch); + + if (prio_add_fn(dev, sch->handle, sch->parent, bands) < 0) { + printk(KERN_DEBUG "%s: PRIO Creation on %s: fail: handle 0x%X\n", + __func__, dev->name, sch->handle); + } + } +} + +static inline void _prio_flush_hook(struct Qdisc *sch) +{ + + if (prio_flush_fn) { + struct net_device *dev = qdisc_dev(sch); + + if (prio_flush_fn(dev, sch->handle, sch->parent) < 0) { + printk(KERN_DEBUG "%s: PRIO Fush on %s: fail: handle 0x%X\n", + __func__, dev->name, sch->handle); + } + } +} + + +void prio_hook_fn_register(prio_add_hook *add, + prio_flush_hook *flush) +{ + prio_add_fn = add; + prio_flush_fn = flush; +} +EXPORT_SYMBOL(prio_hook_fn_register); +#endif + + static const struct Qdisc_class_ops prio_class_ops = { .graft = prio_graft, .leaf = prio_leaf, |