cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ocelot_police.c (6699B)


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