gpio: rcar: Fix runtime PM imbalance on error
[linux/fpc-iii.git] / drivers / net / ethernet / mscc / ocelot_police.c
blob2e1d8e18733289c1416b2d7dfd03a6b858739c8e
1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2 /* Microsemi Ocelot Switch driver
4 * Copyright (c) 2019 Microsemi Corporation
5 */
7 #include <soc/mscc/ocelot.h>
8 #include "ocelot_police.h"
10 enum mscc_qos_rate_mode {
11 MSCC_QOS_RATE_MODE_DISABLED, /* Policer/shaper disabled */
12 MSCC_QOS_RATE_MODE_LINE, /* Measure line rate in kbps incl. IPG */
13 MSCC_QOS_RATE_MODE_DATA, /* Measures data rate in kbps excl. IPG */
14 MSCC_QOS_RATE_MODE_FRAME, /* Measures frame rate in fps */
15 __MSCC_QOS_RATE_MODE_END,
16 NUM_MSCC_QOS_RATE_MODE = __MSCC_QOS_RATE_MODE_END,
17 MSCC_QOS_RATE_MODE_MAX = __MSCC_QOS_RATE_MODE_END - 1,
20 /* Types for ANA:POL[0-192]:POL_MODE_CFG.FRM_MODE */
21 #define POL_MODE_LINERATE 0 /* Incl IPG. Unit: 33 1/3 kbps, 4096 bytes */
22 #define POL_MODE_DATARATE 1 /* Excl IPG. Unit: 33 1/3 kbps, 4096 bytes */
23 #define POL_MODE_FRMRATE_HI 2 /* Unit: 33 1/3 fps, 32.8 frames */
24 #define POL_MODE_FRMRATE_LO 3 /* Unit: 1/3 fps, 0.3 frames */
26 /* Policer indexes */
27 #define POL_IX_PORT 0 /* 0-11 : Port policers */
28 #define POL_IX_QUEUE 32 /* 32-127 : Queue policers */
30 /* Default policer order */
31 #define POL_ORDER 0x1d3 /* Ocelot policer order: Serial (QoS -> Port -> VCAP) */
33 struct qos_policer_conf {
34 enum mscc_qos_rate_mode mode;
35 bool dlb; /* Enable DLB (dual leaky bucket mode */
36 bool cf; /* Coupling flag (ignored in SLB mode) */
37 u32 cir; /* CIR in kbps/fps (ignored in SLB mode) */
38 u32 cbs; /* CBS in bytes/frames (ignored in SLB mode) */
39 u32 pir; /* PIR in kbps/fps */
40 u32 pbs; /* PBS in bytes/frames */
41 u8 ipg; /* Size of IPG when MSCC_QOS_RATE_MODE_LINE is chosen */
44 static int qos_policer_conf_set(struct ocelot *ocelot, int port, u32 pol_ix,
45 struct qos_policer_conf *conf)
47 u32 cf = 0, cir_ena = 0, frm_mode = POL_MODE_LINERATE;
48 u32 cir = 0, cbs = 0, pir = 0, pbs = 0;
49 bool cir_discard = 0, pir_discard = 0;
50 u32 pbs_max = 0, cbs_max = 0;
51 u8 ipg = 20;
52 u32 value;
54 pir = conf->pir;
55 pbs = conf->pbs;
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;
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;
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 */
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 */
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;
124 /* Check limits */
125 if (pir > GENMASK(15, 0)) {
126 dev_err(ocelot->dev, "Invalid pir for port %d: %u (max %lu)\n",
127 port, pir, GENMASK(15, 0));
128 return -EINVAL;
131 if (cir > GENMASK(15, 0)) {
132 dev_err(ocelot->dev, "Invalid cir for port %d: %u (max %lu)\n",
133 port, cir, GENMASK(15, 0));
134 return -EINVAL;
137 if (pbs > pbs_max) {
138 dev_err(ocelot->dev, "Invalid pbs for port %d: %u (max %u)\n",
139 port, pbs, pbs_max);
140 return -EINVAL;
143 if (cbs > cbs_max) {
144 dev_err(ocelot->dev, "Invalid cbs for port %d: %u (max %u)\n",
145 port, cbs, cbs_max);
146 return -EINVAL;
149 value = (ANA_POL_MODE_CFG_IPG_SIZE(ipg) |
150 ANA_POL_MODE_CFG_FRM_MODE(frm_mode) |
151 (cf ? ANA_POL_MODE_CFG_DLB_COUPLED : 0) |
152 (cir_ena ? ANA_POL_MODE_CFG_CIR_ENA : 0) |
153 ANA_POL_MODE_CFG_OVERSHOOT_ENA);
155 ocelot_write_gix(ocelot, value, ANA_POL_MODE_CFG, pol_ix);
157 ocelot_write_gix(ocelot,
158 ANA_POL_PIR_CFG_PIR_RATE(pir) |
159 ANA_POL_PIR_CFG_PIR_BURST(pbs),
160 ANA_POL_PIR_CFG, pol_ix);
162 ocelot_write_gix(ocelot,
163 (pir_discard ? GENMASK(22, 0) : 0),
164 ANA_POL_PIR_STATE, pol_ix);
166 ocelot_write_gix(ocelot,
167 ANA_POL_CIR_CFG_CIR_RATE(cir) |
168 ANA_POL_CIR_CFG_CIR_BURST(cbs),
169 ANA_POL_CIR_CFG, pol_ix);
171 ocelot_write_gix(ocelot,
172 (cir_discard ? GENMASK(22, 0) : 0),
173 ANA_POL_CIR_STATE, pol_ix);
175 return 0;
178 int ocelot_port_policer_add(struct ocelot *ocelot, int port,
179 struct ocelot_policer *pol)
181 struct qos_policer_conf pp = { 0 };
182 int err;
184 if (!pol)
185 return -EINVAL;
187 pp.mode = MSCC_QOS_RATE_MODE_DATA;
188 pp.pir = pol->rate;
189 pp.pbs = pol->burst;
191 dev_dbg(ocelot->dev, "%s: port %u pir %u kbps, pbs %u bytes\n",
192 __func__, port, pp.pir, pp.pbs);
194 err = qos_policer_conf_set(ocelot, port, POL_IX_PORT + port, &pp);
195 if (err)
196 return err;
198 ocelot_rmw_gix(ocelot,
199 ANA_PORT_POL_CFG_PORT_POL_ENA |
200 ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
201 ANA_PORT_POL_CFG_PORT_POL_ENA |
202 ANA_PORT_POL_CFG_POL_ORDER_M,
203 ANA_PORT_POL_CFG, port);
205 return 0;
207 EXPORT_SYMBOL(ocelot_port_policer_add);
209 int ocelot_port_policer_del(struct ocelot *ocelot, int port)
211 struct qos_policer_conf pp = { 0 };
212 int err;
214 dev_dbg(ocelot->dev, "%s: port %u\n", __func__, port);
216 pp.mode = MSCC_QOS_RATE_MODE_DISABLED;
218 err = qos_policer_conf_set(ocelot, port, POL_IX_PORT + port, &pp);
219 if (err)
220 return err;
222 ocelot_rmw_gix(ocelot,
223 ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
224 ANA_PORT_POL_CFG_PORT_POL_ENA |
225 ANA_PORT_POL_CFG_POL_ORDER_M,
226 ANA_PORT_POL_CFG, port);
228 return 0;
230 EXPORT_SYMBOL(ocelot_port_policer_del);
232 int ocelot_ace_policer_add(struct ocelot *ocelot, u32 pol_ix,
233 struct ocelot_policer *pol)
235 struct qos_policer_conf pp = { 0 };
237 if (!pol)
238 return -EINVAL;
240 pp.mode = MSCC_QOS_RATE_MODE_DATA;
241 pp.pir = pol->rate;
242 pp.pbs = pol->burst;
244 return qos_policer_conf_set(ocelot, 0, pol_ix, &pp);
247 int ocelot_ace_policer_del(struct ocelot *ocelot, u32 pol_ix)
249 struct qos_policer_conf pp = { 0 };
251 pp.mode = MSCC_QOS_RATE_MODE_DISABLED;
253 return qos_policer_conf_set(ocelot, 0, pol_ix, &pp);