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, qopt: 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, f: type_data, ingress); |
79 | case TC_SETUP_CLSFLOWER: |
80 | return lan966x_tc_flower(port, f: 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, ingress: 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, ingress: 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, driver_list: &lan966x_tc_block_cb_list, |
116 | cb, cb_ident: port, cb_priv: port, ingress_only: 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, mqprio: type_data); |
127 | case TC_SETUP_QDISC_TAPRIO: |
128 | return lan966x_tc_setup_qdisc_taprio(port, taprio: type_data); |
129 | case TC_SETUP_QDISC_TBF: |
130 | return lan966x_tc_setup_qdisc_tbf(port, qopt: type_data); |
131 | case TC_SETUP_QDISC_CBS: |
132 | return lan966x_tc_setup_qdisc_cbs(port, qopt: type_data); |
133 | case TC_SETUP_QDISC_ETS: |
134 | return lan966x_tc_setup_qdisc_ets(port, qopt: type_data); |
135 | case TC_SETUP_BLOCK: |
136 | return lan966x_tc_setup_block(port, f: type_data); |
137 | default: |
138 | return -EOPNOTSUPP; |
139 | } |
140 | |
141 | return 0; |
142 | } |
143 | |