Commit 1397a2eb authored by Vladimir Oltean's avatar Vladimir Oltean Committed by David S. Miller

net: mscc: ocelot: create TCAM skeleton from tc filter chains

For Ocelot switches, there are 2 ingress pipelines for flow offload
rules: VCAP IS1 (Ingress Classification) and IS2 (Security Enforcement).
IS1 and IS2 support different sets of actions. The pipeline order for a
packet on ingress is:

Basic classification -> VCAP IS1 -> VCAP IS2

Furthermore, IS1 is looked up 3 times, and IS2 is looked up twice (each
TCAM entry can be configured to match only on the first lookup, or only
on the second, or on both etc).

Because the TCAMs are completely independent in hardware, and because of
the fixed pipeline, we actually have very limited options when it comes
to offloading complex rules to them while still maintaining the same
semantics with the software data path.

This patch maps flow offload rules to ingress TCAMs according to a
predefined chain index number. There is going to be a script in
selftests that clarifies the usage model.

There is also an egress TCAM (VCAP ES0, the Egress Rewriter), which is
modeled on top of the default chain 0 of the egress qdisc, because it
doesn't have multiple lookups.
Suggested-by: default avatarAllan W. Nielsen <allan.nielsen@microchip.com>
Co-developed-by: default avatarXiaoliang Yang <xiaoliang.yang_1@nxp.com>
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 319e4dd1
This diff is collapsed.
...@@ -640,10 +640,10 @@ static void is2_entry_set(struct ocelot *ocelot, int ix, ...@@ -640,10 +640,10 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_WRITE, VCAP_SEL_ALL); vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_WRITE, VCAP_SEL_ALL);
} }
static void static void vcap_entry_get(struct ocelot *ocelot, int ix,
vcap_entry_get(struct ocelot *ocelot, struct ocelot_vcap_filter *filter, int ix) struct ocelot_vcap_filter *filter)
{ {
const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS2]; const struct vcap_props *vcap = &ocelot->vcap[filter->block_id];
struct vcap_data data; struct vcap_data data;
int row, count; int row, count;
u32 cnt; u32 cnt;
...@@ -660,6 +660,13 @@ vcap_entry_get(struct ocelot *ocelot, struct ocelot_vcap_filter *filter, int ix) ...@@ -660,6 +660,13 @@ vcap_entry_get(struct ocelot *ocelot, struct ocelot_vcap_filter *filter, int ix)
filter->stats.pkts = cnt; filter->stats.pkts = cnt;
} }
static void vcap_entry_set(struct ocelot *ocelot, int ix,
struct ocelot_vcap_filter *filter)
{
if (filter->block_id == VCAP_IS2)
return is2_entry_set(ocelot, ix, filter);
}
static int ocelot_vcap_policer_add(struct ocelot *ocelot, u32 pol_ix, static int ocelot_vcap_policer_add(struct ocelot *ocelot, u32 pol_ix,
struct ocelot_policer *pol) struct ocelot_policer *pol)
{ {
...@@ -688,7 +695,8 @@ static void ocelot_vcap_policer_del(struct ocelot *ocelot, ...@@ -688,7 +695,8 @@ static void ocelot_vcap_policer_del(struct ocelot *ocelot,
list_for_each_entry(filter, &block->rules, list) { list_for_each_entry(filter, &block->rules, list) {
index++; index++;
if (filter->action.police_ena && if (filter->block_id == VCAP_IS2 &&
filter->action.police_ena &&
filter->action.pol_ix < pol_ix) { filter->action.pol_ix < pol_ix) {
filter->action.pol_ix += 1; filter->action.pol_ix += 1;
ocelot_vcap_policer_add(ocelot, filter->action.pol_ix, ocelot_vcap_policer_add(ocelot, filter->action.pol_ix,
...@@ -710,7 +718,7 @@ static void ocelot_vcap_filter_add_to_block(struct ocelot *ocelot, ...@@ -710,7 +718,7 @@ static void ocelot_vcap_filter_add_to_block(struct ocelot *ocelot,
struct ocelot_vcap_filter *tmp; struct ocelot_vcap_filter *tmp;
struct list_head *pos, *n; struct list_head *pos, *n;
if (filter->action.police_ena) { if (filter->block_id == VCAP_IS2 && filter->action.police_ena) {
block->pol_lpr--; block->pol_lpr--;
filter->action.pol_ix = block->pol_lpr; filter->action.pol_ix = block->pol_lpr;
ocelot_vcap_policer_add(ocelot, filter->action.pol_ix, ocelot_vcap_policer_add(ocelot, filter->action.pol_ix,
...@@ -848,7 +856,7 @@ static bool ...@@ -848,7 +856,7 @@ static bool
ocelot_exclusive_mac_etype_filter_rules(struct ocelot *ocelot, ocelot_exclusive_mac_etype_filter_rules(struct ocelot *ocelot,
struct ocelot_vcap_filter *filter) struct ocelot_vcap_filter *filter)
{ {
struct ocelot_vcap_block *block = &ocelot->block; struct ocelot_vcap_block *block = &ocelot->block[filter->block_id];
struct ocelot_vcap_filter *tmp; struct ocelot_vcap_filter *tmp;
unsigned long port; unsigned long port;
int i; int i;
...@@ -886,7 +894,7 @@ int ocelot_vcap_filter_add(struct ocelot *ocelot, ...@@ -886,7 +894,7 @@ int ocelot_vcap_filter_add(struct ocelot *ocelot,
struct ocelot_vcap_filter *filter, struct ocelot_vcap_filter *filter,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct ocelot_vcap_block *block = &ocelot->block; struct ocelot_vcap_block *block = &ocelot->block[filter->block_id];
int i, index; int i, index;
if (!ocelot_exclusive_mac_etype_filter_rules(ocelot, filter)) { if (!ocelot_exclusive_mac_etype_filter_rules(ocelot, filter)) {
...@@ -908,11 +916,11 @@ int ocelot_vcap_filter_add(struct ocelot *ocelot, ...@@ -908,11 +916,11 @@ int ocelot_vcap_filter_add(struct ocelot *ocelot,
struct ocelot_vcap_filter *tmp; struct ocelot_vcap_filter *tmp;
tmp = ocelot_vcap_block_find_filter_by_index(block, i); tmp = ocelot_vcap_block_find_filter_by_index(block, i);
is2_entry_set(ocelot, i, tmp); vcap_entry_set(ocelot, i, tmp);
} }
/* Now insert the new filter */ /* Now insert the new filter */
is2_entry_set(ocelot, index, filter); vcap_entry_set(ocelot, index, filter);
return 0; return 0;
} }
...@@ -926,7 +934,8 @@ static void ocelot_vcap_block_remove_filter(struct ocelot *ocelot, ...@@ -926,7 +934,8 @@ static void ocelot_vcap_block_remove_filter(struct ocelot *ocelot,
list_for_each_safe(pos, q, &block->rules) { list_for_each_safe(pos, q, &block->rules) {
tmp = list_entry(pos, struct ocelot_vcap_filter, list); tmp = list_entry(pos, struct ocelot_vcap_filter, list);
if (tmp->id == filter->id) { if (tmp->id == filter->id) {
if (tmp->action.police_ena) if (tmp->block_id == VCAP_IS2 &&
tmp->action.police_ena)
ocelot_vcap_policer_del(ocelot, block, ocelot_vcap_policer_del(ocelot, block,
tmp->action.pol_ix); tmp->action.pol_ix);
...@@ -941,7 +950,7 @@ static void ocelot_vcap_block_remove_filter(struct ocelot *ocelot, ...@@ -941,7 +950,7 @@ static void ocelot_vcap_block_remove_filter(struct ocelot *ocelot,
int ocelot_vcap_filter_del(struct ocelot *ocelot, int ocelot_vcap_filter_del(struct ocelot *ocelot,
struct ocelot_vcap_filter *filter) struct ocelot_vcap_filter *filter)
{ {
struct ocelot_vcap_block *block = &ocelot->block; struct ocelot_vcap_block *block = &ocelot->block[filter->block_id];
struct ocelot_vcap_filter del_filter; struct ocelot_vcap_filter del_filter;
int i, index; int i, index;
...@@ -960,11 +969,11 @@ int ocelot_vcap_filter_del(struct ocelot *ocelot, ...@@ -960,11 +969,11 @@ int ocelot_vcap_filter_del(struct ocelot *ocelot,
struct ocelot_vcap_filter *tmp; struct ocelot_vcap_filter *tmp;
tmp = ocelot_vcap_block_find_filter_by_index(block, i); tmp = ocelot_vcap_block_find_filter_by_index(block, i);
is2_entry_set(ocelot, i, tmp); vcap_entry_set(ocelot, i, tmp);
} }
/* Now delete the last filter, because it is duplicated */ /* Now delete the last filter, because it is duplicated */
is2_entry_set(ocelot, block->count, &del_filter); vcap_entry_set(ocelot, block->count, &del_filter);
return 0; return 0;
} }
...@@ -972,7 +981,7 @@ int ocelot_vcap_filter_del(struct ocelot *ocelot, ...@@ -972,7 +981,7 @@ int ocelot_vcap_filter_del(struct ocelot *ocelot,
int ocelot_vcap_filter_stats_update(struct ocelot *ocelot, int ocelot_vcap_filter_stats_update(struct ocelot *ocelot,
struct ocelot_vcap_filter *filter) struct ocelot_vcap_filter *filter)
{ {
struct ocelot_vcap_block *block = &ocelot->block; struct ocelot_vcap_block *block = &ocelot->block[filter->block_id];
struct ocelot_vcap_filter tmp; struct ocelot_vcap_filter tmp;
int index; int index;
...@@ -980,12 +989,12 @@ int ocelot_vcap_filter_stats_update(struct ocelot *ocelot, ...@@ -980,12 +989,12 @@ int ocelot_vcap_filter_stats_update(struct ocelot *ocelot,
if (index < 0) if (index < 0)
return index; return index;
vcap_entry_get(ocelot, filter, index); vcap_entry_get(ocelot, index, filter);
/* After we get the result we need to clear the counters */ /* After we get the result we need to clear the counters */
tmp = *filter; tmp = *filter;
tmp.stats.pkts = 0; tmp.stats.pkts = 0;
is2_entry_set(ocelot, index, &tmp); vcap_entry_set(ocelot, index, &tmp);
return 0; return 0;
} }
...@@ -1080,7 +1089,6 @@ static void ocelot_vcap_detect_constants(struct ocelot *ocelot, ...@@ -1080,7 +1089,6 @@ static void ocelot_vcap_detect_constants(struct ocelot *ocelot,
int ocelot_vcap_init(struct ocelot *ocelot) int ocelot_vcap_init(struct ocelot *ocelot)
{ {
struct ocelot_vcap_block *block = &ocelot->block;
int i; int i;
/* Create a policer that will drop the frames for the cpu. /* Create a policer that will drop the frames for the cpu.
...@@ -1099,15 +1107,17 @@ int ocelot_vcap_init(struct ocelot *ocelot) ...@@ -1099,15 +1107,17 @@ int ocelot_vcap_init(struct ocelot *ocelot)
OCELOT_POLICER_DISCARD); OCELOT_POLICER_DISCARD);
for (i = 0; i < OCELOT_NUM_VCAP_BLOCKS; i++) { for (i = 0; i < OCELOT_NUM_VCAP_BLOCKS; i++) {
struct ocelot_vcap_block *block = &ocelot->block[i];
struct vcap_props *vcap = &ocelot->vcap[i]; struct vcap_props *vcap = &ocelot->vcap[i];
INIT_LIST_HEAD(&block->rules);
block->pol_lpr = OCELOT_POLICER_DISCARD - 1;
ocelot_vcap_detect_constants(ocelot, vcap); ocelot_vcap_detect_constants(ocelot, vcap);
ocelot_vcap_init_one(ocelot, vcap); ocelot_vcap_init_one(ocelot, vcap);
} }
block->pol_lpr = OCELOT_POLICER_DISCARD - 1; INIT_LIST_HEAD(&ocelot->dummy_rules);
INIT_LIST_HEAD(&block->rules);
return 0; return 0;
} }
...@@ -204,9 +204,19 @@ struct ocelot_vcap_stats { ...@@ -204,9 +204,19 @@ struct ocelot_vcap_stats {
u64 used; u64 used;
}; };
enum ocelot_vcap_filter_type {
OCELOT_VCAP_FILTER_DUMMY,
OCELOT_VCAP_FILTER_PAG,
OCELOT_VCAP_FILTER_OFFLOAD,
};
struct ocelot_vcap_filter { struct ocelot_vcap_filter {
struct list_head list; struct list_head list;
enum ocelot_vcap_filter_type type;
int block_id;
int goto_target;
int lookup;
u16 prio; u16 prio;
u32 id; u32 id;
......
...@@ -633,7 +633,8 @@ struct ocelot { ...@@ -633,7 +633,8 @@ struct ocelot {
struct list_head multicast; struct list_head multicast;
struct ocelot_vcap_block block; struct list_head dummy_rules;
struct ocelot_vcap_block block[3];
struct vcap_props *vcap; struct vcap_props *vcap;
/* Workqueue to check statistics for overflow with its lock */ /* Workqueue to check statistics for overflow with its lock */
......
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