net: mscc: ocelot: add action of police on vcap_is2
authorXiaoliang Yang <xiaoliang.yang_1@nxp.com>
Sun, 29 Mar 2020 11:51:57 +0000 (14:51 +0300)
committerDavid S. Miller <davem@davemloft.net>
Mon, 30 Mar 2020 18:44:00 +0000 (11:44 -0700)
Ocelot has 384 policers that can be allocated to ingress ports,
QoS classes per port, and VCAP IS2 entries. ocelot_police.c
supports to set policers which can be allocated to police action
of VCAP IS2. We allocate policers from maximum pol_id, and
decrease the pol_id when add a new vcap_is2 entry which is
police action.

Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mscc/ocelot_ace.c
drivers/net/ethernet/mscc/ocelot_ace.h
drivers/net/ethernet/mscc/ocelot_flower.c
drivers/net/ethernet/mscc/ocelot_police.c
drivers/net/ethernet/mscc/ocelot_police.h
include/soc/mscc/ocelot.h

index 906b54025b1734c4adebbc013bee1b6f9b26381d..3bd28604448043a73c54928e6907501ccd4d0b71 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/proc_fs.h>
 
 #include <soc/mscc/ocelot_vcap.h>
+#include "ocelot_police.h"
 #include "ocelot_ace.h"
 #include "ocelot_s2.h"
 
@@ -299,9 +300,9 @@ static void vcap_action_set(struct ocelot *ocelot, struct vcap_data *data,
 }
 
 static void is2_action_set(struct ocelot *ocelot, struct vcap_data *data,
-                          enum ocelot_ace_action action)
+                          struct ocelot_ace_rule *ace)
 {
-       switch (action) {
+       switch (ace->action) {
        case OCELOT_ACL_ACTION_DROP:
                vcap_action_set(ocelot, data, VCAP_IS2_ACT_PORT_MASK, 0);
                vcap_action_set(ocelot, data, VCAP_IS2_ACT_MASK_MODE, 1);
@@ -319,6 +320,15 @@ static void is2_action_set(struct ocelot *ocelot, struct vcap_data *data,
                vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_QU_NUM, 0);
                vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_COPY_ENA, 1);
                break;
+       case OCELOT_ACL_ACTION_POLICE:
+               vcap_action_set(ocelot, data, VCAP_IS2_ACT_PORT_MASK, 0);
+               vcap_action_set(ocelot, data, VCAP_IS2_ACT_MASK_MODE, 0);
+               vcap_action_set(ocelot, data, VCAP_IS2_ACT_POLICE_ENA, 1);
+               vcap_action_set(ocelot, data, VCAP_IS2_ACT_POLICE_IDX,
+                               ace->pol_ix);
+               vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_QU_NUM, 0);
+               vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_COPY_ENA, 0);
+               break;
        }
 }
 
@@ -611,7 +621,7 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
        }
 
        vcap_key_set(ocelot, &data, VCAP_IS2_TYPE, type, type_mask);
-       is2_action_set(ocelot, &data, ace->action);
+       is2_action_set(ocelot, &data, ace);
        vcap_data_set(data.counter, data.counter_offset,
                      vcap_is2->counter_width, ace->stats.pkts);
 
@@ -639,12 +649,19 @@ static void is2_entry_get(struct ocelot *ocelot, struct ocelot_ace_rule *rule,
        rule->stats.pkts = cnt;
 }
 
