diff options
Diffstat (limited to 'drivers/net/ethernet/netronome/nfp/abm/main.c')
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/abm/main.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/drivers/net/ethernet/netronome/nfp/abm/main.c b/drivers/net/ethernet/netronome/nfp/abm/main.c index 22251d88c958..d0c21899a8b7 100644 --- a/drivers/net/ethernet/netronome/nfp/abm/main.c +++ b/drivers/net/ethernet/netronome/nfp/abm/main.c @@ -40,6 +40,7 @@ #include <linux/slab.h> #include <net/pkt_cls.h> #include <net/pkt_sched.h> +#include <net/red.h> #include "../nfpcore/nfp.h" #include "../nfpcore/nfp_cpp.h" @@ -57,6 +58,23 @@ static u32 nfp_abm_portid(enum nfp_repr_type rtype, unsigned int id) FIELD_PREP(NFP_ABM_PORTID_ID, id); } +static int nfp_abm_reset_stats(struct nfp_abm_link *alink) +{ + int err; + + err = nfp_abm_ctrl_read_stats(alink, &alink->qdiscs[0].stats); + if (err) + return err; + alink->qdiscs[0].stats.backlog_pkts = 0; + alink->qdiscs[0].stats.backlog_bytes = 0; + + err = nfp_abm_ctrl_read_xstats(alink, &alink->qdiscs[0].xstats); + if (err) + return err; + + return 0; +} + static void nfp_abm_red_destroy(struct net_device *netdev, struct nfp_abm_link *alink, u32 handle) @@ -88,16 +106,86 @@ nfp_abm_red_replace(struct net_device *netdev, struct nfp_abm_link *alink, if (err) goto err_destroy; + /* Reset stats only on new qdisc */ + if (alink->qdiscs[0].handle != opt->handle) { + err = nfp_abm_reset_stats(alink); + if (err) + goto err_destroy; + } + alink->qdiscs[0].handle = opt->handle; port->tc_offload_cnt = 1; return 0; err_destroy: + /* If the qdisc keeps on living, but we can't offload undo changes */ + if (alink->qdiscs[0].handle == opt->handle) { + opt->set.qstats->qlen -= alink->qdiscs[0].stats.backlog_pkts; + opt->set.qstats->backlog -= + alink->qdiscs[0].stats.backlog_bytes; + } if (alink->qdiscs[0].handle != TC_H_UNSPEC) nfp_abm_red_destroy(netdev, alink, alink->qdiscs[0].handle); return err; } +static void +nfp_abm_update_stats(struct nfp_alink_stats *new, struct nfp_alink_stats *old, + struct tc_qopt_offload_stats *stats) +{ + _bstats_update(stats->bstats, new->tx_bytes - old->tx_bytes, + new->tx_pkts - old->tx_pkts); + stats->qstats->qlen += new->backlog_pkts - old->backlog_pkts; + stats->qstats->backlog += new->backlog_bytes - old->backlog_bytes; + stats->qstats->overlimits += new->overlimits - old->overlimits; + stats->qstats->drops += new->drops - old->drops; +} + +static int +nfp_abm_red_stats(struct nfp_abm_link *alink, struct tc_red_qopt_offload *opt) +{ + struct nfp_alink_stats *prev_stats; + struct nfp_alink_stats stats; + int err; + + if (alink->qdiscs[0].handle != opt->handle) + return -EOPNOTSUPP; + prev_stats = &alink->qdiscs[0].stats; + + err = nfp_abm_ctrl_read_stats(alink, &stats); + if (err) + return err; + + nfp_abm_update_stats(&stats, prev_stats, &opt->stats); + + *prev_stats = stats; + + return 0; +} + +static int +nfp_abm_red_xstats(struct nfp_abm_link *alink, struct tc_red_qopt_offload *opt) +{ + struct nfp_alink_xstats *prev_xstats; + struct nfp_alink_xstats xstats; + int err; + + if (alink->qdiscs[0].handle != opt->handle) + return -EOPNOTSUPP; + prev_xstats = &alink->qdiscs[0].xstats; + + err = nfp_abm_ctrl_read_xstats(alink, &xstats); + if (err) + return err; + + opt->xstats->forced_mark += xstats.ecn_marked - prev_xstats->ecn_marked; + opt->xstats->pdrop += xstats.pdrop - prev_xstats->pdrop; + + *prev_xstats = xstats; + + return 0; +} + static int nfp_abm_setup_tc_red(struct net_device *netdev, struct nfp_abm_link *alink, struct tc_red_qopt_offload *opt) @@ -111,6 +199,10 @@ nfp_abm_setup_tc_red(struct net_device *netdev, struct nfp_abm_link *alink, case TC_RED_DESTROY: nfp_abm_red_destroy(netdev, alink, opt->handle); return 0; + case TC_RED_STATS: + return nfp_abm_red_stats(alink, opt); + case TC_RED_XSTATS: + return nfp_abm_red_xstats(alink, opt); default: return -EOPNOTSUPP; } |