Linux Audio

Check our new training course

Loading...
v6.13.7
  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);
v5.4
  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
  9enum 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
 32struct 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
 43static int qos_policer_conf_set(struct ocelot_port *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	struct ocelot *ocelot = port->ocelot;
 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		netdev_err(port->dev, "Invalid pir\n");
 
 
127		return -EINVAL;
128	}
129
130	if (cir > GENMASK(15, 0)) {
131		netdev_err(port->dev, "Invalid cir\n");
 
 
132		return -EINVAL;
133	}
134
135	if (pbs > pbs_max) {
136		netdev_err(port->dev, "Invalid pbs\n");
 
 
137		return -EINVAL;
138	}
139
140	if (cbs > cbs_max) {
141		netdev_err(port->dev, "Invalid cbs\n");
 
 
142		return -EINVAL;
143	}
144
145	value = (ANA_POL_MODE_CFG_IPG_SIZE(ipg) |
146		 ANA_POL_MODE_CFG_FRM_MODE(frm_mode) |
147		 (cf ? ANA_POL_MODE_CFG_DLB_COUPLED : 0) |
148		 (cir_ena ? ANA_POL_MODE_CFG_CIR_ENA : 0) |
149		 ANA_POL_MODE_CFG_OVERSHOOT_ENA);
150
151	ocelot_write_gix(ocelot, value, ANA_POL_MODE_CFG, pol_ix);
152
153	ocelot_write_gix(ocelot,
154			 ANA_POL_PIR_CFG_PIR_RATE(pir) |
155			 ANA_POL_PIR_CFG_PIR_BURST(pbs),
156			 ANA_POL_PIR_CFG, pol_ix);
157
158	ocelot_write_gix(ocelot,
159			 (pir_discard ? GENMASK(22, 0) : 0),
160			 ANA_POL_PIR_STATE, pol_ix);
161
162	ocelot_write_gix(ocelot,
163			 ANA_POL_CIR_CFG_CIR_RATE(cir) |
164			 ANA_POL_CIR_CFG_CIR_BURST(cbs),
165			 ANA_POL_CIR_CFG, pol_ix);
166
167	ocelot_write_gix(ocelot,
168			 (cir_discard ? GENMASK(22, 0) : 0),
169			 ANA_POL_CIR_STATE, pol_ix);
170
171	return 0;
172}
173
174int ocelot_port_policer_add(struct ocelot_port *port,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175			    struct ocelot_policer *pol)
176{
177	struct ocelot *ocelot = port->ocelot;
178	struct qos_policer_conf pp = { 0 };
179	int err;
180
181	if (!pol)
182		return -EINVAL;
183
184	pp.mode = MSCC_QOS_RATE_MODE_DATA;
185	pp.pir = pol->rate;
186	pp.pbs = pol->burst;
187
188	netdev_dbg(port->dev,
189		   "%s: port %u pir %u kbps, pbs %u bytes\n",
190		   __func__, port->chip_port, pp.pir, pp.pbs);
191
192	err = qos_policer_conf_set(port, POL_IX_PORT + port->chip_port, &pp);
193	if (err)
194		return err;
195
196	ocelot_rmw_gix(ocelot,
197		       ANA_PORT_POL_CFG_PORT_POL_ENA |
198		       ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
199		       ANA_PORT_POL_CFG_PORT_POL_ENA |
200		       ANA_PORT_POL_CFG_POL_ORDER_M,
201		       ANA_PORT_POL_CFG, port->chip_port);
202
203	return 0;
204}
 
205
206int ocelot_port_policer_del(struct ocelot_port *port)
207{
208	struct ocelot *ocelot = port->ocelot;
209	struct qos_policer_conf pp = { 0 };
210	int err;
211
212	netdev_dbg(port->dev, "%s: port %u\n", __func__, port->chip_port);
213
214	pp.mode = MSCC_QOS_RATE_MODE_DISABLED;
215
216	err = qos_policer_conf_set(port, POL_IX_PORT + port->chip_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->chip_port);
225
226	return 0;
227}