Commit c9a7fe12 authored by Xiaoliang Yang's avatar Xiaoliang Yang Committed by David S. Miller

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: default avatarXiaoliang Yang <xiaoliang.yang_1@nxp.com>
Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0d5d6045
...@@ -7,6 +7,7 @@ ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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 @@ ...@@ -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 { ...@@ -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 { ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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 { ...@@ -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 {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment