diff options
-rw-r--r-- | drivers/net/dsa/ocelot/felix_vsc9959.c | 32 |
1 files changed, 31 insertions, 1 deletions
diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index f8d770384344..eb6c05f29883 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -1341,6 +1341,7 @@ static int vsc9959_port_setup_tc(struct dsa_switch *ds, int port, #define VSC9959_PSFP_SFID_MAX 175 #define VSC9959_PSFP_GATE_ID_MAX 183 +#define VSC9959_PSFP_POLICER_BASE 63 #define VSC9959_PSFP_POLICER_MAX 383 #define VSC9959_PSFP_GATE_LIST_NUM 4 #define VSC9959_PSFP_GATE_CYCLETIME_MIN 5000 @@ -1841,7 +1842,10 @@ static int vsc9959_psfp_filter_add(struct ocelot *ocelot, struct felix_stream stream = {0}; struct felix_stream_gate *sgi; struct ocelot_psfp_list *psfp; + struct ocelot_policer pol; int ret, i, size; + u64 rate, burst; + u32 index; psfp = &ocelot->psfp; @@ -1860,13 +1864,33 @@ static int vsc9959_psfp_filter_add(struct ocelot *ocelot, ret = vsc9959_psfp_sgi_table_add(ocelot, sgi); if (ret) { kfree(sgi); - return ret; + goto err; } sfi.sg_valid = 1; sfi.sgid = sgi->index; kfree(sgi); break; case FLOW_ACTION_POLICE: + index = a->police.index + VSC9959_PSFP_POLICER_BASE; + if (index > VSC9959_PSFP_POLICER_MAX) { + ret = -EINVAL; + goto err; + } + + rate = a->police.rate_bytes_ps; + burst = rate * PSCHED_NS2TICKS(a->police.burst); + pol = (struct ocelot_policer) { + .burst = div_u64(burst, PSCHED_TICKS_PER_SEC), + .rate = div_u64(rate, 1000) * 8, + }; + ret = ocelot_vcap_policer_add(ocelot, index, &pol); + if (ret) + goto err; + + sfi.fm_valid = 1; + sfi.fmid = index; + sfi.maxsdu = a->police.mtu; + break; default: return -EOPNOTSUPP; } @@ -1903,6 +1927,9 @@ err: if (sfi.sg_valid) vsc9959_psfp_sgi_table_del(ocelot, sfi.sgid); + if (sfi.fm_valid) + ocelot_vcap_policer_del(ocelot, sfi.fmid); + return ret; } @@ -1926,6 +1953,9 @@ static int vsc9959_psfp_filter_del(struct ocelot *ocelot, if (sfi->sg_valid) vsc9959_psfp_sgi_table_del(ocelot, sfi->sgid); + if (sfi->fm_valid) + ocelot_vcap_policer_del(ocelot, sfi->fmid); + vsc9959_psfp_sfi_table_del(ocelot, stream->sfid); stream->sfid_valid = 0; |