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