0001
0002
0003
0004
0005
0006
0007 #include <soc/mscc/ocelot.h>
0008 #include "ocelot_police.h"
0009
0010
0011 #define POL_MODE_LINERATE 0
0012 #define POL_MODE_DATARATE 1
0013 #define POL_MODE_FRMRATE_HI 2
0014 #define POL_MODE_FRMRATE_LO 3
0015
0016
0017 #define POL_IX_PORT 0
0018 #define POL_IX_QUEUE 32
0019
0020
0021 #define POL_ORDER 0x1d3
0022
0023 int qos_policer_conf_set(struct ocelot *ocelot, u32 pol_ix,
0024 struct qos_policer_conf *conf)
0025 {
0026 u32 cf = 0, cir_ena = 0, frm_mode = POL_MODE_LINERATE;
0027 u32 cir = 0, cbs = 0, pir = 0, pbs = 0;
0028 bool cir_discard = 0, pir_discard = 0;
0029 u32 pbs_max = 0, cbs_max = 0;
0030 u8 ipg = 20;
0031 u32 value;
0032
0033 pir = conf->pir;
0034 pbs = conf->pbs;
0035
0036 switch (conf->mode) {
0037 case MSCC_QOS_RATE_MODE_LINE:
0038 case MSCC_QOS_RATE_MODE_DATA:
0039 if (conf->mode == MSCC_QOS_RATE_MODE_LINE) {
0040 frm_mode = POL_MODE_LINERATE;
0041 ipg = min_t(u8, GENMASK(4, 0), conf->ipg);
0042 } else {
0043 frm_mode = POL_MODE_DATARATE;
0044 }
0045 if (conf->dlb) {
0046 cir_ena = 1;
0047 cir = conf->cir;
0048 cbs = conf->cbs;
0049 if (cir == 0 && cbs == 0) {
0050
0051 cir_discard = 1;
0052 } else {
0053 cir = DIV_ROUND_UP(cir, 100);
0054 cir *= 3;
0055 cbs = DIV_ROUND_UP(cbs, 4096);
0056 cbs = (cbs ? cbs : 1);
0057 cbs_max = 60;
0058 cf = conf->cf;
0059 if (cf)
0060 pir += conf->cir;
0061 }
0062 }
0063 if (pir == 0 && pbs == 0) {
0064
0065 pir_discard = 1;
0066 } else {
0067 pir = DIV_ROUND_UP(pir, 100);
0068 pir *= 3;
0069 pbs = DIV_ROUND_UP(pbs, 4096);
0070 pbs = (pbs ? pbs : 1);
0071 pbs_max = 60;
0072 }
0073 break;
0074 case MSCC_QOS_RATE_MODE_FRAME:
0075 if (pir >= 100) {
0076 frm_mode = POL_MODE_FRMRATE_HI;
0077 pir = DIV_ROUND_UP(pir, 100);
0078 pir *= 3;
0079 pbs = (pbs * 10) / 328;
0080 pbs = (pbs ? pbs : 1);
0081 pbs_max = GENMASK(6, 0);
0082 } else {
0083 frm_mode = POL_MODE_FRMRATE_LO;
0084 if (pir == 0 && pbs == 0) {
0085
0086 pir_discard = 1;
0087 cir_discard = 1;
0088 } else {
0089 pir *= 3;
0090 pbs = (pbs * 10) / 3;
0091 pbs = (pbs ? pbs : 1);
0092 pbs_max = 61;
0093 }
0094 }
0095 break;
0096 default:
0097
0098 pir = GENMASK(15, 0);
0099 pbs = 0;
0100 break;
0101 }
0102
0103
0104 if (pir > GENMASK(15, 0)) {
0105 dev_err(ocelot->dev,
0106 "Invalid pir for policer %u: %u (max %lu)\n",
0107 pol_ix, pir, GENMASK(15, 0));
0108 return -EINVAL;
0109 }
0110
0111 if (cir > GENMASK(15, 0)) {
0112 dev_err(ocelot->dev,
0113 "Invalid cir for policer %u: %u (max %lu)\n",
0114 pol_ix, cir, GENMASK(15, 0));
0115 return -EINVAL;
0116 }
0117
0118 if (pbs > pbs_max) {
0119 dev_err(ocelot->dev,
0120 "Invalid pbs for policer %u: %u (max %u)\n",
0121 pol_ix, pbs, pbs_max);
0122 return -EINVAL;
0123 }
0124
0125 if (cbs > cbs_max) {
0126 dev_err(ocelot->dev,
0127 "Invalid cbs for policer %u: %u (max %u)\n",
0128 pol_ix, cbs, cbs_max);
0129 return -EINVAL;
0130 }
0131
0132 value = (ANA_POL_MODE_CFG_IPG_SIZE(ipg) |
0133 ANA_POL_MODE_CFG_FRM_MODE(frm_mode) |
0134 (cf ? ANA_POL_MODE_CFG_DLB_COUPLED : 0) |
0135 (cir_ena ? ANA_POL_MODE_CFG_CIR_ENA : 0) |
0136 ANA_POL_MODE_CFG_OVERSHOOT_ENA);
0137
0138 ocelot_write_gix(ocelot, value, ANA_POL_MODE_CFG, pol_ix);
0139
0140 ocelot_write_gix(ocelot,
0141 ANA_POL_PIR_CFG_PIR_RATE(pir) |
0142 ANA_POL_PIR_CFG_PIR_BURST(pbs),
0143 ANA_POL_PIR_CFG, pol_ix);
0144
0145 ocelot_write_gix(ocelot,
0146 (pir_discard ? GENMASK(22, 0) : 0),
0147 ANA_POL_PIR_STATE, pol_ix);
0148
0149 ocelot_write_gix(ocelot,
0150 ANA_POL_CIR_CFG_CIR_RATE(cir) |
0151 ANA_POL_CIR_CFG_CIR_BURST(cbs),
0152 ANA_POL_CIR_CFG, pol_ix);
0153
0154 ocelot_write_gix(ocelot,
0155 (cir_discard ? GENMASK(22, 0) : 0),
0156 ANA_POL_CIR_STATE, pol_ix);
0157
0158 return 0;
0159 }
0160
0161 int ocelot_policer_validate(const struct flow_action *action,
0162 const struct flow_action_entry *a,
0163 struct netlink_ext_ack *extack)
0164 {
0165 if (a->police.exceed.act_id != FLOW_ACTION_DROP) {
0166 NL_SET_ERR_MSG_MOD(extack,
0167 "Offload not supported when exceed action is not drop");
0168 return -EOPNOTSUPP;
0169 }
0170
0171 if (a->police.notexceed.act_id != FLOW_ACTION_PIPE &&
0172 a->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
0173 NL_SET_ERR_MSG_MOD(extack,
0174 "Offload not supported when conform action is not pipe or ok");
0175 return -EOPNOTSUPP;
0176 }
0177
0178 if (a->police.notexceed.act_id == FLOW_ACTION_ACCEPT &&
0179 !flow_action_is_last_entry(action, a)) {
0180 NL_SET_ERR_MSG_MOD(extack,
0181 "Offload not supported when conform action is ok, but police action is not last");
0182 return -EOPNOTSUPP;
0183 }
0184
0185 if (a->police.peakrate_bytes_ps ||
0186 a->police.avrate || a->police.overhead) {
0187 NL_SET_ERR_MSG_MOD(extack,
0188 "Offload not supported when peakrate/avrate/overhead is configured");
0189 return -EOPNOTSUPP;
0190 }
0191
0192 if (a->police.rate_pkt_ps) {
0193 NL_SET_ERR_MSG_MOD(extack,
0194 "Offload does not support packets per second");
0195 return -EOPNOTSUPP;
0196 }
0197
0198 return 0;
0199 }
0200 EXPORT_SYMBOL(ocelot_policer_validate);
0201
0202 int ocelot_port_policer_add(struct ocelot *ocelot, int port,
0203 struct ocelot_policer *pol)
0204 {
0205 struct qos_policer_conf pp = { 0 };
0206 int err;
0207
0208 if (!pol)
0209 return -EINVAL;
0210
0211 pp.mode = MSCC_QOS_RATE_MODE_DATA;
0212 pp.pir = pol->rate;
0213 pp.pbs = pol->burst;
0214
0215 dev_dbg(ocelot->dev, "%s: port %u pir %u kbps, pbs %u bytes\n",
0216 __func__, port, pp.pir, pp.pbs);
0217
0218 err = qos_policer_conf_set(ocelot, POL_IX_PORT + port, &pp);
0219 if (err)
0220 return err;
0221
0222 ocelot_rmw_gix(ocelot,
0223 ANA_PORT_POL_CFG_PORT_POL_ENA |
0224 ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
0225 ANA_PORT_POL_CFG_PORT_POL_ENA |
0226 ANA_PORT_POL_CFG_POL_ORDER_M,
0227 ANA_PORT_POL_CFG, port);
0228
0229 return 0;
0230 }
0231 EXPORT_SYMBOL(ocelot_port_policer_add);
0232
0233 int ocelot_port_policer_del(struct ocelot *ocelot, int port)
0234 {
0235 struct qos_policer_conf pp = { 0 };
0236 int err;
0237
0238 dev_dbg(ocelot->dev, "%s: port %u\n", __func__, port);
0239
0240 pp.mode = MSCC_QOS_RATE_MODE_DISABLED;
0241
0242 err = qos_policer_conf_set(ocelot, POL_IX_PORT + port, &pp);
0243 if (err)
0244 return err;
0245
0246 ocelot_rmw_gix(ocelot,
0247 ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER),
0248 ANA_PORT_POL_CFG_PORT_POL_ENA |
0249 ANA_PORT_POL_CFG_POL_ORDER_M,
0250 ANA_PORT_POL_CFG, port);
0251
0252 return 0;
0253 }
0254 EXPORT_SYMBOL(ocelot_port_policer_del);