1 // SPDX-License-Identifier: GPL-2.0+
2 
3 #include <net/pkt_cls.h>
4 
5 #include "lan966x_main.h"
6 
7 static LIST_HEAD(lan966x_tc_block_cb_list);
8 
9 static int lan966x_tc_setup_qdisc_mqprio(struct lan966x_port *port,
10 					 struct tc_mqprio_qopt_offload *mqprio)
11 {
12 	u8 num_tc = mqprio->qopt.num_tc;
13 
14 	mqprio->qopt.hw = TC_MQPRIO_HW_OFFLOAD_TCS;
15 
16 	return num_tc ? lan966x_mqprio_add(port, num_tc) :
17 			lan966x_mqprio_del(port);
18 }
19 
20 static int lan966x_tc_setup_qdisc_taprio(struct lan966x_port *port,
21 					 struct tc_taprio_qopt_offload *taprio)
22 {
23 	return taprio->enable ? lan966x_taprio_add(port, taprio) :
24 				lan966x_taprio_del(port);
25 }
26 
27 static int lan966x_tc_setup_qdisc_tbf(struct lan966x_port *port,
28 				      struct tc_tbf_qopt_offload *qopt)
29 {
30 	switch (qopt->command) {
31 	case TC_TBF_REPLACE:
32 		return lan966x_tbf_add(port, qopt);
33 	case TC_TBF_DESTROY:
34 		return lan966x_tbf_del(port, qopt);
35 	default:
36 		return -EOPNOTSUPP;
37 	}
38 
39 	return -EOPNOTSUPP;
40 }
41 
42 static int lan966x_tc_setup_qdisc_cbs(struct lan966x_port *port,
43 				      struct tc_cbs_qopt_offload *qopt)
44 {
45 	return qopt->enable ? lan966x_cbs_add(port, qopt) :
46 			      lan966x_cbs_del(port, qopt);
47 }
48 
49 static int lan966x_tc_setup_qdisc_ets(struct lan966x_port *port,
50 				      struct tc_ets_qopt_offload *qopt)
51 {
52 	switch (qopt->command) {
53 	case TC_ETS_REPLACE:
54 		return lan966x_ets_add(port, qopt);
55 	case TC_ETS_DESTROY:
56 		return lan966x_ets_del(port, qopt);
57 	default:
58 		return -EOPNOTSUPP;
59 	};
60 
61 	return -EOPNOTSUPP;
62 }
63 
64 static int lan966x_tc_block_cb(enum tc_setup_type type, void *type_data,
65 			       void *cb_priv, bool ingress)
66 {
67 	struct lan966x_port *port = cb_priv;
68 
69 	switch (type) {
70 	case TC_SETUP_CLSMATCHALL:
71 		return lan966x_tc_matchall(port, type_data, ingress);
72 	case TC_SETUP_CLSFLOWER:
73 		return lan966x_tc_flower(port, type_data);
74 	default:
75 		return -EOPNOTSUPP;
76 	}
77 }
78 
79 static int lan966x_tc_block_cb_ingress(enum tc_setup_type type,
80 				       void *type_data, void *cb_priv)
81 {
82 	return lan966x_tc_block_cb(type, type_data, cb_priv, true);
83 }
84 
85 static int lan966x_tc_block_cb_egress(enum tc_setup_type type,
86 				      void *type_data, void *cb_priv)
87 {
88 	return lan966x_tc_block_cb(type, type_data, cb_priv, false);
89 }
90 
91 static int lan966x_tc_setup_block(struct lan966x_port *port,
92 				  struct flow_block_offload *f)
93 {
94 	flow_setup_cb_t *cb;
95 	bool ingress;
96 
97 	if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) {
98 		cb = lan966x_tc_block_cb_ingress;
99 		port->tc.ingress_shared_block = f->block_shared;
100 		ingress = true;
101 	} else if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) {
102 		cb = lan966x_tc_block_cb_egress;
103 		ingress = false;
104 	} else {
105 		return -EOPNOTSUPP;
106 	}
107 
108 	return flow_block_cb_setup_simple(f, &lan966x_tc_block_cb_list,
109 					  cb, port, port, ingress);
110 }
111 
112 int lan966x_tc_setup(struct net_device *dev, enum tc_setup_type type,
113 		     void *type_data)
114 {
115 	struct lan966x_port *port = netdev_priv(dev);
116 
117 	switch (type) {
118 	case TC_SETUP_QDISC_MQPRIO:
119 		return lan966x_tc_setup_qdisc_mqprio(port, type_data);
120 	case TC_SETUP_QDISC_TAPRIO:
121 		return lan966x_tc_setup_qdisc_taprio(port, type_data);
122 	case TC_SETUP_QDISC_TBF:
123 		return lan966x_tc_setup_qdisc_tbf(port, type_data);
124 	case TC_SETUP_QDISC_CBS:
125 		return lan966x_tc_setup_qdisc_cbs(port, type_data);
126 	case TC_SETUP_QDISC_ETS:
127 		return lan966x_tc_setup_qdisc_ets(port, type_data);
128 	case TC_SETUP_BLOCK:
129 		return lan966x_tc_setup_block(port, type_data);
130 	default:
131 		return -EOPNOTSUPP;
132 	}
133 
134 	return 0;
135 }
136