Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
0002 /* Microsemi Ocelot Switch driver
0003  *
0004  * Copyright (c) 2019 Microsemi Corporation
0005  */
0006 
0007 #include <soc/mscc/ocelot.h>
0008 #include "ocelot_police.h"
0009 
0010 /* Types for ANA:POL[0-192]:POL_MODE_CFG.FRM_MODE */
0011 #define POL_MODE_LINERATE   0 /* Incl IPG. Unit: 33 1/3 kbps, 4096 bytes */
0012 #define POL_MODE_DATARATE   1 /* Excl IPG. Unit: 33 1/3 kbps, 4096 bytes  */
0013 #define POL_MODE_FRMRATE_HI 2 /* Unit: 33 1/3 fps, 32.8 frames */
0014 #define POL_MODE_FRMRATE_LO 3 /* Unit: 1/3 fps, 0.3 frames */
0015 
0016 /* Policer indexes */
0017 #define POL_IX_PORT    0    /* 0-11    : Port policers */
0018 #define POL_IX_QUEUE   32   /* 32-127  : Queue policers  */
0019 
0020 /* Default policer order */
0021 #define POL_ORDER 0x1d3 /* Ocelot policer order: Serial (QoS -> Port -> VCAP) */
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                 /* Discard cir frames */
0051                 cir_discard = 1;
0052             } else {
0053                 cir = DIV_ROUND_UP(cir, 100);
0054                 cir *= 3; /* 33 1/3 kbps */
0055                 cbs = DIV_ROUND_UP(cbs, 4096);
0056                 cbs = (cbs ? cbs : 1); /* No zero burst size */
0057                 cbs_max = 60; /* Limit burst size */
0058                 cf = conf->cf;
0059                 if (cf)
0060                     pir += conf->cir;
0061             }
0062         }
0063         if (pir == 0 && pbs == 0) {
0064             /* Discard PIR frames */
0065             pir_discard = 1;
0066         } else {
0067             pir = DIV_ROUND_UP(pir, 100);
0068             pir *= 3;  /* 33 1/3 kbps */
0069             pbs = DIV_ROUND_UP(pbs, 4096);
0070             pbs = (pbs ? pbs : 1); /* No zero burst size */
0071             pbs_max = 60; /* Limit burst size */
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;  /* 33 1/3 fps */
0079             pbs = (pbs * 10) / 328; /* 32.8 frames */
0080             pbs = (pbs ? pbs : 1); /* No zero burst size */
0081             pbs_max = GENMASK(6, 0); /* Limit burst size */
0082         } else {
0083             frm_mode = POL_MODE_FRMRATE_LO;
0084             if (pir == 0 && pbs == 0) {
0085                 /* Discard all frames */
0086                 pir_discard = 1;
0087                 cir_discard = 1;
0088             } else {
0089                 pir *= 3; /* 1/3 fps */
0090                 pbs = (pbs * 10) / 3; /* 0.3 frames */
0091                 pbs = (pbs ? pbs : 1); /* No zero burst size */
0092                 pbs_max = 61; /* Limit burst size */
0093             }
0094         }
0095         break;
0096     default: /* MSCC_QOS_RATE_MODE_DISABLED */
0097         /* Disable policer using maximum rate and zero burst */
0098         pir = GENMASK(15, 0);
0099         pbs = 0;
0100         break;
0101     }
0102 
0103     /* Check limits */
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);