* [PATCH net-next 0/3] Add hw offload of TC police on MSCC ocelot
@ 2019-05-02 9:40 Joergen Andreasen
2019-05-02 9:40 ` [PATCH net-next 1/3] net/sched: act_police: move police parameters into separate header file Joergen Andreasen
` (2 more replies)
0 siblings, 3 replies; 13+ messages in thread
From: Joergen Andreasen @ 2019-05-02 9:40 UTC (permalink / raw)
To: netdev
Cc: Joergen Andreasen, Jamal Hadi Salim, Cong Wang, Jiri Pirko,
Alexandre Belloni, Microchip Linux Driver Support,
David S. Miller, Ralf Baechle, Paul Burton, James Hogan,
linux-mips, linux-kernel
This patch series enables hardware offload of ingress port policing
on the MSCC ocelot board.
Joergen Andreasen (3):
net/sched: act_police: move police parameters into separate header
file
net: mscc: ocelot: Implement port policers via tc command
MIPS: generic: Add police related options to ocelot_defconfig
arch/mips/configs/generic/board-ocelot.config | 7 +
drivers/net/ethernet/mscc/Makefile | 2 +-
drivers/net/ethernet/mscc/ocelot.c | 6 +-
drivers/net/ethernet/mscc/ocelot.h | 3 +
drivers/net/ethernet/mscc/ocelot_police.c | 289 ++++++++++++++++++
drivers/net/ethernet/mscc/ocelot_police.h | 16 +
drivers/net/ethernet/mscc/ocelot_tc.c | 151 +++++++++
drivers/net/ethernet/mscc/ocelot_tc.h | 19 ++
include/net/tc_act/tc_police.h | 41 +++
net/sched/act_police.c | 27 +-
10 files changed, 532 insertions(+), 29 deletions(-)
create mode 100644 drivers/net/ethernet/mscc/ocelot_police.c
create mode 100644 drivers/net/ethernet/mscc/ocelot_police.h
create mode 100644 drivers/net/ethernet/mscc/ocelot_tc.c
create mode 100644 drivers/net/ethernet/mscc/ocelot_tc.h
create mode 100644 include/net/tc_act/tc_police.h
--
2.17.1
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH net-next 1/3] net/sched: act_police: move police parameters into separate header file
2019-05-02 9:40 [PATCH net-next 0/3] Add hw offload of TC police on MSCC ocelot Joergen Andreasen
@ 2019-05-02 9:40 ` Joergen Andreasen
2019-05-02 20:38 ` Jiri Pirko
2019-05-02 9:40 ` [PATCH net-next 2/3] net: mscc: ocelot: Implement port policers via tc command Joergen Andreasen
2019-05-02 9:40 ` [PATCH net-next 3/3] MIPS: generic: Add police related options to ocelot_defconfig Joergen Andreasen
2 siblings, 1 reply; 13+ messages in thread
From: Joergen Andreasen @ 2019-05-02 9:40 UTC (permalink / raw)
To: netdev
Cc: Joergen Andreasen, Jamal Hadi Salim, Cong Wang, Jiri Pirko,
Alexandre Belloni, Microchip Linux Driver Support,
David S. Miller, Ralf Baechle, Paul Burton, James Hogan,
linux-mips, linux-kernel
Hardware offloading a policer requires access to it's parameters.
This is now possible by including net/tc_act/tc_police.h.
Signed-off-by: Joergen Andreasen <joergen.andreasen@microchip.com>
---
include/net/tc_act/tc_police.h | 41 ++++++++++++++++++++++++++++++++++
net/sched/act_police.c | 27 +---------------------
2 files changed, 42 insertions(+), 26 deletions(-)
create mode 100644 include/net/tc_act/tc_police.h
diff --git a/include/net/tc_act/tc_police.h b/include/net/tc_act/tc_police.h
new file mode 100644
index 000000000000..052dc5f37aa9
--- /dev/null
+++ b/include/net/tc_act/tc_police.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __NET_TC_POLICE_H
+#define __NET_TC_POLICE_H
+
+#include <net/act_api.h>
+
+struct tcf_police_params {
+ int tcfp_result;
+ u32 tcfp_ewma_rate;
+ s64 tcfp_burst;
+ u32 tcfp_mtu;
+ s64 tcfp_mtu_ptoks;
+ struct psched_ratecfg rate;
+ bool rate_present;
+ struct psched_ratecfg peak;
+ bool peak_present;
+ struct rcu_head rcu;
+};
+
+struct tcf_police {
+ struct tc_action common;
+ struct tcf_police_params __rcu *params;
+
+ spinlock_t tcfp_lock ____cacheline_aligned_in_smp;
+ s64 tcfp_toks;
+ s64 tcfp_ptoks;
+ s64 tcfp_t_c;
+};
+
+#define to_police(pc) ((struct tcf_police *)pc)
+
+static inline bool is_tcf_police(const struct tc_action *a)
+{
+#ifdef CONFIG_NET_CLS_ACT
+ if (a->ops && a->ops->id == TCA_ID_POLICE)
+ return true;
+#endif
+ return false;
+}
+
+#endif /* __NET_TC_POLICE_H */
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index 2b8581f6ab51..5cb053f2c7b1 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -19,35 +19,10 @@
#include <linux/rtnetlink.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <net/act_api.h>
+#include <net/tc_act/tc_police.h>
#include <net/netlink.h>
#include <net/pkt_cls.h>
-struct tcf_police_params {
- int tcfp_result;
- u32 tcfp_ewma_rate;
- s64 tcfp_burst;
- u32 tcfp_mtu;
- s64 tcfp_mtu_ptoks;
- struct psched_ratecfg rate;
- bool rate_present;
- struct psched_ratecfg peak;
- bool peak_present;
- struct rcu_head rcu;
-};
-
-struct tcf_police {
- struct tc_action common;
- struct tcf_police_params __rcu *params;
-
- spinlock_t tcfp_lock ____cacheline_aligned_in_smp;
- s64 tcfp_toks;
- s64 tcfp_ptoks;
- s64 tcfp_t_c;
-};
-
-#define to_police(pc) ((struct tcf_police *)pc)
-
/* old policer structure from before tc actions */
struct tc_police_compat {
u32 index;
--
2.17.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH net-next 2/3] net: mscc: ocelot: Implement port policers via tc command
2019-05-02 9:40 [PATCH net-next 0/3] Add hw offload of TC police on MSCC ocelot Joergen Andreasen
2019-05-02 9:40 ` [PATCH net-next 1/3] net/sched: act_police: move police parameters into separate header file Joergen Andreasen
@ 2019-05-02 9:40 ` Joergen Andreasen
2019-05-02 12:32 ` Andrew Lunn
` (2 more replies)
2019-05-02 9:40 ` [PATCH net-next 3/3] MIPS: generic: Add police related options to ocelot_defconfig Joergen Andreasen
2 siblings, 3 replies; 13+ messages in thread
From: Joergen Andreasen @ 2019-05-02 9:40 UTC (permalink / raw)
To: netdev
Cc: Joergen Andreasen, Jamal Hadi Salim, Cong Wang, Jiri Pirko,
Alexandre Belloni, Microchip Linux Driver Support,
David S. Miller, Ralf Baechle, Paul Burton, James Hogan,
linux-mips, linux-kernel
Hardware offload of port policers are now supported via the tc command.
Supported police parameters are: rate, burst and overhead.
Example:
Add:
tc qdisc add dev eth3 handle ffff: ingress
tc filter add dev eth3 parent ffff: prio 1 handle 2 \
matchall skip_sw \
action police rate 100Mbit burst 10000 overhead 20
Show:
tc -s -d qdisc show dev eth3
tc -s -d filter show dev eth3 ingress
Delete:
tc filter del dev eth3 parent ffff: prio 1
tc qdisc del dev eth3 handle ffff: ingress
Signed-off-by: Joergen Andreasen <joergen.andreasen@microchip.com>
---
drivers/net/ethernet/mscc/Makefile | 2 +-
drivers/net/ethernet/mscc/ocelot.c | 6 +-
drivers/net/ethernet/mscc/ocelot.h | 3 +
drivers/net/ethernet/mscc/ocelot_police.c | 289 ++++++++++++++++++++++
drivers/net/ethernet/mscc/ocelot_police.h | 16 ++
drivers/net/ethernet/mscc/ocelot_tc.c | 151 +++++++++++
drivers/net/ethernet/mscc/ocelot_tc.h | 19 ++
7 files changed, 483 insertions(+), 3 deletions(-)
create mode 100644 drivers/net/ethernet/mscc/ocelot_police.c
create mode 100644 drivers/net/ethernet/mscc/ocelot_police.h
create mode 100644 drivers/net/ethernet/mscc/ocelot_tc.c
create mode 100644 drivers/net/ethernet/mscc/ocelot_tc.h
diff --git a/drivers/net/ethernet/mscc/Makefile b/drivers/net/ethernet/mscc/Makefile
index cb52a3b128ae..5e694dc1f7f8 100644
--- a/drivers/net/ethernet/mscc/Makefile
+++ b/drivers/net/ethernet/mscc/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: (GPL-2.0 OR MIT)
obj-$(CONFIG_MSCC_OCELOT_SWITCH) += mscc_ocelot_common.o
mscc_ocelot_common-y := ocelot.o ocelot_io.o
-mscc_ocelot_common-y += ocelot_regs.o
+mscc_ocelot_common-y += ocelot_regs.o ocelot_tc.o ocelot_police.o
obj-$(CONFIG_MSCC_OCELOT_SWITCH_OCELOT) += ocelot_board.o
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
index d715ef4fc92f..3ec7864d9dc8 100644
--- a/drivers/net/ethernet/mscc/ocelot.c
+++ b/drivers/net/ethernet/mscc/ocelot.c
@@ -943,6 +943,7 @@ static const struct net_device_ops ocelot_port_netdev_ops = {
.ndo_vlan_rx_kill_vid = ocelot_vlan_rx_kill_vid,
.ndo_set_features = ocelot_set_features,
.ndo_get_port_parent_id = ocelot_get_port_parent_id,
+ .ndo_setup_tc = ocelot_setup_tc,
};
static void ocelot_get_strings(struct net_device *netdev, u32 sset, u8 *data)
@@ -1663,8 +1664,9 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port,
dev->netdev_ops = &ocelot_port_netdev_ops;
dev->ethtool_ops = &ocelot_ethtool_ops;
- dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_RXFCS;
- dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
+ dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_RXFCS |
+ NETIF_F_HW_TC;
+ dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_TC;
memcpy(dev->dev_addr, ocelot->base_mac, ETH_ALEN);
dev->dev_addr[ETH_ALEN - 1] += port;
diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h
index ba3b3380b4d0..9514979fa075 100644
--- a/drivers/net/ethernet/mscc/ocelot.h
+++ b/drivers/net/ethernet/mscc/ocelot.h
@@ -22,6 +22,7 @@
#include "ocelot_rew.h"
#include "ocelot_sys.h"
#include "ocelot_qs.h"
+#include "ocelot_tc.h"
#define PGID_AGGR 64
#define PGID_SRC 80
@@ -458,6 +459,8 @@ struct ocelot_port {
phy_interface_t phy_mode;
struct phy *serdes;
+
+ struct ocelot_port_tc tc;
};
u32 __ocelot_read_ix(struct ocelot *ocelot, u32 reg, u32 offset);
diff --git a/drivers/net/ethernet/mscc/ocelot_police.c b/drivers/net/ethernet/mscc/ocelot_police.c
new file mode 100644
index 000000000000..b40382dcc748
--- /dev/null
+++ b/drivers/net/ethernet/mscc/ocelot_police.c
@@ -0,0 +1,289 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Microsemi Ocelot Switch TC driver
+ *
+ * Copyright (c) 2019 Microsemi Corporation
+ */
+
+#include "ocelot_police.h"
+
+#define MSCC_RC(expr) \
+ do { \
+ int __rc__ = (expr); \
+ if (__rc__ < 0) \
+ return __rc__; \
+ } \
+ while (0)
+
+/* The following two functions do the same as in iproute2 */
+#define TIME_UNITS_PER_SEC 1000000
+static unsigned int tc_core_tick2time(unsigned int tick)
+{
+ return (tick * (u32)PSCHED_TICKS2NS(1)) / 1000;
+}
+
+static unsigned int tc_calc_xmitsize(u64 rate, unsigned int ticks)
+{
+ return div_u64(rate * tc_core_tick2time(ticks), TIME_UNITS_PER_SEC);
+}
+
+enum mscc_qos_rate_mode {
+ MSCC_QOS_RATE_MODE_DISABLED, /* Policer/shaper disabled */
+ MSCC_QOS_RATE_MODE_LINE, /* Measure line rate in kbps incl. IPG */
+ MSCC_QOS_RATE_MODE_DATA, /* Measures data rate in kbps excl. IPG */
+ MSCC_QOS_RATE_MODE_FRAME, /* Measures frame rate in fps */
+ __MSCC_QOS_RATE_MODE_END,
+ NUM_MSCC_QOS_RATE_MODE = __MSCC_QOS_RATE_MODE_END,
+ MSCC_QOS_RATE_MODE_MAX = __MSCC_QOS_RATE_MODE_END - 1,
+};
+
+/* Round x divided by y to nearest integer. x and y are integers */
+#define MSCC_ROUNDING_DIVISION(x, y) (((x) + ((y) / 2)) / (y))
+
+/* Round x divided by y to nearest higher integer. x and y are integers */
+#define MSCC_DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y))
+
+/* Types for ANA:POL[0-192]:POL_MODE_CFG.FRM_MODE */
+#define POL_MODE_LINERATE 0 /* Incl IPG. Unit: 33 1/3 kbps, 4096 bytes */
+#define POL_MODE_DATARATE 1 /* Excl IPG. Unit: 33 1/3 kbps, 4096 bytes */
+#define POL_MODE_FRMRATE_HI 2 /* Unit: 33 1/3 fps, 32.8 frames */
+#define POL_MODE_FRMRATE_LO 3 /* Unit: 1/3 fps, 0.3 frames */
+
+/* Policer indexes */
+#define POL_IX_PORT 0 /* 0-11 : Port policers */
+#define POL_IX_QUEUE 32 /* 32-127 : Queue policers */
+
+/* Default policer order */
+#define POL_ORDER 0x1d3 /* Ocelot policer order: Serial (QoS -> Port -> VCAP) */
+
+struct qos_policer_conf {
+ enum mscc_qos_rate_mode mode;
+ bool dlb; /* Enable DLB (dual leaky bucket mode */
+ bool cf; /* Coupling flag (ignored in SLB mode) */
+ u32 cir; /* CIR in kbps/fps (ignored in SLB mode) */
+ u32 cbs; /* CBS in bytes/frames (ignored in SLB mode) */
+ u32 pir; /* PIR in kbps/fps */
+ u32 pbs; /* PBS in bytes/frames */
+ u8 ipg; /* Size of IPG when MSCC_QOS_RATE_MODE_LINE is chosen */
+};
+
+static int qos_policer_conf_set(struct ocelot_port *port,
+ u32 pol_ix,
+ struct qos_policer_conf *conf)
+{
+ struct ocelot *ocelot = port->ocelot;
+ u32 cir = 0, cbs = 0, pir = 0, pbs = 0;
+ u32 cf = 0, cir_ena = 0, frm_mode = 0;
+ u32 pbs_max = 0, cbs_max = 0;
+ bool cir_discard = 0, pir_discard = 0;
+ u8 ipg = 20;
+ u32 value;
+
+ pir = conf->pir;
+ pbs = conf->pbs;
+
+ switch (conf->mode) {
+ case MSCC_QOS_RATE_MODE_LINE:
+ case MSCC_QOS_RATE_MODE_DATA:
+ if (conf->mode == MSCC_QOS_RATE_MODE_LINE) {
+ frm_mode = POL_MODE_LINERATE;
+ ipg = min_t(u8, GENMASK(4, 0), conf->ipg);
+ } else {
+ frm_mode = POL_MODE_DATARATE;
+ }
+ if (conf->dlb) {
+ cir_ena = 1;
+ cir = conf->cir;
+ cbs = conf->cbs;
+ if (cir == 0 && cbs == 0) {
+ /* Discard cir frames */
+ cir_discard = 1;
+ } else {
+ cir = MSCC_DIV_ROUND_UP(cir, 100);
+ cir *= 3; /* 33 1/3 kbps */
+ cbs = MSCC_DIV_ROUND_UP(cbs, 4096);
+ cbs = (cbs ? cbs : 1); /* No zero burst size */
+ cbs_max = 60; /* Limit burst size */
+ cf = conf->cf;
+ if (cf)
+ pir += conf->cir;
+ }
+ }
+ if (pir == 0 && pbs == 0) {
+ /* Discard PIR frames */
+ pir_discard = 1;
+ } else {
+ pir = MSCC_DIV_ROUND_UP(pir, 100);
+ pir *= 3; /* 33 1/3 kbps */
+ pbs = MSCC_DIV_ROUND_UP(pbs, 4096);
+ pbs = (pbs ? pbs : 1); /* No zero burst size */
+ pbs_max = 60; /* Limit burst size */
+ }
+ break;
+ case MSCC_QOS_RATE_MODE_FRAME:
+ if (pir >= 100) {
+ frm_mode = POL_MODE_FRMRATE_HI;
+ pir = MSCC_DIV_ROUND_UP(pir, 100);
+ pir *= 3; /* 33 1/3 fps */
+ pbs = (pbs * 10) / 328; /* 32.8 frames */
+ pbs = (pbs ? pbs : 1); /* No zero burst size */
+ pbs_max = GENMASK(6, 0); /* Limit burst size */
+ } else {
+ frm_mode = POL_MODE_FRMRATE_LO;
+ if (pir == 0 && pbs == 0) {
+ /* Discard all frames */
+ pir_discard = 1;
+ cir_discard = 1;
+ } else {
+ pir *= 3; /* 1/3 fps */
+ pbs = (pbs * 10) / 3; /* 0.3 frames */
+ pbs = (pbs ? pbs : 1); /* No zero burst size */
+ pbs_max = 61; /* Limit burst size */
+ }
+ }
+ break;
+ default: /* MSCC_QOS_RATE_MODE_DISABLED */
+ /* Disable policer using maximum rate and zero burst */
+ pir = GENMASK(15, 0);
+ pbs = 0;
+ break;
+ }
+
+ /* Limit to maximum values */
+ pir = min_t(u32, GENMASK(15, 0), pir);
+ cir = min_t(u32, GENMASK(15, 0), cir);
+ pbs = min_t(u32, pbs_max, pbs);
+ cbs = min_t(u32, cbs_max, cbs);
+
+ value = (ANA_POL_MODE_CFG_IPG_SIZE(ipg) |
+ ANA_POL_MODE_CFG_FRM_MODE(frm_mode) |
+ (cf ? ANA_POL_MODE_CFG_DLB_COUPLED : 0) |
+ (cir_ena ? ANA_POL_MODE_CFG_CIR_ENA : 0) |
+ ANA_POL_MODE_CFG_OVERSHOOT_ENA);
+
+ ocelot_write_gix(ocelot,
+ value,
+ ANA_POL_MODE_CFG,
+ pol_ix);
+
+ ocelot_write_gix(ocelot,
+ ANA_POL_PIR_CFG_PIR_RATE(pir) |
+ ANA_POL_PIR_CFG_PIR_BURST(pbs),
+ ANA_POL_PIR_CFG,
+ pol_ix);
+
+ ocelot_write_gix(ocelot,
+ (pir_discard ? GENMASK(22, 0) : 0),
+ ANA_POL_PIR_STATE,
+ pol_ix);
+
+ ocelot_write_gix(ocelot,
+ ANA_POL_CIR_CFG_CIR_RATE(cir) |
+ ANA_POL_CIR_CFG_CIR_BURST(cbs),
+ ANA_POL_CIR_CFG,
+ pol_ix);
+
+ ocelot_write_gix(ocelot,
+ (cir_discard ? GENMASK(22, 0) : 0),
+ ANA_POL_CIR_STATE,
+ pol_ix);
+
+ return 0;
+}
+
+int ocelot_port_policer_add(struct ocelot_port *port,
+ struct tcf_police *p)
+{
+ struct ocelot *ocelot = port->ocelot;
+ struct qos_policer_conf pp;
+
+ if (!p)
+ return -EINVAL;
+
+ netdev_dbg(port->dev,
+ "result %d ewma_rate %u burst %lld mtu %u mtu_pktoks %lld\n",
+ p->params->tcfp_result,
+ p->params->tcfp_ewma_rate,
+ p->params->tcfp_burst,
+ p->params->tcfp_mtu,
+ p->params->tcfp_mtu_ptoks);
+
+ if (p->params->rate_present)
+ netdev_dbg(port->dev,
+ "rate: rate %llu mult %u over %u link %u shift %u\n",
+ p->params->rate.rate_bytes_ps,
+ p->params->rate.mult,
+ p->params->rate.overhead,
+ p->params->rate.linklayer,
+ p->params->rate.shift);
+
+ if (p->params->peak_present)
+ netdev_dbg(port->dev,
+ "peak: rate %llu mult %u over %u link %u shift %u\n",
+ p->params->peak.rate_bytes_ps,
+ p->params->peak.mult,
+ p->params->peak.overhead,
+ p->params->peak.linklayer,
+ p->params->peak.shift);
+
+ memset(&pp, 0, sizeof(pp));
+
+ if (p->params->tcfp_ewma_rate) {
+ netdev_err(port->dev, "tcfp_ewma_rate is not supported\n");
+ return -EOPNOTSUPP;
+ }
+ if (p->params->peak_present) {
+ netdev_err(port->dev, "peakrate is not supported\n");
+ return -EOPNOTSUPP;
+ }
+ if (!p->params->rate_present) {
+ netdev_err(port->dev, "rate not specified\n");
+ return -EINVAL;
+ }
+ if (p->params->rate.overhead) {
+ pp.mode = MSCC_QOS_RATE_MODE_LINE;
+ pp.ipg = p->params->rate.overhead;
+ } else {
+ pp.mode = MSCC_QOS_RATE_MODE_DATA;
+ }
+
+ pp.pir = (u32)div_u64(p->params->rate.rate_bytes_ps, 1000) * 8;
+ pp.pbs = tc_calc_xmitsize(p->params->rate.rate_bytes_ps,
+ PSCHED_NS2TICKS(p->params->tcfp_burst));
+ netdev_dbg(port->dev,
+ "%s: port %u pir %u kbps, pbs %u bytes, ipg %u bytes\n",
+ __func__, port->chip_port, pp.pir, pp.pbs, pp.ipg);
+
+ MSCC_RC(qos_policer_conf_set(port, POL_IX_PORT + port->chip_port, &pp));
+
+ ocelot_rmw_gix(ocelot,
+ ANA_PORT_POL_CFG_PORT_POL_ENA |
+ ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
+ ANA_PORT_POL_CFG_PORT_POL_ENA |
+ ANA_PORT_POL_CFG_POL_ORDER_M,
+ ANA_PORT_POL_CFG,
+ port->chip_port);
+
+ return 0;
+}
+
+int ocelot_port_policer_del(struct ocelot_port *port)
+{
+ struct ocelot *ocelot = port->ocelot;
+ struct qos_policer_conf pp;
+
+ netdev_dbg(port->dev, "%s: port %u\n", __func__, port->chip_port);
+
+ memset(&pp, 0, sizeof(pp));
+ pp.mode = MSCC_QOS_RATE_MODE_DISABLED;
+
+ MSCC_RC(qos_policer_conf_set(port, POL_IX_PORT + port->chip_port, &pp));
+
+ ocelot_rmw_gix(ocelot, 0 |
+ ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
+ ANA_PORT_POL_CFG_PORT_POL_ENA |
+ ANA_PORT_POL_CFG_POL_ORDER_M,
+ ANA_PORT_POL_CFG,
+ port->chip_port);
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/mscc/ocelot_police.h b/drivers/net/ethernet/mscc/ocelot_police.h
new file mode 100644
index 000000000000..bc4dc34c684e
--- /dev/null
+++ b/drivers/net/ethernet/mscc/ocelot_police.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/* Microsemi Ocelot Switch driver
+ *
+ * Copyright (c) 2019 Microsemi Corporation
+ */
+
+#ifndef _MSCC_OCELOT_POLICE_H_
+#define _MSCC_OCELOT_POLICE_H_
+
+#include <net/tc_act/tc_police.h>
+#include "ocelot.h"
+
+int ocelot_port_policer_add(struct ocelot_port *port, struct tcf_police *p);
+int ocelot_port_policer_del(struct ocelot_port *port);
+
+#endif /* _MSCC_OCELOT_POLICE_H_ */
diff --git a/drivers/net/ethernet/mscc/ocelot_tc.c b/drivers/net/ethernet/mscc/ocelot_tc.c
new file mode 100644
index 000000000000..97b0a7bf5d06
--- /dev/null
+++ b/drivers/net/ethernet/mscc/ocelot_tc.c
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/* Microsemi Ocelot Switch TC driver
+ *
+ * Copyright (c) 2019 Microsemi Corporation
+ */
+
+#include "ocelot_tc.h"
+#include "ocelot_police.h"
+#include <net/pkt_cls.h>
+
+static int ocelot_setup_tc_cls_matchall(struct ocelot_port *port,
+ struct tc_cls_matchall_offload *f,
+ bool ingress)
+{
+ const struct tc_action *a;
+ int err;
+
+ netdev_dbg(port->dev,
+ "%s: port %u cookie %lu\n",
+ __func__, port->chip_port, f->cookie);
+ switch (f->command) {
+ case TC_CLSMATCHALL_REPLACE:
+ if (!tcf_exts_has_one_action(f->exts)) {
+ netdev_err(port->dev, "only one action is supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ a = tcf_exts_first_action(f->exts);
+
+ if (is_tcf_police(a)) {
+ if (!ingress)
+ return -EOPNOTSUPP;
+
+ if (port->tc.police_id &&
+ port->tc.police_id != f->cookie) {
+ netdev_warn(port->dev,
+ "Only one policer per port is supported\n");
+ return -EEXIST;
+ }
+
+ err = ocelot_port_policer_add(port, to_police(a));
+ if (err) {
+ netdev_err(port->dev, "Could not add policer\n");
+ return err;
+ }
+ port->tc.police_id = f->cookie;
+ return 0;
+ } else {
+ return -EOPNOTSUPP;
+ }
+ case TC_CLSMATCHALL_DESTROY:
+ if (port->tc.police_id != f->cookie)
+ return -ENOENT;
+
+ err = ocelot_port_policer_del(port);
+ if (err) {
+ netdev_err(port->dev, "Could not delete policer\n");
+ return err;
+ }
+ port->tc.police_id = 0;
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int ocelot_setup_tc_block_cb(enum tc_setup_type type,
+ void *type_data,
+ void *cb_priv, bool ingress)
+{
+ struct ocelot_port *port = cb_priv;
+
+ if (!tc_cls_can_offload_and_chain0(port->dev, type_data))
+ return -EOPNOTSUPP;
+
+ switch (type) {
+ case TC_SETUP_CLSMATCHALL:
+ netdev_dbg(port->dev, "tc_block_cb: TC_SETUP_CLSMATCHALL %s\n",
+ ingress ? "ingress" : "egress");
+
+ return ocelot_setup_tc_cls_matchall(port, type_data, ingress);
+ case TC_SETUP_CLSFLOWER:
+ netdev_dbg(port->dev, "tc_block_cb: TC_SETUP_CLSFLOWER %s\n",
+ ingress ? "ingress" : "egress");
+
+ return -EOPNOTSUPP;
+ default:
+ netdev_dbg(port->dev, "tc_block_cb: type %d %s\n",
+ type,
+ ingress ? "ingress" : "egress");
+
+ return -EOPNOTSUPP;
+ }
+}
+
+static int ocelot_setup_tc_block_cb_ig(enum tc_setup_type type,
+ void *type_data,
+ void *cb_priv)
+{
+ return ocelot_setup_tc_block_cb(type, type_data,
+ cb_priv, true);
+}
+
+static int ocelot_setup_tc_block_cb_eg(enum tc_setup_type type,
+ void *type_data,
+ void *cb_priv)
+{
+ return ocelot_setup_tc_block_cb(type, type_data,
+ cb_priv, false);
+}
+
+static int ocelot_setup_tc_block(struct ocelot_port *port,
+ struct tc_block_offload *f)
+{
+ tc_setup_cb_t *cb;
+
+ netdev_dbg(port->dev, "tc_block command %d, binder_type %d\n",
+ f->command, f->binder_type);
+
+ if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
+ cb = ocelot_setup_tc_block_cb_ig;
+ else if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
+ cb = ocelot_setup_tc_block_cb_eg;
+ else
+ return -EOPNOTSUPP;
+
+ switch (f->command) {
+ case TC_BLOCK_BIND:
+ return tcf_block_cb_register(f->block, cb, port,
+ port, f->extack);
+ case TC_BLOCK_UNBIND:
+ tcf_block_cb_unregister(f->block, cb, port);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+int ocelot_setup_tc(struct net_device *dev, enum tc_setup_type type,
+ void *type_data)
+{
+ struct ocelot_port *port = netdev_priv(dev);
+
+ switch (type) {
+ case TC_SETUP_BLOCK:
+ return ocelot_setup_tc_block(port, type_data);
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
diff --git a/drivers/net/ethernet/mscc/ocelot_tc.h b/drivers/net/ethernet/mscc/ocelot_tc.h
new file mode 100644
index 000000000000..c905b98b6b4c
--- /dev/null
+++ b/drivers/net/ethernet/mscc/ocelot_tc.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/* Microsemi Ocelot Switch driver
+ *
+ * Copyright (c) 2019 Microsemi Corporation
+ */
+
+#ifndef _MSCC_OCELOT_TC_H_
+#define _MSCC_OCELOT_TC_H_
+
+#include <linux/netdevice.h>
+
+struct ocelot_port_tc {
+ unsigned long police_id;
+};
+
+int ocelot_setup_tc(struct net_device *dev, enum tc_setup_type type,
+ void *type_data);
+
+#endif /* _MSCC_OCELOT_TC_H_ */
--
2.17.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH net-next 3/3] MIPS: generic: Add police related options to ocelot_defconfig
2019-05-02 9:40 [PATCH net-next 0/3] Add hw offload of TC police on MSCC ocelot Joergen Andreasen
2019-05-02 9:40 ` [PATCH net-next 1/3] net/sched: act_police: move police parameters into separate header file Joergen Andreasen
2019-05-02 9:40 ` [PATCH net-next 2/3] net: mscc: ocelot: Implement port policers via tc command Joergen Andreasen
@ 2019-05-02 9:40 ` Joergen Andreasen
2019-05-02 16:27 ` Alexandre Belloni
2 siblings, 1 reply; 13+ messages in thread
From: Joergen Andreasen @ 2019-05-02 9:40 UTC (permalink / raw)
To: netdev
Cc: Joergen Andreasen, Jamal Hadi Salim, Cong Wang, Jiri Pirko,
Alexandre Belloni, Microchip Linux Driver Support,
David S. Miller, Ralf Baechle, Paul Burton, James Hogan,
linux-mips, linux-kernel
Add default support for ingress qdisc, matchall classification
and police action on MSCC Ocelot.
Signed-off-by: Joergen Andreasen <joergen.andreasen@microchip.com>
---
arch/mips/configs/generic/board-ocelot.config | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/arch/mips/configs/generic/board-ocelot.config b/arch/mips/configs/generic/board-ocelot.config
index 5e53b4bc47f1..5c7360dd819c 100644
--- a/arch/mips/configs/generic/board-ocelot.config
+++ b/arch/mips/configs/generic/board-ocelot.config
@@ -25,6 +25,13 @@ CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_NETDEVICES=y
CONFIG_NET_SWITCHDEV=y
CONFIG_NET_DSA=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_MATCHALL=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+CONFIG_NET_ACT_GACT=y
+
CONFIG_MSCC_OCELOT_SWITCH=y
CONFIG_MSCC_OCELOT_SWITCH_OCELOT=y
CONFIG_MDIO_MSCC_MIIM=y
--
2.17.1
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH net-next 2/3] net: mscc: ocelot: Implement port policers via tc command
2019-05-02 9:40 ` [PATCH net-next 2/3] net: mscc: ocelot: Implement port policers via tc command Joergen Andreasen
@ 2019-05-02 12:32 ` Andrew Lunn
2019-05-03 11:23 ` Joergen Andreasen
2019-05-02 20:36 ` Jiri Pirko
2019-05-04 13:07 ` Jiri Pirko
2 siblings, 1 reply; 13+ messages in thread
From: Andrew Lunn @ 2019-05-02 12:32 UTC (permalink / raw)
To: Joergen Andreasen
Cc: netdev, Jamal Hadi Salim, Cong Wang, Jiri Pirko,
Alexandre Belloni, Microchip Linux Driver Support,
David S. Miller, Ralf Baechle, Paul Burton, James Hogan,
linux-mips, linux-kernel
Hi Joergen
> +
> +#define MSCC_RC(expr) \
> + do { \
> + int __rc__ = (expr); \
> + if (__rc__ < 0) \
> + return __rc__; \
> + } \
> + while (0)
I'm sure checkpatch warned about this. A return inside a macros is a
bad idea. I inherited code doing this, and broke it when adding
locking, because it was not obvious there was a return.
> +
> +/* The following two functions do the same as in iproute2 */
> +#define TIME_UNITS_PER_SEC 1000000
> +static unsigned int tc_core_tick2time(unsigned int tick)
> +{
> + return (tick * (u32)PSCHED_TICKS2NS(1)) / 1000;
> +}
> +
> +static unsigned int tc_calc_xmitsize(u64 rate, unsigned int ticks)
> +{
> + return div_u64(rate * tc_core_tick2time(ticks), TIME_UNITS_PER_SEC);
> +}
Should these but put somewhere others can use them?
> +
> +enum mscc_qos_rate_mode {
> + MSCC_QOS_RATE_MODE_DISABLED, /* Policer/shaper disabled */
> + MSCC_QOS_RATE_MODE_LINE, /* Measure line rate in kbps incl. IPG */
> + MSCC_QOS_RATE_MODE_DATA, /* Measures data rate in kbps excl. IPG */
> + MSCC_QOS_RATE_MODE_FRAME, /* Measures frame rate in fps */
> + __MSCC_QOS_RATE_MODE_END,
> + NUM_MSCC_QOS_RATE_MODE = __MSCC_QOS_RATE_MODE_END,
> + MSCC_QOS_RATE_MODE_MAX = __MSCC_QOS_RATE_MODE_END - 1,
> +};
> +
> +/* Round x divided by y to nearest integer. x and y are integers */
> +#define MSCC_ROUNDING_DIVISION(x, y) (((x) + ((y) / 2)) / (y))
linux/kernel.h defines DIV_ROUND_UP(). Maybe add DIV_ROUND_DOWN()?
> +
> +/* Round x divided by y to nearest higher integer. x and y are integers */
> +#define MSCC_DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y))
DIV_ROUND_UP() ?
> + /* Limit to maximum values */
> + pir = min_t(u32, GENMASK(15, 0), pir);
> + cir = min_t(u32, GENMASK(15, 0), cir);
> + pbs = min_t(u32, pbs_max, pbs);
> + cbs = min_t(u32, cbs_max, cbs);
If it does need to limit, maybe return -EOPNOTSUPP?
> +int ocelot_port_policer_add(struct ocelot_port *port,
> + struct tcf_police *p)
> +{
> + struct ocelot *ocelot = port->ocelot;
> + struct qos_policer_conf pp;
> +
> + if (!p)
> + return -EINVAL;
> +
> + netdev_dbg(port->dev,
> + "result %d ewma_rate %u burst %lld mtu %u mtu_pktoks %lld\n",
> + p->params->tcfp_result,
> + p->params->tcfp_ewma_rate,
> + p->params->tcfp_burst,
> + p->params->tcfp_mtu,
> + p->params->tcfp_mtu_ptoks);
> +
> + if (p->params->rate_present)
> + netdev_dbg(port->dev,
> + "rate: rate %llu mult %u over %u link %u shift %u\n",
> + p->params->rate.rate_bytes_ps,
> + p->params->rate.mult,
> + p->params->rate.overhead,
> + p->params->rate.linklayer,
> + p->params->rate.shift);
> +
> + if (p->params->peak_present)
> + netdev_dbg(port->dev,
> + "peak: rate %llu mult %u over %u link %u shift %u\n",
> + p->params->peak.rate_bytes_ps,
> + p->params->peak.mult,
> + p->params->peak.overhead,
> + p->params->peak.linklayer,
> + p->params->peak.shift);
> +
> + memset(&pp, 0, sizeof(pp));
Rather than memset, you can do:
struct qos_policer_conf pp = { 0 };
Andrew
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net-next 3/3] MIPS: generic: Add police related options to ocelot_defconfig
2019-05-02 9:40 ` [PATCH net-next 3/3] MIPS: generic: Add police related options to ocelot_defconfig Joergen Andreasen
@ 2019-05-02 16:27 ` Alexandre Belloni
2019-05-03 10:47 ` Joergen Andreasen
0 siblings, 1 reply; 13+ messages in thread
From: Alexandre Belloni @ 2019-05-02 16:27 UTC (permalink / raw)
To: Joergen Andreasen
Cc: netdev, Jamal Hadi Salim, Cong Wang, Jiri Pirko,
Microchip Linux Driver Support, David S. Miller, Ralf Baechle,
Paul Burton, James Hogan, linux-mips, linux-kernel
Hi Joergen,
On 02/05/2019 11:40:29+0200, Joergen Andreasen wrote:
> Add default support for ingress qdisc, matchall classification
> and police action on MSCC Ocelot.
>
This patch should be separated from the series as this doesn't have any
dependencies and should go through the MIPS tree.
> Signed-off-by: Joergen Andreasen <joergen.andreasen@microchip.com>
> ---
> arch/mips/configs/generic/board-ocelot.config | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/arch/mips/configs/generic/board-ocelot.config b/arch/mips/configs/generic/board-ocelot.config
> index 5e53b4bc47f1..5c7360dd819c 100644
> --- a/arch/mips/configs/generic/board-ocelot.config
> +++ b/arch/mips/configs/generic/board-ocelot.config
> @@ -25,6 +25,13 @@ CONFIG_SERIAL_OF_PLATFORM=y
> CONFIG_NETDEVICES=y
> CONFIG_NET_SWITCHDEV=y
> CONFIG_NET_DSA=y
> +CONFIG_NET_SCHED=y
> +CONFIG_NET_SCH_INGRESS=y
> +CONFIG_NET_CLS_MATCHALL=y
> +CONFIG_NET_CLS_ACT=y
> +CONFIG_NET_ACT_POLICE=y
> +CONFIG_NET_ACT_GACT=y
> +
> CONFIG_MSCC_OCELOT_SWITCH=y
> CONFIG_MSCC_OCELOT_SWITCH_OCELOT=y
> CONFIG_MDIO_MSCC_MIIM=y
> --
> 2.17.1
>
--
Alexandre Belloni, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net-next 2/3] net: mscc: ocelot: Implement port policers via tc command
2019-05-02 9:40 ` [PATCH net-next 2/3] net: mscc: ocelot: Implement port policers via tc command Joergen Andreasen
2019-05-02 12:32 ` Andrew Lunn
@ 2019-05-02 20:36 ` Jiri Pirko
2019-05-03 11:38 ` Joergen Andreasen
2019-05-04 13:07 ` Jiri Pirko
2 siblings, 1 reply; 13+ messages in thread
From: Jiri Pirko @ 2019-05-02 20:36 UTC (permalink / raw)
To: Joergen Andreasen
Cc: netdev, Jamal Hadi Salim, Cong Wang, Alexandre Belloni,
Microchip Linux Driver Support, David S. Miller, Ralf Baechle,
Paul Burton, James Hogan, linux-mips, linux-kernel
Thu, May 02, 2019 at 11:40:28AM CEST, joergen.andreasen@microchip.com wrote:
>Hardware offload of port policers are now supported via the tc command.
>Supported police parameters are: rate, burst and overhead.
Interesting, you offload matchall cls, yet you don't mention it at all.
Please, do it.
>
>Example:
>
>Add:
>tc qdisc add dev eth3 handle ffff: ingress
>tc filter add dev eth3 parent ffff: prio 1 handle 2 \
> matchall skip_sw \
> action police rate 100Mbit burst 10000 overhead 20
>
>Show:
>tc -s -d qdisc show dev eth3
>tc -s -d filter show dev eth3 ingress
>
>Delete:
>tc filter del dev eth3 parent ffff: prio 1
>tc qdisc del dev eth3 handle ffff: ingress
>
>Signed-off-by: Joergen Andreasen <joergen.andreasen@microchip.com>
>---
> drivers/net/ethernet/mscc/Makefile | 2 +-
> drivers/net/ethernet/mscc/ocelot.c | 6 +-
> drivers/net/ethernet/mscc/ocelot.h | 3 +
> drivers/net/ethernet/mscc/ocelot_police.c | 289 ++++++++++++++++++++++
> drivers/net/ethernet/mscc/ocelot_police.h | 16 ++
> drivers/net/ethernet/mscc/ocelot_tc.c | 151 +++++++++++
> drivers/net/ethernet/mscc/ocelot_tc.h | 19 ++
> 7 files changed, 483 insertions(+), 3 deletions(-)
> create mode 100644 drivers/net/ethernet/mscc/ocelot_police.c
> create mode 100644 drivers/net/ethernet/mscc/ocelot_police.h
> create mode 100644 drivers/net/ethernet/mscc/ocelot_tc.c
> create mode 100644 drivers/net/ethernet/mscc/ocelot_tc.h
>
>diff --git a/drivers/net/ethernet/mscc/Makefile b/drivers/net/ethernet/mscc/Makefile
>index cb52a3b128ae..5e694dc1f7f8 100644
>--- a/drivers/net/ethernet/mscc/Makefile
>+++ b/drivers/net/ethernet/mscc/Makefile
>@@ -1,5 +1,5 @@
> # SPDX-License-Identifier: (GPL-2.0 OR MIT)
> obj-$(CONFIG_MSCC_OCELOT_SWITCH) += mscc_ocelot_common.o
> mscc_ocelot_common-y := ocelot.o ocelot_io.o
>-mscc_ocelot_common-y += ocelot_regs.o
>+mscc_ocelot_common-y += ocelot_regs.o ocelot_tc.o ocelot_police.o
> obj-$(CONFIG_MSCC_OCELOT_SWITCH_OCELOT) += ocelot_board.o
>diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
>index d715ef4fc92f..3ec7864d9dc8 100644
>--- a/drivers/net/ethernet/mscc/ocelot.c
>+++ b/drivers/net/ethernet/mscc/ocelot.c
>@@ -943,6 +943,7 @@ static const struct net_device_ops ocelot_port_netdev_ops = {
> .ndo_vlan_rx_kill_vid = ocelot_vlan_rx_kill_vid,
> .ndo_set_features = ocelot_set_features,
> .ndo_get_port_parent_id = ocelot_get_port_parent_id,
>+ .ndo_setup_tc = ocelot_setup_tc,
> };
>
> static void ocelot_get_strings(struct net_device *netdev, u32 sset, u8 *data)
>@@ -1663,8 +1664,9 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port,
> dev->netdev_ops = &ocelot_port_netdev_ops;
> dev->ethtool_ops = &ocelot_ethtool_ops;
>
>- dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_RXFCS;
>- dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
>+ dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_RXFCS |
>+ NETIF_F_HW_TC;
>+ dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_TC;
>
> memcpy(dev->dev_addr, ocelot->base_mac, ETH_ALEN);
> dev->dev_addr[ETH_ALEN - 1] += port;
>diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h
>index ba3b3380b4d0..9514979fa075 100644
>--- a/drivers/net/ethernet/mscc/ocelot.h
>+++ b/drivers/net/ethernet/mscc/ocelot.h
>@@ -22,6 +22,7 @@
> #include "ocelot_rew.h"
> #include "ocelot_sys.h"
> #include "ocelot_qs.h"
>+#include "ocelot_tc.h"
>
> #define PGID_AGGR 64
> #define PGID_SRC 80
>@@ -458,6 +459,8 @@ struct ocelot_port {
>
> phy_interface_t phy_mode;
> struct phy *serdes;
>+
>+ struct ocelot_port_tc tc;
> };
>
> u32 __ocelot_read_ix(struct ocelot *ocelot, u32 reg, u32 offset);
>diff --git a/drivers/net/ethernet/mscc/ocelot_police.c b/drivers/net/ethernet/mscc/ocelot_police.c
>new file mode 100644
>index 000000000000..b40382dcc748
>--- /dev/null
>+++ b/drivers/net/ethernet/mscc/ocelot_police.c
>@@ -0,0 +1,289 @@
>+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
>+/* Microsemi Ocelot Switch TC driver
"TC driver" ? That sounds quite odd...
>+ *
>+ * Copyright (c) 2019 Microsemi Corporation
>+ */
>+
>+#include "ocelot_police.h"
>+
>+#define MSCC_RC(expr) \
>+ do { \
>+ int __rc__ = (expr); \
>+ if (__rc__ < 0) \
>+ return __rc__; \
>+ } \
>+ while (0)
Please don't use macros like this.
>+
>+/* The following two functions do the same as in iproute2 */
>+#define TIME_UNITS_PER_SEC 1000000
>+static unsigned int tc_core_tick2time(unsigned int tick)
>+{
>+ return (tick * (u32)PSCHED_TICKS2NS(1)) / 1000;
>+}
>+
>+static unsigned int tc_calc_xmitsize(u64 rate, unsigned int ticks)
>+{
>+ return div_u64(rate * tc_core_tick2time(ticks), TIME_UNITS_PER_SEC);
>+}
>+
>+enum mscc_qos_rate_mode {
>+ MSCC_QOS_RATE_MODE_DISABLED, /* Policer/shaper disabled */
>+ MSCC_QOS_RATE_MODE_LINE, /* Measure line rate in kbps incl. IPG */
>+ MSCC_QOS_RATE_MODE_DATA, /* Measures data rate in kbps excl. IPG */
>+ MSCC_QOS_RATE_MODE_FRAME, /* Measures frame rate in fps */
>+ __MSCC_QOS_RATE_MODE_END,
>+ NUM_MSCC_QOS_RATE_MODE = __MSCC_QOS_RATE_MODE_END,
>+ MSCC_QOS_RATE_MODE_MAX = __MSCC_QOS_RATE_MODE_END - 1,
>+};
>+
>+/* Round x divided by y to nearest integer. x and y are integers */
>+#define MSCC_ROUNDING_DIVISION(x, y) (((x) + ((y) / 2)) / (y))
>+
>+/* Round x divided by y to nearest higher integer. x and y are integers */
>+#define MSCC_DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y))
>+
>+/* Types for ANA:POL[0-192]:POL_MODE_CFG.FRM_MODE */
>+#define POL_MODE_LINERATE 0 /* Incl IPG. Unit: 33 1/3 kbps, 4096 bytes */
>+#define POL_MODE_DATARATE 1 /* Excl IPG. Unit: 33 1/3 kbps, 4096 bytes */
>+#define POL_MODE_FRMRATE_HI 2 /* Unit: 33 1/3 fps, 32.8 frames */
>+#define POL_MODE_FRMRATE_LO 3 /* Unit: 1/3 fps, 0.3 frames */
>+
>+/* Policer indexes */
>+#define POL_IX_PORT 0 /* 0-11 : Port policers */
>+#define POL_IX_QUEUE 32 /* 32-127 : Queue policers */
>+
>+/* Default policer order */
>+#define POL_ORDER 0x1d3 /* Ocelot policer order: Serial (QoS -> Port -> VCAP) */
>+
>+struct qos_policer_conf {
>+ enum mscc_qos_rate_mode mode;
>+ bool dlb; /* Enable DLB (dual leaky bucket mode */
>+ bool cf; /* Coupling flag (ignored in SLB mode) */
>+ u32 cir; /* CIR in kbps/fps (ignored in SLB mode) */
>+ u32 cbs; /* CBS in bytes/frames (ignored in SLB mode) */
>+ u32 pir; /* PIR in kbps/fps */
>+ u32 pbs; /* PBS in bytes/frames */
>+ u8 ipg; /* Size of IPG when MSCC_QOS_RATE_MODE_LINE is chosen */
>+};
>+
>+static int qos_policer_conf_set(struct ocelot_port *port,
>+ u32 pol_ix,
>+ struct qos_policer_conf *conf)
>+{
>+ struct ocelot *ocelot = port->ocelot;
>+ u32 cir = 0, cbs = 0, pir = 0, pbs = 0;
>+ u32 cf = 0, cir_ena = 0, frm_mode = 0;
>+ u32 pbs_max = 0, cbs_max = 0;
>+ bool cir_discard = 0, pir_discard = 0;
>+ u8 ipg = 20;
>+ u32 value;
>+
>+ pir = conf->pir;
>+ pbs = conf->pbs;
>+
>+ switch (conf->mode) {
>+ case MSCC_QOS_RATE_MODE_LINE:
>+ case MSCC_QOS_RATE_MODE_DATA:
>+ if (conf->mode == MSCC_QOS_RATE_MODE_LINE) {
>+ frm_mode = POL_MODE_LINERATE;
>+ ipg = min_t(u8, GENMASK(4, 0), conf->ipg);
>+ } else {
>+ frm_mode = POL_MODE_DATARATE;
>+ }
>+ if (conf->dlb) {
>+ cir_ena = 1;
>+ cir = conf->cir;
>+ cbs = conf->cbs;
>+ if (cir == 0 && cbs == 0) {
>+ /* Discard cir frames */
>+ cir_discard = 1;
>+ } else {
>+ cir = MSCC_DIV_ROUND_UP(cir, 100);
>+ cir *= 3; /* 33 1/3 kbps */
>+ cbs = MSCC_DIV_ROUND_UP(cbs, 4096);
>+ cbs = (cbs ? cbs : 1); /* No zero burst size */
>+ cbs_max = 60; /* Limit burst size */
>+ cf = conf->cf;
>+ if (cf)
>+ pir += conf->cir;
>+ }
>+ }
>+ if (pir == 0 && pbs == 0) {
>+ /* Discard PIR frames */
>+ pir_discard = 1;
>+ } else {
>+ pir = MSCC_DIV_ROUND_UP(pir, 100);
>+ pir *= 3; /* 33 1/3 kbps */
>+ pbs = MSCC_DIV_ROUND_UP(pbs, 4096);
>+ pbs = (pbs ? pbs : 1); /* No zero burst size */
>+ pbs_max = 60; /* Limit burst size */
>+ }
>+ break;
>+ case MSCC_QOS_RATE_MODE_FRAME:
>+ if (pir >= 100) {
>+ frm_mode = POL_MODE_FRMRATE_HI;
>+ pir = MSCC_DIV_ROUND_UP(pir, 100);
>+ pir *= 3; /* 33 1/3 fps */
>+ pbs = (pbs * 10) / 328; /* 32.8 frames */
>+ pbs = (pbs ? pbs : 1); /* No zero burst size */
>+ pbs_max = GENMASK(6, 0); /* Limit burst size */
>+ } else {
>+ frm_mode = POL_MODE_FRMRATE_LO;
>+ if (pir == 0 && pbs == 0) {
>+ /* Discard all frames */
>+ pir_discard = 1;
>+ cir_discard = 1;
>+ } else {
>+ pir *= 3; /* 1/3 fps */
>+ pbs = (pbs * 10) / 3; /* 0.3 frames */
>+ pbs = (pbs ? pbs : 1); /* No zero burst size */
>+ pbs_max = 61; /* Limit burst size */
>+ }
>+ }
>+ break;
>+ default: /* MSCC_QOS_RATE_MODE_DISABLED */
>+ /* Disable policer using maximum rate and zero burst */
>+ pir = GENMASK(15, 0);
>+ pbs = 0;
>+ break;
>+ }
>+
>+ /* Limit to maximum values */
>+ pir = min_t(u32, GENMASK(15, 0), pir);
>+ cir = min_t(u32, GENMASK(15, 0), cir);
>+ pbs = min_t(u32, pbs_max, pbs);
>+ cbs = min_t(u32, cbs_max, cbs);
>+
>+ value = (ANA_POL_MODE_CFG_IPG_SIZE(ipg) |
>+ ANA_POL_MODE_CFG_FRM_MODE(frm_mode) |
>+ (cf ? ANA_POL_MODE_CFG_DLB_COUPLED : 0) |
>+ (cir_ena ? ANA_POL_MODE_CFG_CIR_ENA : 0) |
>+ ANA_POL_MODE_CFG_OVERSHOOT_ENA);
>+
>+ ocelot_write_gix(ocelot,
>+ value,
>+ ANA_POL_MODE_CFG,
>+ pol_ix);
>+
>+ ocelot_write_gix(ocelot,
>+ ANA_POL_PIR_CFG_PIR_RATE(pir) |
>+ ANA_POL_PIR_CFG_PIR_BURST(pbs),
>+ ANA_POL_PIR_CFG,
>+ pol_ix);
>+
>+ ocelot_write_gix(ocelot,
>+ (pir_discard ? GENMASK(22, 0) : 0),
>+ ANA_POL_PIR_STATE,
>+ pol_ix);
>+
>+ ocelot_write_gix(ocelot,
>+ ANA_POL_CIR_CFG_CIR_RATE(cir) |
>+ ANA_POL_CIR_CFG_CIR_BURST(cbs),
>+ ANA_POL_CIR_CFG,
>+ pol_ix);
>+
>+ ocelot_write_gix(ocelot,
>+ (cir_discard ? GENMASK(22, 0) : 0),
>+ ANA_POL_CIR_STATE,
>+ pol_ix);
I understand that you want to wrap all 5 calls in the same way. But
still, pol_ix does not have to be on a separate line.
>+
>+ return 0;
>+}
>+
>+int ocelot_port_policer_add(struct ocelot_port *port,
>+ struct tcf_police *p)
>+{
>+ struct ocelot *ocelot = port->ocelot;
>+ struct qos_policer_conf pp;
>+
>+ if (!p)
>+ return -EINVAL;
>+
>+ netdev_dbg(port->dev,
Unnecessary line wrap.
>+ "result %d ewma_rate %u burst %lld mtu %u mtu_pktoks %lld\n",
>+ p->params->tcfp_result,
>+ p->params->tcfp_ewma_rate,
>+ p->params->tcfp_burst,
>+ p->params->tcfp_mtu,
>+ p->params->tcfp_mtu_ptoks);
>+
>+ if (p->params->rate_present)
>+ netdev_dbg(port->dev,
Again, no need to wrap.
>+ "rate: rate %llu mult %u over %u link %u shift %u\n",
>+ p->params->rate.rate_bytes_ps,
>+ p->params->rate.mult,
>+ p->params->rate.overhead,
>+ p->params->rate.linklayer,
>+ p->params->rate.shift);
>+
>+ if (p->params->peak_present)
>+ netdev_dbg(port->dev,
Again, no need to wrap.
>+ "peak: rate %llu mult %u over %u link %u shift %u\n",
>+ p->params->peak.rate_bytes_ps,
>+ p->params->peak.mult,
>+ p->params->peak.overhead,
>+ p->params->peak.linklayer,
>+ p->params->peak.shift);
>+
>+ memset(&pp, 0, sizeof(pp));
>+
>+ if (p->params->tcfp_ewma_rate) {
>+ netdev_err(port->dev, "tcfp_ewma_rate is not supported\n");
>+ return -EOPNOTSUPP;
>+ }
>+ if (p->params->peak_present) {
>+ netdev_err(port->dev, "peakrate is not supported\n");
>+ return -EOPNOTSUPP;
>+ }
>+ if (!p->params->rate_present) {
>+ netdev_err(port->dev, "rate not specified\n");
>+ return -EINVAL;
>+ }
>+ if (p->params->rate.overhead) {
>+ pp.mode = MSCC_QOS_RATE_MODE_LINE;
>+ pp.ipg = p->params->rate.overhead;
>+ } else {
>+ pp.mode = MSCC_QOS_RATE_MODE_DATA;
>+ }
>+
>+ pp.pir = (u32)div_u64(p->params->rate.rate_bytes_ps, 1000) * 8;
>+ pp.pbs = tc_calc_xmitsize(p->params->rate.rate_bytes_ps,
>+ PSCHED_NS2TICKS(p->params->tcfp_burst));
>+ netdev_dbg(port->dev,
Again, no need to wrap.
>+ "%s: port %u pir %u kbps, pbs %u bytes, ipg %u bytes\n",
>+ __func__, port->chip_port, pp.pir, pp.pbs, pp.ipg);
>+
>+ MSCC_RC(qos_policer_conf_set(port, POL_IX_PORT + port->chip_port, &pp));
>+
>+ ocelot_rmw_gix(ocelot,
>+ ANA_PORT_POL_CFG_PORT_POL_ENA |
>+ ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
>+ ANA_PORT_POL_CFG_PORT_POL_ENA |
>+ ANA_PORT_POL_CFG_POL_ORDER_M,
>+ ANA_PORT_POL_CFG,
>+ port->chip_port);
>+
>+ return 0;
>+}
>+
>+int ocelot_port_policer_del(struct ocelot_port *port)
>+{
>+ struct ocelot *ocelot = port->ocelot;
>+ struct qos_policer_conf pp;
>+
>+ netdev_dbg(port->dev, "%s: port %u\n", __func__, port->chip_port);
>+
>+ memset(&pp, 0, sizeof(pp));
>+ pp.mode = MSCC_QOS_RATE_MODE_DISABLED;
>+
>+ MSCC_RC(qos_policer_conf_set(port, POL_IX_PORT + port->chip_port, &pp));
>+
>+ ocelot_rmw_gix(ocelot, 0 |
>+ ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
>+ ANA_PORT_POL_CFG_PORT_POL_ENA |
>+ ANA_PORT_POL_CFG_POL_ORDER_M,
>+ ANA_PORT_POL_CFG,
>+ port->chip_port);
>+
>+ return 0;
>+}
>diff --git a/drivers/net/ethernet/mscc/ocelot_police.h b/drivers/net/ethernet/mscc/ocelot_police.h
>new file mode 100644
>index 000000000000..bc4dc34c684e
>--- /dev/null
>+++ b/drivers/net/ethernet/mscc/ocelot_police.h
>@@ -0,0 +1,16 @@
>+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
>+/* Microsemi Ocelot Switch driver
>+ *
>+ * Copyright (c) 2019 Microsemi Corporation
>+ */
>+
>+#ifndef _MSCC_OCELOT_POLICE_H_
>+#define _MSCC_OCELOT_POLICE_H_
>+
>+#include <net/tc_act/tc_police.h>
>+#include "ocelot.h"
>+
>+int ocelot_port_policer_add(struct ocelot_port *port, struct tcf_police *p);
>+int ocelot_port_policer_del(struct ocelot_port *port);
>+
>+#endif /* _MSCC_OCELOT_POLICE_H_ */
>diff --git a/drivers/net/ethernet/mscc/ocelot_tc.c b/drivers/net/ethernet/mscc/ocelot_tc.c
>new file mode 100644
>index 000000000000..97b0a7bf5d06
>--- /dev/null
>+++ b/drivers/net/ethernet/mscc/ocelot_tc.c
>@@ -0,0 +1,151 @@
>+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
>+/* Microsemi Ocelot Switch TC driver
>+ *
>+ * Copyright (c) 2019 Microsemi Corporation
>+ */
>+
>+#include "ocelot_tc.h"
>+#include "ocelot_police.h"
>+#include <net/pkt_cls.h>
>+
>+static int ocelot_setup_tc_cls_matchall(struct ocelot_port *port,
>+ struct tc_cls_matchall_offload *f,
>+ bool ingress)
>+{
>+ const struct tc_action *a;
>+ int err;
>+
>+ netdev_dbg(port->dev,
Again, no need to wrap.
>+ "%s: port %u cookie %lu\n",
>+ __func__, port->chip_port, f->cookie);
>+ switch (f->command) {
>+ case TC_CLSMATCHALL_REPLACE:
>+ if (!tcf_exts_has_one_action(f->exts)) {
>+ netdev_err(port->dev, "only one action is supported\n");
>+ return -EOPNOTSUPP;
>+ }
>+
>+ a = tcf_exts_first_action(f->exts);
>+
>+ if (is_tcf_police(a)) {
>+ if (!ingress)
>+ return -EOPNOTSUPP;
>+
>+ if (port->tc.police_id &&
>+ port->tc.police_id != f->cookie) {
>+ netdev_warn(port->dev,
Again, no need to wrap.
>+ "Only one policer per port is supported\n");
>+ return -EEXIST;
>+ }
>+
>+ err = ocelot_port_policer_add(port, to_police(a));
>+ if (err) {
>+ netdev_err(port->dev, "Could not add policer\n");
>+ return err;
>+ }
>+ port->tc.police_id = f->cookie;
>+ return 0;
>+ } else {
>+ return -EOPNOTSUPP;
>+ }
>+ case TC_CLSMATCHALL_DESTROY:
>+ if (port->tc.police_id != f->cookie)
>+ return -ENOENT;
>+
>+ err = ocelot_port_policer_del(port);
>+ if (err) {
>+ netdev_err(port->dev, "Could not delete policer\n");
>+ return err;
>+ }
>+ port->tc.police_id = 0;
>+ return 0;
>+ default:
>+ return -EOPNOTSUPP;
>+ }
>+}
>+
>+static int ocelot_setup_tc_block_cb(enum tc_setup_type type,
>+ void *type_data,
>+ void *cb_priv, bool ingress)
>+{
>+ struct ocelot_port *port = cb_priv;
>+
>+ if (!tc_cls_can_offload_and_chain0(port->dev, type_data))
>+ return -EOPNOTSUPP;
>+
>+ switch (type) {
>+ case TC_SETUP_CLSMATCHALL:
>+ netdev_dbg(port->dev, "tc_block_cb: TC_SETUP_CLSMATCHALL %s\n",
>+ ingress ? "ingress" : "egress");
>+
>+ return ocelot_setup_tc_cls_matchall(port, type_data, ingress);
>+ case TC_SETUP_CLSFLOWER:
>+ netdev_dbg(port->dev, "tc_block_cb: TC_SETUP_CLSFLOWER %s\n",
>+ ingress ? "ingress" : "egress");
>+
>+ return -EOPNOTSUPP;
>+ default:
>+ netdev_dbg(port->dev, "tc_block_cb: type %d %s\n",
>+ type,
>+ ingress ? "ingress" : "egress");
>+
>+ return -EOPNOTSUPP;
>+ }
>+}
>+
>+static int ocelot_setup_tc_block_cb_ig(enum tc_setup_type type,
>+ void *type_data,
>+ void *cb_priv)
>+{
>+ return ocelot_setup_tc_block_cb(type, type_data,
Again, no need to wrap.
>+ cb_priv, true);
>+}
>+
>+static int ocelot_setup_tc_block_cb_eg(enum tc_setup_type type,
>+ void *type_data,
>+ void *cb_priv)
>+{
>+ return ocelot_setup_tc_block_cb(type, type_data,
Again, no need to wrap.
>+ cb_priv, false);
>+}
>+
>+static int ocelot_setup_tc_block(struct ocelot_port *port,
>+ struct tc_block_offload *f)
>+{
>+ tc_setup_cb_t *cb;
>+
>+ netdev_dbg(port->dev, "tc_block command %d, binder_type %d\n",
>+ f->command, f->binder_type);
>+
>+ if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
>+ cb = ocelot_setup_tc_block_cb_ig;
>+ else if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
>+ cb = ocelot_setup_tc_block_cb_eg;
>+ else
>+ return -EOPNOTSUPP;
>+
>+ switch (f->command) {
>+ case TC_BLOCK_BIND:
>+ return tcf_block_cb_register(f->block, cb, port,
>+ port, f->extack);
>+ case TC_BLOCK_UNBIND:
>+ tcf_block_cb_unregister(f->block, cb, port);
>+ return 0;
>+ default:
>+ return -EOPNOTSUPP;
>+ }
>+}
>+
>+int ocelot_setup_tc(struct net_device *dev, enum tc_setup_type type,
>+ void *type_data)
>+{
>+ struct ocelot_port *port = netdev_priv(dev);
>+
>+ switch (type) {
>+ case TC_SETUP_BLOCK:
>+ return ocelot_setup_tc_block(port, type_data);
>+ default:
>+ return -EOPNOTSUPP;
>+ }
>+ return 0;
>+}
>diff --git a/drivers/net/ethernet/mscc/ocelot_tc.h b/drivers/net/ethernet/mscc/ocelot_tc.h
>new file mode 100644
>index 000000000000..c905b98b6b4c
>--- /dev/null
>+++ b/drivers/net/ethernet/mscc/ocelot_tc.h
>@@ -0,0 +1,19 @@
>+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
>+/* Microsemi Ocelot Switch driver
>+ *
>+ * Copyright (c) 2019 Microsemi Corporation
>+ */
>+
>+#ifndef _MSCC_OCELOT_TC_H_
>+#define _MSCC_OCELOT_TC_H_
>+
>+#include <linux/netdevice.h>
>+
>+struct ocelot_port_tc {
>+ unsigned long police_id;
>+};
>+
>+int ocelot_setup_tc(struct net_device *dev, enum tc_setup_type type,
>+ void *type_data);
>+
>+#endif /* _MSCC_OCELOT_TC_H_ */
>--
>2.17.1
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net-next 1/3] net/sched: act_police: move police parameters into separate header file
2019-05-02 9:40 ` [PATCH net-next 1/3] net/sched: act_police: move police parameters into separate header file Joergen Andreasen
@ 2019-05-02 20:38 ` Jiri Pirko
0 siblings, 0 replies; 13+ messages in thread
From: Jiri Pirko @ 2019-05-02 20:38 UTC (permalink / raw)
To: Joergen Andreasen
Cc: netdev, Jamal Hadi Salim, Cong Wang, Alexandre Belloni,
Microchip Linux Driver Support, David S. Miller, Ralf Baechle,
Paul Burton, James Hogan, linux-mips, linux-kernel
Thu, May 02, 2019 at 11:40:27AM CEST, joergen.andreasen@microchip.com wrote:
>Hardware offloading a policer requires access to it's parameters.
>This is now possible by including net/tc_act/tc_police.h.
>
>Signed-off-by: Joergen Andreasen <joergen.andreasen@microchip.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net-next 3/3] MIPS: generic: Add police related options to ocelot_defconfig
2019-05-02 16:27 ` Alexandre Belloni
@ 2019-05-03 10:47 ` Joergen Andreasen
0 siblings, 0 replies; 13+ messages in thread
From: Joergen Andreasen @ 2019-05-03 10:47 UTC (permalink / raw)
To: Alexandre Belloni
Cc: netdev, Jamal Hadi Salim, Cong Wang, Jiri Pirko,
Microchip Linux Driver Support, David S. Miller, Ralf Baechle,
Paul Burton, James Hogan, linux-mips, linux-kernel,
Joergen Andreasen
Hi Alexandre,
The 05/02/2019 18:27, Alexandre Belloni wrote:
> External E-Mail
>
>
> Hi Joergen,
>
> On 02/05/2019 11:40:29+0200, Joergen Andreasen wrote:
> > Add default support for ingress qdisc, matchall classification
> > and police action on MSCC Ocelot.
> >
>
> This patch should be separated from the series as this doesn't have any
> dependencies and should go through the MIPS tree.
>
I will create a separate patch for this when the other patches has been
accepted.
> > Signed-off-by: Joergen Andreasen <joergen.andreasen@microchip.com>
> > ---
> > arch/mips/configs/generic/board-ocelot.config | 7 +++++++
> > 1 file changed, 7 insertions(+)
> >
> > diff --git a/arch/mips/configs/generic/board-ocelot.config b/arch/mips/configs/generic/board-ocelot.config
> > index 5e53b4bc47f1..5c7360dd819c 100644
> > --- a/arch/mips/configs/generic/board-ocelot.config
> > +++ b/arch/mips/configs/generic/board-ocelot.config
> > @@ -25,6 +25,13 @@ CONFIG_SERIAL_OF_PLATFORM=y
> > CONFIG_NETDEVICES=y
> > CONFIG_NET_SWITCHDEV=y
> > CONFIG_NET_DSA=y
> > +CONFIG_NET_SCHED=y
> > +CONFIG_NET_SCH_INGRESS=y
> > +CONFIG_NET_CLS_MATCHALL=y
> > +CONFIG_NET_CLS_ACT=y
> > +CONFIG_NET_ACT_POLICE=y
> > +CONFIG_NET_ACT_GACT=y
> > +
> > CONFIG_MSCC_OCELOT_SWITCH=y
> > CONFIG_MSCC_OCELOT_SWITCH_OCELOT=y
> > CONFIG_MDIO_MSCC_MIIM=y
> > --
> > 2.17.1
> >
>
> --
> Alexandre Belloni, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com
>
--
Joergen Andreasen, Microchip
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net-next 2/3] net: mscc: ocelot: Implement port policers via tc command
2019-05-02 12:32 ` Andrew Lunn
@ 2019-05-03 11:23 ` Joergen Andreasen
0 siblings, 0 replies; 13+ messages in thread
From: Joergen Andreasen @ 2019-05-03 11:23 UTC (permalink / raw)
To: Andrew Lunn
Cc: netdev, Jamal Hadi Salim, Cong Wang, Jiri Pirko,
Alexandre Belloni, Microchip Linux Driver Support,
David S. Miller, Ralf Baechle, Paul Burton, James Hogan,
linux-mips, linux-kernel, Joergen Andreasen
Hi Andrew,
The 05/02/2019 14:32, Andrew Lunn wrote:
> External E-Mail
>
>
> Hi Joergen
>
> > +
> > +#define MSCC_RC(expr) \
> > + do { \
> > + int __rc__ = (expr); \
> > + if (__rc__ < 0) \
> > + return __rc__; \
> > + } \
> > + while (0)
>
> I'm sure checkpatch warned about this. A return inside a macros is a
> bad idea. I inherited code doing this, and broke it when adding
> locking, because it was not obvious there was a return.
>
I saw the warning but I assumed that it wasn't a problem in this small context.
The macro will be removed in v2.
> > +
> > +/* The following two functions do the same as in iproute2 */
> > +#define TIME_UNITS_PER_SEC 1000000
> > +static unsigned int tc_core_tick2time(unsigned int tick)
> > +{
> > + return (tick * (u32)PSCHED_TICKS2NS(1)) / 1000;
> > +}
> > +
> > +static unsigned int tc_calc_xmitsize(u64 rate, unsigned int ticks)
> > +{
> > + return div_u64(rate * tc_core_tick2time(ticks), TIME_UNITS_PER_SEC);
> > +}
>
> Should these but put somewhere others can use them?
>
It would be nice to put them in a more public place, but I am in doubt where to
put them and what to call them.
Maybe they belong in the new file: include/net/tc_act/tc_police.h.
Would that be ok?
> > +
> > +enum mscc_qos_rate_mode {
> > + MSCC_QOS_RATE_MODE_DISABLED, /* Policer/shaper disabled */
> > + MSCC_QOS_RATE_MODE_LINE, /* Measure line rate in kbps incl. IPG */
> > + MSCC_QOS_RATE_MODE_DATA, /* Measures data rate in kbps excl. IPG */
> > + MSCC_QOS_RATE_MODE_FRAME, /* Measures frame rate in fps */
> > + __MSCC_QOS_RATE_MODE_END,
> > + NUM_MSCC_QOS_RATE_MODE = __MSCC_QOS_RATE_MODE_END,
> > + MSCC_QOS_RATE_MODE_MAX = __MSCC_QOS_RATE_MODE_END - 1,
> > +};
> > +
> > +/* Round x divided by y to nearest integer. x and y are integers */
> > +#define MSCC_ROUNDING_DIVISION(x, y) (((x) + ((y) / 2)) / (y))
>
> linux/kernel.h defines DIV_ROUND_UP(). Maybe add DIV_ROUND_DOWN()?
>
This macro is currently not used and I will remove it in v2.
> > +
> > +/* Round x divided by y to nearest higher integer. x and y are integers */
> > +#define MSCC_DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y))
>
> DIV_ROUND_UP() ?
>
I will use DIV_ROUND_UP() in v2.
> > + /* Limit to maximum values */
> > + pir = min_t(u32, GENMASK(15, 0), pir);
> > + cir = min_t(u32, GENMASK(15, 0), cir);
> > + pbs = min_t(u32, pbs_max, pbs);
> > + cbs = min_t(u32, cbs_max, cbs);
>
> If it does need to limit, maybe return -EOPNOTSUPP?
>
It seems fine to return -EOPBITSUPP here.
I will do that in v2.
> > +int ocelot_port_policer_add(struct ocelot_port *port,
> > + struct tcf_police *p)
> > +{
> > + struct ocelot *ocelot = port->ocelot;
> > + struct qos_policer_conf pp;
> > +
> > + if (!p)
> > + return -EINVAL;
> > +
> > + netdev_dbg(port->dev,
> > + "result %d ewma_rate %u burst %lld mtu %u mtu_pktoks %lld\n",
> > + p->params->tcfp_result,
> > + p->params->tcfp_ewma_rate,
> > + p->params->tcfp_burst,
> > + p->params->tcfp_mtu,
> > + p->params->tcfp_mtu_ptoks);
> > +
> > + if (p->params->rate_present)
> > + netdev_dbg(port->dev,
> > + "rate: rate %llu mult %u over %u link %u shift %u\n",
> > + p->params->rate.rate_bytes_ps,
> > + p->params->rate.mult,
> > + p->params->rate.overhead,
> > + p->params->rate.linklayer,
> > + p->params->rate.shift);
> > +
> > + if (p->params->peak_present)
> > + netdev_dbg(port->dev,
> > + "peak: rate %llu mult %u over %u link %u shift %u\n",
> > + p->params->peak.rate_bytes_ps,
> > + p->params->peak.mult,
> > + p->params->peak.overhead,
> > + p->params->peak.linklayer,
> > + p->params->peak.shift);
> > +
> > + memset(&pp, 0, sizeof(pp));
>
> Rather than memset, you can do:
>
> struct qos_policer_conf pp = { 0 };
>
I will do as you suggest in v2.
> Andrew
>
--
Joergen Andreasen, Microchip
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net-next 2/3] net: mscc: ocelot: Implement port policers via tc command
2019-05-02 20:36 ` Jiri Pirko
@ 2019-05-03 11:38 ` Joergen Andreasen
0 siblings, 0 replies; 13+ messages in thread
From: Joergen Andreasen @ 2019-05-03 11:38 UTC (permalink / raw)
To: Jiri Pirko
Cc: netdev, Jamal Hadi Salim, Cong Wang, Alexandre Belloni,
Microchip Linux Driver Support, David S. Miller, Ralf Baechle,
Paul Burton, James Hogan, linux-mips, linux-kernel,
Joergen Andreasen
Hi Jiri,
The 05/02/2019 22:36, Jiri Pirko wrote:
> External E-Mail
>
>
> Thu, May 02, 2019 at 11:40:28AM CEST, joergen.andreasen@microchip.com wrote:
> >Hardware offload of port policers are now supported via the tc command.
> >Supported police parameters are: rate, burst and overhead.
>
> Interesting, you offload matchall cls, yet you don't mention it at all.
> Please, do it.
>
I will mention that we also offload matchall cls in v2.
>
> >
> >Example:
> >
> >Add:
> >tc qdisc add dev eth3 handle ffff: ingress
> >tc filter add dev eth3 parent ffff: prio 1 handle 2 \
> > matchall skip_sw \
> > action police rate 100Mbit burst 10000 overhead 20
> >
> >Show:
> >tc -s -d qdisc show dev eth3
> >tc -s -d filter show dev eth3 ingress
> >
> >Delete:
> >tc filter del dev eth3 parent ffff: prio 1
> >tc qdisc del dev eth3 handle ffff: ingress
> >
> >Signed-off-by: Joergen Andreasen <joergen.andreasen@microchip.com>
> >---
> > drivers/net/ethernet/mscc/Makefile | 2 +-
> > drivers/net/ethernet/mscc/ocelot.c | 6 +-
> > drivers/net/ethernet/mscc/ocelot.h | 3 +
> > drivers/net/ethernet/mscc/ocelot_police.c | 289 ++++++++++++++++++++++
> > drivers/net/ethernet/mscc/ocelot_police.h | 16 ++
> > drivers/net/ethernet/mscc/ocelot_tc.c | 151 +++++++++++
> > drivers/net/ethernet/mscc/ocelot_tc.h | 19 ++
> > 7 files changed, 483 insertions(+), 3 deletions(-)
> > create mode 100644 drivers/net/ethernet/mscc/ocelot_police.c
> > create mode 100644 drivers/net/ethernet/mscc/ocelot_police.h
> > create mode 100644 drivers/net/ethernet/mscc/ocelot_tc.c
> > create mode 100644 drivers/net/ethernet/mscc/ocelot_tc.h
> >
> >diff --git a/drivers/net/ethernet/mscc/Makefile b/drivers/net/ethernet/mscc/Makefile
> >index cb52a3b128ae..5e694dc1f7f8 100644
> >--- a/drivers/net/ethernet/mscc/Makefile
> >+++ b/drivers/net/ethernet/mscc/Makefile
> >@@ -1,5 +1,5 @@
> > # SPDX-License-Identifier: (GPL-2.0 OR MIT)
> > obj-$(CONFIG_MSCC_OCELOT_SWITCH) += mscc_ocelot_common.o
> > mscc_ocelot_common-y := ocelot.o ocelot_io.o
> >-mscc_ocelot_common-y += ocelot_regs.o
> >+mscc_ocelot_common-y += ocelot_regs.o ocelot_tc.o ocelot_police.o
> > obj-$(CONFIG_MSCC_OCELOT_SWITCH_OCELOT) += ocelot_board.o
> >diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
> >index d715ef4fc92f..3ec7864d9dc8 100644
> >--- a/drivers/net/ethernet/mscc/ocelot.c
> >+++ b/drivers/net/ethernet/mscc/ocelot.c
> >@@ -943,6 +943,7 @@ static const struct net_device_ops ocelot_port_netdev_ops = {
> > .ndo_vlan_rx_kill_vid = ocelot_vlan_rx_kill_vid,
> > .ndo_set_features = ocelot_set_features,
> > .ndo_get_port_parent_id = ocelot_get_port_parent_id,
> >+ .ndo_setup_tc = ocelot_setup_tc,
> > };
> >
> > static void ocelot_get_strings(struct net_device *netdev, u32 sset, u8 *data)
> >@@ -1663,8 +1664,9 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port,
> > dev->netdev_ops = &ocelot_port_netdev_ops;
> > dev->ethtool_ops = &ocelot_ethtool_ops;
> >
> >- dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_RXFCS;
> >- dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
> >+ dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_RXFCS |
> >+ NETIF_F_HW_TC;
> >+ dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_TC;
> >
> > memcpy(dev->dev_addr, ocelot->base_mac, ETH_ALEN);
> > dev->dev_addr[ETH_ALEN - 1] += port;
> >diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h
> >index ba3b3380b4d0..9514979fa075 100644
> >--- a/drivers/net/ethernet/mscc/ocelot.h
> >+++ b/drivers/net/ethernet/mscc/ocelot.h
> >@@ -22,6 +22,7 @@
> > #include "ocelot_rew.h"
> > #include "ocelot_sys.h"
> > #include "ocelot_qs.h"
> >+#include "ocelot_tc.h"
> >
> > #define PGID_AGGR 64
> > #define PGID_SRC 80
> >@@ -458,6 +459,8 @@ struct ocelot_port {
> >
> > phy_interface_t phy_mode;
> > struct phy *serdes;
> >+
> >+ struct ocelot_port_tc tc;
> > };
> >
> > u32 __ocelot_read_ix(struct ocelot *ocelot, u32 reg, u32 offset);
> >diff --git a/drivers/net/ethernet/mscc/ocelot_police.c b/drivers/net/ethernet/mscc/ocelot_police.c
> >new file mode 100644
> >index 000000000000..b40382dcc748
> >--- /dev/null
> >+++ b/drivers/net/ethernet/mscc/ocelot_police.c
> >@@ -0,0 +1,289 @@
> >+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
> >+/* Microsemi Ocelot Switch TC driver
>
> "TC driver" ? That sounds quite odd...
>
I will change it to "Microsemi Ocelot Switch driver" in v2.
>
> >+ *
> >+ * Copyright (c) 2019 Microsemi Corporation
> >+ */
> >+
> >+#include "ocelot_police.h"
> >+
> >+#define MSCC_RC(expr) \
> >+ do { \
> >+ int __rc__ = (expr); \
> >+ if (__rc__ < 0) \
> >+ return __rc__; \
> >+ } \
> >+ while (0)
>
> Please don't use macros like this.
>
This macro will be removed in v2.
>
> >+
> >+/* The following two functions do the same as in iproute2 */
> >+#define TIME_UNITS_PER_SEC 1000000
> >+static unsigned int tc_core_tick2time(unsigned int tick)
> >+{
> >+ return (tick * (u32)PSCHED_TICKS2NS(1)) / 1000;
> >+}
> >+
> >+static unsigned int tc_calc_xmitsize(u64 rate, unsigned int ticks)
> >+{
> >+ return div_u64(rate * tc_core_tick2time(ticks), TIME_UNITS_PER_SEC);
> >+}
> >+
> >+enum mscc_qos_rate_mode {
> >+ MSCC_QOS_RATE_MODE_DISABLED, /* Policer/shaper disabled */
> >+ MSCC_QOS_RATE_MODE_LINE, /* Measure line rate in kbps incl. IPG */
> >+ MSCC_QOS_RATE_MODE_DATA, /* Measures data rate in kbps excl. IPG */
> >+ MSCC_QOS_RATE_MODE_FRAME, /* Measures frame rate in fps */
> >+ __MSCC_QOS_RATE_MODE_END,
> >+ NUM_MSCC_QOS_RATE_MODE = __MSCC_QOS_RATE_MODE_END,
> >+ MSCC_QOS_RATE_MODE_MAX = __MSCC_QOS_RATE_MODE_END - 1,
> >+};
> >+
> >+/* Round x divided by y to nearest integer. x and y are integers */
> >+#define MSCC_ROUNDING_DIVISION(x, y) (((x) + ((y) / 2)) / (y))
> >+
> >+/* Round x divided by y to nearest higher integer. x and y are integers */
> >+#define MSCC_DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y))
> >+
> >+/* Types for ANA:POL[0-192]:POL_MODE_CFG.FRM_MODE */
> >+#define POL_MODE_LINERATE 0 /* Incl IPG. Unit: 33 1/3 kbps, 4096 bytes */
> >+#define POL_MODE_DATARATE 1 /* Excl IPG. Unit: 33 1/3 kbps, 4096 bytes */
> >+#define POL_MODE_FRMRATE_HI 2 /* Unit: 33 1/3 fps, 32.8 frames */
> >+#define POL_MODE_FRMRATE_LO 3 /* Unit: 1/3 fps, 0.3 frames */
> >+
> >+/* Policer indexes */
> >+#define POL_IX_PORT 0 /* 0-11 : Port policers */
> >+#define POL_IX_QUEUE 32 /* 32-127 : Queue policers */
> >+
> >+/* Default policer order */
> >+#define POL_ORDER 0x1d3 /* Ocelot policer order: Serial (QoS -> Port -> VCAP) */
> >+
> >+struct qos_policer_conf {
> >+ enum mscc_qos_rate_mode mode;
> >+ bool dlb; /* Enable DLB (dual leaky bucket mode */
> >+ bool cf; /* Coupling flag (ignored in SLB mode) */
> >+ u32 cir; /* CIR in kbps/fps (ignored in SLB mode) */
> >+ u32 cbs; /* CBS in bytes/frames (ignored in SLB mode) */
> >+ u32 pir; /* PIR in kbps/fps */
> >+ u32 pbs; /* PBS in bytes/frames */
> >+ u8 ipg; /* Size of IPG when MSCC_QOS_RATE_MODE_LINE is chosen */
> >+};
> >+
> >+static int qos_policer_conf_set(struct ocelot_port *port,
> >+ u32 pol_ix,
> >+ struct qos_policer_conf *conf)
> >+{
> >+ struct ocelot *ocelot = port->ocelot;
> >+ u32 cir = 0, cbs = 0, pir = 0, pbs = 0;
> >+ u32 cf = 0, cir_ena = 0, frm_mode = 0;
> >+ u32 pbs_max = 0, cbs_max = 0;
> >+ bool cir_discard = 0, pir_discard = 0;
> >+ u8 ipg = 20;
> >+ u32 value;
> >+
> >+ pir = conf->pir;
> >+ pbs = conf->pbs;
> >+
> >+ switch (conf->mode) {
> >+ case MSCC_QOS_RATE_MODE_LINE:
> >+ case MSCC_QOS_RATE_MODE_DATA:
> >+ if (conf->mode == MSCC_QOS_RATE_MODE_LINE) {
> >+ frm_mode = POL_MODE_LINERATE;
> >+ ipg = min_t(u8, GENMASK(4, 0), conf->ipg);
> >+ } else {
> >+ frm_mode = POL_MODE_DATARATE;
> >+ }
> >+ if (conf->dlb) {
> >+ cir_ena = 1;
> >+ cir = conf->cir;
> >+ cbs = conf->cbs;
> >+ if (cir == 0 && cbs == 0) {
> >+ /* Discard cir frames */
> >+ cir_discard = 1;
> >+ } else {
> >+ cir = MSCC_DIV_ROUND_UP(cir, 100);
> >+ cir *= 3; /* 33 1/3 kbps */
> >+ cbs = MSCC_DIV_ROUND_UP(cbs, 4096);
> >+ cbs = (cbs ? cbs : 1); /* No zero burst size */
> >+ cbs_max = 60; /* Limit burst size */
> >+ cf = conf->cf;
> >+ if (cf)
> >+ pir += conf->cir;
> >+ }
> >+ }
> >+ if (pir == 0 && pbs == 0) {
> >+ /* Discard PIR frames */
> >+ pir_discard = 1;
> >+ } else {
> >+ pir = MSCC_DIV_ROUND_UP(pir, 100);
> >+ pir *= 3; /* 33 1/3 kbps */
> >+ pbs = MSCC_DIV_ROUND_UP(pbs, 4096);
> >+ pbs = (pbs ? pbs : 1); /* No zero burst size */
> >+ pbs_max = 60; /* Limit burst size */
> >+ }
> >+ break;
> >+ case MSCC_QOS_RATE_MODE_FRAME:
> >+ if (pir >= 100) {
> >+ frm_mode = POL_MODE_FRMRATE_HI;
> >+ pir = MSCC_DIV_ROUND_UP(pir, 100);
> >+ pir *= 3; /* 33 1/3 fps */
> >+ pbs = (pbs * 10) / 328; /* 32.8 frames */
> >+ pbs = (pbs ? pbs : 1); /* No zero burst size */
> >+ pbs_max = GENMASK(6, 0); /* Limit burst size */
> >+ } else {
> >+ frm_mode = POL_MODE_FRMRATE_LO;
> >+ if (pir == 0 && pbs == 0) {
> >+ /* Discard all frames */
> >+ pir_discard = 1;
> >+ cir_discard = 1;
> >+ } else {
> >+ pir *= 3; /* 1/3 fps */
> >+ pbs = (pbs * 10) / 3; /* 0.3 frames */
> >+ pbs = (pbs ? pbs : 1); /* No zero burst size */
> >+ pbs_max = 61; /* Limit burst size */
> >+ }
> >+ }
> >+ break;
> >+ default: /* MSCC_QOS_RATE_MODE_DISABLED */
> >+ /* Disable policer using maximum rate and zero burst */
> >+ pir = GENMASK(15, 0);
> >+ pbs = 0;
> >+ break;
> >+ }
> >+
> >+ /* Limit to maximum values */
> >+ pir = min_t(u32, GENMASK(15, 0), pir);
> >+ cir = min_t(u32, GENMASK(15, 0), cir);
> >+ pbs = min_t(u32, pbs_max, pbs);
> >+ cbs = min_t(u32, cbs_max, cbs);
> >+
> >+ value = (ANA_POL_MODE_CFG_IPG_SIZE(ipg) |
> >+ ANA_POL_MODE_CFG_FRM_MODE(frm_mode) |
> >+ (cf ? ANA_POL_MODE_CFG_DLB_COUPLED : 0) |
> >+ (cir_ena ? ANA_POL_MODE_CFG_CIR_ENA : 0) |
> >+ ANA_POL_MODE_CFG_OVERSHOOT_ENA);
> >+
> >+ ocelot_write_gix(ocelot,
> >+ value,
> >+ ANA_POL_MODE_CFG,
> >+ pol_ix);
> >+
> >+ ocelot_write_gix(ocelot,
> >+ ANA_POL_PIR_CFG_PIR_RATE(pir) |
> >+ ANA_POL_PIR_CFG_PIR_BURST(pbs),
> >+ ANA_POL_PIR_CFG,
> >+ pol_ix);
> >+
> >+ ocelot_write_gix(ocelot,
> >+ (pir_discard ? GENMASK(22, 0) : 0),
> >+ ANA_POL_PIR_STATE,
> >+ pol_ix);
> >+
> >+ ocelot_write_gix(ocelot,
> >+ ANA_POL_CIR_CFG_CIR_RATE(cir) |
> >+ ANA_POL_CIR_CFG_CIR_BURST(cbs),
> >+ ANA_POL_CIR_CFG,
> >+ pol_ix);
> >+
> >+ ocelot_write_gix(ocelot,
> >+ (cir_discard ? GENMASK(22, 0) : 0),
> >+ ANA_POL_CIR_STATE,
> >+ pol_ix);
>
> I understand that you want to wrap all 5 calls in the same way. But
> still, pol_ix does not have to be on a separate line.
>
I will fix this and the folloeing unnecessary line wraps in v2.
>
> >+
> >+ return 0;
> >+}
> >+
> >+int ocelot_port_policer_add(struct ocelot_port *port,
> >+ struct tcf_police *p)
> >+{
> >+ struct ocelot *ocelot = port->ocelot;
> >+ struct qos_policer_conf pp;
> >+
> >+ if (!p)
> >+ return -EINVAL;
> >+
> >+ netdev_dbg(port->dev,
>
> Unnecessary line wrap.
>
>
> >+ "result %d ewma_rate %u burst %lld mtu %u mtu_pktoks %lld\n",
> >+ p->params->tcfp_result,
> >+ p->params->tcfp_ewma_rate,
> >+ p->params->tcfp_burst,
> >+ p->params->tcfp_mtu,
> >+ p->params->tcfp_mtu_ptoks);
> >+
> >+ if (p->params->rate_present)
> >+ netdev_dbg(port->dev,
>
> Again, no need to wrap.
>
>
> >+ "rate: rate %llu mult %u over %u link %u shift %u\n",
> >+ p->params->rate.rate_bytes_ps,
> >+ p->params->rate.mult,
> >+ p->params->rate.overhead,
> >+ p->params->rate.linklayer,
> >+ p->params->rate.shift);
> >+
> >+ if (p->params->peak_present)
> >+ netdev_dbg(port->dev,
>
> Again, no need to wrap.
>
>
> >+ "peak: rate %llu mult %u over %u link %u shift %u\n",
> >+ p->params->peak.rate_bytes_ps,
> >+ p->params->peak.mult,
> >+ p->params->peak.overhead,
> >+ p->params->peak.linklayer,
> >+ p->params->peak.shift);
> >+
> >+ memset(&pp, 0, sizeof(pp));
> >+
> >+ if (p->params->tcfp_ewma_rate) {
> >+ netdev_err(port->dev, "tcfp_ewma_rate is not supported\n");
> >+ return -EOPNOTSUPP;
> >+ }
> >+ if (p->params->peak_present) {
> >+ netdev_err(port->dev, "peakrate is not supported\n");
> >+ return -EOPNOTSUPP;
> >+ }
> >+ if (!p->params->rate_present) {
> >+ netdev_err(port->dev, "rate not specified\n");
> >+ return -EINVAL;
> >+ }
> >+ if (p->params->rate.overhead) {
> >+ pp.mode = MSCC_QOS_RATE_MODE_LINE;
> >+ pp.ipg = p->params->rate.overhead;
> >+ } else {
> >+ pp.mode = MSCC_QOS_RATE_MODE_DATA;
> >+ }
> >+
> >+ pp.pir = (u32)div_u64(p->params->rate.rate_bytes_ps, 1000) * 8;
> >+ pp.pbs = tc_calc_xmitsize(p->params->rate.rate_bytes_ps,
> >+ PSCHED_NS2TICKS(p->params->tcfp_burst));
> >+ netdev_dbg(port->dev,
>
> Again, no need to wrap.
>
>
> >+ "%s: port %u pir %u kbps, pbs %u bytes, ipg %u bytes\n",
> >+ __func__, port->chip_port, pp.pir, pp.pbs, pp.ipg);
> >+
> >+ MSCC_RC(qos_policer_conf_set(port, POL_IX_PORT + port->chip_port, &pp));
> >+
> >+ ocelot_rmw_gix(ocelot,
> >+ ANA_PORT_POL_CFG_PORT_POL_ENA |
> >+ ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
> >+ ANA_PORT_POL_CFG_PORT_POL_ENA |
> >+ ANA_PORT_POL_CFG_POL_ORDER_M,
> >+ ANA_PORT_POL_CFG,
> >+ port->chip_port);
> >+
> >+ return 0;
> >+}
> >+
> >+int ocelot_port_policer_del(struct ocelot_port *port)
> >+{
> >+ struct ocelot *ocelot = port->ocelot;
> >+ struct qos_policer_conf pp;
> >+
> >+ netdev_dbg(port->dev, "%s: port %u\n", __func__, port->chip_port);
> >+
> >+ memset(&pp, 0, sizeof(pp));
> >+ pp.mode = MSCC_QOS_RATE_MODE_DISABLED;
> >+
> >+ MSCC_RC(qos_policer_conf_set(port, POL_IX_PORT + port->chip_port, &pp));
> >+
> >+ ocelot_rmw_gix(ocelot, 0 |
> >+ ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
> >+ ANA_PORT_POL_CFG_PORT_POL_ENA |
> >+ ANA_PORT_POL_CFG_POL_ORDER_M,
> >+ ANA_PORT_POL_CFG,
> >+ port->chip_port);
> >+
> >+ return 0;
> >+}
> >diff --git a/drivers/net/ethernet/mscc/ocelot_police.h b/drivers/net/ethernet/mscc/ocelot_police.h
> >new file mode 100644
> >index 000000000000..bc4dc34c684e
> >--- /dev/null
> >+++ b/drivers/net/ethernet/mscc/ocelot_police.h
> >@@ -0,0 +1,16 @@
> >+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
> >+/* Microsemi Ocelot Switch driver
> >+ *
> >+ * Copyright (c) 2019 Microsemi Corporation
> >+ */
> >+
> >+#ifndef _MSCC_OCELOT_POLICE_H_
> >+#define _MSCC_OCELOT_POLICE_H_
> >+
> >+#include <net/tc_act/tc_police.h>
> >+#include "ocelot.h"
> >+
> >+int ocelot_port_policer_add(struct ocelot_port *port, struct tcf_police *p);
> >+int ocelot_port_policer_del(struct ocelot_port *port);
> >+
> >+#endif /* _MSCC_OCELOT_POLICE_H_ */
> >diff --git a/drivers/net/ethernet/mscc/ocelot_tc.c b/drivers/net/ethernet/mscc/ocelot_tc.c
> >new file mode 100644
> >index 000000000000..97b0a7bf5d06
> >--- /dev/null
> >+++ b/drivers/net/ethernet/mscc/ocelot_tc.c
> >@@ -0,0 +1,151 @@
> >+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
> >+/* Microsemi Ocelot Switch TC driver
> >+ *
> >+ * Copyright (c) 2019 Microsemi Corporation
> >+ */
> >+
> >+#include "ocelot_tc.h"
> >+#include "ocelot_police.h"
> >+#include <net/pkt_cls.h>
> >+
> >+static int ocelot_setup_tc_cls_matchall(struct ocelot_port *port,
> >+ struct tc_cls_matchall_offload *f,
> >+ bool ingress)
> >+{
> >+ const struct tc_action *a;
> >+ int err;
> >+
> >+ netdev_dbg(port->dev,
>
> Again, no need to wrap.
>
>
> >+ "%s: port %u cookie %lu\n",
> >+ __func__, port->chip_port, f->cookie);
> >+ switch (f->command) {
> >+ case TC_CLSMATCHALL_REPLACE:
> >+ if (!tcf_exts_has_one_action(f->exts)) {
> >+ netdev_err(port->dev, "only one action is supported\n");
> >+ return -EOPNOTSUPP;
> >+ }
> >+
> >+ a = tcf_exts_first_action(f->exts);
> >+
> >+ if (is_tcf_police(a)) {
> >+ if (!ingress)
> >+ return -EOPNOTSUPP;
> >+
> >+ if (port->tc.police_id &&
> >+ port->tc.police_id != f->cookie) {
> >+ netdev_warn(port->dev,
>
> Again, no need to wrap.
>
>
> >+ "Only one policer per port is supported\n");
> >+ return -EEXIST;
> >+ }
> >+
> >+ err = ocelot_port_policer_add(port, to_police(a));
> >+ if (err) {
> >+ netdev_err(port->dev, "Could not add policer\n");
> >+ return err;
> >+ }
> >+ port->tc.police_id = f->cookie;
> >+ return 0;
> >+ } else {
> >+ return -EOPNOTSUPP;
> >+ }
> >+ case TC_CLSMATCHALL_DESTROY:
> >+ if (port->tc.police_id != f->cookie)
> >+ return -ENOENT;
> >+
> >+ err = ocelot_port_policer_del(port);
> >+ if (err) {
> >+ netdev_err(port->dev, "Could not delete policer\n");
> >+ return err;
> >+ }
> >+ port->tc.police_id = 0;
> >+ return 0;
> >+ default:
> >+ return -EOPNOTSUPP;
> >+ }
> >+}
> >+
> >+static int ocelot_setup_tc_block_cb(enum tc_setup_type type,
> >+ void *type_data,
> >+ void *cb_priv, bool ingress)
> >+{
> >+ struct ocelot_port *port = cb_priv;
> >+
> >+ if (!tc_cls_can_offload_and_chain0(port->dev, type_data))
> >+ return -EOPNOTSUPP;
> >+
> >+ switch (type) {
> >+ case TC_SETUP_CLSMATCHALL:
> >+ netdev_dbg(port->dev, "tc_block_cb: TC_SETUP_CLSMATCHALL %s\n",
> >+ ingress ? "ingress" : "egress");
> >+
> >+ return ocelot_setup_tc_cls_matchall(port, type_data, ingress);
> >+ case TC_SETUP_CLSFLOWER:
> >+ netdev_dbg(port->dev, "tc_block_cb: TC_SETUP_CLSFLOWER %s\n",
> >+ ingress ? "ingress" : "egress");
> >+
> >+ return -EOPNOTSUPP;
> >+ default:
> >+ netdev_dbg(port->dev, "tc_block_cb: type %d %s\n",
> >+ type,
> >+ ingress ? "ingress" : "egress");
> >+
> >+ return -EOPNOTSUPP;
> >+ }
> >+}
> >+
> >+static int ocelot_setup_tc_block_cb_ig(enum tc_setup_type type,
> >+ void *type_data,
> >+ void *cb_priv)
> >+{
> >+ return ocelot_setup_tc_block_cb(type, type_data,
>
> Again, no need to wrap.
>
>
> >+ cb_priv, true);
> >+}
> >+
> >+static int ocelot_setup_tc_block_cb_eg(enum tc_setup_type type,
> >+ void *type_data,
> >+ void *cb_priv)
> >+{
> >+ return ocelot_setup_tc_block_cb(type, type_data,
>
> Again, no need to wrap.
>
>
> >+ cb_priv, false);
> >+}
> >+
> >+static int ocelot_setup_tc_block(struct ocelot_port *port,
> >+ struct tc_block_offload *f)
> >+{
> >+ tc_setup_cb_t *cb;
> >+
> >+ netdev_dbg(port->dev, "tc_block command %d, binder_type %d\n",
> >+ f->command, f->binder_type);
> >+
> >+ if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
> >+ cb = ocelot_setup_tc_block_cb_ig;
> >+ else if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
> >+ cb = ocelot_setup_tc_block_cb_eg;
> >+ else
> >+ return -EOPNOTSUPP;
> >+
> >+ switch (f->command) {
> >+ case TC_BLOCK_BIND:
> >+ return tcf_block_cb_register(f->block, cb, port,
> >+ port, f->extack);
> >+ case TC_BLOCK_UNBIND:
> >+ tcf_block_cb_unregister(f->block, cb, port);
> >+ return 0;
> >+ default:
> >+ return -EOPNOTSUPP;
> >+ }
> >+}
> >+
> >+int ocelot_setup_tc(struct net_device *dev, enum tc_setup_type type,
> >+ void *type_data)
> >+{
> >+ struct ocelot_port *port = netdev_priv(dev);
> >+
> >+ switch (type) {
> >+ case TC_SETUP_BLOCK:
> >+ return ocelot_setup_tc_block(port, type_data);
> >+ default:
> >+ return -EOPNOTSUPP;
> >+ }
> >+ return 0;
> >+}
> >diff --git a/drivers/net/ethernet/mscc/ocelot_tc.h b/drivers/net/ethernet/mscc/ocelot_tc.h
> >new file mode 100644
> >index 000000000000..c905b98b6b4c
> >--- /dev/null
> >+++ b/drivers/net/ethernet/mscc/ocelot_tc.h
> >@@ -0,0 +1,19 @@
> >+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
> >+/* Microsemi Ocelot Switch driver
> >+ *
> >+ * Copyright (c) 2019 Microsemi Corporation
> >+ */
> >+
> >+#ifndef _MSCC_OCELOT_TC_H_
> >+#define _MSCC_OCELOT_TC_H_
> >+
> >+#include <linux/netdevice.h>
> >+
> >+struct ocelot_port_tc {
> >+ unsigned long police_id;
> >+};
> >+
> >+int ocelot_setup_tc(struct net_device *dev, enum tc_setup_type type,
> >+ void *type_data);
> >+
> >+#endif /* _MSCC_OCELOT_TC_H_ */
> >--
> >2.17.1
> >
>
--
Joergen Andreasen, Microchip
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net-next 2/3] net: mscc: ocelot: Implement port policers via tc command
2019-05-02 9:40 ` [PATCH net-next 2/3] net: mscc: ocelot: Implement port policers via tc command Joergen Andreasen
2019-05-02 12:32 ` Andrew Lunn
2019-05-02 20:36 ` Jiri Pirko
@ 2019-05-04 13:07 ` Jiri Pirko
2019-05-07 8:30 ` Joergen Andreasen
2 siblings, 1 reply; 13+ messages in thread
From: Jiri Pirko @ 2019-05-04 13:07 UTC (permalink / raw)
To: Joergen Andreasen
Cc: netdev, Jamal Hadi Salim, Cong Wang, Alexandre Belloni,
Microchip Linux Driver Support, David S. Miller, Ralf Baechle,
Paul Burton, James Hogan, linux-mips, linux-kernel,
Jakub Kicinski, pieter.jansenvanvuuren
Thu, May 02, 2019 at 11:40:28AM CEST, joergen.andreasen@microchip.com wrote:
>Hardware offload of port policers are now supported via the tc command.
>Supported police parameters are: rate, burst and overhead.
Joergen, please see:
[PATCH net-next 00/13] net: act_police offload support
That patchset is also pushing flow intermediate representation for this,
so I believe that you should base this patch on top of that.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net-next 2/3] net: mscc: ocelot: Implement port policers via tc command
2019-05-04 13:07 ` Jiri Pirko
@ 2019-05-07 8:30 ` Joergen Andreasen
0 siblings, 0 replies; 13+ messages in thread
From: Joergen Andreasen @ 2019-05-07 8:30 UTC (permalink / raw)
To: Jiri Pirko
Cc: netdev, Jamal Hadi Salim, Cong Wang, Alexandre Belloni,
Microchip Linux Driver Support, David S. Miller, Ralf Baechle,
Paul Burton, James Hogan, linux-mips, linux-kernel,
Jakub Kicinski, pieter.jansenvanvuuren
Hi Jiri,
The 05/04/2019 15:07, Jiri Pirko wrote:
> External E-Mail
>
>
> Thu, May 02, 2019 at 11:40:28AM CEST, joergen.andreasen@microchip.com wrote:
> >Hardware offload of port policers are now supported via the tc command.
> >Supported police parameters are: rate, burst and overhead.
>
> Joergen, please see:
> [PATCH net-next 00/13] net: act_police offload support
> That patchset is also pushing flow intermediate representation for this,
> so I believe that you should base this patch on top of that.
>
I will base my patches on top of that.
--
Joergen Andreasen, Microchip
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2019-05-07 8:30 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-02 9:40 [PATCH net-next 0/3] Add hw offload of TC police on MSCC ocelot Joergen Andreasen
2019-05-02 9:40 ` [PATCH net-next 1/3] net/sched: act_police: move police parameters into separate header file Joergen Andreasen
2019-05-02 20:38 ` Jiri Pirko
2019-05-02 9:40 ` [PATCH net-next 2/3] net: mscc: ocelot: Implement port policers via tc command Joergen Andreasen
2019-05-02 12:32 ` Andrew Lunn
2019-05-03 11:23 ` Joergen Andreasen
2019-05-02 20:36 ` Jiri Pirko
2019-05-03 11:38 ` Joergen Andreasen
2019-05-04 13:07 ` Jiri Pirko
2019-05-07 8:30 ` Joergen Andreasen
2019-05-02 9:40 ` [PATCH net-next 3/3] MIPS: generic: Add police related options to ocelot_defconfig Joergen Andreasen
2019-05-02 16:27 ` Alexandre Belloni
2019-05-03 10:47 ` Joergen Andreasen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).