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 	default:
73 		return -EOPNOTSUPP;
74 	}
75 }
76 
77 static int lan966x_tc_block_cb_ingress(enum tc_setup_type type,
78 				       void *type_data, void *cb_priv)
79 {
80 	return lan966x_tc_block_cb(type, type_data, cb_priv, true);
81 }
82 
83 static int lan966x_tc_block_cb_egress(enum tc_setup_type type,
84 				      void *type_data, void *cb_priv)
85 {
86 	return lan966x_tc_block_cb(type, type_data, cb_priv, false);
87 }
88 
89 static int lan966x_tc_setup_block(struct lan966x_port *port,
90 				  struct flow_block_offload *f)
91 {
92 	flow_setup_cb_t *cb;
93 	bool ingress;
94 
95 	if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) {
96 		cb = lan966x_tc_block_cb_ingress;
97 		port->tc.ingress_shared_block = f->block_shared;
98 		ingress = true;
99 	} else if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) {
100 		cb = lan966x_tc_block_cb_egress;
101 		ingress = false;
102 	} else {
103 		return -EOPNOTSUPP;
104 	}
105 
106 	return flow_block_cb_setup_simple(f, &lan966x_tc_block_cb_list,
107 					  cb, port, port, ingress);
108 }
109 
110 int lan966x_tc_setup(struct net_device *dev, enum tc_setup_type type,
111 		     void *type_data)
112 {
113 	struct lan966x_port *port = netdev_priv(dev);
114 
115 	switch (type) {
116 	case TC_SETUP_QDISC_MQPRIO:
117 		return lan966x_tc_setup_qdisc_mqprio(port, type_data);
118 	case TC_SETUP_QDISC_TAPRIO:
119 		return lan966x_tc_setup_qdisc_taprio(port, type_data);
120 	case TC_SETUP_QDISC_TBF:
121 		return lan966x_tc_setup_qdisc_tbf(port, type_data);
122 	case TC_SETUP_QDISC_CBS:
123 		return lan966x_tc_setup_qdisc_cbs(port, type_data);
124 	case TC_SETUP_QDISC_ETS:
125 		return lan966x_tc_setup_qdisc_ets(port, type_data);
126 	case TC_SETUP_BLOCK:
127 		return lan966x_tc_setup_block(port, type_data);
128 	default:
129 		return -EOPNOTSUPP;
130 	}
131 
132 	return 0;
133 }
134