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 23 int qos_policer_conf_set(struct ocelot *ocelot, int port, 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, "Invalid pir for port %d: %u (max %lu)\n", 106 port, pir, GENMASK(15, 0)); 107 return -EINVAL; 108 } 109 110 if (cir > GENMASK(15, 0)) { 111 dev_err(ocelot->dev, "Invalid cir for port %d: %u (max %lu)\n", 112 port, cir, GENMASK(15, 0)); 113 return -EINVAL; 114 } 115 116 if (pbs > pbs_max) { 117 dev_err(ocelot->dev, "Invalid pbs for port %d: %u (max %u)\n", 118 port, pbs, pbs_max); 119 return -EINVAL; 120 } 121 122 if (cbs > cbs_max) { 123 dev_err(ocelot->dev, "Invalid cbs for port %d: %u (max %u)\n", 124 port, cbs, cbs_max); 125 return -EINVAL; 126 } 127 128 value = (ANA_POL_MODE_CFG_IPG_SIZE(ipg) | 129 ANA_POL_MODE_CFG_FRM_MODE(frm_mode) | 130 (cf ? ANA_POL_MODE_CFG_DLB_COUPLED : 0) | 131 (cir_ena ? ANA_POL_MODE_CFG_CIR_ENA : 0) | 132 ANA_POL_MODE_CFG_OVERSHOOT_ENA); 133 134 ocelot_write_gix(ocelot, value, ANA_POL_MODE_CFG, pol_ix); 135 136 ocelot_write_gix(ocelot, 137 ANA_POL_PIR_CFG_PIR_RATE(pir) | 138 ANA_POL_PIR_CFG_PIR_BURST(pbs), 139 ANA_POL_PIR_CFG, pol_ix); 140 141 ocelot_write_gix(ocelot, 142 (pir_discard ? GENMASK(22, 0) : 0), 143 ANA_POL_PIR_STATE, pol_ix); 144 145 ocelot_write_gix(ocelot, 146 ANA_POL_CIR_CFG_CIR_RATE(cir) | 147 ANA_POL_CIR_CFG_CIR_BURST(cbs), 148 ANA_POL_CIR_CFG, pol_ix); 149 150 ocelot_write_gix(ocelot, 151 (cir_discard ? GENMASK(22, 0) : 0), 152 ANA_POL_CIR_STATE, pol_ix); 153 154 return 0; 155 } 156 157 int ocelot_policer_validate(const struct flow_action *action, 158 const struct flow_action_entry *a, 159 struct netlink_ext_ack *extack) 160 { 161 if (a->police.exceed.act_id != FLOW_ACTION_DROP) { 162 NL_SET_ERR_MSG_MOD(extack, 163 "Offload not supported when exceed action is not drop"); 164 return -EOPNOTSUPP; 165 } 166 167 if (a->police.notexceed.act_id != FLOW_ACTION_PIPE && 168 a->police.notexceed.act_id != FLOW_ACTION_ACCEPT) { 169 NL_SET_ERR_MSG_MOD(extack, 170 "Offload not supported when conform action is not pipe or ok"); 171 return -EOPNOTSUPP; 172 } 173 174 if (a->police.notexceed.act_id == FLOW_ACTION_ACCEPT && 175 !flow_action_is_last_entry(action, a)) { 176 NL_SET_ERR_MSG_MOD(extack, 177 "Offload not supported when conform action is ok, but police action is not last"); 178 return -EOPNOTSUPP; 179 } 180 181 if (a->police.peakrate_bytes_ps || 182 a->police.avrate || a->police.overhead) { 183 NL_SET_ERR_MSG_MOD(extack, 184 "Offload not supported when peakrate/avrate/overhead is configured"); 185 return -EOPNOTSUPP; 186 } 187 188 if (a->police.rate_pkt_ps) { 189 NL_SET_ERR_MSG_MOD(extack, 190 "Offload does not support packets per second"); 191 return -EOPNOTSUPP; 192 } 193 194 return 0; 195 } 196 EXPORT_SYMBOL(ocelot_policer_validate); 197 198 int ocelot_port_policer_add(struct ocelot *ocelot, int port, 199 struct ocelot_policer *pol) 200 { 201 struct qos_policer_conf pp = { 0 }; 202 int err; 203 204 if (!pol) 205 return -EINVAL; 206 207 pp.mode = MSCC_QOS_RATE_MODE_DATA; 208 pp.pir = pol->rate; 209 pp.pbs = pol->burst; 210 211 dev_dbg(ocelot->dev, "%s: port %u pir %u kbps, pbs %u bytes\n", 212 __func__, port, pp.pir, pp.pbs); 213 214 err = qos_policer_conf_set(ocelot, port, POL_IX_PORT + port, &pp); 215 if (err) 216 return err; 217 218 ocelot_rmw_gix(ocelot, 219 ANA_PORT_POL_CFG_PORT_POL_ENA | 220 ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER), 221 ANA_PORT_POL_CFG_PORT_POL_ENA | 222 ANA_PORT_POL_CFG_POL_ORDER_M, 223 ANA_PORT_POL_CFG, port); 224 225 return 0; 226 } 227 EXPORT_SYMBOL(ocelot_port_policer_add); 228 229 int ocelot_port_policer_del(struct ocelot *ocelot, int port) 230 { 231 struct qos_policer_conf pp = { 0 }; 232 int err; 233 234 dev_dbg(ocelot->dev, "%s: port %u\n", __func__, port); 235 236 pp.mode = MSCC_QOS_RATE_MODE_DISABLED; 237 238 err = qos_policer_conf_set(ocelot, port, POL_IX_PORT + port, &pp); 239 if (err) 240 return err; 241 242 ocelot_rmw_gix(ocelot, 243 ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER), 244 ANA_PORT_POL_CFG_PORT_POL_ENA | 245 ANA_PORT_POL_CFG_POL_ORDER_M, 246 ANA_PORT_POL_CFG, port); 247 248 return 0; 249 } 250 EXPORT_SYMBOL(ocelot_port_policer_del); 251