net: prestera: add police action support
authorVolodymyr Mytnyk <volodymyr.mytnyk@plvision.eu>
Wed, 27 Apr 2022 12:05:48 +0000 (15:05 +0300)
committerJakub Kicinski <kuba@kernel.org>
Fri, 29 Apr 2022 01:37:55 +0000 (18:37 -0700)
- Add HW api to configure policer:
  - SR TCM policer mode is only supported for now.
  - Policer ingress/egress direction support.
- Add police action support into flower

Signed-off-by: Volodymyr Mytnyk <volodymyr.mytnyk@plvision.eu>
Link: https://lore.kernel.org/r/1651061148-21321-1-git-send-email-volodymyr.mytnyk@plvision.eu
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/marvell/prestera/prestera_acl.c
drivers/net/ethernet/marvell/prestera/prestera_acl.h
drivers/net/ethernet/marvell/prestera/prestera_flower.c
drivers/net/ethernet/marvell/prestera/prestera_hw.c
drivers/net/ethernet/marvell/prestera/prestera_hw.h

index e562778..3a141f2 100644 (file)
@@ -35,6 +35,10 @@ struct prestera_acl_rule_entry {
                        u8 valid:1;
                } accept, drop, trap;
                struct {
+                       u8 valid:1;
+                       struct prestera_acl_action_police i;
+               } police;
+               struct {
                        struct prestera_acl_action_jump i;
                        u8 valid:1;
                } jump;
@@ -533,6 +537,12 @@ static int __prestera_acl_rule_entry2hw_add(struct prestera_switch *sw,
                act_hw[act_num].id = PRESTERA_ACL_RULE_ACTION_TRAP;
                act_num++;
        }
