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);
255