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 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,
18 };
19 
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 */
25 
26 /* Policer indexes */
27 #define POL_IX_PORT    0    /* 0-11    : Port policers */
28 #define POL_IX_QUEUE   32   /* 32-127  : Queue policers  */
29 
30 /* Default policer order */
31 #define POL_ORDER 0x1d3 /* Ocelot policer order: Serial (QoS -> Port -> VCAP) */
32 
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 */
42 };
43 
44 static int qos_policer_conf_set(struct ocelot *ocelot, int port, u32 pol_ix,
45 				struct qos_policer_conf *conf)
46 {
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;
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 		dev_err(ocelot->dev, "Invalid pir for port %d: %u (max %lu)\n",
127 			port, pir, GENMASK(15, 0));
128 		return -EINVAL;
129 	}
130 
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;
135 	}
136 
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;
141 	}
142 
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;
147 	}
148 
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);
154 
155 	ocelot_write_gix(ocelot, value, ANA_POL_MODE_CFG, pol_ix);
156 
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);
161 
162 	ocelot_write_gix(ocelot,
163 			 (pir_discard ? GENMASK(22, 0) : 0),
164 			 ANA_POL_PIR_STATE, pol_ix);
165 
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);
170 
171 	ocelot_write_gix(ocelot,
172 			 (cir_discard ? GENMASK(22, 0) : 0),
173 			 ANA_POL_CIR_STATE, pol_ix);
174 
175 	return 0;
176 }
177 
178 int ocelot_port_policer_add(struct ocelot *ocelot, int port,
179 			    struct ocelot_policer *pol)
180 {
181 	struct qos_policer_conf pp = { 0 };
182 	int err;
183 
184 	if (!pol)
185 		return -EINVAL;
186 
187 	pp.mode = MSCC_QOS_RATE_MODE_DATA;
188 	pp.pir = pol->rate;
189 	pp.pbs = pol->burst;
190 
191 	dev_dbg(ocelot->dev, "%s: port %u pir %u kbps, pbs %u bytes\n",
192 		__func__, port, pp.pir, pp.pbs);
193 
194 	err = qos_policer_conf_set(ocelot, port, POL_IX_PORT + port, &pp);
195 	if (err)
196 		return err;
197 
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);
204 
205 	return 0;
206 }
207 EXPORT_SYMBOL(ocelot_port_policer_add);
208 
209 int ocelot_port_policer_del(struct ocelot *ocelot, int port)
210 {
211 	struct qos_policer_conf pp = { 0 };
212 	int err;
213 
214 	dev_dbg(ocelot->dev, "%s: port %u\n", __func__, port);
215 
216 	pp.mode = MSCC_QOS_RATE_MODE_DISABLED;
217 
218 	err = qos_policer_conf_set(ocelot, port, POL_IX_PORT + port, &pp);
219 	if (err)
220 		return err;
221 
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);
227 
228 	return 0;
229 }
230 EXPORT_SYMBOL(ocelot_port_policer_del);
231 
232 int ocelot_ace_policer_add(struct ocelot *ocelot, u32 pol_ix,
233 			   struct ocelot_policer *pol)
234 {
235 	struct qos_policer_conf pp = { 0 };
236 
237 	if (!pol)
238 		return -EINVAL;
239 
240 	pp.mode = MSCC_QOS_RATE_MODE_DATA;
241 	pp.pir = pol->rate;
242 	pp.pbs = pol->burst;
243 
244 	return qos_policer_conf_set(ocelot, 0, pol_ix, &pp);
245 }
246 
247 int ocelot_ace_policer_del(struct ocelot *ocelot, u32 pol_ix)
248 {
249 	struct qos_policer_conf pp = { 0 };
250 
251 	pp.mode = MSCC_QOS_RATE_MODE_DISABLED;
252 
253 	return qos_policer_conf_set(ocelot, 0, pol_ix, &pp);
254 }
255