aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/mscc/ocelot_police.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/mscc/ocelot_police.c')
-rw-r--r--drivers/net/ethernet/mscc/ocelot_police.c67
1 files changed, 56 insertions, 11 deletions
diff --git a/drivers/net/ethernet/mscc/ocelot_police.c b/drivers/net/ethernet/mscc/ocelot_police.c
index 6f5068c1041a..7e1f67be38f5 100644
--- a/drivers/net/ethernet/mscc/ocelot_police.c
+++ b/drivers/net/ethernet/mscc/ocelot_police.c
@@ -20,7 +20,7 @@
/* Default policer order */
#define POL_ORDER 0x1d3 /* Ocelot policer order: Serial (QoS -> Port -> VCAP) */
-int qos_policer_conf_set(struct ocelot *ocelot, int port, u32 pol_ix,
+int qos_policer_conf_set(struct ocelot *ocelot, u32 pol_ix,
struct qos_policer_conf *conf)
{
u32 cf = 0, cir_ena = 0, frm_mode = POL_MODE_LINERATE;
@@ -102,26 +102,30 @@ int qos_policer_conf_set(struct ocelot *ocelot, int port, u32 pol_ix,
/* Check limits */
if (pir > GENMASK(15, 0)) {
- dev_err(ocelot->dev, "Invalid pir for port %d: %u (max %lu)\n",
- port, pir, GENMASK(15, 0));
+ dev_err(ocelot->dev,
+ "Invalid pir for policer %u: %u (max %lu)\n",
+ pol_ix, pir, GENMASK(15, 0));
return -EINVAL;
}
if (cir > GENMASK(15, 0)) {
- dev_err(ocelot->dev, "Invalid cir for port %d: %u (max %lu)\n",
- port, cir, GENMASK(15, 0));
+ dev_err(ocelot->dev,
+ "Invalid cir for policer %u: %u (max %lu)\n",
+ pol_ix, cir, GENMASK(15, 0));
return -EINVAL;
}
if (pbs > pbs_max) {
- dev_err(ocelot->dev, "Invalid pbs for port %d: %u (max %u)\n",
- port, pbs, pbs_max);
+ dev_err(ocelot->dev,
+ "Invalid pbs for policer %u: %u (max %u)\n",
+ pol_ix, pbs, pbs_max);
return -EINVAL;
}
if (cbs > cbs_max) {
- dev_err(ocelot->dev, "Invalid cbs for port %d: %u (max %u)\n",
- port, cbs, cbs_max);
+ dev_err(ocelot->dev,
+ "Invalid cbs for policer %u: %u (max %u)\n",
+ pol_ix, cbs, cbs_max);
return -EINVAL;
}
@@ -154,6 +158,47 @@ int qos_policer_conf_set(struct ocelot *ocelot, int port, u32 pol_ix,
return 0;
}
+int ocelot_policer_validate(const struct flow_action *action,
+ const struct flow_action_entry *a,
+ struct netlink_ext_ack *extack)
+{
+ if (a->police.exceed.act_id != FLOW_ACTION_DROP) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Offload not supported when exceed action is not drop");
+ return -EOPNOTSUPP;
+ }
+
+ if (a->police.notexceed.act_id != FLOW_ACTION_PIPE &&
+ a->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Offload not supported when conform action is not pipe or ok");
+ return -EOPNOTSUPP;
+ }
+
+ if (a->police.notexceed.act_id == FLOW_ACTION_ACCEPT &&
+ !flow_action_is_last_entry(action, a)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Offload not supported when conform action is ok, but police action is not last");
+ return -EOPNOTSUPP;
+ }
+
+ if (a->police.peakrate_bytes_ps ||
+ a->police.avrate || a->police.overhead) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Offload not supported when peakrate/avrate/overhead is configured");
+ return -EOPNOTSUPP;
+ }
+
+ if (a->police.rate_pkt_ps) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Offload does not support packets per second");
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(ocelot_policer_validate);
+
int ocelot_port_policer_add(struct ocelot *ocelot, int port,
struct ocelot_policer *pol)
{
@@ -170,7 +215,7 @@ int ocelot_port_policer_add(struct ocelot *ocelot, int port,
dev_dbg(ocelot->dev, "%s: port %u pir %u kbps, pbs %u bytes\n",
__func__, port, pp.pir, pp.pbs);
- err = qos_policer_conf_set(ocelot, port, POL_IX_PORT + port, &pp);
+ err = qos_policer_conf_set(ocelot, POL_IX_PORT + port, &pp);
if (err)
return err;
@@ -194,7 +239,7 @@ int ocelot_port_policer_del(struct ocelot *ocelot, int port)
pp.mode = MSCC_QOS_RATE_MODE_DISABLED;
- err = qos_policer_conf_set(ocelot, port, POL_IX_PORT + port, &pp);
+ err = qos_policer_conf_set(ocelot, POL_IX_PORT + port, &pp);
if (err)
return err;