net: mscc: ocelot: add action of police on vcap_is2
Ocelot has 384 policers that can be allocated to ingress ports, QoS classes per port, and VCAP IS2 entries. ocelot_police.c supports to set policers which can be allocated to police action of VCAP IS2. We allocate policers from maximum pol_id, and decrease the pol_id when add a new vcap_is2 entry which is police action. Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
0d5d6045a7
commit
c9a7fe1238
|
@ -7,6 +7,7 @@
|
||||||
#include <linux/proc_fs.h>
|
#include <linux/proc_fs.h>
|
||||||
|
|
||||||
#include <soc/mscc/ocelot_vcap.h>
|
#include <soc/mscc/ocelot_vcap.h>
|
||||||
|
#include "ocelot_police.h"
|
||||||
#include "ocelot_ace.h"
|
#include "ocelot_ace.h"
|
||||||
#include "ocelot_s2.h"
|
#include "ocelot_s2.h"
|
||||||
|
|
||||||
|
@ -299,9 +300,9 @@ static void vcap_action_set(struct ocelot *ocelot, struct vcap_data *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void is2_action_set(struct ocelot *ocelot, struct vcap_data *data,
|
static void is2_action_set(struct ocelot *ocelot, struct vcap_data *data,
|
||||||
enum ocelot_ace_action action)
|
struct ocelot_ace_rule *ace)
|
||||||
{
|
{
|
||||||
switch (action) {
|
switch (ace->action) {
|
||||||
case OCELOT_ACL_ACTION_DROP:
|
case OCELOT_ACL_ACTION_DROP:
|
||||||
vcap_action_set(ocelot, data, VCAP_IS2_ACT_PORT_MASK, 0);
|
vcap_action_set(ocelot, data, VCAP_IS2_ACT_PORT_MASK, 0);
|
||||||
vcap_action_set(ocelot, data, VCAP_IS2_ACT_MASK_MODE, 1);
|
vcap_action_set(ocelot, data, VCAP_IS2_ACT_MASK_MODE, 1);
|
||||||
|
@ -319,6 +320,15 @@ static void is2_action_set(struct ocelot *ocelot, struct vcap_data *data,
|
||||||
vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_QU_NUM, 0);
|
vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_QU_NUM, 0);
|
||||||
vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_COPY_ENA, 1);
|
vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_COPY_ENA, 1);
|
||||||
break;
|
break;
|
||||||
|
case OCELOT_ACL_ACTION_POLICE:
|
||||||
|
vcap_action_set(ocelot, data, VCAP_IS2_ACT_PORT_MASK, 0);
|
||||||
|
vcap_action_set(ocelot, data, VCAP_IS2_ACT_MASK_MODE, 0);
|
||||||
|
vcap_action_set(ocelot, data, VCAP_IS2_ACT_POLICE_ENA, 1);
|
||||||
|
vcap_action_set(ocelot, data, VCAP_IS2_ACT_POLICE_IDX,
|
||||||
|
ace->pol_ix);
|
||||||
|
vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_QU_NUM, 0);
|
||||||
|
vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_COPY_ENA, 0);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -611,7 +621,7 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
|
||||||
}
|
}
|
||||||
|
|
||||||
vcap_key_set(ocelot, &data, VCAP_IS2_TYPE, type, type_mask);
|
vcap_key_set(ocelot, &data, VCAP_IS2_TYPE, type, type_mask);
|
||||||
is2_action_set(ocelot, &data, ace->action);
|
is2_action_set(ocelot, &data, ace);
|
||||||
vcap_data_set(data.counter, data.counter_offset,
|
vcap_data_set(data.counter, data.counter_offset,
|
||||||
vcap_is2->counter_width, ace->stats.pkts);
|
vcap_is2->counter_width, ace->stats.pkts);
|
||||||
|
|
||||||
|
@ -639,12 +649,19 @@ static void is2_entry_get(struct ocelot *ocelot, struct ocelot_ace_rule *rule,
|
||||||
rule->stats.pkts = cnt;
|
rule->stats.pkts = cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ocelot_ace_rule_add(struct ocelot_acl_block *block,
|
static void ocelot_ace_rule_add(struct ocelot *ocelot,
|
||||||
|
struct ocelot_acl_block *block,
|
||||||
struct ocelot_ace_rule *rule)
|
struct ocelot_ace_rule *rule)
|
||||||
{
|
{
|
||||||
struct ocelot_ace_rule *tmp;
|
struct ocelot_ace_rule *tmp;
|
||||||
struct list_head *pos, *n;
|
struct list_head *pos, *n;
|
||||||
|
|
||||||
|
if (rule->action == OCELOT_ACL_ACTION_POLICE) {
|
||||||
|
block->pol_lpr--;
|
||||||
|
rule->pol_ix = block->pol_lpr;
|
||||||
|
ocelot_ace_policer_add(ocelot, rule->pol_ix, &rule->pol);
|
||||||
|
}
|
||||||
|
|
||||||
block->count++;
|
block->count++;
|
||||||
|
|
||||||
if (list_empty(&block->rules)) {
|
if (list_empty(&block->rules)) {
|
||||||
|
@ -697,7 +714,7 @@ int ocelot_ace_rule_offload_add(struct ocelot *ocelot,
|
||||||
int i, index;
|
int i, index;
|
||||||
|
|
||||||
/* Add rule to the linked list */
|
/* Add rule to the linked list */
|
||||||
ocelot_ace_rule_add(block, rule);
|
ocelot_ace_rule_add(ocelot, block, rule);
|
||||||
|
|
||||||
/* Get the index of the inserted rule */
|
/* Get the index of the inserted rule */
|
||||||
index = ocelot_ace_rule_get_index_id(block, rule);
|
index = ocelot_ace_rule_get_index_id(block, rule);
|
||||||
|
@ -713,7 +730,33 @@ int ocelot_ace_rule_offload_add(struct ocelot *ocelot,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ocelot_ace_rule_del(struct ocelot_acl_block *block,
|
static void ocelot_ace_police_del(struct ocelot *ocelot,
|
||||||
|
struct ocelot_acl_block *block,
|
||||||
|
u32 ix)
|
||||||
|
{
|
||||||
|
struct ocelot_ace_rule *ace;
|
||||||
|
int index = -1;
|
||||||
|
|
||||||
|
if (ix < block->pol_lpr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
list_for_each_entry(ace, &block->rules, list) {
|
||||||
|
index++;
|
||||||
|
if (ace->action == OCELOT_ACL_ACTION_POLICE &&
|
||||||
|
ace->pol_ix < ix) {
|
||||||
|
ace->pol_ix += 1;
|
||||||
|
ocelot_ace_policer_add(ocelot, ace->pol_ix,
|
||||||
|
&ace->pol);
|
||||||
|
is2_entry_set(ocelot, index, ace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ocelot_ace_policer_del(ocelot, block->pol_lpr);
|
||||||
|
block->pol_lpr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocelot_ace_rule_del(struct ocelot *ocelot,
|
||||||
|
struct ocelot_acl_block *block,
|
||||||
struct ocelot_ace_rule *rule)
|
struct ocelot_ace_rule *rule)
|
||||||
{
|
{
|
||||||
struct ocelot_ace_rule *tmp;
|
struct ocelot_ace_rule *tmp;
|
||||||
|
@ -722,6 +765,10 @@ static void ocelot_ace_rule_del(struct ocelot_acl_block *block,
|
||||||
list_for_each_safe(pos, q, &block->rules) {
|
list_for_each_safe(pos, q, &block->rules) {
|
||||||
tmp = list_entry(pos, struct ocelot_ace_rule, list);
|
tmp = list_entry(pos, struct ocelot_ace_rule, list);
|
||||||
if (tmp->id == rule->id) {
|
if (tmp->id == rule->id) {
|
||||||
|
if (tmp->action == OCELOT_ACL_ACTION_POLICE)
|
||||||
|
ocelot_ace_police_del(ocelot, block,
|
||||||
|
tmp->pol_ix);
|
||||||
|
|
||||||
list_del(pos);
|
list_del(pos);
|
||||||
kfree(tmp);
|
kfree(tmp);
|
||||||
}
|
}
|
||||||
|
@ -744,7 +791,7 @@ int ocelot_ace_rule_offload_del(struct ocelot *ocelot,
|
||||||
index = ocelot_ace_rule_get_index_id(block, rule);
|
index = ocelot_ace_rule_get_index_id(block, rule);
|
||||||
|
|
||||||
/* Delete rule */
|
/* Delete rule */
|
||||||
ocelot_ace_rule_del(block, rule);
|
ocelot_ace_rule_del(ocelot, block, rule);
|
||||||
|
|
||||||
/* Move up all the blocks over the deleted rule */
|
/* Move up all the blocks over the deleted rule */
|
||||||
for (i = index; i < block->count; i++) {
|
for (i = index; i < block->count; i++) {
|
||||||
|
@ -779,6 +826,7 @@ int ocelot_ace_rule_stats_update(struct ocelot *ocelot,
|
||||||
int ocelot_ace_init(struct ocelot *ocelot)
|
int ocelot_ace_init(struct ocelot *ocelot)
|
||||||
{
|
{
|
||||||
const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
|
const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
|
||||||
|
struct ocelot_acl_block *block = &ocelot->acl_block;
|
||||||
struct vcap_data data;
|
struct vcap_data data;
|
||||||
|
|
||||||
memset(&data, 0, sizeof(data));
|
memset(&data, 0, sizeof(data));
|
||||||
|
@ -807,6 +855,8 @@ int ocelot_ace_init(struct ocelot *ocelot)
|
||||||
ocelot_write_gix(ocelot, 0x3fffff, ANA_POL_CIR_STATE,
|
ocelot_write_gix(ocelot, 0x3fffff, ANA_POL_CIR_STATE,
|
||||||
OCELOT_POLICER_DISCARD);
|
OCELOT_POLICER_DISCARD);
|
||||||
|
|
||||||
|
block->pol_lpr = OCELOT_POLICER_DISCARD - 1;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&ocelot->acl_block.rules);
|
INIT_LIST_HEAD(&ocelot->acl_block.rules);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#define _MSCC_OCELOT_ACE_H_
|
#define _MSCC_OCELOT_ACE_H_
|
||||||
|
|
||||||
#include "ocelot.h"
|
#include "ocelot.h"
|
||||||
|
#include "ocelot_police.h"
|
||||||
#include <net/sch_generic.h>
|
#include <net/sch_generic.h>
|
||||||
#include <net/pkt_cls.h>
|
#include <net/pkt_cls.h>
|
||||||
|
|
||||||
|
@ -176,6 +177,7 @@ struct ocelot_ace_frame_ipv6 {
|
||||||
enum ocelot_ace_action {
|
enum ocelot_ace_action {
|
||||||
OCELOT_ACL_ACTION_DROP,
|
OCELOT_ACL_ACTION_DROP,
|
||||||
OCELOT_ACL_ACTION_TRAP,
|
OCELOT_ACL_ACTION_TRAP,
|
||||||
|
OCELOT_ACL_ACTION_POLICE,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ocelot_ace_stats {
|
struct ocelot_ace_stats {
|
||||||
|
@ -208,6 +210,8 @@ struct ocelot_ace_rule {
|
||||||
struct ocelot_ace_frame_ipv4 ipv4;
|
struct ocelot_ace_frame_ipv4 ipv4;
|
||||||
struct ocelot_ace_frame_ipv6 ipv6;
|
struct ocelot_ace_frame_ipv6 ipv6;
|
||||||
} frame;
|
} frame;
|
||||||
|
struct ocelot_policer pol;
|
||||||
|
u32 pol_ix;
|
||||||
};
|
};
|
||||||
|
|
||||||
int ocelot_ace_rule_offload_add(struct ocelot *ocelot,
|
int ocelot_ace_rule_offload_add(struct ocelot *ocelot,
|
||||||
|
|
|
@ -12,6 +12,8 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f,
|
||||||
struct ocelot_ace_rule *ace)
|
struct ocelot_ace_rule *ace)
|
||||||
{
|
{
|
||||||
const struct flow_action_entry *a;
|
const struct flow_action_entry *a;
|
||||||
|
s64 burst;
|
||||||
|
u64 rate;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!flow_offload_has_one_action(&f->rule->action))
|
if (!flow_offload_has_one_action(&f->rule->action))
|
||||||
|
@ -29,6 +31,13 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f,
|
||||||
case FLOW_ACTION_TRAP:
|
case FLOW_ACTION_TRAP:
|
||||||
ace->action = OCELOT_ACL_ACTION_TRAP;
|
ace->action = OCELOT_ACL_ACTION_TRAP;
|
||||||
break;
|
break;
|
||||||
|
case FLOW_ACTION_POLICE:
|
||||||
|
ace->action = OCELOT_ACL_ACTION_POLICE;
|
||||||
|
rate = a->police.rate_bytes_ps;
|
||||||
|
ace->pol.rate = div_u64(rate, 1000) * 8;
|
||||||
|
burst = rate * PSCHED_NS2TICKS(a->police.burst);
|
||||||
|
ace->pol.burst = div_u64(burst, PSCHED_TICKS_PER_SEC);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
|
@ -225,3 +225,27 @@ int ocelot_port_policer_del(struct ocelot *ocelot, int port)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ocelot_ace_policer_add(struct ocelot *ocelot, u32 pol_ix,
|
||||||
|
struct ocelot_policer *pol)
|
||||||
|
{
|
||||||
|
struct qos_policer_conf pp = { 0 };
|
||||||
|
|
||||||
|
if (!pol)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
pp.mode = MSCC_QOS_RATE_MODE_DATA;
|
||||||
|
pp.pir = pol->rate;
|
||||||
|
pp.pbs = pol->burst;
|
||||||
|
|
||||||
|
return qos_policer_conf_set(ocelot, 0, pol_ix, &pp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ocelot_ace_policer_del(struct ocelot *ocelot, u32 pol_ix)
|
||||||
|
{
|
||||||
|
struct qos_policer_conf pp = { 0 };
|
||||||
|
|
||||||
|
pp.mode = MSCC_QOS_RATE_MODE_DISABLED;
|
||||||
|
|
||||||
|
return qos_policer_conf_set(ocelot, 0, pol_ix, &pp);
|
||||||
|
}
|
||||||
|
|
|
@ -19,4 +19,9 @@ int ocelot_port_policer_add(struct ocelot *ocelot, int port,
|
||||||
|
|
||||||
int ocelot_port_policer_del(struct ocelot *ocelot, int port);
|
int ocelot_port_policer_del(struct ocelot *ocelot, int port);
|
||||||
|
|
||||||
|
int ocelot_ace_policer_add(struct ocelot *ocelot, u32 pol_ix,
|
||||||
|
struct ocelot_policer *pol);
|
||||||
|
|
||||||
|
int ocelot_ace_policer_del(struct ocelot *ocelot, u32 pol_ix);
|
||||||
|
|
||||||
#endif /* _MSCC_OCELOT_POLICE_H_ */
|
#endif /* _MSCC_OCELOT_POLICE_H_ */
|
||||||
|
|
|
@ -468,6 +468,7 @@ struct ocelot_ops {
|
||||||
struct ocelot_acl_block {
|
struct ocelot_acl_block {
|
||||||
struct list_head rules;
|
struct list_head rules;
|
||||||
int count;
|
int count;
|
||||||
|
int pol_lpr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ocelot_port {
|
struct ocelot_port {
|
||||||
|
|
Loading…
Reference in New Issue