net: lan966x: Add TC filter chaining support for IS1 and IS2 VCAPs
authorHoratiu Vultur <horatiu.vultur@microchip.com>
Tue, 7 Mar 2023 22:09:28 +0000 (23:09 +0100)
committerJakub Kicinski <kuba@kernel.org>
Sat, 11 Mar 2023 00:44:25 +0000 (16:44 -0800)
Allow rules to be chained between IS1 VCAP and IS2 VCAP. Chaining
between IS1 lookups or between IS2 lookups are not supported by the
hardware.

Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/microchip/lan966x/lan966x_tc_flower.c

index 8391652c1c45e262947240ac67127ecf4a3d1a78..570ac28736e0320a01fb9e53c216c40a46523206 100644 (file)
@@ -309,6 +309,75 @@ static int lan966x_tc_set_actionset(struct vcap_admin *admin,
        return err;
 }
 
+static int lan966x_tc_add_rule_link_target(struct vcap_admin *admin,
+                                          struct vcap_rule *vrule,
+                                          int target_cid)
+{
+       int link_val = target_cid % VCAP_CID_LOOKUP_SIZE;
+       int err;
+
+       if (!link_val)
+               return 0;
+
+       switch (admin->vtype) {
+       case VCAP_TYPE_IS1:
+               /* Choose IS1 specific NXT_IDX key (for chaining rules from IS1) */
+               err = vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX_SEL,
+                                           1, ~0);
+               if (err)
+                       return err;
+
+               return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX,
+                                            link_val, ~0);
+       case VCAP_TYPE_IS2:
+               /* Add IS2 specific PAG key (for chaining rules from IS1) */
+               return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_PAG,
+                                            link_val, ~0);
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int lan966x_tc_add_rule_link(struct vcap_control *vctrl,
+                                   struct vcap_admin *admin,
+                                   struct vcap_rule *vrule,
+                                   struct flow_cls_offload *f,
+                                   int to_cid)
+{
+       struct vcap_admin *to_admin = vcap_find_admin(vctrl, to_cid);
+       int diff, err = 0;
+
+       if (!to_admin) {
+               NL_SET_ERR_MSG_MOD(f->common.extack,
+                                  "Unknown destination chain");
+               return -EINVAL;
+       }
+
+       diff = vcap_chain_offset(vctrl, f->common.chain_index, to_cid);
+       if (!diff)
+               return 0;
+
+       /* Between IS1 and IS2 the PAG value is used */
+       if (admin->vtype == VCAP_TYPE_IS1 && to_admin->vtype == VCAP_TYPE_IS2) {
+               /* This works for IS1->IS2 */
+               err = vcap_rule_add_action_u32(vrule, VCAP_AF_PAG_VAL, diff);
+               if (err)
+                       return err;
+
+               err = vcap_rule_add_action_u32(vrule, VCAP_AF_PAG_OVERRIDE_MASK,
+                                              0xff);
+               if (err)
+                       return err;
+       } else {
+               NL_SET_ERR_MSG_MOD(f->common.extack,
+                                  "Unsupported chain destination");
+               return -EOPNOTSUPP;
+       }
+
+       return err;
+}
+
 static int lan966x_tc_flower_add(struct lan966x_port *port,
                                 struct flow_cls_offload *f,
                                 struct vcap_admin *admin,
@@ -336,6 +405,11 @@ static int lan966x_tc_flower_add(struct lan966x_port *port,
        if (err)
                goto out;
 
+       err = lan966x_tc_add_rule_link_target(admin, vrule,
+                                             f->common.chain_index);
+       if (err)
+               goto out;
+
        frule = flow_cls_offload_flow_rule(f);
 
        flow_action_for_each(idx, act, &frule->action) {
@@ -365,6 +439,12 @@ static int lan966x_tc_flower_add(struct lan966x_port *port,
                        if (err)
                                goto out;
 
+                       err = lan966x_tc_add_rule_link(port->lan966x->vcap_ctrl,
+                                                      admin, vrule,
+                                                      f, act->chain_index);
+                       if (err)
+                               goto out;
+
                        break;
                default:
                        NL_SET_ERR_MSG_MOD(f->common.extack,