Loading...
1// SPDX-License-Identifier: (GPL-2.0 OR MIT)
2/* Microsemi Ocelot Switch driver
3 *
4 * Copyright (c) 2019 Microsemi Corporation
5 */
6
7#include <soc/mscc/ocelot.h>
8#include "ocelot_police.h"
9
10/* Types for ANA:POL[0-192]:POL_MODE_CFG.FRM_MODE */
11#define POL_MODE_LINERATE 0 /* Incl IPG. Unit: 33 1/3 kbps, 4096 bytes */
12#define POL_MODE_DATARATE 1 /* Excl IPG. Unit: 33 1/3 kbps, 4096 bytes */
13#define POL_MODE_FRMRATE_HI 2 /* Unit: 33 1/3 fps, 32.8 frames */
14#define POL_MODE_FRMRATE_LO 3 /* Unit: 1/3 fps, 0.3 frames */
15
16/* Policer indexes */
17#define POL_IX_PORT 0 /* 0-11 : Port policers */
18#define POL_IX_QUEUE 32 /* 32-127 : Queue policers */
19
20/* Default policer order */
21#define POL_ORDER 0x1d3 /* Ocelot policer order: Serial (QoS -> Port -> VCAP) */
22
23int qos_policer_conf_set(struct ocelot *ocelot, u32 pol_ix,
24 struct qos_policer_conf *conf)
25{
26 u32 cf = 0, cir_ena = 0, frm_mode = POL_MODE_LINERATE;
27 u32 cir = 0, cbs = 0, pir = 0, pbs = 0;
28 bool cir_discard = 0, pir_discard = 0;
29 u32 pbs_max = 0, cbs_max = 0;
30 u8 ipg = 20;
31 u32 value;
32
33 pir = conf->pir;
34 pbs = conf->pbs;
35
36 switch (conf->mode) {
37 case MSCC_QOS_RATE_MODE_LINE:
38 case MSCC_QOS_RATE_MODE_DATA:
39 if (conf->mode == MSCC_QOS_RATE_MODE_LINE) {
40 frm_mode = POL_MODE_LINERATE;
41 ipg = min_t(u8, GENMASK(4, 0), conf->ipg);
42 } else {
43 frm_mode = POL_MODE_DATARATE;
44 }
45 if (conf->dlb) {
46 cir_ena = 1;
47 cir = conf->cir;
48 cbs = conf->cbs;
49 if (cir == 0 && cbs == 0) {
50 /* Discard cir frames */
51 cir_discard = 1;
52 } else {
53 cir = DIV_ROUND_UP(cir, 100);
54 cir *= 3; /* 33 1/3 kbps */
55 cbs = DIV_ROUND_UP(cbs, 4096);
56 cbs = (cbs ? cbs : 1); /* No zero burst size */
57 cbs_max = 60; /* Limit burst size */
58 cf = conf->cf;
59 if (cf)
60 pir += conf->cir;
61 }
62 }
63 if (pir == 0 && pbs == 0) {
64 /* Discard PIR frames */
65 pir_discard = 1;
66 } else {
67 pir = DIV_ROUND_UP(pir, 100);
68 pir *= 3; /* 33 1/3 kbps */
69 pbs = DIV_ROUND_UP(pbs, 4096);
70 pbs = (pbs ? pbs : 1); /* No zero burst size */
71 pbs_max = 60; /* Limit burst size */
72 }
73 break;
74 case MSCC_QOS_RATE_MODE_FRAME:
75 if (pir >= 100) {
76 frm_mode = POL_MODE_FRMRATE_HI;
77 pir = DIV_ROUND_UP(pir, 100);
78 pir *= 3; /* 33 1/3 fps */
79 pbs = (pbs * 10) / 328; /* 32.8 frames */
80 pbs = (pbs ? pbs : 1); /* No zero burst size */
81 pbs_max = GENMASK(6, 0); /* Limit burst size */
82 } else {
83 frm_mode = POL_MODE_FRMRATE_LO;
84 if (pir == 0 && pbs == 0) {
85 /* Discard all frames */
86 pir_discard = 1;
87 cir_discard = 1;
88 } else {
89 pir *= 3; /* 1/3 fps */
90 pbs = (pbs * 10) / 3; /* 0.3 frames */
91 pbs = (pbs ? pbs : 1); /* No zero burst size */
92 pbs_max = 61; /* Limit burst size */
93 }
94 }
95 break;
96 default: /* MSCC_QOS_RATE_MODE_DISABLED */
97 /* Disable policer using maximum rate and zero burst */
98 pir = GENMASK(15, 0);
99 pbs = 0;
100 break;
101 }
102
103 /* Check limits */
104 if (pir > GENMASK(15, 0)) {
105 dev_err(ocelot->dev,
106 "Invalid pir for policer %u: %u (max %lu)\n",
107 pol_ix, pir, GENMASK(15, 0));
108 return -EINVAL;
109 }
110
111 if (cir > GENMASK(15, 0)) {
112 dev_err(ocelot->dev,
113 "Invalid cir for policer %u: %u (max %lu)\n",
114 pol_ix, cir, GENMASK(15, 0));
115 return -EINVAL;
116 }
117
118 if (pbs > pbs_max) {
119 dev_err(ocelot->dev,
120 "Invalid pbs for policer %u: %u (max %u)\n",
121 pol_ix, pbs, pbs_max);
122 return -EINVAL;
123 }
124
125 if (cbs > cbs_max) {
126 dev_err(ocelot->dev,
127 "Invalid cbs for policer %u: %u (max %u)\n",
128 pol_ix, cbs, cbs_max);
129 return -EINVAL;
130 }
131
132 value = (ANA_POL_MODE_CFG_IPG_SIZE(ipg) |
133 ANA_POL_MODE_CFG_FRM_MODE(frm_mode) |
134 (cf ? ANA_POL_MODE_CFG_DLB_COUPLED : 0) |
135 (cir_ena ? ANA_POL_MODE_CFG_CIR_ENA : 0) |
136 ANA_POL_MODE_CFG_OVERSHOOT_ENA);
137
138 ocelot_write_gix(ocelot, value, ANA_POL_MODE_CFG, pol_ix);
139
140 ocelot_write_gix(ocelot,
141 ANA_POL_PIR_CFG_PIR_RATE(pir) |
142 ANA_POL_PIR_CFG_PIR_BURST(pbs),
143 ANA_POL_PIR_CFG, pol_ix);
144
145 ocelot_write_gix(ocelot,
146 (pir_discard ? GENMASK(22, 0) : 0),
147 ANA_POL_PIR_STATE, pol_ix);
148
149 ocelot_write_gix(ocelot,
150 ANA_POL_CIR_CFG_CIR_RATE(cir) |
151 ANA_POL_CIR_CFG_CIR_BURST(cbs),
152 ANA_POL_CIR_CFG, pol_ix);
153
154 ocelot_write_gix(ocelot,
155 (cir_discard ? GENMASK(22, 0) : 0),
156 ANA_POL_CIR_STATE, pol_ix);
157
158 return 0;
159}
160
161int ocelot_policer_validate(const struct flow_action *action,
162 const struct flow_action_entry *a,
163 struct netlink_ext_ack *extack)
164{
165 if (a->police.exceed.act_id != FLOW_ACTION_DROP) {
166 NL_SET_ERR_MSG_MOD(extack,
167 "Offload not supported when exceed action is not drop");
168 return -EOPNOTSUPP;
169 }
170
171 if (a->police.notexceed.act_id != FLOW_ACTION_PIPE &&
172 a->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
173 NL_SET_ERR_MSG_MOD(extack,
174 "Offload not supported when conform action is not pipe or ok");
175 return -EOPNOTSUPP;
176 }
177
178 if (a->police.notexceed.act_id == FLOW_ACTION_ACCEPT &&
179 !flow_action_is_last_entry(action, a)) {
180 NL_SET_ERR_MSG_MOD(extack,
181 "Offload not supported when conform action is ok, but police action is not last");
182 return -EOPNOTSUPP;
183 }
184
185 if (a->police.peakrate_bytes_ps ||
186 a->police.avrate || a->police.overhead) {
187 NL_SET_ERR_MSG_MOD(extack,
188 "Offload not supported when peakrate/avrate/overhead is configured");
189 return -EOPNOTSUPP;
190 }
191
192 if (a->police.rate_pkt_ps) {
193 NL_SET_ERR_MSG_MOD(extack,
194 "Offload does not support packets per second");
195 return -EOPNOTSUPP;
196 }
197
198 return 0;
199}
200EXPORT_SYMBOL(ocelot_policer_validate);
201
202int ocelot_port_policer_add(struct ocelot *ocelot, int port,
203 struct ocelot_policer *pol)
204{
205 struct qos_policer_conf pp = { 0 };
206 int err;
207
208 if (!pol)
209 return -EINVAL;
210
211 pp.mode = MSCC_QOS_RATE_MODE_DATA;
212 pp.pir = pol->rate;
213 pp.pbs = pol->burst;
214
215 dev_dbg(ocelot->dev, "%s: port %u pir %u kbps, pbs %u bytes\n",
216 __func__, port, pp.pir, pp.pbs);
217
218 err = qos_policer_conf_set(ocelot, POL_IX_PORT + port, &pp);
219 if (err)
220 return err;
221
222 ocelot_rmw_gix(ocelot,
223 ANA_PORT_POL_CFG_PORT_POL_ENA |
224 ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
225 ANA_PORT_POL_CFG_PORT_POL_ENA |
226 ANA_PORT_POL_CFG_POL_ORDER_M,
227 ANA_PORT_POL_CFG, port);
228
229 return 0;
230}
231EXPORT_SYMBOL(ocelot_port_policer_add);
232
233int ocelot_port_policer_del(struct ocelot *ocelot, int port)
234{
235 struct qos_policer_conf pp = { 0 };
236 int err;
237
238 dev_dbg(ocelot->dev, "%s: port %u\n", __func__, port);
239
240 pp.mode = MSCC_QOS_RATE_MODE_DISABLED;
241
242 err = qos_policer_conf_set(ocelot, POL_IX_PORT + port, &pp);
243 if (err)
244 return err;
245
246 ocelot_rmw_gix(ocelot,
247 ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
248 ANA_PORT_POL_CFG_PORT_POL_ENA |
249 ANA_PORT_POL_CFG_POL_ORDER_M,
250 ANA_PORT_POL_CFG, port);
251
252 return 0;
253}
254EXPORT_SYMBOL(ocelot_port_policer_del);
1// SPDX-License-Identifier: (GPL-2.0 OR MIT)
2/* Microsemi Ocelot Switch driver
3 *
4 * Copyright (c) 2019 Microsemi Corporation
5 */
6
7#include "ocelot_police.h"
8
9enum mscc_qos_rate_mode {
10 MSCC_QOS_RATE_MODE_DISABLED, /* Policer/shaper disabled */
11 MSCC_QOS_RATE_MODE_LINE, /* Measure line rate in kbps incl. IPG */
12 MSCC_QOS_RATE_MODE_DATA, /* Measures data rate in kbps excl. IPG */
13 MSCC_QOS_RATE_MODE_FRAME, /* Measures frame rate in fps */
14 __MSCC_QOS_RATE_MODE_END,
15 NUM_MSCC_QOS_RATE_MODE = __MSCC_QOS_RATE_MODE_END,
16 MSCC_QOS_RATE_MODE_MAX = __MSCC_QOS_RATE_MODE_END - 1,
17};
18
19/* Types for ANA:POL[0-192]:POL_MODE_CFG.FRM_MODE */
20#define POL_MODE_LINERATE 0 /* Incl IPG. Unit: 33 1/3 kbps, 4096 bytes */
21#define POL_MODE_DATARATE 1 /* Excl IPG. Unit: 33 1/3 kbps, 4096 bytes */
22#define POL_MODE_FRMRATE_HI 2 /* Unit: 33 1/3 fps, 32.8 frames */
23#define POL_MODE_FRMRATE_LO 3 /* Unit: 1/3 fps, 0.3 frames */
24
25/* Policer indexes */
26#define POL_IX_PORT 0 /* 0-11 : Port policers */
27#define POL_IX_QUEUE 32 /* 32-127 : Queue policers */
28
29/* Default policer order */
30#define POL_ORDER 0x1d3 /* Ocelot policer order: Serial (QoS -> Port -> VCAP) */
31
32struct qos_policer_conf {
33 enum mscc_qos_rate_mode mode;
34 bool dlb; /* Enable DLB (dual leaky bucket mode */
35 bool cf; /* Coupling flag (ignored in SLB mode) */
36 u32 cir; /* CIR in kbps/fps (ignored in SLB mode) */
37 u32 cbs; /* CBS in bytes/frames (ignored in SLB mode) */
38 u32 pir; /* PIR in kbps/fps */
39 u32 pbs; /* PBS in bytes/frames */
40 u8 ipg; /* Size of IPG when MSCC_QOS_RATE_MODE_LINE is chosen */
41};
42
43static int qos_policer_conf_set(struct ocelot_port *port, u32 pol_ix,
44 struct qos_policer_conf *conf)
45{
46 u32 cf = 0, cir_ena = 0, frm_mode = POL_MODE_LINERATE;
47 u32 cir = 0, cbs = 0, pir = 0, pbs = 0;
48 bool cir_discard = 0, pir_discard = 0;
49 struct ocelot *ocelot = port->ocelot;
50 u32 pbs_max = 0, cbs_max = 0;
51 u8 ipg = 20;
52 u32 value;
53
54 pir = conf->pir;
55 pbs = conf->pbs;
56
57 switch (conf->mode) {
58 case MSCC_QOS_RATE_MODE_LINE:
59 case MSCC_QOS_RATE_MODE_DATA:
60 if (conf->mode == MSCC_QOS_RATE_MODE_LINE) {
61 frm_mode = POL_MODE_LINERATE;
62 ipg = min_t(u8, GENMASK(4, 0), conf->ipg);
63 } else {
64 frm_mode = POL_MODE_DATARATE;
65 }
66 if (conf->dlb) {
67 cir_ena = 1;
68 cir = conf->cir;
69 cbs = conf->cbs;
70 if (cir == 0 && cbs == 0) {
71 /* Discard cir frames */
72 cir_discard = 1;
73 } else {
74 cir = DIV_ROUND_UP(cir, 100);
75 cir *= 3; /* 33 1/3 kbps */
76 cbs = DIV_ROUND_UP(cbs, 4096);
77 cbs = (cbs ? cbs : 1); /* No zero burst size */
78 cbs_max = 60; /* Limit burst size */
79 cf = conf->cf;
80 if (cf)
81 pir += conf->cir;
82 }
83 }
84 if (pir == 0 && pbs == 0) {
85 /* Discard PIR frames */
86 pir_discard = 1;
87 } else {
88 pir = DIV_ROUND_UP(pir, 100);
89 pir *= 3; /* 33 1/3 kbps */
90 pbs = DIV_ROUND_UP(pbs, 4096);
91 pbs = (pbs ? pbs : 1); /* No zero burst size */
92 pbs_max = 60; /* Limit burst size */
93 }
94 break;
95 case MSCC_QOS_RATE_MODE_FRAME:
96 if (pir >= 100) {
97 frm_mode = POL_MODE_FRMRATE_HI;
98 pir = DIV_ROUND_UP(pir, 100);
99 pir *= 3; /* 33 1/3 fps */
100 pbs = (pbs * 10) / 328; /* 32.8 frames */
101 pbs = (pbs ? pbs : 1); /* No zero burst size */
102 pbs_max = GENMASK(6, 0); /* Limit burst size */
103 } else {
104 frm_mode = POL_MODE_FRMRATE_LO;
105 if (pir == 0 && pbs == 0) {
106 /* Discard all frames */
107 pir_discard = 1;
108 cir_discard = 1;
109 } else {
110 pir *= 3; /* 1/3 fps */
111 pbs = (pbs * 10) / 3; /* 0.3 frames */
112 pbs = (pbs ? pbs : 1); /* No zero burst size */
113 pbs_max = 61; /* Limit burst size */
114 }
115 }
116 break;
117 default: /* MSCC_QOS_RATE_MODE_DISABLED */
118 /* Disable policer using maximum rate and zero burst */
119 pir = GENMASK(15, 0);
120 pbs = 0;
121 break;
122 }
123
124 /* Check limits */
125 if (pir > GENMASK(15, 0)) {
126 netdev_err(port->dev, "Invalid pir\n");
127 return -EINVAL;
128 }
129
130 if (cir > GENMASK(15, 0)) {
131 netdev_err(port->dev, "Invalid cir\n");
132 return -EINVAL;
133 }
134
135 if (pbs > pbs_max) {
136 netdev_err(port->dev, "Invalid pbs\n");
137 return -EINVAL;
138 }
139
140 if (cbs > cbs_max) {
141 netdev_err(port->dev, "Invalid cbs\n");
142 return -EINVAL;
143 }
144
145 value = (ANA_POL_MODE_CFG_IPG_SIZE(ipg) |
146 ANA_POL_MODE_CFG_FRM_MODE(frm_mode) |
147 (cf ? ANA_POL_MODE_CFG_DLB_COUPLED : 0) |
148 (cir_ena ? ANA_POL_MODE_CFG_CIR_ENA : 0) |
149 ANA_POL_MODE_CFG_OVERSHOOT_ENA);
150
151 ocelot_write_gix(ocelot, value, ANA_POL_MODE_CFG, pol_ix);
152
153 ocelot_write_gix(ocelot,
154 ANA_POL_PIR_CFG_PIR_RATE(pir) |
155 ANA_POL_PIR_CFG_PIR_BURST(pbs),
156 ANA_POL_PIR_CFG, pol_ix);
157
158 ocelot_write_gix(ocelot,
159 (pir_discard ? GENMASK(22, 0) : 0),
160 ANA_POL_PIR_STATE, pol_ix);
161
162 ocelot_write_gix(ocelot,
163 ANA_POL_CIR_CFG_CIR_RATE(cir) |
164 ANA_POL_CIR_CFG_CIR_BURST(cbs),
165 ANA_POL_CIR_CFG, pol_ix);
166
167 ocelot_write_gix(ocelot,
168 (cir_discard ? GENMASK(22, 0) : 0),
169 ANA_POL_CIR_STATE, pol_ix);
170
171 return 0;
172}
173
174int ocelot_port_policer_add(struct ocelot_port *port,
175 struct ocelot_policer *pol)
176{
177 struct ocelot *ocelot = port->ocelot;
178 struct qos_policer_conf pp = { 0 };
179 int err;
180
181 if (!pol)
182 return -EINVAL;
183
184 pp.mode = MSCC_QOS_RATE_MODE_DATA;
185 pp.pir = pol->rate;
186 pp.pbs = pol->burst;
187
188 netdev_dbg(port->dev,
189 "%s: port %u pir %u kbps, pbs %u bytes\n",
190 __func__, port->chip_port, pp.pir, pp.pbs);
191
192 err = qos_policer_conf_set(port, POL_IX_PORT + port->chip_port, &pp);
193 if (err)
194 return err;
195
196 ocelot_rmw_gix(ocelot,
197 ANA_PORT_POL_CFG_PORT_POL_ENA |
198 ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
199 ANA_PORT_POL_CFG_PORT_POL_ENA |
200 ANA_PORT_POL_CFG_POL_ORDER_M,
201 ANA_PORT_POL_CFG, port->chip_port);
202
203 return 0;
204}
205
206int ocelot_port_policer_del(struct ocelot_port *port)
207{
208 struct ocelot *ocelot = port->ocelot;
209 struct qos_policer_conf pp = { 0 };
210 int err;
211
212 netdev_dbg(port->dev, "%s: port %u\n", __func__, port->chip_port);
213
214 pp.mode = MSCC_QOS_RATE_MODE_DISABLED;
215
216 err = qos_policer_conf_set(port, POL_IX_PORT + port->chip_port, &pp);
217 if (err)
218 return err;
219
220 ocelot_rmw_gix(ocelot,
221 ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
222 ANA_PORT_POL_CFG_PORT_POL_ENA |
223 ANA_PORT_POL_CFG_POL_ORDER_M,
224 ANA_PORT_POL_CFG, port->chip_port);
225
226 return 0;
227}