+       /* police */
+       if (e->police.valid) {
+               act_hw[act_num].id = PRESTERA_ACL_RULE_ACTION_POLICE;
+               act_hw[act_num].police = e->police.i;
+               act_num++;
+       }
        /* jump */
        if (e->jump.valid) {
                act_hw[act_num].id = PRESTERA_ACL_RULE_ACTION_JUMP;
@@ -557,6 +567,9 @@ __prestera_acl_rule_entry_act_destruct(struct prestera_switch *sw,
 {
        /* counter */
        prestera_counter_put(sw->counter, e->counter.block, e->counter.id);
+       /* police */
+       if (e->police.valid)
+               prestera_hw_policer_release(sw, e->police.i.id);
 }
 
 void prestera_acl_rule_entry_destroy(struct prestera_acl *acl,
@@ -579,6 +592,8 @@ __prestera_acl_rule_entry_act_construct(struct prestera_switch *sw,
                                        struct prestera_acl_rule_entry *e,
                                        struct prestera_acl_rule_entry_arg *arg)
 {
+       int err;
+
        /* accept */
        e->accept.valid = arg->accept.valid;
        /* drop */
@@ -588,10 +603,26 @@ __prestera_acl_rule_entry_act_construct(struct prestera_switch *sw,
        /* jump */
        e->jump.valid = arg->jump.valid;
        e->jump.i = arg->jump.i;
+       /* police */
+       if (arg->police.valid) {
+               u8 type = arg->police.ingress ? PRESTERA_POLICER_TYPE_INGRESS :
+                                               PRESTERA_POLICER_TYPE_EGRESS;
+
+               err = prestera_hw_policer_create(sw, type, &e->police.i.id);
+               if (err)
+                       goto err_out;
+
+               err = prestera_hw_policer_sr_tcm_set(sw, e->police.i.id,
+                                                    arg->police.rate,
+                                                    arg->police.burst);
+               if (err) {
+                       prestera_hw_policer_release(sw, e->police.i.id);
+                       goto err_out;
+               }
+               e->police.valid = arg->police.valid;
+       }
        /* counter */
        if (arg->count.valid) {
-               int err;
-
                err = prestera_counter_get(sw->counter, arg->count.client,
                                           &e->counter.block,
                                           &e->counter.id);
index 6d2ad27..f963e1e 100644 (file)
@@ -56,6 +56,7 @@ enum prestera_acl_rule_action {
        PRESTERA_ACL_RULE_ACTION_TRAP = 2,
        PRESTERA_ACL_RULE_ACTION_JUMP = 5,
        PRESTERA_ACL_RULE_ACTION_COUNT = 7,
+       PRESTERA_ACL_RULE_ACTION_POLICE = 8,
 
        PRESTERA_ACL_RULE_ACTION_MAX
 };
@@ -74,6 +75,10 @@ struct prestera_acl_action_jump {
        u32 index;
 };
 
+struct prestera_acl_action_police {
+       u32 id;
+};
+
 struct prestera_acl_action_count {
        u32 id;
 };
@@ -86,6 +91,7 @@ struct prestera_acl_rule_entry_key {
 struct prestera_acl_hw_action_info {
        enum prestera_acl_rule_action id;
        union {
+               struct prestera_acl_action_police police;
                struct prestera_acl_action_count count;
                struct prestera_acl_action_jump jump;
        };
@@ -107,6 +113,12 @@ struct prestera_acl_rule_entry_arg {
                } jump;
                struct {
                        u8 valid:1;
+                       u64 rate;
+                       u64 burst;
+                       bool ingress;
+               } police;
+               struct {
+                       u8 valid:1;
                        u32 client;
                } count;
        };
index c12b09a..d43e503 100644 (file)
@@ -108,6 +108,16 @@ static int prestera_flower_parse_actions(struct prestera_flow_block *block,
 
                        rule->re_arg.trap.valid = 1;
                        break;
+               case FLOW_ACTION_POLICE:
+                       if (rule->re_arg.police.valid)
+                               return -EEXIST;
+
+                       rule->re_arg.police.valid = 1;
+                       rule->re_arg.police.rate =
+                               act->police.rate_bytes_ps;
+                       rule->re_arg.police.burst = act->police.burst;
+                       rule->re_arg.police.ingress = true;
+                       break;
                case FLOW_ACTION_GOTO:
                        err = prestera_flower_parse_goto_action(block, rule,
                                                                chain_index,
index c66cc92..79fd3ca 100644 (file)
@@ -74,6 +74,10 @@ enum prestera_cmd_type_t {
        PRESTERA_CMD_TYPE_SPAN_UNBIND = 0x1102,
        PRESTERA_CMD_TYPE_SPAN_RELEASE = 0x1103,
 
+       PRESTERA_CMD_TYPE_POLICER_CREATE = 0x1500,
+       PRESTERA_CMD_TYPE_POLICER_RELEASE = 0x1501,
+       PRESTERA_CMD_TYPE_POLICER_SET = 0x1502,
+
        PRESTERA_CMD_TYPE_CPU_CODE_COUNTERS_GET = 0x2000,
 
        PRESTERA_CMD_TYPE_ACK = 0x10000,
@@ -164,6 +168,10 @@ enum {
 };
 
 enum {
+       PRESTERA_POLICER_MODE_SR_TCM
+};
+
+enum {
        PRESTERA_HW_FDB_ENTRY_TYPE_REG_PORT = 0,
        PRESTERA_HW_FDB_ENTRY_TYPE_LAG = 1,
        PRESTERA_HW_FDB_ENTRY_TYPE_MAX = 2,
@@ -430,6 +438,9 @@ struct prestera_msg_acl_action {
                } jump;
                struct {
                        __le32 id;
+               } police;
+               struct {
+                       __le32 id;
                } count;
                __le32 reserved[6];
        };
@@ -570,6 +581,26 @@ struct mvsw_msg_cpu_code_counter_ret {
        __le64 packet_count;
 };
 
+struct prestera_msg_policer_req {
+       struct prestera_msg_cmd cmd;
+       __le32 id;
+       union {
+               struct {
+                       __le64 cir;
+                       __le32 cbs;
+               } __packed sr_tcm; /* make sure always 12 bytes size */
+               __le32 reserved[6];
+       };
+       u8 mode;
+       u8 type;
+       u8 pad[2];
+};
+
+struct prestera_msg_policer_resp {
+       struct prestera_msg_ret ret;
+       __le32 id;
+};
+
 struct prestera_msg_event {
        __le16 type;
        __le16 id;
@@ -622,6 +653,7 @@ static void prestera_hw_build_tests(void)
        BUILD_BUG_ON(sizeof(struct prestera_msg_rif_req) != 36);
        BUILD_BUG_ON(sizeof(struct prestera_msg_vr_req) != 8);
        BUILD_BUG_ON(sizeof(struct prestera_msg_lpm_req) != 36);
+       BUILD_BUG_ON(sizeof(struct prestera_msg_policer_req) != 36);
 
        /*  structure that are part of req/resp fw messages */
        BUILD_BUG_ON(sizeof(struct prestera_msg_iface) != 16);
@@ -640,6 +672,7 @@ static void prestera_hw_build_tests(void)
        BUILD_BUG_ON(sizeof(struct prestera_msg_counter_resp) != 24);
        BUILD_BUG_ON(sizeof(struct prestera_msg_rif_resp) != 12);
        BUILD_BUG_ON(sizeof(struct prestera_msg_vr_resp) != 12);
+       BUILD_BUG_ON(sizeof(struct prestera_msg_policer_resp) != 12);
 
        /* check events */
        BUILD_BUG_ON(sizeof(struct prestera_msg_event_port) != 20);
@@ -1192,6 +1225,9 @@ prestera_acl_rule_add_put_action(struct prestera_msg_acl_action *action,
        case PRESTERA_ACL_RULE_ACTION_JUMP:
                action->jump.index = __cpu_to_le32(info->jump.index);
                break;
+       case PRESTERA_ACL_RULE_ACTION_POLICE:
+               action->police.id = __cpu_to_le32(info->police.id);
+               break;
        case PRESTERA_ACL_RULE_ACTION_COUNT:
                action->count.id = __cpu_to_le32(info->count.id);
                break;
@@ -2163,3 +2199,48 @@ int prestera_hw_counter_clear(struct prestera_switch *sw, u32 block_id,
        return prestera_cmd(sw, PRESTERA_CMD_TYPE_COUNTER_CLEAR,
                            &req.cmd, sizeof(req));
 }
+
+int prestera_hw_policer_create(struct prestera_switch *sw, u8 type,
+                              u32 *policer_id)
+{
+       struct prestera_msg_policer_resp resp;
+       struct prestera_msg_policer_req req = {
+               .type = type
+       };
+       int err;
+
+       err = prestera_cmd_ret(sw, PRESTERA_CMD_TYPE_POLICER_CREATE,
+                              &req.cmd, sizeof(req), &resp.ret, sizeof(resp));
+       if (err)
+               return err;
+
+       *policer_id = __le32_to_cpu(resp.id);
+       return 0;
+}
+
+int prestera_hw_policer_release(struct prestera_switch *sw,
+                               u32 policer_id)
+{
+       struct prestera_msg_policer_req req = {
+               .id = __cpu_to_le32(policer_id)
+       };
+
+       return prestera_cmd(sw, PRESTERA_CMD_TYPE_POLICER_RELEASE,
+                           &req.cmd, sizeof(req));
+}
+
+int prestera_hw_policer_sr_tcm_set(struct prestera_switch *sw,
+                                  u32 policer_id, u64 cir, u32 cbs)
+{
+       struct prestera_msg_policer_req req = {
+               .mode = PRESTERA_POLICER_MODE_SR_TCM,
+               .id = __cpu_to_le32(policer_id),
+               .sr_tcm = {
+                       .cir = __cpu_to_le64(cir),
+                       .cbs = __cpu_to_le32(cbs)
+               }
+       };
+
+       return prestera_cmd(sw, PRESTERA_CMD_TYPE_POLICER_SET,
+                           &req.cmd, sizeof(req));
+}
index fd896a8..579d9ba 100644 (file)
@@ -107,6 +107,11 @@ enum {
        PRESTERA_STP_FORWARD,
 };
 
+enum {
+       PRESTERA_POLICER_TYPE_INGRESS,
+       PRESTERA_POLICER_TYPE_EGRESS
+};
+
 enum prestera_hw_cpu_code_cnt_t {
        PRESTERA_HW_CPU_CODE_CNT_TYPE_DROP = 0,
        PRESTERA_HW_CPU_CODE_CNT_TYPE_TRAP = 1,
@@ -288,4 +293,12 @@ prestera_hw_cpu_code_counters_get(struct prestera_switch *sw, u8 code,
                                  enum prestera_hw_cpu_code_cnt_t counter_type,
                                  u64 *packet_count);
 
+/* Policer API */
+int prestera_hw_policer_create(struct prestera_switch *sw, u8 type,
+                              u32 *policer_id);
+int prestera_hw_policer_release(struct prestera_switch *sw,
+                               u32 policer_id);
+int prestera_hw_policer_sr_tcm_set(struct prestera_switch *sw,
+                                  u32 policer_id, u64 cir, u32 cbs);
+
 #endif /* _PRESTERA_HW_H_ */