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 enum mscc_qos_rate_mode { 11 MSCC_QOS_RATE_MODE_DISABLED, /* Policer/shaper disabled */ 12 MSCC_QOS_RATE_MODE_LINE, /* Measure line rate in kbps incl. IPG */ 13 MSCC_QOS_RATE_MODE_DATA, /* Measures data rate in kbps excl. IPG */ 14 MSCC_QOS_RATE_MODE_FRAME, /* Measures frame rate in fps */ 15 __MSCC_QOS_RATE_MODE_END, 16 NUM_MSCC_QOS_RATE_MODE = __MSCC_QOS_RATE_MODE_END, 17 MSCC_QOS_RATE_MODE_MAX = __MSCC_QOS_RATE_MODE_END - 1, 18 }; 19 20 /* Types for ANA:POL[0-192]:POL_MODE_CFG.FRM_MODE */ 21 #define POL_MODE_LINERATE 0 /* Incl IPG. Unit: 33 1/3 kbps, 4096 bytes */ 22 #define POL_MODE_DATARATE 1 /* Excl IPG. Unit: 33 1/3 kbps, 4096 bytes */ 23 #define POL_MODE_FRMRATE_HI 2 /* Unit: 33 1/3 fps, 32.8 frames */ 24 #define POL_MODE_FRMRATE_LO 3 /* Unit: 1/3 fps, 0.3 frames */ 25 26 /* Policer indexes */ 27 #define POL_IX_PORT 0 /* 0-11 : Port policers */ 28 #define POL_IX_QUEUE 32 /* 32-127 : Queue policers */ 29 30 /* Default policer order */ 31 #define POL_ORDER 0x1d3 /* Ocelot policer order: Serial (QoS -> Port -> VCAP) */ 32 33 struct qos_policer_conf { 34 enum mscc_qos_rate_mode mode; 35 bool dlb; /* Enable DLB (dual leaky bucket mode */ 36 bool cf; /* Coupling flag (ignored in SLB mode) */ 37 u32 cir; /* CIR in kbps/fps (ignored in SLB mode) */ 38 u32 cbs; /* CBS in bytes/frames (ignored in SLB mode) */ 39 u32 pir; /* PIR in kbps/fps */ 40 u32 pbs; /* PBS in bytes/frames */ 41 u8 ipg; /* Size of IPG when MSCC_QOS_RATE_MODE_LINE is chosen */ 42 }; 43 44 static int qos_policer_conf_set(struct ocelot *ocelot, int port, u32 pol_ix, 45 struct qos_policer_conf *conf) 46 { 47 u32 cf = 0, cir_ena = 0, frm_mode = POL_MODE_LINERATE; 48 u32 cir = 0, cbs = 0, pir = 0, pbs = 0; 49 bool cir_discard = 0, pir_discard = 0; 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 dev_err(ocelot->dev, "Invalid pir for port %d: %u (max %lu)\n", 127 port, pir, GENMASK(15, 0)); 128 return -EINVAL; 129 } 130 131 if (cir > GENMASK(15, 0)) { 132 dev_err(ocelot->dev, "Invalid cir for port %d: %u (max %lu)\n", 133 port, cir, GENMASK(15, 0)); 134 return -EINVAL; 135 } 136 137 if (pbs > pbs_max) { 138 dev_err(ocelot->dev, "Invalid pbs for port %d: %u (max %u)\n", 139 port, pbs, pbs_max); 140 return -EINVAL; 141 } 142 143 if (cbs > cbs_max) { 144 dev_err(ocelot->dev, "Invalid cbs for port %d: %u (max %u)\n", 145 port, cbs, cbs_max); 146 return -EINVAL; 147 } 148 149 value = (ANA_POL_MODE_CFG_IPG_SIZE(ipg) | 150 ANA_POL_MODE_CFG_FRM_MODE(frm_mode) | 151 (cf ? ANA_POL_MODE_CFG_DLB_COUPLED : 0) | 152 (cir_ena ? ANA_POL_MODE_CFG_CIR_ENA : 0) | 153 ANA_POL_MODE_CFG_OVERSHOOT_ENA); 154 155 ocelot_write_gix(ocelot, value, ANA_POL_MODE_CFG, pol_ix); 156 157 ocelot_write_gix(ocelot, 158 ANA_POL_PIR_CFG_PIR_RATE(pir) | 159 ANA_POL_PIR_CFG_PIR_BURST(pbs), 160 ANA_POL_PIR_CFG, pol_ix); 161 162 ocelot_write_gix(ocelot, 163 (pir_discard ? GENMASK(22, 0) : 0), 164 ANA_POL_PIR_STATE, pol_ix); 165 166 ocelot_write_gix(ocelot, 167 ANA_POL_CIR_CFG_CIR_RATE(cir) | 168 ANA_POL_CIR_CFG_CIR_BURST(cbs), 169 ANA_POL_CIR_CFG, pol_ix); 170 171 ocelot_write_gix(ocelot, 172 (cir_discard ? GENMASK(22, 0) : 0), 173 ANA_POL_CIR_STATE, pol_ix); 174 175 return 0; 176 } 177 178 int ocelot_port_policer_add(struct ocelot *ocelot, int port, 179 struct ocelot_policer *pol) 180 { 181 struct qos_policer_conf pp = { 0 }; 182 int err; 183 184 if (!pol) 185 return -EINVAL; 186 187 pp.mode = MSCC_QOS_RATE_MODE_DATA; 188 pp.pir = pol->rate; 189 pp.pbs = pol->burst; 190 191 dev_dbg(ocelot->dev, "%s: port %u pir %u kbps, pbs %u bytes\n", 192 __func__, port, pp.pir, pp.pbs); 193 194 err = qos_policer_conf_set(ocelot, port, POL_IX_PORT + port, &pp); 195 if (err) 196 return err; 197 198 ocelot_rmw_gix(ocelot, 199 ANA_PORT_POL_CFG_PORT_POL_ENA | 200 ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER), 201 ANA_PORT_POL_CFG_PORT_POL_ENA | 202 ANA_PORT_POL_CFG_POL_ORDER_M, 203 ANA_PORT_POL_CFG, port); 204 205 return 0; 206 } 207 EXPORT_SYMBOL(ocelot_port_policer_add); 208 209 int ocelot_port_policer_del(struct ocelot *ocelot, int port) 210 { 211 struct qos_policer_conf pp = { 0 }; 212 int err; 213 214 dev_dbg(ocelot->dev, "%s: port %u\n", __func__, port); 215 216 pp.mode = MSCC_QOS_RATE_MODE_DISABLED; 217 218 err = qos_policer_conf_set(ocelot, port, POL_IX_PORT + port, &pp); 219 if (err) 220 return err; 221 222 ocelot_rmw_gix(ocelot, 223 ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER), 224 ANA_PORT_POL_CFG_PORT_POL_ENA | 225 ANA_PORT_POL_CFG_POL_ORDER_M, 226 ANA_PORT_POL_CFG, port); 227 228 return 0; 229 } 230 EXPORT_SYMBOL(ocelot_port_policer_del); 231 232 int ocelot_ace_policer_add(struct ocelot *ocelot, u32 pol_ix, 233 struct ocelot_policer *pol) 234 { 235 struct qos_policer_conf pp = { 0 }; 236 237 if (!pol) 238 return -EINVAL; 239 240 pp.mode = MSCC_QOS_RATE_MODE_DATA; 241 pp.pir = pol->rate; 242 pp.pbs = pol->burst; 243 244 return qos_policer_conf_set(ocelot, 0, pol_ix, &pp); 245 } 246 247 int ocelot_ace_policer_del(struct ocelot *ocelot, u32 pol_ix) 248 { 249 struct qos_policer_conf pp = { 0 }; 250 251 pp.mode = MSCC_QOS_RATE_MODE_DISABLED; 252 253 return qos_policer_conf_set(ocelot, 0, pol_ix, &pp); 254 } 255