-static void ocelot_ace_rule_add(struct ocelot_acl_block *block,
+static void ocelot_ace_rule_add(struct ocelot *ocelot,
+                               struct ocelot_acl_block *block,
                                struct ocelot_ace_rule *rule)
 {
        struct ocelot_ace_rule *tmp;
        struct list_head *pos, *n;
 
+       if (rule->action == OCELOT_ACL_ACTION_POLICE) {
+               block->pol_lpr--;
+               rule->pol_ix = block->pol_lpr;
+               ocelot_ace_policer_add(ocelot, rule->pol_ix, &rule->pol);
+       }
+
        block->count++;
 
        if (list_empty(&block->rules)) {
@@ -697,7 +714,7 @@ int ocelot_ace_rule_offload_add(struct ocelot *ocelot,
        int i, index;
 
        /* Add rule to the linked list */
-       ocelot_ace_rule_add(block, rule);
+       ocelot_ace_rule_add(ocelot, block, rule);
 
        /* Get the index of the inserted rule */
        index = ocelot_ace_rule_get_index_id(block, rule);
@@ -713,7 +730,33 @@ int ocelot_ace_rule_offload_add(struct ocelot *ocelot,
        return 0;
 }
 
-static void ocelot_ace_rule_del(struct ocelot_acl_block *block,
+static void ocelot_ace_police_del(struct ocelot *ocelot,
+                                 struct ocelot_acl_block *block,
+                                 u32 ix)
+{
+       struct ocelot_ace_rule *ace;
+       int index = -1;
+
+       if (ix < block->pol_lpr)
+               return;
+
+       list_for_each_entry(ace, &block->rules, list) {
+               index++;
+               if (ace->action == OCELOT_ACL_ACTION_POLICE &&
+                   ace->pol_ix < ix) {
+                       ace->pol_ix += 1;
+                       ocelot_ace_policer_add(ocelot, ace->pol_ix,
+                                              &ace->pol);
+                       is2_entry_set(ocelot, index, ace);
+               }
+       }
+
+       ocelot_ace_policer_del(ocelot, block->pol_lpr);
+       block->pol_lpr++;
+}
+
+static void ocelot_ace_rule_del(struct ocelot *ocelot,
+                               struct ocelot_acl_block *block,
                                struct ocelot_ace_rule *rule)
 {
        struct ocelot_ace_rule *tmp;
@@ -722,6 +765,10 @@ static void ocelot_ace_rule_del(struct ocelot_acl_block *block,
        list_for_each_safe(pos, q, &block->rules) {
                tmp = list_entry(pos, struct ocelot_ace_rule, list);
                if (tmp->id == rule->id) {
+                       if (tmp->action == OCELOT_ACL_ACTION_POLICE)
+                               ocelot_ace_police_del(ocelot, block,
+                                                     tmp->pol_ix);
+
                        list_del(pos);
                        kfree(tmp);
                }
@@ -744,7 +791,7 @@ int ocelot_ace_rule_offload_del(struct ocelot *ocelot,
        index = ocelot_ace_rule_get_index_id(block, rule);
 
        /* Delete rule */
-       ocelot_ace_rule_del(block, rule);
+       ocelot_ace_rule_del(ocelot, block, rule);
 
        /* Move up all the blocks over the deleted rule */
        for (i = index; i < block->count; i++) {
@@ -779,6 +826,7 @@ int ocelot_ace_rule_stats_update(struct ocelot *ocelot,
 int ocelot_ace_init(struct ocelot *ocelot)
 {
        const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
+       struct ocelot_acl_block *block = &ocelot->acl_block;
        struct vcap_data data;
 
        memset(&data, 0, sizeof(data));
@@ -807,6 +855,8 @@ int ocelot_ace_init(struct ocelot *ocelot)
        ocelot_write_gix(ocelot, 0x3fffff, ANA_POL_CIR_STATE,
                         OCELOT_POLICER_DISCARD);
 
+       block->pol_lpr = OCELOT_POLICER_DISCARD - 1;
+
        INIT_LIST_HEAD(&ocelot->acl_block.rules);
 
        return 0;
index b9a5868e3f15b925ae4aaf02ba793e563b30ba12..29d22c5667865bc664afa1471c5e040d8de7af1c 100644 (file)
@@ -7,6 +7,7 @@
 #define _MSCC_OCELOT_ACE_H_
 
 #include "ocelot.h"
+#include "ocelot_police.h"
 #include <net/sch_generic.h>
 #include <net/pkt_cls.h>
 
@@ -176,6 +177,7 @@ struct ocelot_ace_frame_ipv6 {
 enum ocelot_ace_action {
        OCELOT_ACL_ACTION_DROP,
        OCELOT_ACL_ACTION_TRAP,
+       OCELOT_ACL_ACTION_POLICE,
 };
 
 struct ocelot_ace_stats {
@@ -208,6 +210,8 @@ struct ocelot_ace_rule {
                struct ocelot_ace_frame_ipv4 ipv4;
                struct ocelot_ace_frame_ipv6 ipv6;
        } frame;
+       struct ocelot_policer pol;
+       u32 pol_ix;
 };
 
 int ocelot_ace_rule_offload_add(struct ocelot *ocelot,
index 829987eb74cbd1d9249fb322844ee52541cec2c9..341923311fec3ad783efa929cdd0cabe481d85aa 100644 (file)
@@ -12,6 +12,8 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f,
                                      struct ocelot_ace_rule *ace)
 {
        const struct flow_action_entry *a;
+       s64 burst;
+       u64 rate;
        int i;
 
        if (!flow_offload_has_one_action(&f->rule->action))
@@ -29,6 +31,13 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f,
                case FLOW_ACTION_TRAP:
                        ace->action = OCELOT_ACL_ACTION_TRAP;
                        break;
+               case FLOW_ACTION_POLICE:
+                       ace->action = OCELOT_ACL_ACTION_POLICE;
+                       rate = a->police.rate_bytes_ps;
+                       ace->pol.rate = div_u64(rate, 1000) * 8;
+                       burst = rate * PSCHED_NS2TICKS(a->police.burst);
+                       ace->pol.burst = div_u64(burst, PSCHED_TICKS_PER_SEC);
+                       break;
                default:
                        return -EOPNOTSUPP;
                }
index faddce43f2e32819d89537a2e6715ba4be416162..8d25b2706ff0bb2ba139b87c3c5fca41bbadffc0 100644 (file)
@@ -225,3 +225,27 @@ int ocelot_port_policer_del(struct ocelot *ocelot, int port)
 
        return 0;
 }
+
+int ocelot_ace_policer_add(struct ocelot *ocelot, u32 pol_ix,
+                          struct ocelot_policer *pol)
+{
+       struct qos_policer_conf pp = { 0 };
+
+       if (!pol)
+               return -EINVAL;
+
+       pp.mode = MSCC_QOS_RATE_MODE_DATA;
+       pp.pir = pol->rate;
+       pp.pbs = pol->burst;
+
+       return qos_policer_conf_set(ocelot, 0, pol_ix, &pp);
+}
+
+int ocelot_ace_policer_del(struct ocelot *ocelot, u32 pol_ix)
+{
+       struct qos_policer_conf pp = { 0 };
+
+       pp.mode = MSCC_QOS_RATE_MODE_DISABLED;
+
+       return qos_policer_conf_set(ocelot, 0, pol_ix, &pp);
+}
index ae9509229463f6c147c700d22ab4c52594642a77..22025cce0a6affb64aa4b0e869a4019b3acfa2a4 100644 (file)
@@ -19,4 +19,9 @@ int ocelot_port_policer_add(struct ocelot *ocelot, int port,
 
 int ocelot_port_policer_del(struct ocelot *ocelot, int port);
 
+int ocelot_ace_policer_add(struct ocelot *ocelot, u32 pol_ix,
+                          struct ocelot_policer *pol);
+
+int ocelot_ace_policer_del(struct ocelot *ocelot, u32 pol_ix);
+
 #endif /* _MSCC_OCELOT_POLICE_H_ */
index eadbc2ddfcb5cc5385bcf7b102633d5aa7cc9ade..b5d61af9f7436fdb9bab35cfa30ed98c002be146 100644 (file)
@@ -468,6 +468,7 @@ struct ocelot_ops {
 struct ocelot_acl_block {
        struct list_head rules;
        int count;
+       int pol_lpr;
 };
 
 struct ocelot_port {