Loading...
Note: File does not exist in v5.4.
1// SPDX-License-Identifier: GPL-2.0+
2/* Microchip Sparx5 Switch driver
3 *
4 * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
5 */
6
7#include <net/pkt_cls.h>
8
9#include "sparx5_tc.h"
10#include "sparx5_main.h"
11#include "sparx5_qos.h"
12
13/* tc block handling */
14static LIST_HEAD(sparx5_block_cb_list);
15
16static int sparx5_tc_block_cb(enum tc_setup_type type,
17 void *type_data,
18 void *cb_priv, bool ingress)
19{
20 struct net_device *ndev = cb_priv;
21
22 switch (type) {
23 case TC_SETUP_CLSMATCHALL:
24 return sparx5_tc_matchall(ndev, type_data, ingress);
25 case TC_SETUP_CLSFLOWER:
26 return sparx5_tc_flower(ndev, type_data, ingress);
27 default:
28 return -EOPNOTSUPP;
29 }
30}
31
32static int sparx5_tc_block_cb_ingress(enum tc_setup_type type,
33 void *type_data,
34 void *cb_priv)
35{
36 return sparx5_tc_block_cb(type, type_data, cb_priv, true);
37}
38
39static int sparx5_tc_block_cb_egress(enum tc_setup_type type,
40 void *type_data,
41 void *cb_priv)
42{
43 return sparx5_tc_block_cb(type, type_data, cb_priv, false);
44}
45
46static int sparx5_tc_setup_block(struct net_device *ndev,
47 struct flow_block_offload *fbo)
48{
49 flow_setup_cb_t *cb;
50
51 if (fbo->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
52 cb = sparx5_tc_block_cb_ingress;
53 else if (fbo->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
54 cb = sparx5_tc_block_cb_egress;
55 else
56 return -EOPNOTSUPP;
57
58 return flow_block_cb_setup_simple(fbo, &sparx5_block_cb_list,
59 cb, ndev, ndev, false);
60}
61
62static void sparx5_tc_get_layer_and_idx(u32 parent, u32 portno, u32 *layer,
63 u32 *idx)
64{
65 if (parent == TC_H_ROOT) {
66 *layer = 2;
67 *idx = portno;
68 } else {
69 u32 queue = TC_H_MIN(parent) - 1;
70 *layer = 0;
71 *idx = SPX5_HSCH_L0_GET_IDX(portno, queue);
72 }
73}
74
75static int sparx5_tc_setup_qdisc_mqprio(struct net_device *ndev,
76 struct tc_mqprio_qopt_offload *m)
77{
78 m->qopt.hw = TC_MQPRIO_HW_OFFLOAD_TCS;
79
80 if (m->qopt.num_tc == 0)
81 return sparx5_tc_mqprio_del(ndev);
82 else
83 return sparx5_tc_mqprio_add(ndev, m->qopt.num_tc);
84}
85
86static int sparx5_tc_setup_qdisc_tbf(struct net_device *ndev,
87 struct tc_tbf_qopt_offload *qopt)
88{
89 struct sparx5_port *port = netdev_priv(ndev);
90 u32 layer, se_idx;
91
92 sparx5_tc_get_layer_and_idx(qopt->parent, port->portno, &layer,
93 &se_idx);
94
95 switch (qopt->command) {
96 case TC_TBF_REPLACE:
97 return sparx5_tc_tbf_add(port, &qopt->replace_params, layer,
98 se_idx);
99 case TC_TBF_DESTROY:
100 return sparx5_tc_tbf_del(port, layer, se_idx);
101 case TC_TBF_STATS:
102 return -EOPNOTSUPP;
103 default:
104 return -EOPNOTSUPP;
105 }
106
107 return -EOPNOTSUPP;
108}
109
110static int sparx5_tc_setup_qdisc_ets(struct net_device *ndev,
111 struct tc_ets_qopt_offload *qopt)
112{
113 struct tc_ets_qopt_offload_replace_params *params =
114 &qopt->replace_params;
115 struct sparx5_port *port = netdev_priv(ndev);
116 int i;
117
118 /* Only allow ets on ports */
119 if (qopt->parent != TC_H_ROOT)
120 return -EOPNOTSUPP;
121
122 switch (qopt->command) {
123 case TC_ETS_REPLACE:
124
125 /* We support eight priorities */
126 if (params->bands != SPX5_PRIOS)
127 return -EOPNOTSUPP;
128
129 /* Sanity checks */
130 for (i = 0; i < SPX5_PRIOS; ++i) {
131 /* Priority map is *always* reverse e.g: 7 6 5 .. 0 */
132 if (params->priomap[i] != (7 - i))
133 return -EOPNOTSUPP;
134 /* Throw an error if we receive zero weights by tc */
135 if (params->quanta[i] && params->weights[i] == 0) {
136 pr_err("Invalid ets configuration; band %d has weight zero",
137 i);
138 return -EINVAL;
139 }
140 }
141
142 return sparx5_tc_ets_add(port, params);
143 case TC_ETS_DESTROY:
144
145 return sparx5_tc_ets_del(port);
146 case TC_ETS_GRAFT:
147 return -EOPNOTSUPP;
148
149 default:
150 return -EOPNOTSUPP;
151 }
152
153 return -EOPNOTSUPP;
154}
155
156int sparx5_port_setup_tc(struct net_device *ndev, enum tc_setup_type type,
157 void *type_data)
158{
159 switch (type) {
160 case TC_SETUP_BLOCK:
161 return sparx5_tc_setup_block(ndev, type_data);
162 case TC_SETUP_QDISC_MQPRIO:
163 return sparx5_tc_setup_qdisc_mqprio(ndev, type_data);
164 case TC_SETUP_QDISC_TBF:
165 return sparx5_tc_setup_qdisc_tbf(ndev, type_data);
166 case TC_SETUP_QDISC_ETS:
167 return sparx5_tc_setup_qdisc_ets(ndev, type_data);
168 default:
169 return -EOPNOTSUPP;
170 }
171
172 return 0;
173}