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 
23 int qos_policer_conf_set(struct ocelot *ocelot, int port, 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, "Invalid pir for port %d: %u (max %lu)\n",
106 			port, pir, GENMASK(15, 0));
107 		return -EINVAL;
108 	}
109 
110 	if (cir > GENMASK(15, 0)) {
111 		dev_err(ocelot->dev, "Invalid cir for port %d: %u (max %lu)\n",
112 			port, cir, GENMASK(15, 0));
113 		return -EINVAL;
114 	}
115 
116 	if (pbs > pbs_max) {
117 		dev_err(ocelot->dev, "Invalid pbs for port %d: %u (max %u)\n",
118 			port, pbs, pbs_max);
119 		return -EINVAL;
120 	}
121 
122 	if (cbs > cbs_max) {
123 		dev_err(ocelot->dev, "Invalid cbs for port %d: %u (max %u)\n",
124 			port, cbs, cbs_max);
125 		return -EINVAL;
126 	}
127 
128 	value = (ANA_POL_MODE_CFG_IPG_SIZE(ipg) |
129 		 ANA_POL_MODE_CFG_FRM_MODE(frm_mode) |
130 		 (cf ? ANA_POL_MODE_CFG_DLB_COUPLED : 0) |
131 		 (cir_ena ? ANA_POL_MODE_CFG_CIR_ENA : 0) |
132 		 ANA_POL_MODE_CFG_OVERSHOOT_ENA);
133 
134 	ocelot_write_gix(ocelot, value, ANA_POL_MODE_CFG, pol_ix);
135 
136 	ocelot_write_gix(ocelot,
137 			 ANA_POL_PIR_CFG_PIR_RATE(pir) |
138 			 ANA_POL_PIR_CFG_PIR_BURST(pbs),
139 			 ANA_POL_PIR_CFG, pol_ix);
140 
141 	ocelot_write_gix(ocelot,
142 			 (pir_discard ? GENMASK(22, 0) : 0),
143 			 ANA_POL_PIR_STATE, pol_ix);
144 
145 	ocelot_write_gix(ocelot,
146 			 ANA_POL_CIR_CFG_CIR_RATE(cir) |
147 			 ANA_POL_CIR_CFG_CIR_BURST(cbs),
148 			 ANA_POL_CIR_CFG, pol_ix);
149 
150 	ocelot_write_gix(ocelot,
151 			 (cir_discard ? GENMASK(22, 0) : 0),
152 			 ANA_POL_CIR_STATE, pol_ix);
153 
154 	return 0;
155 }
156 
157 int ocelot_policer_validate(const struct flow_action *action,
158 			    const struct flow_action_entry *a,
159 			    struct netlink_ext_ack *extack)
160 {
161 	if (a->police.exceed.act_id != FLOW_ACTION_DROP) {
162 		NL_SET_ERR_MSG_MOD(extack,
163 				   "Offload not supported when exceed action is not drop");
164 		return -EOPNOTSUPP;
165 	}
166 
167 	if (a->police.notexceed.act_id != FLOW_ACTION_PIPE &&
168 	    a->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
169 		NL_SET_ERR_MSG_MOD(extack,
170 				   "Offload not supported when conform action is not pipe or ok");
171 		return -EOPNOTSUPP;
172 	}
173 
174 	if (a->police.notexceed.act_id == FLOW_ACTION_ACCEPT &&
175 	    !flow_action_is_last_entry(action, a)) {
176 		NL_SET_ERR_MSG_MOD(extack,
177 				   "Offload not supported when conform action is ok, but police action is not last");
178 		return -EOPNOTSUPP;
179 	}
180 
181 	if (a->police.peakrate_bytes_ps ||
182 	    a->police.avrate || a->police.overhead) {
183 		NL_SET_ERR_MSG_MOD(extack,
184 				   "Offload not supported when peakrate/avrate/overhead is configured");
185 		return -EOPNOTSUPP;
186 	}
187 
188 	if (a->police.rate_pkt_ps) {
189 		NL_SET_ERR_MSG_MOD(extack,
190 				   "Offload does not support packets per second");
191 		return -EOPNOTSUPP;
192 	}
193 
194 	return 0;
195 }
196 EXPORT_SYMBOL(ocelot_policer_validate);
197 
198 int ocelot_port_policer_add(struct ocelot *ocelot, int port,
199 			    struct ocelot_policer *pol)
200 {
201 	struct qos_policer_conf pp = { 0 };
202 	int err;
203 
204 	if (!pol)
205 		return -EINVAL;
206 
207 	pp.mode = MSCC_QOS_RATE_MODE_DATA;
208 	pp.pir = pol->rate;
209 	pp.pbs = pol->burst;
210 
211 	dev_dbg(ocelot->dev, "%s: port %u pir %u kbps, pbs %u bytes\n",
212 		__func__, port, pp.pir, pp.pbs);
213 
214 	err = qos_policer_conf_set(ocelot, port, POL_IX_PORT + port, &pp);
215 	if (err)
216 		return err;
217 
218 	ocelot_rmw_gix(ocelot,
219 		       ANA_PORT_POL_CFG_PORT_POL_ENA |
220 		       ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
221 		       ANA_PORT_POL_CFG_PORT_POL_ENA |
222 		       ANA_PORT_POL_CFG_POL_ORDER_M,
223 		       ANA_PORT_POL_CFG, port);
224 
225 	return 0;
226 }
227 EXPORT_SYMBOL(ocelot_port_policer_add);
228 
229 int ocelot_port_policer_del(struct ocelot *ocelot, int port)
230 {
231 	struct qos_policer_conf pp = { 0 };
232 	int err;
233 
234 	dev_dbg(ocelot->dev, "%s: port %u\n", __func__, port);
235 
236 	pp.mode = MSCC_QOS_RATE_MODE_DISABLED;
237 
238 	err = qos_policer_conf_set(ocelot, port, POL_IX_PORT + port, &pp);
239 	if (err)
240 		return err;
241 
242 	ocelot_rmw_gix(ocelot,
243 		       ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
244 		       ANA_PORT_POL_CFG_PORT_POL_ENA |
245 		       ANA_PORT_POL_CFG_POL_ORDER_M,
246 		       ANA_PORT_POL_CFG, port);
247 
248 	return 0;
249 }
250 EXPORT_SYMBOL(ocelot_port_policer_del);
251