1 From 68622c8bb029f9fd4c83ffa3bd979fa62a3599d0 Mon Sep 17 00:00:00 2001
2 From: Bogdan Purcareata <bogdan.purcareata@nxp.com>
3 Date: Mon, 13 Nov 2017 17:26:13 +0200
4 Subject: [PATCH] dpaa2-eth: Add CEETM qdisc support
7 - dual rate shaping support
8 - per-channel shaping and classification
9 - strict / weighted scheduling among num_tc classes
10 - TD enabled for configured class queues
11 - prio class (leaf) firmware statistics support
12 - weights normalized based on max
13 - tc filters based classification
15 Only 1 CEETM ch supported, only channel shaping supported.
17 Signed-off-by: Bogdan Purcareata <bogdan.purcareata@nxp.com>
18 Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
20 drivers/net/ethernet/freescale/dpaa2/Kconfig | 7 +
21 drivers/net/ethernet/freescale/dpaa2/Makefile | 1 +
22 .../net/ethernet/freescale/dpaa2/dpaa2-eth-ceetm.c | 1219 ++++++++++++++++++++
23 .../net/ethernet/freescale/dpaa2/dpaa2-eth-ceetm.h | 207 ++++
24 drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 53 +-
25 drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h | 7 +
26 6 files changed, 1482 insertions(+), 12 deletions(-)
27 create mode 100644 drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-ceetm.c
28 create mode 100644 drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-ceetm.h
30 --- a/drivers/net/ethernet/freescale/dpaa2/Kconfig
31 +++ b/drivers/net/ethernet/freescale/dpaa2/Kconfig
32 @@ -25,6 +25,13 @@ config FSL_DPAA2_ETH_USE_ERR_QUEUE
34 This may impact performance, recommended for debugging
37 +config FSL_DPAA2_ETH_CEETM
38 + depends on NET_SCHED
39 + bool "DPAA2 Ethernet CEETM QoS"
42 + Enable QoS offloading support through the CEETM hardware block.
45 config FSL_DPAA2_PTP_CLOCK
46 --- a/drivers/net/ethernet/freescale/dpaa2/Makefile
47 +++ b/drivers/net/ethernet/freescale/dpaa2/Makefile
48 @@ -8,6 +8,7 @@ obj-$(CONFIG_FSL_DPAA2_PTP_CLOCK) += fsl
50 fsl-dpaa2-eth-objs := dpaa2-eth.o dpaa2-ethtool.o dpni.o
51 fsl-dpaa2-eth-${CONFIG_DEBUG_FS} += dpaa2-eth-debugfs.o
52 +fsl-dpaa2-eth-${CONFIG_FSL_DPAA2_ETH_CEETM} += dpaa2-eth-ceetm.o
53 fsl-dpaa2-ptp-objs := dpaa2-ptp.o dprtc.o
55 # Needed by the tracing framework
57 +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-ceetm.c
59 +/* Copyright 2017 NXP
61 + * Redistribution and use in source and binary forms, with or without
62 + * modification, are permitted provided that the following conditions are met:
63 + * * Redistributions of source code must retain the above copyright
64 + * notice, this list of conditions and the following disclaimer.
65 + * * Redistributions in binary form must reproduce the above copyright
66 + * notice, this list of conditions and the following disclaimer in the
67 + * documentation and/or other materials provided with the distribution.
68 + * * Neither the name of Freescale Semiconductor nor the
69 + * names of its contributors may be used to endorse or promote products
70 + * derived from this software without specific prior written permission.
73 + * ALTERNATIVELY, this software may be distributed under the terms of the
74 + * GNU General Public License ("GPL") as published by the Free Software
75 + * Foundation, either version 2 of that License or (at your option) any
78 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
79 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
80 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
81 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
82 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
83 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
84 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
85 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
86 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
87 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
90 +#include <linux/init.h>
91 +#include <linux/module.h>
93 +#include "dpaa2-eth-ceetm.h"
94 +#include "dpaa2-eth.h"
96 +#define DPAA2_CEETM_DESCRIPTION "FSL DPAA2 CEETM qdisc"
97 +/* Conversion formula from userspace passed Bps to expected Mbit */
98 +#define dpaa2_eth_bps_to_mbit(rate) (rate >> 17)
100 +static const struct nla_policy dpaa2_ceetm_policy[DPAA2_CEETM_TCA_MAX] = {
101 + [DPAA2_CEETM_TCA_COPT] = { .len = sizeof(struct dpaa2_ceetm_tc_copt) },
102 + [DPAA2_CEETM_TCA_QOPS] = { .len = sizeof(struct dpaa2_ceetm_tc_qopt) },
105 +struct Qdisc_ops dpaa2_ceetm_qdisc_ops;
107 +static inline int dpaa2_eth_set_ch_shaping(struct dpaa2_eth_priv *priv,
108 + struct dpni_tx_shaping_cfg *scfg,
109 + struct dpni_tx_shaping_cfg *ecfg,
110 + int coupled, int ch_id)
114 + netdev_dbg(priv->net_dev, "%s: ch_id %d rate %d mbps\n", __func__,
115 + ch_id, scfg->rate_limit);
116 + err = dpni_set_tx_shaping(priv->mc_io, 0, priv->mc_token, scfg,
119 + netdev_err(priv->net_dev, "dpni_set_tx_shaping err\n");
124 +static inline int dpaa2_eth_reset_ch_shaping(struct dpaa2_eth_priv *priv,
127 + struct dpni_tx_shaping_cfg cfg = { 0 };
129 + return dpaa2_eth_set_ch_shaping(priv, &cfg, &cfg, 0, ch_id);
133 +dpaa2_eth_update_shaping_cfg(struct net_device *dev,
134 + struct dpaa2_ceetm_shaping_cfg cfg,
135 + struct dpni_tx_shaping_cfg *scfg,
136 + struct dpni_tx_shaping_cfg *ecfg)
138 + scfg->rate_limit = dpaa2_eth_bps_to_mbit(cfg.cir);
139 + ecfg->rate_limit = dpaa2_eth_bps_to_mbit(cfg.eir);
141 + if (cfg.cbs > DPAA2_ETH_MAX_BURST_SIZE) {
142 + netdev_err(dev, "Committed burst size must be under %d\n",
143 + DPAA2_ETH_MAX_BURST_SIZE);
147 + scfg->max_burst_size = cfg.cbs;
149 + if (cfg.ebs > DPAA2_ETH_MAX_BURST_SIZE) {
150 + netdev_err(dev, "Excess burst size must be under %d\n",
151 + DPAA2_ETH_MAX_BURST_SIZE);
155 + ecfg->max_burst_size = cfg.ebs;
157 + if ((!cfg.cir || !cfg.eir) && cfg.coupled) {
158 + netdev_err(dev, "Coupling can be set when both CIR and EIR are finite\n");
165 +enum update_tx_prio {
170 +/* Normalize weights based on max passed value */
171 +static inline int dpaa2_eth_normalize_tx_prio(struct dpaa2_ceetm_qdisc *priv)
173 + struct dpni_tx_schedule_cfg *sched_cfg;
174 + struct dpaa2_ceetm_class *cl;
176 + u16 weight_max = 0, increment;
179 + /* Check the boundaries of the provided values */
180 + for (i = 0; i < priv->clhash.hashsize; i++)
181 + hlist_for_each_entry(cl, &priv->clhash.hash[i], common.hnode)
182 + weight_max = (weight_max == 0 ? cl->prio.weight :
183 + (weight_max < cl->prio.weight ?
184 + cl->prio.weight : weight_max));
186 + /* If there are no elements, there's nothing to do */
187 + if (weight_max == 0)
190 + increment = (DPAA2_CEETM_MAX_WEIGHT - DPAA2_CEETM_MIN_WEIGHT) /
193 + for (i = 0; i < priv->clhash.hashsize; i++) {
194 + hlist_for_each_entry(cl, &priv->clhash.hash[i], common.hnode) {
195 + if (cl->prio.mode == STRICT_PRIORITY)
198 + qpri = cl->prio.qpri;
199 + sched_cfg = &priv->prio.tx_prio_cfg.tc_sched[qpri];
201 + sched_cfg->delta_bandwidth =
202 + DPAA2_CEETM_MIN_WEIGHT +
203 + (cl->prio.weight * increment);
205 + pr_debug("%s: Normalized CQ qpri %d weight to %d\n",
206 + __func__, qpri, sched_cfg->delta_bandwidth);
213 +static inline int dpaa2_eth_update_tx_prio(struct dpaa2_eth_priv *priv,
214 + struct dpaa2_ceetm_class *cl,
215 + enum update_tx_prio type)
217 + struct dpaa2_ceetm_qdisc *sch = qdisc_priv(cl->parent);
218 + struct dpni_tx_schedule_cfg *sched_cfg;
219 + struct dpni_taildrop td = {0};
220 + u8 ch_id = 0, tc_id = 0;
224 + qpri = cl->prio.qpri;
225 + tc_id = DPNI_BUILD_CH_TC(ch_id, qpri);
228 + case DPAA2_ETH_ADD_CQ:
229 + /* Enable taildrop */
231 + td.units = DPNI_CONGESTION_UNIT_FRAMES;
232 + td.threshold = DPAA2_CEETM_TD_THRESHOLD;
233 + err = dpni_set_taildrop(priv->mc_io, 0, priv->mc_token,
234 + DPNI_CP_GROUP, DPNI_QUEUE_TX, tc_id,
237 + netdev_err(priv->net_dev, "Error enabling Tx taildrop %d\n",
242 + case DPAA2_ETH_DEL_CQ:
243 + /* Disable taildrop */
245 + err = dpni_set_taildrop(priv->mc_io, 0, priv->mc_token,
246 + DPNI_CP_GROUP, DPNI_QUEUE_TX, tc_id,
249 + netdev_err(priv->net_dev, "Error disabling Tx taildrop %d\n",
256 + /* We can zero out the structure in the tx_prio_conf array */
257 + if (type == DPAA2_ETH_DEL_CQ) {
258 + sched_cfg = &sch->prio.tx_prio_cfg.tc_sched[qpri];
259 + memset(sched_cfg, 0, sizeof(*sched_cfg));
262 + /* Normalize priorities */
263 + err = dpaa2_eth_normalize_tx_prio(sch);
265 + /* Debug print goes here */
266 + print_hex_dump_debug("tx_prio: ", DUMP_PREFIX_OFFSET, 16, 1,
267 + &sch->prio.tx_prio_cfg,
268 + sizeof(sch->prio.tx_prio_cfg), 0);
270 + /* Call dpni_set_tx_priorities for the entire prio qdisc */
271 + err = dpni_set_tx_priorities(priv->mc_io, 0, priv->mc_token,
272 + &sch->prio.tx_prio_cfg);
274 + netdev_err(priv->net_dev, "dpni_set_tx_priorities err %d\n",
280 +static void dpaa2_eth_ceetm_enable(struct dpaa2_eth_priv *priv)
282 + priv->ceetm_en = true;
285 +static void dpaa2_eth_ceetm_disable(struct dpaa2_eth_priv *priv)
287 + priv->ceetm_en = false;
290 +/* Find class in qdisc hash table using given handle */
291 +static inline struct dpaa2_ceetm_class *dpaa2_ceetm_find(u32 handle,
294 + struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
295 + struct Qdisc_class_common *clc;
297 + pr_debug(KBUILD_BASENAME " : %s : find class %X in qdisc %X\n",
298 + __func__, handle, sch->handle);
300 + clc = qdisc_class_find(&priv->clhash, handle);
301 + return clc ? container_of(clc, struct dpaa2_ceetm_class, common) : NULL;
304 +/* Insert a class in the qdisc's class hash */
305 +static void dpaa2_ceetm_link_class(struct Qdisc *sch,
306 + struct Qdisc_class_hash *clhash,
307 + struct Qdisc_class_common *common)
309 + sch_tree_lock(sch);
310 + qdisc_class_hash_insert(clhash, common);
311 + sch_tree_unlock(sch);
312 + qdisc_class_hash_grow(sch, clhash);
315 +/* Destroy a ceetm class */
316 +static void dpaa2_ceetm_cls_destroy(struct Qdisc *sch,
317 + struct dpaa2_ceetm_class *cl)
319 + struct net_device *dev = qdisc_dev(sch);
320 + struct dpaa2_eth_priv *priv = netdev_priv(dev);
325 + pr_debug(KBUILD_BASENAME " : %s : destroy class %X from under %X\n",
326 + __func__, cl->common.classid, sch->handle);
328 + /* Recurse into child first */
330 + qdisc_put(cl->child);
334 + switch (cl->type) {
336 + if (dpaa2_eth_reset_ch_shaping(priv, cl->root.ch_id))
337 + netdev_err(dev, "Error resetting channel shaping\n");
342 + if (dpaa2_eth_update_tx_prio(priv, cl, DPAA2_ETH_DEL_CQ))
343 + netdev_err(dev, "Error resetting tx_priorities\n");
345 + if (cl->prio.cstats)
346 + free_percpu(cl->prio.cstats);
351 + tcf_block_put(cl->block);
355 +/* Destroy a ceetm qdisc */
356 +static void dpaa2_ceetm_destroy(struct Qdisc *sch)
359 + struct hlist_node *next;
360 + struct dpaa2_ceetm_class *cl;
361 + struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
362 + struct net_device *dev = qdisc_dev(sch);
363 + struct dpaa2_eth_priv *priv_eth = netdev_priv(dev);
365 + pr_debug(KBUILD_BASENAME " : %s : destroy qdisc %X\n",
366 + __func__, sch->handle);
368 + /* All filters need to be removed before destroying the classes */
369 + tcf_block_put(priv->block);
371 + for (i = 0; i < priv->clhash.hashsize; i++) {
372 + hlist_for_each_entry(cl, &priv->clhash.hash[i], common.hnode)
373 + tcf_block_put(cl->block);
376 + for (i = 0; i < priv->clhash.hashsize; i++) {
377 + hlist_for_each_entry_safe(cl, next, &priv->clhash.hash[i],
379 + dpaa2_ceetm_cls_destroy(sch, cl);
382 + qdisc_class_hash_destroy(&priv->clhash);
384 + switch (priv->type) {
386 + dpaa2_eth_ceetm_disable(priv_eth);
388 + if (priv->root.qstats)
389 + free_percpu(priv->root.qstats);
391 + if (!priv->root.qdiscs)
394 + /* Destroy the pfifo qdiscs in case they haven't been attached
395 + * to the netdev queues yet.
397 + for (i = 0; i < dev->num_tx_queues; i++)
398 + if (priv->root.qdiscs[i])
399 + qdisc_put(priv->root.qdiscs[i]);
401 + kfree(priv->root.qdiscs);
405 + if (priv->prio.parent)
406 + priv->prio.parent->child = NULL;
411 +static int dpaa2_ceetm_dump(struct Qdisc *sch, struct sk_buff *skb)
413 + struct Qdisc *qdisc;
414 + unsigned int ntx, i;
415 + struct nlattr *nest;
416 + struct dpaa2_ceetm_tc_qopt qopt;
417 + struct dpaa2_ceetm_qdisc_stats *qstats;
418 + struct net_device *dev = qdisc_dev(sch);
419 + struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
421 + pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
423 + sch_tree_lock(sch);
424 + memset(&qopt, 0, sizeof(qopt));
425 + qopt.type = priv->type;
426 + qopt.shaped = priv->shaped;
428 + switch (priv->type) {
430 + /* Gather statistics from the underlying pfifo qdiscs */
432 + memset(&sch->bstats, 0, sizeof(sch->bstats));
433 + memset(&sch->qstats, 0, sizeof(sch->qstats));
435 + for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
436 + qdisc = netdev_get_tx_queue(dev, ntx)->qdisc_sleeping;
437 + sch->q.qlen += qdisc->q.qlen;
438 + sch->bstats.bytes += qdisc->bstats.bytes;
439 + sch->bstats.packets += qdisc->bstats.packets;
440 + sch->qstats.qlen += qdisc->qstats.qlen;
441 + sch->qstats.backlog += qdisc->qstats.backlog;
442 + sch->qstats.drops += qdisc->qstats.drops;
443 + sch->qstats.requeues += qdisc->qstats.requeues;
444 + sch->qstats.overlimits += qdisc->qstats.overlimits;
447 + for_each_online_cpu(i) {
448 + qstats = per_cpu_ptr(priv->root.qstats, i);
449 + sch->qstats.drops += qstats->drops;
455 + qopt.prio_group_A = priv->prio.tx_prio_cfg.prio_group_A;
456 + qopt.prio_group_B = priv->prio.tx_prio_cfg.prio_group_B;
457 + qopt.separate_groups = priv->prio.tx_prio_cfg.separate_groups;
461 + pr_err(KBUILD_BASENAME " : %s : invalid qdisc\n", __func__);
462 + sch_tree_unlock(sch);
466 + nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
468 + goto nla_put_failure;
469 + if (nla_put(skb, DPAA2_CEETM_TCA_QOPS, sizeof(qopt), &qopt))
470 + goto nla_put_failure;
471 + nla_nest_end(skb, nest);
473 + sch_tree_unlock(sch);
477 + sch_tree_unlock(sch);
478 + nla_nest_cancel(skb, nest);
482 +static int dpaa2_ceetm_change_prio(struct Qdisc *sch,
483 + struct dpaa2_ceetm_qdisc *priv,
484 + struct dpaa2_ceetm_tc_qopt *qopt)
486 + /* TODO: Once LX2 support is added */
487 + /* priv->shaped = parent_cl->shaped; */
488 + priv->prio.tx_prio_cfg.prio_group_A = qopt->prio_group_A;
489 + priv->prio.tx_prio_cfg.prio_group_B = qopt->prio_group_B;
490 + priv->prio.tx_prio_cfg.separate_groups = qopt->separate_groups;
495 +/* Edit a ceetm qdisc */
496 +static int dpaa2_ceetm_change(struct Qdisc *sch, struct nlattr *opt,
497 + struct netlink_ext_ack *extack)
499 + struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
500 + struct nlattr *tb[DPAA2_CEETM_TCA_QOPS + 1];
501 + struct dpaa2_ceetm_tc_qopt *qopt;
504 + pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
506 + err = nla_parse_nested_deprecated(tb, DPAA2_CEETM_TCA_QOPS, opt,
507 + dpaa2_ceetm_policy, extack);
509 + pr_err(KBUILD_BASENAME " : %s : tc error in %s\n", __func__,
510 + "nla_parse_nested_deprecated");
514 + if (!tb[DPAA2_CEETM_TCA_QOPS]) {
515 + pr_err(KBUILD_BASENAME " : %s : tc error in %s\n", __func__,
520 + if (TC_H_MIN(sch->handle)) {
521 + pr_err("CEETM: a qdisc should not have a minor\n");
525 + qopt = nla_data(tb[DPAA2_CEETM_TCA_QOPS]);
527 + if (priv->type != qopt->type) {
528 + pr_err("CEETM: qdisc %X is not of the provided type\n",
533 + switch (priv->type) {
535 + err = dpaa2_ceetm_change_prio(sch, priv, qopt);
538 + pr_err(KBUILD_BASENAME " : %s : invalid qdisc\n", __func__);
545 +/* Configure a root ceetm qdisc */
546 +static int dpaa2_ceetm_init_root(struct Qdisc *sch,
547 + struct dpaa2_ceetm_qdisc *priv,
548 + struct dpaa2_ceetm_tc_qopt *qopt,
549 + struct netlink_ext_ack *extack)
551 + struct net_device *dev = qdisc_dev(sch);
552 + struct dpaa2_eth_priv *priv_eth = netdev_priv(dev);
553 + struct netdev_queue *dev_queue;
554 + unsigned int i, parent_id;
555 + struct Qdisc *qdisc;
557 + pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
559 + /* Validate inputs */
560 + if (sch->parent != TC_H_ROOT) {
561 + pr_err("CEETM: a root ceetm qdisc must be root\n");
565 + /* Pre-allocate underlying pfifo qdiscs.
567 + * We want to offload shaping and scheduling decisions to the hardware.
568 + * The pfifo qdiscs will be attached to the netdev queues and will
569 + * guide the traffic from the IP stack down to the driver with minimum
572 + * The CEETM qdiscs and classes will be crossed when the traffic
573 + * reaches the driver.
575 + priv->root.qdiscs = kcalloc(dev->num_tx_queues,
576 + sizeof(priv->root.qdiscs[0]),
578 + if (!priv->root.qdiscs)
581 + for (i = 0; i < dev->num_tx_queues; i++) {
582 + dev_queue = netdev_get_tx_queue(dev, i);
583 + parent_id = TC_H_MAKE(TC_H_MAJ(sch->handle),
584 + TC_H_MIN(i + PFIFO_MIN_OFFSET));
586 + qdisc = qdisc_create_dflt(dev_queue, &pfifo_qdisc_ops,
587 + parent_id, extack);
591 + priv->root.qdiscs[i] = qdisc;
592 + qdisc->flags |= TCQ_F_ONETXQUEUE;
595 + sch->flags |= TCQ_F_MQROOT;
597 + priv->root.qstats = alloc_percpu(struct dpaa2_ceetm_qdisc_stats);
598 + if (!priv->root.qstats) {
599 + pr_err(KBUILD_BASENAME " : %s : alloc_percpu() failed\n",
604 + dpaa2_eth_ceetm_enable(priv_eth);
608 +/* Configure a prio ceetm qdisc */
609 +static int dpaa2_ceetm_init_prio(struct Qdisc *sch,
610 + struct dpaa2_ceetm_qdisc *priv,
611 + struct dpaa2_ceetm_tc_qopt *qopt)
613 + struct net_device *dev = qdisc_dev(sch);
614 + struct dpaa2_ceetm_class *parent_cl;
615 + struct Qdisc *parent_qdisc;
617 + pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
619 + if (sch->parent == TC_H_ROOT) {
620 + pr_err("CEETM: a prio ceetm qdisc can not be root\n");
624 + parent_qdisc = qdisc_lookup(dev, TC_H_MAJ(sch->parent));
625 + if (strcmp(parent_qdisc->ops->id, dpaa2_ceetm_qdisc_ops.id)) {
626 + pr_err("CEETM: a ceetm qdisc can not be attached to other qdisc/class types\n");
630 + /* Obtain the parent root ceetm_class */
631 + parent_cl = dpaa2_ceetm_find(sch->parent, parent_qdisc);
633 + if (!parent_cl || parent_cl->type != CEETM_ROOT) {
634 + pr_err("CEETM: a prio ceetm qdiscs can be added only under a root ceetm class\n");
638 + priv->prio.parent = parent_cl;
639 + parent_cl->child = sch;
641 + return dpaa2_ceetm_change_prio(sch, priv, qopt);
644 +/* Configure a generic ceetm qdisc */
645 +static int dpaa2_ceetm_init(struct Qdisc *sch, struct nlattr *opt,
646 + struct netlink_ext_ack *extack)
648 + struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
649 + struct net_device *dev = qdisc_dev(sch);
650 + struct nlattr *tb[DPAA2_CEETM_TCA_QOPS + 1];
651 + struct dpaa2_ceetm_tc_qopt *qopt;
654 + pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
656 + if (!netif_is_multiqueue(dev))
657 + return -EOPNOTSUPP;
659 + err = tcf_block_get(&priv->block, &priv->filter_list, sch, extack);
661 + pr_err("CEETM: unable to get tcf_block\n");
666 + pr_err(KBUILD_BASENAME " : %s : tc error - opt = NULL\n",
671 + err = nla_parse_nested_deprecated(tb, DPAA2_CEETM_TCA_QOPS, opt,
672 + dpaa2_ceetm_policy, extack);
674 + pr_err(KBUILD_BASENAME " : %s : tc error in %s\n", __func__,
675 + "nla_parse_nested_deprecated");
679 + if (!tb[DPAA2_CEETM_TCA_QOPS]) {
680 + pr_err(KBUILD_BASENAME " : %s : tc error in %s\n", __func__,
685 + if (TC_H_MIN(sch->handle)) {
686 + pr_err("CEETM: a qdisc should not have a minor\n");
690 + qopt = nla_data(tb[DPAA2_CEETM_TCA_QOPS]);
692 + /* Initialize the class hash list. Each qdisc has its own class hash */
693 + err = qdisc_class_hash_init(&priv->clhash);
695 + pr_err(KBUILD_BASENAME " : %s : qdisc_class_hash_init failed\n",
700 + priv->type = qopt->type;
701 + priv->shaped = qopt->shaped;
703 + switch (priv->type) {
705 + err = dpaa2_ceetm_init_root(sch, priv, qopt, extack);
708 + err = dpaa2_ceetm_init_prio(sch, priv, qopt);
711 + pr_err(KBUILD_BASENAME " : %s : invalid qdisc\n", __func__);
712 + /* Note: dpaa2_ceetm_destroy() will be called by our caller */
719 +/* Attach the underlying pfifo qdiscs */
720 +static void dpaa2_ceetm_attach(struct Qdisc *sch)
722 + struct net_device *dev = qdisc_dev(sch);
723 + struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
724 + struct Qdisc *qdisc, *old_qdisc;
727 + pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
729 + for (i = 0; i < dev->num_tx_queues; i++) {
730 + qdisc = priv->root.qdiscs[i];
731 + old_qdisc = dev_graft_qdisc(qdisc->dev_queue, qdisc);
733 + qdisc_put(old_qdisc);
736 + /* Remove the references to the pfifo qdiscs since the kernel will
737 + * destroy them when needed. No cleanup from our part is required from
740 + kfree(priv->root.qdiscs);
741 + priv->root.qdiscs = NULL;
744 +static unsigned long dpaa2_ceetm_cls_find(struct Qdisc *sch, u32 classid)
746 + struct dpaa2_ceetm_class *cl;
748 + pr_debug(KBUILD_BASENAME " : %s : classid %X from qdisc %X\n",
749 + __func__, classid, sch->handle);
750 + cl = dpaa2_ceetm_find(classid, sch);
752 + return (unsigned long)cl;
755 +static int dpaa2_ceetm_cls_change_root(struct dpaa2_ceetm_class *cl,
756 + struct dpaa2_ceetm_tc_copt *copt,
757 + struct net_device *dev)
759 + struct dpaa2_eth_priv *priv = netdev_priv(dev);
760 + struct dpni_tx_shaping_cfg scfg = { 0 }, ecfg = { 0 };
763 + pr_debug(KBUILD_BASENAME " : %s : class %X\n", __func__,
764 + cl->common.classid);
769 + if (dpaa2_eth_update_shaping_cfg(dev, copt->shaping_cfg,
773 + err = dpaa2_eth_set_ch_shaping(priv, &scfg, &ecfg,
774 + copt->shaping_cfg.coupled,
779 + memcpy(&cl->root.shaping_cfg, &copt->shaping_cfg,
780 + sizeof(struct dpaa2_ceetm_shaping_cfg));
785 +static int dpaa2_ceetm_cls_change_prio(struct dpaa2_ceetm_class *cl,
786 + struct dpaa2_ceetm_tc_copt *copt,
787 + struct net_device *dev)
789 + struct dpaa2_ceetm_qdisc *sch = qdisc_priv(cl->parent);
790 + struct dpni_tx_schedule_cfg *sched_cfg;
791 + struct dpaa2_eth_priv *priv = netdev_priv(dev);
794 + pr_debug(KBUILD_BASENAME " : %s : class %X mode %d weight %d\n",
795 + __func__, cl->common.classid, copt->mode, copt->weight);
797 + if (!cl->prio.cstats) {
798 + cl->prio.cstats = alloc_percpu(struct dpaa2_ceetm_class_stats);
799 + if (!cl->prio.cstats) {
800 + pr_err(KBUILD_BASENAME " : %s : alloc_percpu() failed\n",
806 + cl->prio.mode = copt->mode;
807 + cl->prio.weight = copt->weight;
809 + sched_cfg = &sch->prio.tx_prio_cfg.tc_sched[cl->prio.qpri];
811 + switch (copt->mode) {
812 + case STRICT_PRIORITY:
813 + sched_cfg->mode = DPNI_TX_SCHED_STRICT_PRIORITY;
816 + sched_cfg->mode = DPNI_TX_SCHED_WEIGHTED_A;
819 + sched_cfg->mode = DPNI_TX_SCHED_WEIGHTED_B;
823 + err = dpaa2_eth_update_tx_prio(priv, cl, DPAA2_ETH_ADD_CQ);
828 +/* Add a new ceetm class */
829 +static int dpaa2_ceetm_cls_add(struct Qdisc *sch, u32 classid,
830 + struct dpaa2_ceetm_tc_copt *copt,
831 + unsigned long *arg,
832 + struct netlink_ext_ack *extack)
834 + struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
835 + struct net_device *dev = qdisc_dev(sch);
836 + struct dpaa2_eth_priv *priv_eth = netdev_priv(dev);
837 + struct dpaa2_ceetm_class *cl;
840 + if (copt->type == CEETM_ROOT &&
841 + priv->clhash.hashelems == dpaa2_eth_ch_count(priv_eth)) {
842 + pr_err("CEETM: only %d channel%s per DPNI allowed, sorry\n",
843 + dpaa2_eth_ch_count(priv_eth),
844 + dpaa2_eth_ch_count(priv_eth) == 1 ? "" : "s");
848 + if (copt->type == CEETM_PRIO &&
849 + priv->clhash.hashelems == dpaa2_eth_tc_count(priv_eth)) {
850 + pr_err("CEETM: only %d queue%s per channel allowed, sorry\n",
851 + dpaa2_eth_tc_count(priv_eth),
852 + dpaa2_eth_tc_count(priv_eth) == 1 ? "" : "s");
856 + cl = kzalloc(sizeof(*cl), GFP_KERNEL);
860 + err = tcf_block_get(&cl->block, &cl->filter_list, sch, extack);
862 + pr_err("%s: Unable to set new root class\n", __func__);
866 + cl->common.classid = classid;
870 + /* Add class handle in Qdisc */
871 + dpaa2_ceetm_link_class(sch, &priv->clhash, &cl->common);
873 + cl->shaped = copt->shaped;
874 + cl->type = copt->type;
876 + /* Claim a CEETM channel / tc - DPAA2. will assume transition from
877 + * classid to qdid/qpri, starting from qdid / qpri 0
879 + switch (copt->type) {
881 + cl->root.ch_id = classid - sch->handle - 1;
882 + err = dpaa2_ceetm_cls_change_root(cl, copt, dev);
885 + cl->prio.qpri = classid - sch->handle - 1;
886 + err = dpaa2_ceetm_cls_change_prio(cl, copt, dev);
891 + pr_err("%s: Unable to set new %s class\n", __func__,
892 + (copt->type == CEETM_ROOT ? "root" : "prio"));
896 + switch (copt->type) {
898 + pr_debug(KBUILD_BASENAME " : %s : configured root class %X associated with channel qdid %d\n",
899 + __func__, classid, cl->root.ch_id);
902 + pr_debug(KBUILD_BASENAME " : %s : configured prio class %X associated with queue qpri %d\n",
903 + __func__, classid, cl->prio.qpri);
907 + *arg = (unsigned long)cl;
915 +/* Add or configure a ceetm class */
916 +static int dpaa2_ceetm_cls_change(struct Qdisc *sch, u32 classid, u32 parentid,
917 + struct nlattr **tca, unsigned long *arg,
918 + struct netlink_ext_ack *extack)
920 + struct dpaa2_ceetm_qdisc *priv;
921 + struct dpaa2_ceetm_class *cl = (struct dpaa2_ceetm_class *)*arg;
922 + struct nlattr *opt = tca[TCA_OPTIONS];
923 + struct nlattr *tb[DPAA2_CEETM_TCA_MAX];
924 + struct dpaa2_ceetm_tc_copt *copt;
925 + struct net_device *dev = qdisc_dev(sch);
928 + pr_debug(KBUILD_BASENAME " : %s : classid %X under qdisc %X\n",
929 + __func__, classid, sch->handle);
931 + if (strcmp(sch->ops->id, dpaa2_ceetm_qdisc_ops.id)) {
932 + pr_err("CEETM: a ceetm class can not be attached to other qdisc/class types\n");
936 + priv = qdisc_priv(sch);
939 + pr_err(KBUILD_BASENAME " : %s : tc error NULL opt\n", __func__);
943 + err = nla_parse_nested_deprecated(tb, DPAA2_CEETM_TCA_COPT, opt,
944 + dpaa2_ceetm_policy, extack);
946 + pr_err(KBUILD_BASENAME " : %s : tc error in %s\n", __func__,
947 + "nla_parse_nested_deprecated");
951 + if (!tb[DPAA2_CEETM_TCA_COPT]) {
952 + pr_err(KBUILD_BASENAME " : %s : tc error in %s\n", __func__,
957 + copt = nla_data(tb[DPAA2_CEETM_TCA_COPT]);
959 + /* Configure an existing ceetm class */
961 + if (copt->type != cl->type) {
962 + pr_err("CEETM: class %X is not of the provided type\n",
963 + cl->common.classid);
967 + switch (copt->type) {
969 + return dpaa2_ceetm_cls_change_root(cl, copt, dev);
971 + return dpaa2_ceetm_cls_change_prio(cl, copt, dev);
974 + pr_err(KBUILD_BASENAME " : %s : invalid class\n",
980 + return dpaa2_ceetm_cls_add(sch, classid, copt, arg, extack);
983 +static void dpaa2_ceetm_cls_walk(struct Qdisc *sch, struct qdisc_walker *arg)
985 + struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
986 + struct dpaa2_ceetm_class *cl;
989 + pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle);
994 + for (i = 0; i < priv->clhash.hashsize; i++) {
995 + hlist_for_each_entry(cl, &priv->clhash.hash[i], common.hnode) {
996 + if (arg->count < arg->skip) {
1000 + if (arg->fn(sch, (unsigned long)cl, arg) < 0) {
1009 +static int dpaa2_ceetm_cls_dump(struct Qdisc *sch, unsigned long arg,
1010 + struct sk_buff *skb, struct tcmsg *tcm)
1012 + struct dpaa2_ceetm_class *cl = (struct dpaa2_ceetm_class *)arg;
1013 + struct nlattr *nest;
1014 + struct dpaa2_ceetm_tc_copt copt;
1016 + pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n",
1017 + __func__, cl->common.classid, sch->handle);
1019 + sch_tree_lock(sch);
1021 + tcm->tcm_parent = ((struct Qdisc *)cl->parent)->handle;
1022 + tcm->tcm_handle = cl->common.classid;
1024 + memset(&copt, 0, sizeof(copt));
1026 + copt.shaped = cl->shaped;
1027 + copt.type = cl->type;
1029 + switch (cl->type) {
1032 + tcm->tcm_info = cl->child->handle;
1034 + memcpy(&copt.shaping_cfg, &cl->root.shaping_cfg,
1035 + sizeof(struct dpaa2_ceetm_shaping_cfg));
1041 + tcm->tcm_info = cl->child->handle;
1043 + copt.mode = cl->prio.mode;
1044 + copt.weight = cl->prio.weight;
1049 + nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
1051 + goto nla_put_failure;
1052 + if (nla_put(skb, DPAA2_CEETM_TCA_COPT, sizeof(copt), &copt))
1053 + goto nla_put_failure;
1054 + nla_nest_end(skb, nest);
1055 + sch_tree_unlock(sch);
1059 + sch_tree_unlock(sch);
1060 + nla_nest_cancel(skb, nest);
1064 +static int dpaa2_ceetm_cls_delete(struct Qdisc *sch, unsigned long arg)
1066 + struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
1067 + struct dpaa2_ceetm_class *cl = (struct dpaa2_ceetm_class *)arg;
1069 + pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n",
1070 + __func__, cl->common.classid, sch->handle);
1072 + sch_tree_lock(sch);
1073 + qdisc_class_hash_remove(&priv->clhash, &cl->common);
1074 + sch_tree_unlock(sch);
1078 +/* Get the class' child qdisc, if any */
1079 +static struct Qdisc *dpaa2_ceetm_cls_leaf(struct Qdisc *sch, unsigned long arg)
1081 + struct dpaa2_ceetm_class *cl = (struct dpaa2_ceetm_class *)arg;
1083 + pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n",
1084 + __func__, cl->common.classid, sch->handle);
1086 + switch (cl->type) {
1095 +static int dpaa2_ceetm_cls_graft(struct Qdisc *sch, unsigned long arg,
1096 + struct Qdisc *new, struct Qdisc **old,
1097 + struct netlink_ext_ack *extack)
1099 + if (new && strcmp(new->ops->id, dpaa2_ceetm_qdisc_ops.id)) {
1100 + pr_err("CEETM: only ceetm qdiscs can be attached to ceetm classes\n");
1101 + return -EOPNOTSUPP;
1107 +static int dpaa2_ceetm_cls_dump_stats(struct Qdisc *sch, unsigned long arg,
1108 + struct gnet_dump *d)
1110 + struct dpaa2_ceetm_class *cl = (struct dpaa2_ceetm_class *)arg;
1111 + struct gnet_stats_basic_packed tmp_bstats;
1112 + struct dpaa2_ceetm_tc_xstats xstats;
1113 + union dpni_statistics dpni_stats;
1114 + struct net_device *dev = qdisc_dev(sch);
1115 + struct dpaa2_eth_priv *priv_eth = netdev_priv(dev);
1119 + memset(&xstats, 0, sizeof(xstats));
1120 + memset(&tmp_bstats, 0, sizeof(tmp_bstats));
1122 + if (cl->type == CEETM_ROOT)
1125 + err = dpni_get_statistics(priv_eth->mc_io, 0, priv_eth->mc_token, 3,
1126 + DPNI_BUILD_CH_TC(ch_id, cl->prio.qpri),
1129 + netdev_warn(dev, "dpni_get_stats(%d) failed - %d\n", 3, err);
1131 + xstats.ceetm_dequeue_bytes = dpni_stats.page_3.egress_dequeue_bytes;
1132 + xstats.ceetm_dequeue_frames = dpni_stats.page_3.egress_dequeue_frames;
1133 + xstats.ceetm_reject_bytes = dpni_stats.page_3.egress_reject_bytes;
1134 + xstats.ceetm_reject_frames = dpni_stats.page_3.egress_reject_frames;
1136 + return gnet_stats_copy_app(d, &xstats, sizeof(xstats));
1139 +static struct tcf_block *dpaa2_ceetm_tcf_block(struct Qdisc *sch,
1140 + unsigned long arg,
1141 + struct netlink_ext_ack *extack)
1143 + struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
1144 + struct dpaa2_ceetm_class *cl = (struct dpaa2_ceetm_class *)arg;
1146 + pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n", __func__,
1147 + cl ? cl->common.classid : 0, sch->handle);
1148 + return cl ? cl->block : priv->block;
1151 +static unsigned long dpaa2_ceetm_tcf_bind(struct Qdisc *sch,
1152 + unsigned long parent,
1155 + struct dpaa2_ceetm_class *cl = dpaa2_ceetm_find(classid, sch);
1157 + pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n", __func__,
1158 + cl ? cl->common.classid : 0, sch->handle);
1159 + return (unsigned long)cl;
1162 +static void dpaa2_ceetm_tcf_unbind(struct Qdisc *sch, unsigned long arg)
1164 + struct dpaa2_ceetm_class *cl = (struct dpaa2_ceetm_class *)arg;
1166 + pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n", __func__,
1167 + cl ? cl->common.classid : 0, sch->handle);
1170 +const struct Qdisc_class_ops dpaa2_ceetm_cls_ops = {
1171 + .graft = dpaa2_ceetm_cls_graft,
1172 + .leaf = dpaa2_ceetm_cls_leaf,
1173 + .find = dpaa2_ceetm_cls_find,
1174 + .change = dpaa2_ceetm_cls_change,
1175 + .delete = dpaa2_ceetm_cls_delete,
1176 + .walk = dpaa2_ceetm_cls_walk,
1177 + .tcf_block = dpaa2_ceetm_tcf_block,
1178 + .bind_tcf = dpaa2_ceetm_tcf_bind,
1179 + .unbind_tcf = dpaa2_ceetm_tcf_unbind,
1180 + .dump = dpaa2_ceetm_cls_dump,
1181 + .dump_stats = dpaa2_ceetm_cls_dump_stats,
1184 +struct Qdisc_ops dpaa2_ceetm_qdisc_ops __read_mostly = {
1186 + .priv_size = sizeof(struct dpaa2_ceetm_qdisc),
1187 + .cl_ops = &dpaa2_ceetm_cls_ops,
1188 + .init = dpaa2_ceetm_init,
1189 + .destroy = dpaa2_ceetm_destroy,
1190 + .change = dpaa2_ceetm_change,
1191 + .dump = dpaa2_ceetm_dump,
1192 + .attach = dpaa2_ceetm_attach,
1193 + .owner = THIS_MODULE,
1196 +/* Run the filters and classifiers attached to the qdisc on the provided skb */
1197 +int dpaa2_ceetm_classify(struct sk_buff *skb, struct Qdisc *sch,
1198 + int *qdid, u8 *qpri)
1200 + struct dpaa2_ceetm_qdisc *priv = qdisc_priv(sch);
1201 + struct dpaa2_ceetm_class *cl = NULL;
1202 + struct tcf_result res;
1203 + struct tcf_proto *tcf;
1206 + tcf = rcu_dereference_bh(priv->filter_list);
1207 + while (tcf && (result = tcf_classify(skb, tcf, &res, false)) >= 0) {
1208 +#ifdef CONFIG_NET_CLS_ACT
1210 + case TC_ACT_QUEUED:
1211 + case TC_ACT_STOLEN:
1213 + /* No valid class found due to action */
1217 + cl = (void *)res.class;
1219 + /* The filter leads to the qdisc */
1220 + if (res.classid == sch->handle)
1223 + cl = dpaa2_ceetm_find(res.classid, sch);
1224 + /* The filter leads to an invalid class */
1229 + /* The class might have its own filters attached */
1230 + tcf = rcu_dereference_bh(cl->filter_list);
1233 + /* No valid class found */
1237 + switch (cl->type) {
1239 + *qdid = cl->root.ch_id;
1241 + /* The root class does not have a child prio qdisc */
1245 + /* Run the prio qdisc classifiers */
1246 + return dpaa2_ceetm_classify(skb, cl->child, qdid, qpri);
1249 + *qpri = cl->prio.qpri;
1256 +int __init dpaa2_ceetm_register(void)
1260 + pr_debug(KBUILD_MODNAME ": " DPAA2_CEETM_DESCRIPTION "\n");
1262 + err = register_qdisc(&dpaa2_ceetm_qdisc_ops);
1263 + if (unlikely(err))
1264 + pr_err(KBUILD_MODNAME
1265 + ": %s:%hu:%s(): register_qdisc() = %d\n",
1266 + KBUILD_BASENAME ".c", __LINE__, __func__, err);
1271 +void __exit dpaa2_ceetm_unregister(void)
1273 + pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
1274 + KBUILD_BASENAME ".c", __func__);
1276 + unregister_qdisc(&dpaa2_ceetm_qdisc_ops);
1279 +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth-ceetm.h
1281 +/* Copyright 2017 NXP
1283 + * Redistribution and use in source and binary forms, with or without
1284 + * modification, are permitted provided that the following conditions are met:
1285 + * * Redistributions of source code must retain the above copyright
1286 + * notice, this list of conditions and the following disclaimer.
1287 + * * Redistributions in binary form must reproduce the above copyright
1288 + * notice, this list of conditions and the following disclaimer in the
1289 + * documentation and/or other materials provided with the distribution.
1290 + * * Neither the name of Freescale Semiconductor nor the
1291 + * names of its contributors may be used to endorse or promote products
1292 + * derived from this software without specific prior written permission.
1295 + * ALTERNATIVELY, this software may be distributed under the terms of the
1296 + * GNU General Public License ("GPL") as published by the Free Software
1297 + * Foundation, either version 2 of that License or (at your option) any
1300 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
1301 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1302 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1303 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
1304 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1305 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1306 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1307 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1308 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1309 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1312 +#ifndef __DPAA2_ETH_CEETM_H
1313 +#define __DPAA2_ETH_CEETM_H
1315 +#include <net/pkt_sched.h>
1316 +#include <net/pkt_cls.h>
1317 +#include <net/netlink.h>
1319 +#include "dpaa2-eth.h"
1321 +/* For functional purposes, there are num_tx_queues pfifo qdiscs through which
1322 + * frames reach the driver. Their handles start from 1:21. Handles 1:1 to 1:20
1323 + * are reserved for the maximum 32 CEETM channels (majors and minors are in
1326 +#define PFIFO_MIN_OFFSET 0x21
1328 +#define DPAA2_CEETM_MIN_WEIGHT 100
1329 +#define DPAA2_CEETM_MAX_WEIGHT 24800
1331 +#define DPAA2_CEETM_TD_THRESHOLD 1000
1333 +enum wbfs_group_type {
1340 + DPAA2_CEETM_TCA_UNSPEC,
1341 + DPAA2_CEETM_TCA_COPT,
1342 + DPAA2_CEETM_TCA_QOPS,
1343 + DPAA2_CEETM_TCA_MAX,
1346 +/* CEETM configuration types */
1347 +enum dpaa2_ceetm_type {
1353 + STRICT_PRIORITY = 0,
1358 +struct dpaa2_ceetm_shaping_cfg {
1359 + __u64 cir; /* committed information rate */
1360 + __u64 eir; /* excess information rate */
1361 + __u16 cbs; /* committed burst size */
1362 + __u16 ebs; /* excess burst size */
1363 + __u8 coupled; /* shaper coupling */
1366 +extern const struct nla_policy ceetm_policy[DPAA2_CEETM_TCA_MAX];
1368 +struct dpaa2_ceetm_class;
1369 +struct dpaa2_ceetm_qdisc_stats;
1370 +struct dpaa2_ceetm_class_stats;
1372 +/* corresponds to CEETM shaping at LNI level */
1373 +struct dpaa2_root_q {
1374 + struct Qdisc **qdiscs;
1375 + struct dpaa2_ceetm_qdisc_stats __percpu *qstats;
1378 +/* corresponds to the number of priorities a channel serves */
1379 +struct dpaa2_prio_q {
1380 + struct dpaa2_ceetm_class *parent;
1381 + struct dpni_tx_priorities_cfg tx_prio_cfg;
1384 +struct dpaa2_ceetm_qdisc {
1385 + struct Qdisc_class_hash clhash;
1386 + struct tcf_proto *filter_list; /* qdisc attached filters */
1387 + struct tcf_block *block;
1389 + enum dpaa2_ceetm_type type; /* ROOT/PRIO */
1392 + struct dpaa2_root_q root;
1393 + struct dpaa2_prio_q prio;
1397 +/* CEETM Qdisc configuration parameters */
1398 +struct dpaa2_ceetm_tc_qopt {
1399 + enum dpaa2_ceetm_type type;
1401 + __u8 prio_group_A;
1402 + __u8 prio_group_B;
1403 + __u8 separate_groups;
1406 +/* root class - corresponds to a channel */
1407 +struct dpaa2_root_c {
1408 + struct dpaa2_ceetm_shaping_cfg shaping_cfg;
1412 +/* prio class - corresponds to a strict priority queue (group) */
1413 +struct dpaa2_prio_c {
1414 + struct dpaa2_ceetm_class_stats __percpu *cstats;
1420 +struct dpaa2_ceetm_class {
1421 + struct Qdisc_class_common common;
1422 + struct tcf_proto *filter_list; /* class attached filters */
1423 + struct tcf_block *block;
1424 + struct Qdisc *parent;
1425 + struct Qdisc *child;
1427 + enum dpaa2_ceetm_type type; /* ROOT/PRIO */
1430 + struct dpaa2_root_c root;
1431 + struct dpaa2_prio_c prio;
1435 +/* CEETM Class configuration parameters */
1436 +struct dpaa2_ceetm_tc_copt {
1437 + enum dpaa2_ceetm_type type;
1438 + struct dpaa2_ceetm_shaping_cfg shaping_cfg;
1445 +struct dpaa2_ceetm_qdisc_stats {
1449 +struct dpaa2_ceetm_class_stats {
1450 + /* Software counters */
1451 + struct gnet_stats_basic_packed bstats;
1452 + __u32 ern_drop_count;
1455 +struct dpaa2_ceetm_tc_xstats {
1456 + __u64 ceetm_dequeue_bytes;
1457 + __u64 ceetm_dequeue_frames;
1458 + __u64 ceetm_reject_bytes;
1459 + __u64 ceetm_reject_frames;
1462 +#ifdef CONFIG_FSL_DPAA2_ETH_CEETM
1463 +int __init dpaa2_ceetm_register(void);
1464 +void __exit dpaa2_ceetm_unregister(void);
1465 +int dpaa2_ceetm_classify(struct sk_buff *skb, struct Qdisc *sch,
1466 + int *qdid, u8 *qpri);
1468 +static inline int dpaa2_ceetm_register(void)
1473 +static inline void dpaa2_ceetm_unregister(void) {}
1475 +static inline int dpaa2_ceetm_classify(struct sk_buff *skb, struct Qdisc *sch,
1476 + int *qdid, u8 *qpri)
1482 +static inline bool dpaa2_eth_ceetm_is_enabled(struct dpaa2_eth_priv *priv)
1484 + return priv->ceetm_en;
1488 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
1489 +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
1491 #include <net/sock.h>
1493 #include "dpaa2-eth.h"
1494 +#include "dpaa2-eth-ceetm.h"
1496 /* CREATE_TRACE_POINTS only needs to be defined once. Other dpa files
1497 * using trace events only need to #include <trace/events/sched.h>
1498 @@ -816,7 +817,7 @@ static netdev_tx_t dpaa2_eth_tx(struct s
1499 unsigned int needed_headroom;
1503 + int err, i, ch_id = 0;
1505 percpu_stats = this_cpu_ptr(priv->percpu_stats);
1506 percpu_extras = this_cpu_ptr(priv->percpu_extras);
1507 @@ -887,6 +888,15 @@ static netdev_tx_t dpaa2_eth_tx(struct s
1509 fq = &priv->fq[queue_mapping];
1511 + if (dpaa2_eth_ceetm_is_enabled(priv)) {
1512 + err = dpaa2_ceetm_classify(skb, net_dev->qdisc, &ch_id, &prio);
1514 + free_tx_fd(priv, fq, &fd, false);
1515 + percpu_stats->tx_dropped++;
1516 + return NETDEV_TX_OK;
1520 fd_len = dpaa2_fd_get_len(&fd);
1521 nq = netdev_get_tx_queue(net_dev, queue_mapping);
1522 netdev_tx_sent_queue(nq, fd_len);
1523 @@ -2075,17 +2085,13 @@ static int update_xps(struct dpaa2_eth_p
1527 -static int dpaa2_eth_setup_tc(struct net_device *net_dev,
1528 - enum tc_setup_type type, void *type_data)
1529 +static int dpaa2_eth_setup_mqprio(struct net_device *net_dev,
1530 + struct tc_mqprio_qopt *mqprio)
1532 struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
1533 - struct tc_mqprio_qopt *mqprio = type_data;
1534 u8 num_tc, num_queues;
1537 - if (type != TC_SETUP_QDISC_MQPRIO)
1540 mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
1541 num_queues = dpaa2_eth_queue_count(priv);
1542 num_tc = mqprio->num_tc;
1543 @@ -2117,6 +2123,20 @@ out:
1547 +static int dpaa2_eth_setup_tc(struct net_device *net_dev,
1548 + enum tc_setup_type type,
1552 + case TC_SETUP_BLOCK:
1554 + case TC_SETUP_QDISC_MQPRIO:
1555 + return dpaa2_eth_setup_mqprio(net_dev, type_data);
1557 + return -EOPNOTSUPP;
1561 static const struct net_device_ops dpaa2_eth_ops = {
1562 .ndo_open = dpaa2_eth_open,
1563 .ndo_start_xmit = dpaa2_eth_tx,
1564 @@ -4171,18 +4191,27 @@ static int __init dpaa2_eth_driver_init(
1566 dpaa2_eth_dbg_init();
1567 err = fsl_mc_driver_register(&dpaa2_eth_driver);
1569 - dpaa2_eth_dbg_exit();
1573 + goto out_debugfs_err;
1575 + err = dpaa2_ceetm_register();
1577 + goto out_ceetm_err;
1582 + fsl_mc_driver_unregister(&dpaa2_eth_driver);
1584 + dpaa2_eth_dbg_exit();
1588 static void __exit dpaa2_eth_driver_exit(void)
1590 - dpaa2_eth_dbg_exit();
1591 + dpaa2_ceetm_unregister();
1592 fsl_mc_driver_unregister(&dpaa2_eth_driver);
1593 + dpaa2_eth_dbg_exit();
1596 module_init(dpaa2_eth_driver_init);
1597 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
1598 +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
1599 @@ -454,6 +454,8 @@ struct dpaa2_eth_priv {
1600 struct dpaa2_debugfs dbg;
1602 struct dpni_tx_shaping_cfg shaping_cfg;
1607 #define DPAA2_RXH_SUPPORTED (RXH_L2DA | RXH_VLAN | RXH_L3_PROTO \
1608 @@ -574,6 +576,11 @@ static inline unsigned int dpaa2_eth_rx_
1609 return priv->tx_data_offset - DPAA2_ETH_RX_HWA_SIZE;
1612 +static inline int dpaa2_eth_ch_count(struct dpaa2_eth_priv *priv)
1617 int dpaa2_eth_set_hash(struct net_device *net_dev, u64 flags);
1618 int dpaa2_eth_set_cls(struct net_device *net_dev, u64 key);
1619 int dpaa2_eth_cls_key_size(u64 key);