Skip to content

Commit

Permalink
net: microchip: sparx5: Add support for IS2 VCAP rule counters
Browse files Browse the repository at this point in the history
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: Steen Hegelund <steen.hegelund@microchip.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Steen Hegelund authored and David S. Miller committed Nov 14, 2022
1 parent 990e483 commit f13230a
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 2 deletions.
47 changes: 45 additions & 2 deletions drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -428,15 +428,58 @@ static void sparx5_vcap_cache_write(struct net_device *ndev,
default:
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 */
static void sparx5_vcap_cache_read(struct net_device *ndev,
struct vcap_admin *admin,
enum vcap_selection sel, u32 start,
enum vcap_selection sel,
u32 start,
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 */
Expand Down
71 changes: 71 additions & 0 deletions drivers/net/ethernet/microchip/vcap/vcap_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ struct vcap_rule_internal {
int actionset_sw_regs; /* registers in a subword in an actionset */
int size; /* the size of the rule: max(entry, action) */
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 */
Expand Down Expand Up @@ -651,6 +653,20 @@ static int vcap_write_rule(struct vcap_rule_internal *ri)
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 */
int vcap_chain_id_to_lookup(struct vcap_admin *admin, int cur_cid)
{
Expand Down Expand Up @@ -1547,6 +1563,20 @@ int vcap_rule_add_action_u32(struct vcap_rule *rule,
}
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 */
void vcap_netbytes_copy(u8 *dst, u8 *src, int count)
{
Expand Down Expand Up @@ -1690,6 +1720,47 @@ int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev,
}
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
#include "vcap_api_kunit.c"
#endif
11 changes: 11 additions & 0 deletions drivers/net/ethernet/microchip/vcap/vcap_api_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ enum vcap_bit {
VCAP_BIT_1
};

struct vcap_counter {
u32 value;
bool sticky;
};

/* Enable/Disable the VCAP instance lookups. Chain id 0 means disable */
int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev,
int chain_id, unsigned long cookie, bool enable);
Expand Down Expand Up @@ -170,6 +175,8 @@ int vcap_set_rule_set_keyset(struct vcap_rule *rule,
/* Update the actionset for the rule */
int vcap_set_rule_set_actionset(struct vcap_rule *rule,
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 */
int vcap_rule_add_key_bit(struct vcap_rule *rule, enum vcap_key_field key,
Expand All @@ -187,6 +194,10 @@ int vcap_rule_add_action_bit(struct vcap_rule *rule,
int vcap_rule_add_action_u32(struct vcap_rule *rule,
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 */
/* Convert a chain id to a VCAP lookup index */
int vcap_chain_id_to_lookup(struct vcap_admin *admin, int cur_cid);
Expand Down

0 comments on commit f13230a

Please sign in to comment.