1 // SPDX-License-Identifier: GPL-2.0+
2 
3 #include "lan966x_main.h"
4 
5 static int lan966x_tc_matchall_add(struct lan966x_port *port,
6 				   struct tc_cls_matchall_offload *f,
7 				   bool ingress)
8 {
9 	struct flow_action_entry *act;
10 
11 	if (!flow_offload_has_one_action(&f->rule->action)) {
12 		NL_SET_ERR_MSG_MOD(f->common.extack,
13 				   "Only once action per filter is supported");
14 		return -EOPNOTSUPP;
15 	}
16 
17 	act = &f->rule->action.entries[0];
18 	switch (act->id) {
19 	case FLOW_ACTION_POLICE:
20 		return lan966x_police_port_add(port, &f->rule->action, act,
21 					       f->cookie, ingress,
22 					       f->common.extack);
23 	case FLOW_ACTION_MIRRED:
24 		return lan966x_mirror_port_add(port, act, f->cookie,
25 					       ingress, f->common.extack);
26 	case FLOW_ACTION_GOTO:
27 		return lan966x_goto_port_add(port, act, f->cookie,
28 					     f->common.extack);
29 	default:
30 		NL_SET_ERR_MSG_MOD(f->common.extack,
31 				   "Unsupported action");
32 		return -EOPNOTSUPP;
33 	}
34 
35 	return 0;
36 }
37 
38 static int lan966x_tc_matchall_del(struct lan966x_port *port,
39 				   struct tc_cls_matchall_offload *f,
40 				   bool ingress)
41 {
42 	if (f->cookie == port->tc.police_id) {
43 		return lan966x_police_port_del(port, f->cookie,
44 					       f->common.extack);
45 	} else if (f->cookie == port->tc.ingress_mirror_id ||
46 		   f->cookie == port->tc.egress_mirror_id) {
47 		return lan966x_mirror_port_del(port, ingress,
48 					       f->common.extack);
49 	} else if (f->cookie == port->tc.goto_id) {
50 		return lan966x_goto_port_del(port, f->cookie,
51 					     f->common.extack);
52 	} else {
53 		NL_SET_ERR_MSG_MOD(f->common.extack,
54 				   "Unsupported action");
55 		return -EOPNOTSUPP;
56 	}
57 
58 	return 0;
59 }
60 
61 static int lan966x_tc_matchall_stats(struct lan966x_port *port,
62 				     struct tc_cls_matchall_offload *f,
63 				     bool ingress)
64 {
65 	if (f->cookie == port->tc.police_id) {
66 		lan966x_police_port_stats(port, &f->stats);
67 	} else if (f->cookie == port->tc.ingress_mirror_id ||
68 		   f->cookie == port->tc.egress_mirror_id) {
69 		lan966x_mirror_port_stats(port, &f->stats, ingress);
70 	} else {
71 		NL_SET_ERR_MSG_MOD(f->common.extack,
72 				   "Unsupported action");
73 		return -EOPNOTSUPP;
74 	}
75 
76 	return 0;
77 }
78 
79 int lan966x_tc_matchall(struct lan966x_port *port,
80 			struct tc_cls_matchall_offload *f,
81 			bool ingress)
82 {
83 	if (!tc_cls_can_offload_and_chain0(port->dev, &f->common)) {
84 		NL_SET_ERR_MSG_MOD(f->common.extack,
85 				   "Only chain zero is supported");
86 		return -EOPNOTSUPP;
87 	}
88 
89 	switch (f->command) {
90 	case TC_CLSMATCHALL_REPLACE:
91 		return lan966x_tc_matchall_add(port, f, ingress);
92 	case TC_CLSMATCHALL_DESTROY:
93 		return lan966x_tc_matchall_del(port, f, ingress);
94 	case TC_CLSMATCHALL_STATS:
95 		return lan966x_tc_matchall_stats(port, f, ingress);
96 	default:
97 		return -EOPNOTSUPP;
98 	}
99 
100 	return 0;
101 }
102