]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - drivers/net/ethernet/mscc/ocelot_police.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[mirror_ubuntu-jammy-kernel.git] / drivers / net / ethernet / mscc / ocelot_police.c
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
9 enum 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
32 struct 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
43 static int qos_policer_conf_set(struct ocelot *ocelot, int 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 u32 pbs_max = 0, cbs_max = 0;
50 u8 ipg = 20;
51 u32 value;
52
53 pir = conf->pir;
54 pbs = conf->pbs;
55
56 switch (conf->mode) {
57 case MSCC_QOS_RATE_MODE_LINE:
58 case MSCC_QOS_RATE_MODE_DATA:
59 if (conf->mode == MSCC_QOS_RATE_MODE_LINE) {
60 frm_mode = POL_MODE_LINERATE;
61 ipg = min_t(u8, GENMASK(4, 0), conf->ipg);
62 } else {
63 frm_mode = POL_MODE_DATARATE;
64 }
65 if (conf->dlb) {
66 cir_ena = 1;
67 cir = conf->cir;
68 cbs = conf->cbs;
69 if (cir == 0 && cbs == 0) {
70 /* Discard cir frames */
71 cir_discard = 1;
72 } else {
73 cir = DIV_ROUND_UP(cir, 100);
74 cir *= 3; /* 33 1/3 kbps */
75 cbs = DIV_ROUND_UP(cbs, 4096);
76 cbs = (cbs ? cbs : 1); /* No zero burst size */
77 cbs_max = 60; /* Limit burst size */
78 cf = conf->cf;
79 if (cf)
80 pir += conf->cir;
81 }
82 }
83 if (pir == 0 && pbs == 0) {
84 /* Discard PIR frames */
85 pir_discard = 1;
86 } else {
87 pir = DIV_ROUND_UP(pir, 100);
88 pir *= 3; /* 33 1/3 kbps */
89 pbs = DIV_ROUND_UP(pbs, 4096);
90 pbs = (pbs ? pbs : 1); /* No zero burst size */
91 pbs_max = 60; /* Limit burst size */
92 }
93 break;
94 case MSCC_QOS_RATE_MODE_FRAME:
95 if (pir >= 100) {
96 frm_mode = POL_MODE_FRMRATE_HI;
97 pir = DIV_ROUND_UP(pir, 100);
98 pir *= 3; /* 33 1/3 fps */
99 pbs = (pbs * 10) / 328; /* 32.8 frames */
100 pbs = (pbs ? pbs : 1); /* No zero burst size */
101 pbs_max = GENMASK(6, 0); /* Limit burst size */
102 } else {
103 frm_mode = POL_MODE_FRMRATE_LO;
104 if (pir == 0 && pbs == 0) {
105 /* Discard all frames */
106 pir_discard = 1;
107 cir_discard = 1;
108 } else {
109 pir *= 3; /* 1/3 fps */
110 pbs = (pbs * 10) / 3; /* 0.3 frames */
111 pbs = (pbs ? pbs : 1); /* No zero burst size */
112 pbs_max = 61; /* Limit burst size */
113 }
114 }
115 break;
116 default: /* MSCC_QOS_RATE_MODE_DISABLED */
117 /* Disable policer using maximum rate and zero burst */
118 pir = GENMASK(15, 0);
119 pbs = 0;
120 break;
121 }
122
123 /* Check limits */
124 if (pir > GENMASK(15, 0)) {
125 dev_err(ocelot->dev, "Invalid pir for port %d: %u (max %lu)\n",
126 port, pir, GENMASK(15, 0));
127 return -EINVAL;
128 }
129
130 if (cir > GENMASK(15, 0)) {
131 dev_err(ocelot->dev, "Invalid cir for port %d: %u (max %lu)\n",
132 port, cir, GENMASK(15, 0));
133 return -EINVAL;
134 }
135
136 if (pbs > pbs_max) {
137 dev_err(ocelot->dev, "Invalid pbs for port %d: %u (max %u)\n",
138 port, pbs, pbs_max);
139 return -EINVAL;
140 }
141
142 if (cbs > cbs_max) {
143 dev_err(ocelot->dev, "Invalid cbs for port %d: %u (max %u)\n",
144 port, cbs, cbs_max);
145 return -EINVAL;
146 }
147
148 value = (ANA_POL_MODE_CFG_IPG_SIZE(ipg) |
149 ANA_POL_MODE_CFG_FRM_MODE(frm_mode) |
150 (cf ? ANA_POL_MODE_CFG_DLB_COUPLED : 0) |
151 (cir_ena ? ANA_POL_MODE_CFG_CIR_ENA : 0) |
152 ANA_POL_MODE_CFG_OVERSHOOT_ENA);
153
154 ocelot_write_gix(ocelot, value, ANA_POL_MODE_CFG, pol_ix);
155
156 ocelot_write_gix(ocelot,
157 ANA_POL_PIR_CFG_PIR_RATE(pir) |
158 ANA_POL_PIR_CFG_PIR_BURST(pbs),
159 ANA_POL_PIR_CFG, pol_ix);
160
161 ocelot_write_gix(ocelot,
162 (pir_discard ? GENMASK(22, 0) : 0),
163 ANA_POL_PIR_STATE, pol_ix);
164
165 ocelot_write_gix(ocelot,
166 ANA_POL_CIR_CFG_CIR_RATE(cir) |
167 ANA_POL_CIR_CFG_CIR_BURST(cbs),
168 ANA_POL_CIR_CFG, pol_ix);
169
170 ocelot_write_gix(ocelot,
171 (cir_discard ? GENMASK(22, 0) : 0),
172 ANA_POL_CIR_STATE, pol_ix);
173
174 return 0;
175 }
176
177 int ocelot_port_policer_add(struct ocelot *ocelot, int port,
178 struct ocelot_policer *pol)
179 {
180 struct qos_policer_conf pp = { 0 };
181 int err;
182
183 if (!pol)
184 return -EINVAL;
185
186 pp.mode = MSCC_QOS_RATE_MODE_DATA;
187 pp.pir = pol->rate;
188 pp.pbs = pol->burst;
189
190 dev_dbg(ocelot->dev, "%s: port %u pir %u kbps, pbs %u bytes\n",
191 __func__, port, pp.pir, pp.pbs);
192
193 err = qos_policer_conf_set(ocelot, port, POL_IX_PORT + port, &pp);
194 if (err)
195 return err;
196
197 ocelot_rmw_gix(ocelot,
198 ANA_PORT_POL_CFG_PORT_POL_ENA |
199 ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
200 ANA_PORT_POL_CFG_PORT_POL_ENA |
201 ANA_PORT_POL_CFG_POL_ORDER_M,
202 ANA_PORT_POL_CFG, port);
203
204 return 0;
205 }
206
207 int ocelot_port_policer_del(struct ocelot *ocelot, int port)
208 {
209 struct qos_policer_conf pp = { 0 };
210 int err;
211
212 dev_dbg(ocelot->dev, "%s: port %u\n", __func__, port);
213
214 pp.mode = MSCC_QOS_RATE_MODE_DISABLED;
215
216 err = qos_policer_conf_set(ocelot, port, POL_IX_PORT + 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);
225
226 return 0;
227 }