Commit f13230a4 authored by Steen Hegelund's avatar Steen Hegelund Committed by David S. Miller

net: microchip: sparx5: Add support for IS2 VCAP rule counters

This adds API methods to set and get a rule counter.

A VCAP instance may contain the counter as part of the VCAP cache area, and
this counter may be one or more bits in width.  This type of counter
automatically increments it value when the rule is hit.

Other VCAP instances have a dedicated counter area outside of the VCAP and
in this case the rule must contain the counter id to be able to locate the
counter value.  In this case there must also be a rule action that updates
the counter using the rule id when the rule is hit.

The Sparx5 IS2 VCAP uses a dedicated counter area.
Signed-off-by: default avatarSteen Hegelund <steen.hegelund@microchip.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 990e4839
...@@ -428,15 +428,58 @@ static void sparx5_vcap_cache_write(struct net_device *ndev, ...@@ -428,15 +428,58 @@ static void sparx5_vcap_cache_write(struct net_device *ndev,
default: default:
break; break;
} }
if (sel & VCAP_SEL_COUNTER) {
start = start & 0xfff; /* counter limit */
if (admin->vinst == 0)
spx5_wr(admin->cache.counter, sparx5,
ANA_ACL_CNT_A(start));
else
spx5_wr(admin->cache.counter, sparx5,
ANA_ACL_CNT_B(start));
spx5_wr(admin->cache.sticky, sparx5,
VCAP_SUPER_VCAP_CNT_DAT(0));
}
} }
/* API callback used for reading from the VCAP into the VCAP cache */ /* API callback used for reading from the VCAP into the VCAP cache */
static void sparx5_vcap_cache_read(struct net_device *ndev, static void sparx5_vcap_cache_read(struct net_device *ndev,
struct vcap_admin *admin, struct vcap_admin *admin,
enum vcap_selection sel, u32 start, enum vcap_selection sel,
u32 start,
u32 count) u32 count)
{ {
/* this will be added later */ struct sparx5_port *port = netdev_priv(ndev);
struct sparx5 *sparx5 = port->sparx5;
u32 *keystr, *mskstr, *actstr;
int idx;
keystr = &admin->cache.keystream[start];
mskstr = &admin->cache.maskstream[start];
actstr = &admin->cache.actionstream[start];
if (sel & VCAP_SEL_ENTRY) {
for (idx = 0; idx < count; ++idx) {
keystr[idx] = spx5_rd(sparx5,
VCAP_SUPER_VCAP_ENTRY_DAT(idx));
mskstr[idx] = ~spx5_rd(sparx5,
VCAP_SUPER_VCAP_MASK_DAT(idx));
}
}
if (sel & VCAP_SEL_ACTION) {
for (idx = 0; idx < count; ++idx)
actstr[idx] = spx5_rd(sparx5,
VCAP_SUPER_VCAP_ACTION_DAT(idx));
}
if (sel & VCAP_SEL_COUNTER) {
start = start & 0xfff; /* counter limit */
if (admin->vinst == 0)
admin->cache.counter =
spx5_rd(sparx5, ANA_ACL_CNT_A(start));
else
admin->cache.counter =
spx5_rd(sparx5, ANA_ACL_CNT_B(start));
admin->cache.sticky =
spx5_rd(sparx5, VCAP_SUPER_VCAP_CNT_DAT(0));
}
} }
/* API callback used for initializing a VCAP address range */ /* API callback used for initializing a VCAP address range */
......
...@@ -25,6 +25,8 @@ struct vcap_rule_internal { ...@@ -25,6 +25,8 @@ struct vcap_rule_internal {
int actionset_sw_regs; /* registers in a subword in an actionset */ int actionset_sw_regs; /* registers in a subword in an actionset */
int size; /* the size of the rule: max(entry, action) */ int size; /* the size of the rule: max(entry, action) */
u32 addr; /* address in the VCAP at insertion */ u32 addr; /* address in the VCAP at insertion */
u32 counter_id; /* counter id (if a dedicated counter is available) */
struct vcap_counter counter; /* last read counter value */
}; };
/* Moving a rule in the VCAP address space */ /* Moving a rule in the VCAP address space */
...@@ -651,6 +653,20 @@ static int vcap_write_rule(struct vcap_rule_internal *ri) ...@@ -651,6 +653,20 @@ static int vcap_write_rule(struct vcap_rule_internal *ri)
return 0; return 0;
} }
static int vcap_write_counter(struct vcap_rule_internal *ri,
struct vcap_counter *ctr)
{
struct vcap_admin *admin = ri->admin;
admin->cache.counter = ctr->value;
admin->cache.sticky = ctr->sticky;
ri->vctrl->ops->cache_write(ri->ndev, admin, VCAP_SEL_COUNTER,
ri->counter_id, 0);
ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_WRITE,
VCAP_SEL_COUNTER, ri->addr);
return 0;
}
/* Convert a chain id to a VCAP lookup index */ /* Convert a chain id to a VCAP lookup index */
int vcap_chain_id_to_lookup(struct vcap_admin *admin, int cur_cid) int vcap_chain_id_to_lookup(struct vcap_admin *admin, int cur_cid)
{ {
...@@ -1547,6 +1563,20 @@ int vcap_rule_add_action_u32(struct vcap_rule *rule, ...@@ -1547,6 +1563,20 @@ int vcap_rule_add_action_u32(struct vcap_rule *rule,
} }
EXPORT_SYMBOL_GPL(vcap_rule_add_action_u32); EXPORT_SYMBOL_GPL(vcap_rule_add_action_u32);
static int vcap_read_counter(struct vcap_rule_internal *ri,
struct vcap_counter *ctr)
{
struct vcap_admin *admin = ri->admin;
ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_READ, VCAP_SEL_COUNTER,
ri->addr);
ri->vctrl->ops->cache_read(ri->ndev, admin, VCAP_SEL_COUNTER,
ri->counter_id, 0);
ctr->value = admin->cache.counter;
ctr->sticky = admin->cache.sticky;
return 0;
}
/* Copy to host byte order */ /* Copy to host byte order */
void vcap_netbytes_copy(u8 *dst, u8 *src, int count) void vcap_netbytes_copy(u8 *dst, u8 *src, int count)
{ {
...@@ -1690,6 +1720,47 @@ int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev, ...@@ -1690,6 +1720,47 @@ int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev,
} }
EXPORT_SYMBOL_GPL(vcap_enable_lookups); EXPORT_SYMBOL_GPL(vcap_enable_lookups);
/* Set a rule counter id (for certain vcaps only) */
void vcap_rule_set_counter_id(struct vcap_rule *rule, u32 counter_id)
{
struct vcap_rule_internal *ri = to_intrule(rule);
ri->counter_id = counter_id;
}
EXPORT_SYMBOL_GPL(vcap_rule_set_counter_id);
int vcap_rule_set_counter(struct vcap_rule *rule, struct vcap_counter *ctr)
{
struct vcap_rule_internal *ri = to_intrule(rule);
int err;
err = vcap_api_check(ri->vctrl);
if (err)
return err;
if (!ctr) {
pr_err("%s:%d: counter is missing\n", __func__, __LINE__);
return -EINVAL;
}
return vcap_write_counter(ri, ctr);
}
EXPORT_SYMBOL_GPL(vcap_rule_set_counter);
int vcap_rule_get_counter(struct vcap_rule *rule, struct vcap_counter *ctr)
{
struct vcap_rule_internal *ri = to_intrule(rule);
int err;
err = vcap_api_check(ri->vctrl);
if (err)
return err;
if (!ctr) {
pr_err("%s:%d: counter is missing\n", __func__, __LINE__);
return -EINVAL;
}
return vcap_read_counter(ri, ctr);
}
EXPORT_SYMBOL_GPL(vcap_rule_get_counter);
#ifdef CONFIG_VCAP_KUNIT_TEST #ifdef CONFIG_VCAP_KUNIT_TEST
#include "vcap_api_kunit.c" #include "vcap_api_kunit.c"
#endif #endif
...@@ -143,6 +143,11 @@ enum vcap_bit { ...@@ -143,6 +143,11 @@ enum vcap_bit {
VCAP_BIT_1 VCAP_BIT_1
}; };
struct vcap_counter {
u32 value;
bool sticky;
};
/* Enable/Disable the VCAP instance lookups. Chain id 0 means disable */ /* Enable/Disable the VCAP instance lookups. Chain id 0 means disable */
int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev, int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev,
int chain_id, unsigned long cookie, bool enable); int chain_id, unsigned long cookie, bool enable);
...@@ -170,6 +175,8 @@ int vcap_set_rule_set_keyset(struct vcap_rule *rule, ...@@ -170,6 +175,8 @@ int vcap_set_rule_set_keyset(struct vcap_rule *rule,
/* Update the actionset for the rule */ /* Update the actionset for the rule */
int vcap_set_rule_set_actionset(struct vcap_rule *rule, int vcap_set_rule_set_actionset(struct vcap_rule *rule,
enum vcap_actionfield_set actionset); enum vcap_actionfield_set actionset);
/* Set a rule counter id (for certain VCAPs only) */
void vcap_rule_set_counter_id(struct vcap_rule *rule, u32 counter_id);
/* VCAP rule field operations */ /* VCAP rule field operations */
int vcap_rule_add_key_bit(struct vcap_rule *rule, enum vcap_key_field key, int vcap_rule_add_key_bit(struct vcap_rule *rule, enum vcap_key_field key,
...@@ -187,6 +194,10 @@ int vcap_rule_add_action_bit(struct vcap_rule *rule, ...@@ -187,6 +194,10 @@ int vcap_rule_add_action_bit(struct vcap_rule *rule,
int vcap_rule_add_action_u32(struct vcap_rule *rule, int vcap_rule_add_action_u32(struct vcap_rule *rule,
enum vcap_action_field action, u32 value); enum vcap_action_field action, u32 value);
/* VCAP rule counter operations */
int vcap_rule_set_counter(struct vcap_rule *rule, struct vcap_counter *ctr);
int vcap_rule_get_counter(struct vcap_rule *rule, struct vcap_counter *ctr);
/* VCAP lookup operations */ /* VCAP lookup operations */
/* Convert a chain id to a VCAP lookup index */ /* Convert a chain id to a VCAP lookup index */
int vcap_chain_id_to_lookup(struct vcap_admin *admin, int cur_cid); int vcap_chain_id_to_lookup(struct vcap_admin *admin, int cur_cid);
......
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