Commit b0be25c5 authored by David S. Miller's avatar David S. Miller

Merge branch 'net-mvpp2-Classifier-updates-and-cleanups'

Maxime Chevallier says:

====================
net: mvpp2: Classifier updates and cleanups

In preparation for the future addition of classification offload
support, this series cleans-up the current code dealing with the
classification engines.

As of today, the classification code only deals with RSS, which is a
very narrow use-case when considering all of the classifier's features.

This lead to design and naming decisions that don't really stand when
considering using more classification features.

This series therefore includes quite a lot a renaming of functions and
macros, and tries to make the naming schemes more consistent and the
code more readable.

The debugfs interface that allows reading the various Parsing and
Classification engines has been cleaned-up and made more generic,
allowing to read the Flow Table and C2 engine hit counters on a
per-entry basis.

The Classifier itself has been made more robust by introducing the
lu_type field in classification lookups, that prevents false-positive
matches in the future. We also initialise the various engine in a more
extensive and less error-prone way by assining default values to all
entries in the C2 and Flow table.

This is a pretty big series considering it's mostly cleanup, but my goal
is to make the future series that will contain new big features easier
to review, focusing on the real logic.

Besides the debugfs interface, this series doesn't intend to introduce any
new features or change in behaviours.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5133a4a8 c2d3d8ee
......@@ -101,6 +101,7 @@
#define MVPP2_CLS_FLOW_TBL1_REG 0x1828
#define MVPP2_CLS_FLOW_TBL1_N_FIELDS_MASK 0x7
#define MVPP2_CLS_FLOW_TBL1_N_FIELDS(x) (x)
#define MVPP2_CLS_FLOW_TBL1_LU_TYPE(lu) (((lu) & 0x3f) << 3)
#define MVPP2_CLS_FLOW_TBL1_PRIO_MASK 0x3f
#define MVPP2_CLS_FLOW_TBL1_PRIO(x) ((x) << 9)
#define MVPP2_CLS_FLOW_TBL1_SEQ_MASK 0x7
......@@ -123,7 +124,10 @@
#define MVPP22_CLS_C2_TCAM_DATA2 0x1b18
#define MVPP22_CLS_C2_TCAM_DATA3 0x1b1c
#define MVPP22_CLS_C2_TCAM_DATA4 0x1b20
#define MVPP22_CLS_C2_LU_TYPE(lu) ((lu) & 0x3f)
#define MVPP22_CLS_C2_PORT_ID(port) ((port) << 8)
#define MVPP22_CLS_C2_TCAM_INV 0x1b24
#define MVPP22_CLS_C2_TCAM_INV_BIT BIT(31)
#define MVPP22_CLS_C2_HIT_CTR 0x1b50
#define MVPP22_CLS_C2_ACT 0x1b60
#define MVPP22_CLS_C2_ACT_RSS_EN(act) (((act) & 0x3) << 19)
......@@ -610,6 +614,8 @@
#define MVPP2_BIT_TO_WORD(bit) ((bit) / 32)
#define MVPP2_BIT_IN_WORD(bit) ((bit) % 32)
#define MVPP2_N_PRS_FLOWS 52
/* RSS constants */
#define MVPP22_RSS_TABLE_ENTRIES 32
......@@ -710,6 +716,7 @@ enum mvpp2_prs_l3_cast {
#define MVPP2_DESC_DMA_MASK DMA_BIT_MASK(40)
/* Definitions */
struct mvpp2_dbgfs_entries;
/* Shared Packet Processor resources */
struct mvpp2 {
......@@ -771,6 +778,9 @@ struct mvpp2 {
/* Debugfs root entry */
struct dentry *dbgfs_dir;
/* Debugfs entries private data */
struct mvpp2_dbgfs_entries *dbgfs_entries;
};
struct mvpp2_pcpu_stats {
......
......@@ -22,7 +22,7 @@
} \
}
static struct mvpp2_cls_flow cls_flows[MVPP2_N_FLOWS] = {
static const struct mvpp2_cls_flow cls_flows[MVPP2_N_PRS_FLOWS] = {
/* TCP over IPv4 flows, Not fragmented, no vlan tag */
MVPP2_DEF_FLOW(TCP_V4_FLOW, MVPP2_FL_IP4_TCP_NF_UNTAG,
MVPP22_CLS_HEK_IP4_5T,
......@@ -429,12 +429,6 @@ static void mvpp2_cls_flow_port_id_sel(struct mvpp2_cls_flow_entry *fe,
fe->data[0] &= ~MVPP2_CLS_FLOW_TBL0_PORT_ID_SEL;
}
static void mvpp2_cls_flow_seq_set(struct mvpp2_cls_flow_entry *fe, u32 seq)
{
fe->data[1] &= ~MVPP2_CLS_FLOW_TBL1_SEQ(MVPP2_CLS_FLOW_TBL1_SEQ_MASK);
fe->data[1] |= MVPP2_CLS_FLOW_TBL1_SEQ(seq);
}
static void mvpp2_cls_flow_last_set(struct mvpp2_cls_flow_entry *fe,
bool is_last)
{
......@@ -454,9 +448,16 @@ static void mvpp2_cls_flow_port_add(struct mvpp2_cls_flow_entry *fe,
fe->data[0] |= MVPP2_CLS_FLOW_TBL0_PORT_ID(port);
}
static void mvpp2_cls_flow_lu_type_set(struct mvpp2_cls_flow_entry *fe,
u8 lu_type)
{
fe->data[1] &= ~MVPP2_CLS_FLOW_TBL1_LU_TYPE(MVPP2_CLS_LU_TYPE_MASK);
fe->data[1] |= MVPP2_CLS_FLOW_TBL1_LU_TYPE(lu_type);
}
/* Initialize the parser entry for the given flow */
static void mvpp2_cls_flow_prs_init(struct mvpp2 *priv,
struct mvpp2_cls_flow *flow)
const struct mvpp2_cls_flow *flow)
{
mvpp2_prs_add_flow(priv, flow->flow_id, flow->prs_ri.ri,
flow->prs_ri.ri_mask);
......@@ -464,7 +465,7 @@ static void mvpp2_cls_flow_prs_init(struct mvpp2 *priv,
/* Initialize the Lookup Id table entry for the given flow */
static void mvpp2_cls_flow_lkp_init(struct mvpp2 *priv,
struct mvpp2_cls_flow *flow)
const struct mvpp2_cls_flow *flow)
{
struct mvpp2_cls_lookup_entry le;
......@@ -477,7 +478,7 @@ static void mvpp2_cls_flow_lkp_init(struct mvpp2 *priv,
/* We point on the first lookup in the sequence for the flow, that is
* the C2 lookup.
*/
le.data |= MVPP2_CLS_LKP_FLOW_PTR(MVPP2_FLOW_C2_ENTRY(flow->flow_id));
le.data |= MVPP2_CLS_LKP_FLOW_PTR(MVPP2_CLS_FLT_FIRST(flow->flow_id));
/* CLS is always enabled, RSS is enabled/disabled in C2 lookup */
le.data |= MVPP2_CLS_LKP_TBL_LOOKUP_EN_MASK;
......@@ -485,21 +486,86 @@ static void mvpp2_cls_flow_lkp_init(struct mvpp2 *priv,
mvpp2_cls_lookup_write(priv, &le);
}
static void mvpp2_cls_c2_write(struct mvpp2 *priv,
struct mvpp2_cls_c2_entry *c2)
{
u32 val;
mvpp2_write(priv, MVPP22_CLS_C2_TCAM_IDX, c2->index);
val = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_INV);
if (c2->valid)
val &= ~MVPP22_CLS_C2_TCAM_INV_BIT;
else
val |= MVPP22_CLS_C2_TCAM_INV_BIT;
mvpp2_write(priv, MVPP22_CLS_C2_TCAM_INV, val);
mvpp2_write(priv, MVPP22_CLS_C2_ACT, c2->act);
mvpp2_write(priv, MVPP22_CLS_C2_ATTR0, c2->attr[0]);
mvpp2_write(priv, MVPP22_CLS_C2_ATTR1, c2->attr[1]);
mvpp2_write(priv, MVPP22_CLS_C2_ATTR2, c2->attr[2]);
mvpp2_write(priv, MVPP22_CLS_C2_ATTR3, c2->attr[3]);
mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA0, c2->tcam[0]);
mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA1, c2->tcam[1]);
mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA2, c2->tcam[2]);
mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA3, c2->tcam[3]);
/* Writing TCAM_DATA4 flushes writes to TCAM_DATA0-4 and INV to HW */
mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA4, c2->tcam[4]);
}
void mvpp2_cls_c2_read(struct mvpp2 *priv, int index,
struct mvpp2_cls_c2_entry *c2)
{
u32 val;
mvpp2_write(priv, MVPP22_CLS_C2_TCAM_IDX, index);
c2->index = index;
c2->tcam[0] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA0);
c2->tcam[1] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA1);
c2->tcam[2] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA2);
c2->tcam[3] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA3);
c2->tcam[4] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA4);
c2->act = mvpp2_read(priv, MVPP22_CLS_C2_ACT);
c2->attr[0] = mvpp2_read(priv, MVPP22_CLS_C2_ATTR0);
c2->attr[1] = mvpp2_read(priv, MVPP22_CLS_C2_ATTR1);
c2->attr[2] = mvpp2_read(priv, MVPP22_CLS_C2_ATTR2);
c2->attr[3] = mvpp2_read(priv, MVPP22_CLS_C2_ATTR3);
val = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_INV);
c2->valid = !(val & MVPP22_CLS_C2_TCAM_INV_BIT);
}
/* Initialize the flow table entries for the given flow */
static void mvpp2_cls_flow_init(struct mvpp2 *priv, struct mvpp2_cls_flow *flow)
static void mvpp2_cls_flow_init(struct mvpp2 *priv,
const struct mvpp2_cls_flow *flow)
{
struct mvpp2_cls_flow_entry fe;
int i;
int i, pri = 0;
/* Assign default values to all entries in the flow */
for (i = MVPP2_CLS_FLT_FIRST(flow->flow_id);
i <= MVPP2_CLS_FLT_LAST(flow->flow_id); i++) {
memset(&fe, 0, sizeof(fe));
fe.index = i;
mvpp2_cls_flow_pri_set(&fe, pri++);
/* C2 lookup */
memset(&fe, 0, sizeof(fe));
fe.index = MVPP2_FLOW_C2_ENTRY(flow->flow_id);
if (i == MVPP2_CLS_FLT_LAST(flow->flow_id))
mvpp2_cls_flow_last_set(&fe, 1);
mvpp2_cls_flow_write(priv, &fe);
}
/* RSS config C2 lookup */
mvpp2_cls_flow_read(priv, MVPP2_CLS_FLT_C2_RSS_ENTRY(flow->flow_id),
&fe);
mvpp2_cls_flow_eng_set(&fe, MVPP22_CLS_ENGINE_C2);
mvpp2_cls_flow_port_id_sel(&fe, true);
mvpp2_cls_flow_last_set(&fe, 0);
mvpp2_cls_flow_pri_set(&fe, 0);
mvpp2_cls_flow_seq_set(&fe, MVPP2_CLS_FLOW_SEQ_FIRST1);
mvpp2_cls_flow_lu_type_set(&fe, MVPP2_CLS_LU_ALL);
/* Add all ports */
for (i = 0; i < MVPP2_MAX_PORTS; i++)
......@@ -509,22 +575,19 @@ static void mvpp2_cls_flow_init(struct mvpp2 *priv, struct mvpp2_cls_flow *flow)
/* C3Hx lookups */
for (i = 0; i < MVPP2_MAX_PORTS; i++) {
memset(&fe, 0, sizeof(fe));
fe.index = MVPP2_PORT_FLOW_HASH_ENTRY(i, flow->flow_id);
mvpp2_cls_flow_read(priv,
MVPP2_CLS_FLT_HASH_ENTRY(i, flow->flow_id),
&fe);
/* Set a default engine. Will be overwritten when setting the
* real HEK parameters
*/
mvpp2_cls_flow_eng_set(&fe, MVPP22_CLS_ENGINE_C3HA);
mvpp2_cls_flow_port_id_sel(&fe, true);
mvpp2_cls_flow_pri_set(&fe, i + 1);
mvpp2_cls_flow_seq_set(&fe, MVPP2_CLS_FLOW_SEQ_MIDDLE);
mvpp2_cls_flow_port_add(&fe, BIT(i));
mvpp2_cls_flow_write(priv, &fe);
}
/* Update the last entry */
mvpp2_cls_flow_last_set(&fe, 1);
mvpp2_cls_flow_seq_set(&fe, MVPP2_CLS_FLOW_SEQ_LAST);
mvpp2_cls_flow_write(priv, &fe);
}
/* Adds a field to the Header Extracted Key generation parameters*/
......@@ -555,6 +618,9 @@ static int mvpp2_flow_set_hek_fields(struct mvpp2_cls_flow_entry *fe,
for_each_set_bit(i, &hash_opts, MVPP22_CLS_HEK_N_FIELDS) {
switch (BIT(i)) {
case MVPP22_CLS_HEK_OPT_MAC_DA:
field_id = MVPP22_CLS_FIELD_MAC_DA;
break;
case MVPP22_CLS_HEK_OPT_VLAN:
field_id = MVPP22_CLS_FIELD_VLAN;
break;
......@@ -586,9 +652,9 @@ static int mvpp2_flow_set_hek_fields(struct mvpp2_cls_flow_entry *fe,
return 0;
}
struct mvpp2_cls_flow *mvpp2_cls_flow_get(int flow)
const struct mvpp2_cls_flow *mvpp2_cls_flow_get(int flow)
{
if (flow >= MVPP2_N_FLOWS)
if (flow >= MVPP2_N_PRS_FLOWS)
return NULL;
return &cls_flows[flow];
......@@ -608,21 +674,17 @@ struct mvpp2_cls_flow *mvpp2_cls_flow_get(int flow)
static int mvpp2_port_rss_hash_opts_set(struct mvpp2_port *port, int flow_type,
u16 requested_opts)
{
const struct mvpp2_cls_flow *flow;
struct mvpp2_cls_flow_entry fe;
struct mvpp2_cls_flow *flow;
int i, engine, flow_index;
u16 hash_opts;
for (i = 0; i < MVPP2_N_FLOWS; i++) {
for_each_cls_flow_id_with_type(i, flow_type) {
flow = mvpp2_cls_flow_get(i);
if (!flow)
return -EINVAL;
if (flow->flow_type != flow_type)
continue;
flow_index = MVPP2_PORT_FLOW_HASH_ENTRY(port->id,
flow->flow_id);
flow_index = MVPP2_CLS_FLT_HASH_ENTRY(port->id, flow->flow_id);
mvpp2_cls_flow_read(port->priv, flow_index, &fe);
......@@ -697,21 +759,17 @@ u16 mvpp2_flow_get_hek_fields(struct mvpp2_cls_flow_entry *fe)
*/
static u16 mvpp2_port_rss_hash_opts_get(struct mvpp2_port *port, int flow_type)
{
const struct mvpp2_cls_flow *flow;
struct mvpp2_cls_flow_entry fe;
struct mvpp2_cls_flow *flow;
int i, flow_index;
u16 hash_opts = 0;
for (i = 0; i < MVPP2_N_FLOWS; i++) {
for_each_cls_flow_id_with_type(i, flow_type) {
flow = mvpp2_cls_flow_get(i);
if (!flow)
return 0;
if (flow->flow_type != flow_type)
continue;
flow_index = MVPP2_PORT_FLOW_HASH_ENTRY(port->id,
flow->flow_id);
flow_index = MVPP2_CLS_FLT_HASH_ENTRY(port->id, flow->flow_id);
mvpp2_cls_flow_read(port->priv, flow_index, &fe);
......@@ -723,10 +781,10 @@ static u16 mvpp2_port_rss_hash_opts_get(struct mvpp2_port *port, int flow_type)
static void mvpp2_cls_port_init_flows(struct mvpp2 *priv)
{
struct mvpp2_cls_flow *flow;
const struct mvpp2_cls_flow *flow;
int i;
for (i = 0; i < MVPP2_N_FLOWS; i++) {
for (i = 0; i < MVPP2_N_PRS_FLOWS; i++) {
flow = mvpp2_cls_flow_get(i);
if (!flow)
break;
......@@ -737,47 +795,6 @@ static void mvpp2_cls_port_init_flows(struct mvpp2 *priv)
}
}
static void mvpp2_cls_c2_write(struct mvpp2 *priv,
struct mvpp2_cls_c2_entry *c2)
{
mvpp2_write(priv, MVPP22_CLS_C2_TCAM_IDX, c2->index);
/* Write TCAM */
mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA0, c2->tcam[0]);
mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA1, c2->tcam[1]);
mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA2, c2->tcam[2]);
mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA3, c2->tcam[3]);
mvpp2_write(priv, MVPP22_CLS_C2_TCAM_DATA4, c2->tcam[4]);
mvpp2_write(priv, MVPP22_CLS_C2_ACT, c2->act);
mvpp2_write(priv, MVPP22_CLS_C2_ATTR0, c2->attr[0]);
mvpp2_write(priv, MVPP22_CLS_C2_ATTR1, c2->attr[1]);
mvpp2_write(priv, MVPP22_CLS_C2_ATTR2, c2->attr[2]);
mvpp2_write(priv, MVPP22_CLS_C2_ATTR3, c2->attr[3]);
}
void mvpp2_cls_c2_read(struct mvpp2 *priv, int index,
struct mvpp2_cls_c2_entry *c2)
{
mvpp2_write(priv, MVPP22_CLS_C2_TCAM_IDX, index);
c2->index = index;
c2->tcam[0] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA0);
c2->tcam[1] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA1);
c2->tcam[2] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA2);
c2->tcam[3] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA3);
c2->tcam[4] = mvpp2_read(priv, MVPP22_CLS_C2_TCAM_DATA4);
c2->act = mvpp2_read(priv, MVPP22_CLS_C2_ACT);
c2->attr[0] = mvpp2_read(priv, MVPP22_CLS_C2_ATTR0);
c2->attr[1] = mvpp2_read(priv, MVPP22_CLS_C2_ATTR1);
c2->attr[2] = mvpp2_read(priv, MVPP22_CLS_C2_ATTR2);
c2->attr[3] = mvpp2_read(priv, MVPP22_CLS_C2_ATTR3);
}
static void mvpp2_port_c2_cls_init(struct mvpp2_port *port)
{
struct mvpp2_cls_c2_entry c2;
......@@ -791,6 +808,10 @@ static void mvpp2_port_c2_cls_init(struct mvpp2_port *port)
c2.tcam[4] = MVPP22_CLS_C2_PORT_ID(pmap);
c2.tcam[4] |= MVPP22_CLS_C2_TCAM_EN(MVPP22_CLS_C2_PORT_ID(pmap));
/* Match on Lookup Type */
c2.tcam[4] |= MVPP22_CLS_C2_TCAM_EN(MVPP22_CLS_C2_LU_TYPE(MVPP2_CLS_LU_TYPE_MASK));
c2.tcam[4] |= MVPP22_CLS_C2_LU_TYPE(MVPP2_CLS_LU_ALL);
/* Update RSS status after matching this entry */
c2.act = MVPP22_CLS_C2_ACT_RSS_EN(MVPP22_C2_UPD_LOCK);
......@@ -809,6 +830,8 @@ static void mvpp2_port_c2_cls_init(struct mvpp2_port *port)
c2.attr[0] = MVPP22_CLS_C2_ATTR0_QHIGH(qh) |
MVPP22_CLS_C2_ATTR0_QLOW(ql);
c2.valid = true;
mvpp2_cls_c2_write(port->priv, &c2);
}
......@@ -817,6 +840,7 @@ void mvpp2_cls_init(struct mvpp2 *priv)
{
struct mvpp2_cls_lookup_entry le;
struct mvpp2_cls_flow_entry fe;
struct mvpp2_cls_c2_entry c2;
int index;
/* Enable classifier */
......@@ -840,6 +864,14 @@ void mvpp2_cls_init(struct mvpp2 *priv)
mvpp2_cls_lookup_write(priv, &le);
}
/* Clear C2 TCAM engine table */
memset(&c2, 0, sizeof(c2));
c2.valid = false;
for (index = 0; index < MVPP22_CLS_C2_N_ENTRIES; index++) {
c2.index = index;
mvpp2_cls_c2_write(priv, &c2);
}
mvpp2_cls_port_init_flows(priv);
}
......@@ -902,12 +934,12 @@ static void mvpp2_rss_port_c2_disable(struct mvpp2_port *port)
mvpp2_cls_c2_write(port->priv, &c2);
}
void mvpp22_rss_enable(struct mvpp2_port *port)
void mvpp22_port_rss_enable(struct mvpp2_port *port)
{
mvpp2_rss_port_c2_enable(port);
}
void mvpp22_rss_disable(struct mvpp2_port *port)
void mvpp22_port_rss_disable(struct mvpp2_port *port)
{
mvpp2_rss_port_c2_disable(port);
}
......@@ -1037,7 +1069,7 @@ int mvpp2_ethtool_rxfh_get(struct mvpp2_port *port, struct ethtool_rxnfc *info)
return 0;
}
void mvpp22_rss_port_init(struct mvpp2_port *port)
void mvpp22_port_rss_init(struct mvpp2_port *port)
{
struct mvpp2 *priv = port->priv;
int i;
......
......@@ -71,14 +71,6 @@ enum mvpp2_cls_field_id {
MVPP22_CLS_FIELD_L4DIP = 0x1e,
};
enum mvpp2_cls_flow_seq {
MVPP2_CLS_FLOW_SEQ_NORMAL = 0,
MVPP2_CLS_FLOW_SEQ_FIRST1,
MVPP2_CLS_FLOW_SEQ_FIRST2,
MVPP2_CLS_FLOW_SEQ_LAST,
MVPP2_CLS_FLOW_SEQ_MIDDLE
};
/* Classifier C2 engine constants */
#define MVPP22_CLS_C2_TCAM_EN(data) ((data) << 16)
......@@ -105,34 +97,25 @@ enum mvpp22_cls_c2_fwd_action {
struct mvpp2_cls_c2_entry {
u32 index;
/* TCAM lookup key */
u32 tcam[MVPP2_CLS_C2_TCAM_WORDS];
/* Actions to perform upon TCAM match */
u32 act;
/* Attributes relative to the actions to perform */
u32 attr[MVPP2_CLS_C2_ATTR_WORDS];
/* Entry validity */
u8 valid;
};
/* Classifier C2 engine entries */
#define MVPP22_CLS_C2_RSS_ENTRY(port) (port)
#define MVPP22_CLS_C2_N_ENTRIES MVPP2_MAX_PORTS
#define MVPP22_CLS_C2_N_ENTRIES 256
/* RSS flow entries in the flow table. We have 2 entries per port for RSS.
*
* The first performs a lookup using the C2 TCAM engine, to tag the
* packet for software forwarding (needed for RSS), enable or disable RSS, and
* assign the default rx queue.
*
* The second configures the hash generation, by specifying which fields of the
* packet header are used to generate the hash, and specifies the relevant hash
* engine to use.
*/
#define MVPP22_RSS_FLOW_C2_OFFS 0
#define MVPP22_RSS_FLOW_HASH_OFFS 1
#define MVPP22_RSS_FLOW_SIZE (MVPP22_RSS_FLOW_HASH_OFFS + 1)
/* Number of per-port dedicated entries in the C2 TCAM */
#define MVPP22_CLS_C2_PORT_RANGE 8
#define MVPP22_RSS_FLOW_C2(port) ((port) * MVPP22_RSS_FLOW_SIZE + \
MVPP22_RSS_FLOW_C2_OFFS)
#define MVPP22_RSS_FLOW_HASH(port) ((port) * MVPP22_RSS_FLOW_SIZE + \
MVPP22_RSS_FLOW_HASH_OFFS)
#define MVPP22_RSS_FLOW_FIRST(port) MVPP22_RSS_FLOW_C2(port)
#define MVPP22_CLS_C2_PORT_FIRST(p) (MVPP22_CLS_C2_N_ENTRIES - \
((p) * MVPP22_CLS_C2_PORT_RANGE))
#define MVPP22_CLS_C2_RSS_ENTRY(p) (MVPP22_CLS_C2_PORT_FIRST(p) - 1)
/* Packet flow ID */
enum mvpp2_prs_flow {
......@@ -162,6 +145,15 @@ enum mvpp2_prs_flow {
MVPP2_FL_LAST,
};
enum mvpp2_cls_lu_type {
MVPP2_CLS_LU_ALL = 0,
};
/* LU Type defined for all engines, and specified in the flow table */
#define MVPP2_CLS_LU_TYPE_MASK 0x3f
#define MVPP2_N_FLOWS (MVPP2_FL_LAST - MVPP2_FL_START)
struct mvpp2_cls_flow {
/* The L2-L4 traffic flow type */
int flow_type;
......@@ -176,12 +168,37 @@ struct mvpp2_cls_flow {
struct mvpp2_prs_result_info prs_ri;
};
#define MVPP2_N_FLOWS 52
#define MVPP2_CLS_FLT_ENTRIES_PER_FLOW (MVPP2_MAX_PORTS + 1)
#define MVPP2_CLS_FLT_FIRST(id) (((id) - MVPP2_FL_START) * \
MVPP2_CLS_FLT_ENTRIES_PER_FLOW)
#define MVPP2_CLS_FLT_C2_RSS_ENTRY(id) (MVPP2_CLS_FLT_FIRST(id))
#define MVPP2_CLS_FLT_HASH_ENTRY(port, id) (MVPP2_CLS_FLT_C2_RSS_ENTRY(id) + (port) + 1)
#define MVPP2_CLS_FLT_LAST(id) (MVPP2_CLS_FLT_FIRST(id) + \
MVPP2_CLS_FLT_ENTRIES_PER_FLOW - 1)
/* Iterate on each classifier flow id. Sets 'i' to be the index of the first
* entry in the cls_flows table for each different flow_id.
* This relies on entries having the same flow_id in the cls_flows table being
* contiguous.
*/
#define for_each_cls_flow_id(i) \
for ((i) = 0; (i) < MVPP2_N_PRS_FLOWS; (i)++) \
if ((i) > 0 && \
cls_flows[(i)].flow_id == cls_flows[(i) - 1].flow_id) \
continue; \
else
/* Iterate on each classifier flow that has a given flow_type. Sets 'i' to be
* the index of the first entry in the cls_flow table for each different flow_id
* that has the given flow_type. This allows to operate on all flows that
* matches a given ethtool flow type.
*/
#define for_each_cls_flow_id_with_type(i, type) \
for_each_cls_flow_id((i)) \
if (cls_flows[(i)].flow_type != (type)) \
continue; \
else
#define MVPP2_ENTRIES_PER_FLOW (MVPP2_MAX_PORTS + 1)
#define MVPP2_FLOW_C2_ENTRY(id) ((id) * MVPP2_ENTRIES_PER_FLOW)
#define MVPP2_PORT_FLOW_HASH_ENTRY(port, id) ((id) * MVPP2_ENTRIES_PER_FLOW + \
(port) + 1)
struct mvpp2_cls_flow_entry {
u32 index;
u32 data[MVPP2_CLS_FLOWS_TBL_DATA_WORDS];
......@@ -194,11 +211,10 @@ struct mvpp2_cls_lookup_entry {
};
void mvpp22_rss_fill_table(struct mvpp2_port *port, u32 table);
void mvpp22_port_rss_init(struct mvpp2_port *port);
void mvpp22_rss_port_init(struct mvpp2_port *port);
void mvpp22_rss_enable(struct mvpp2_port *port);
void mvpp22_rss_disable(struct mvpp2_port *port);
void mvpp22_port_rss_enable(struct mvpp2_port *port);
void mvpp22_port_rss_disable(struct mvpp2_port *port);
int mvpp2_ethtool_rxfh_get(struct mvpp2_port *port, struct ethtool_rxnfc *info);
int mvpp2_ethtool_rxfh_set(struct mvpp2_port *port, struct ethtool_rxnfc *info);
......@@ -213,7 +229,7 @@ int mvpp2_cls_flow_eng_get(struct mvpp2_cls_flow_entry *fe);
u16 mvpp2_flow_get_hek_fields(struct mvpp2_cls_flow_entry *fe);
struct mvpp2_cls_flow *mvpp2_cls_flow_get(int flow);
const struct mvpp2_cls_flow *mvpp2_cls_flow_get(int flow);
u32 mvpp2_cls_flow_hits(struct mvpp2 *priv, int index);
......
......@@ -18,22 +18,48 @@ struct mvpp2_dbgfs_prs_entry {
struct mvpp2 *priv;
};
struct mvpp2_dbgfs_c2_entry {
int id;
struct mvpp2 *priv;
};
struct mvpp2_dbgfs_flow_entry {
int flow;
struct mvpp2 *priv;
};
struct mvpp2_dbgfs_flow_tbl_entry {
int id;
struct mvpp2 *priv;
};
struct mvpp2_dbgfs_port_flow_entry {
struct mvpp2_port *port;
struct mvpp2_dbgfs_flow_entry *dbg_fe;
};
struct mvpp2_dbgfs_entries {
/* Entries for Header Parser debug info */
struct mvpp2_dbgfs_prs_entry prs_entries[MVPP2_PRS_TCAM_SRAM_SIZE];
/* Entries for Classifier C2 engine debug info */
struct mvpp2_dbgfs_c2_entry c2_entries[MVPP22_CLS_C2_N_ENTRIES];
/* Entries for Classifier Flow Table debug info */
struct mvpp2_dbgfs_flow_tbl_entry flt_entries[MVPP2_CLS_FLOWS_TBL_SIZE];
/* Entries for Classifier flows debug info */
struct mvpp2_dbgfs_flow_entry flow_entries[MVPP2_N_PRS_FLOWS];
/* Entries for per-port flows debug info */
struct mvpp2_dbgfs_port_flow_entry port_flow_entries[MVPP2_MAX_PORTS];
};
static int mvpp2_dbgfs_flow_flt_hits_show(struct seq_file *s, void *unused)
{
struct mvpp2_dbgfs_flow_entry *entry = s->private;
int id = MVPP2_FLOW_C2_ENTRY(entry->flow);
struct mvpp2_dbgfs_flow_tbl_entry *entry = s->private;
u32 hits = mvpp2_cls_flow_hits(entry->priv, id);
u32 hits = mvpp2_cls_flow_hits(entry->priv, entry->id);
seq_printf(s, "%u\n", hits);
......@@ -58,7 +84,7 @@ DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_dec_hits);
static int mvpp2_dbgfs_flow_type_show(struct seq_file *s, void *unused)
{
struct mvpp2_dbgfs_flow_entry *entry = s->private;
struct mvpp2_cls_flow *f;
const struct mvpp2_cls_flow *f;
const char *flow_name;
f = mvpp2_cls_flow_get(entry->flow);
......@@ -93,30 +119,12 @@ static int mvpp2_dbgfs_flow_type_show(struct seq_file *s, void *unused)
return 0;
}
static int mvpp2_dbgfs_flow_type_open(struct inode *inode, struct file *file)
{
return single_open(file, mvpp2_dbgfs_flow_type_show, inode->i_private);
}
static int mvpp2_dbgfs_flow_type_release(struct inode *inode, struct file *file)
{
struct seq_file *seq = file->private_data;
struct mvpp2_dbgfs_flow_entry *flow_entry = seq->private;
kfree(flow_entry);
return single_release(inode, file);
}
static const struct file_operations mvpp2_dbgfs_flow_type_fops = {
.open = mvpp2_dbgfs_flow_type_open,
.read = seq_read,
.release = mvpp2_dbgfs_flow_type_release,
};
DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_type);
static int mvpp2_dbgfs_flow_id_show(struct seq_file *s, void *unused)
{
struct mvpp2_dbgfs_flow_entry *entry = s->private;
struct mvpp2_cls_flow *f;
const struct mvpp2_dbgfs_flow_entry *entry = s->private;
const struct mvpp2_cls_flow *f;
f = mvpp2_cls_flow_get(entry->flow);
if (!f)
......@@ -134,7 +142,7 @@ static int mvpp2_dbgfs_port_flow_hash_opt_show(struct seq_file *s, void *unused)
struct mvpp2_dbgfs_port_flow_entry *entry = s->private;
struct mvpp2_port *port = entry->port;
struct mvpp2_cls_flow_entry fe;
struct mvpp2_cls_flow *f;
const struct mvpp2_cls_flow *f;
int flow_index;
u16 hash_opts;
......@@ -142,7 +150,7 @@ static int mvpp2_dbgfs_port_flow_hash_opt_show(struct seq_file *s, void *unused)
if (!f)
return -EINVAL;
flow_index = MVPP2_PORT_FLOW_HASH_ENTRY(entry->port->id, f->flow_id);
flow_index = MVPP2_CLS_FLT_HASH_ENTRY(entry->port->id, f->flow_id);
mvpp2_cls_flow_read(port->priv, flow_index, &fe);
......@@ -153,42 +161,21 @@ static int mvpp2_dbgfs_port_flow_hash_opt_show(struct seq_file *s, void *unused)
return 0;
}
static int mvpp2_dbgfs_port_flow_hash_opt_open(struct inode *inode,
struct file *file)
{
return single_open(file, mvpp2_dbgfs_port_flow_hash_opt_show,
inode->i_private);
}
static int mvpp2_dbgfs_port_flow_hash_opt_release(struct inode *inode,
struct file *file)
{
struct seq_file *seq = file->private_data;
struct mvpp2_dbgfs_port_flow_entry *flow_entry = seq->private;
kfree(flow_entry);
return single_release(inode, file);
}
static const struct file_operations mvpp2_dbgfs_port_flow_hash_opt_fops = {
.open = mvpp2_dbgfs_port_flow_hash_opt_open,
.read = seq_read,
.release = mvpp2_dbgfs_port_flow_hash_opt_release,
};
DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_port_flow_hash_opt);
static int mvpp2_dbgfs_port_flow_engine_show(struct seq_file *s, void *unused)
{
struct mvpp2_dbgfs_port_flow_entry *entry = s->private;
struct mvpp2_port *port = entry->port;
struct mvpp2_cls_flow_entry fe;
struct mvpp2_cls_flow *f;
const struct mvpp2_cls_flow *f;
int flow_index, engine;
f = mvpp2_cls_flow_get(entry->dbg_fe->flow);
if (!f)
return -EINVAL;
flow_index = MVPP2_PORT_FLOW_HASH_ENTRY(entry->port->id, f->flow_id);
flow_index = MVPP2_CLS_FLT_HASH_ENTRY(entry->port->id, f->flow_id);
mvpp2_cls_flow_read(port->priv, flow_index, &fe);
......@@ -203,11 +190,10 @@ DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_port_flow_engine);
static int mvpp2_dbgfs_flow_c2_hits_show(struct seq_file *s, void *unused)
{
struct mvpp2_port *port = s->private;
struct mvpp2_dbgfs_c2_entry *entry = s->private;
u32 hits;
hits = mvpp2_cls_c2_hit_count(port->priv,
MVPP22_CLS_C2_RSS_ENTRY(port->id));
hits = mvpp2_cls_c2_hit_count(entry->priv, entry->id);
seq_printf(s, "%u\n", hits);
......@@ -218,11 +204,11 @@ DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_c2_hits);
static int mvpp2_dbgfs_flow_c2_rxq_show(struct seq_file *s, void *unused)
{
struct mvpp2_port *port = s->private;
struct mvpp2_dbgfs_c2_entry *entry = s->private;
struct mvpp2_cls_c2_entry c2;
u8 qh, ql;
mvpp2_cls_c2_read(port->priv, MVPP22_CLS_C2_RSS_ENTRY(port->id), &c2);
mvpp2_cls_c2_read(entry->priv, entry->id, &c2);
qh = (c2.attr[0] >> MVPP22_CLS_C2_ATTR0_QHIGH_OFFS) &
MVPP22_CLS_C2_ATTR0_QHIGH_MASK;
......@@ -239,11 +225,11 @@ DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_c2_rxq);
static int mvpp2_dbgfs_flow_c2_enable_show(struct seq_file *s, void *unused)
{
struct mvpp2_port *port = s->private;
struct mvpp2_dbgfs_c2_entry *entry = s->private;
struct mvpp2_cls_c2_entry c2;
int enabled;
mvpp2_cls_c2_read(port->priv, MVPP22_CLS_C2_RSS_ENTRY(port->id), &c2);
mvpp2_cls_c2_read(entry->priv, entry->id, &c2);
enabled = !!(c2.attr[2] & MVPP22_CLS_C2_ATTR2_RSS_EN);
......@@ -456,25 +442,7 @@ static int mvpp2_dbgfs_prs_valid_show(struct seq_file *s, void *unused)
return 0;
}
static int mvpp2_dbgfs_prs_valid_open(struct inode *inode, struct file *file)
{
return single_open(file, mvpp2_dbgfs_prs_valid_show, inode->i_private);
}
static int mvpp2_dbgfs_prs_valid_release(struct inode *inode, struct file *file)
{
struct seq_file *seq = file->private_data;
struct mvpp2_dbgfs_prs_entry *entry = seq->private;
kfree(entry);
return single_release(inode, file);
}
static const struct file_operations mvpp2_dbgfs_prs_valid_fops = {
.open = mvpp2_dbgfs_prs_valid_open,
.read = seq_read,
.release = mvpp2_dbgfs_prs_valid_release,
};
DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_valid);
static int mvpp2_dbgfs_flow_port_init(struct dentry *parent,
struct mvpp2_port *port,
......@@ -487,10 +455,7 @@ static int mvpp2_dbgfs_flow_port_init(struct dentry *parent,
if (IS_ERR(port_dir))
return PTR_ERR(port_dir);
/* This will be freed by 'hash_opts' release op */
port_entry = kmalloc(sizeof(*port_entry), GFP_KERNEL);
if (!port_entry)
return -ENOMEM;
port_entry = &port->priv->dbgfs_entries->port_flow_entries[port->id];
port_entry->port = port;
port_entry->dbg_fe = entry;
......@@ -518,17 +483,11 @@ static int mvpp2_dbgfs_flow_entry_init(struct dentry *parent,
if (!flow_entry_dir)
return -ENOMEM;
/* This will be freed by 'type' release op */
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
return -ENOMEM;
entry = &priv->dbgfs_entries->flow_entries[flow];
entry->flow = flow;
entry->priv = priv;
debugfs_create_file("flow_hits", 0444, flow_entry_dir, entry,
&mvpp2_dbgfs_flow_flt_hits_fops);
debugfs_create_file("dec_hits", 0444, flow_entry_dir, entry,
&mvpp2_dbgfs_flow_dec_hits_fops);
......@@ -545,6 +504,7 @@ static int mvpp2_dbgfs_flow_entry_init(struct dentry *parent,
if (ret)
return ret;
}
return 0;
}
......@@ -557,7 +517,7 @@ static int mvpp2_dbgfs_flow_init(struct dentry *parent, struct mvpp2 *priv)
if (!flow_dir)
return -ENOMEM;
for (i = 0; i < MVPP2_N_FLOWS; i++) {
for (i = 0; i < MVPP2_N_PRS_FLOWS; i++) {
ret = mvpp2_dbgfs_flow_entry_init(flow_dir, priv, i);
if (ret)
return ret;
......@@ -582,10 +542,7 @@ static int mvpp2_dbgfs_prs_entry_init(struct dentry *parent,
if (!prs_entry_dir)
return -ENOMEM;
/* The 'valid' entry's ops will free that */
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
return -ENOMEM;
entry = &priv->dbgfs_entries->prs_entries[tid];
entry->tid = tid;
entry->priv = priv;
......@@ -630,6 +587,98 @@ static int mvpp2_dbgfs_prs_init(struct dentry *parent, struct mvpp2 *priv)
return 0;
}
static int mvpp2_dbgfs_c2_entry_init(struct dentry *parent,
struct mvpp2 *priv, int id)
{
struct mvpp2_dbgfs_c2_entry *entry;
struct dentry *c2_entry_dir;
char c2_entry_name[10];
if (id >= MVPP22_CLS_C2_N_ENTRIES)
return -EINVAL;
sprintf(c2_entry_name, "%03d", id);
c2_entry_dir = debugfs_create_dir(c2_entry_name, parent);
if (!c2_entry_dir)
return -ENOMEM;
entry = &priv->dbgfs_entries->c2_entries[id];
entry->id = id;
entry->priv = priv;
debugfs_create_file("hits", 0444, c2_entry_dir, entry,
&mvpp2_dbgfs_flow_c2_hits_fops);
debugfs_create_file("default_rxq", 0444, c2_entry_dir, entry,
&mvpp2_dbgfs_flow_c2_rxq_fops);
debugfs_create_file("rss_enable", 0444, c2_entry_dir, entry,
&mvpp2_dbgfs_flow_c2_enable_fops);
return 0;
}
static int mvpp2_dbgfs_flow_tbl_entry_init(struct dentry *parent,
struct mvpp2 *priv, int id)
{
struct mvpp2_dbgfs_flow_tbl_entry *entry;
struct dentry *flow_tbl_entry_dir;
char flow_tbl_entry_name[10];
if (id >= MVPP2_CLS_FLOWS_TBL_SIZE)
return -EINVAL;
sprintf(flow_tbl_entry_name, "%03d", id);
flow_tbl_entry_dir = debugfs_create_dir(flow_tbl_entry_name, parent);
if (!flow_tbl_entry_dir)
return -ENOMEM;
entry = &priv->dbgfs_entries->flt_entries[id];
entry->id = id;
entry->priv = priv;
debugfs_create_file("hits", 0444, flow_tbl_entry_dir, entry,
&mvpp2_dbgfs_flow_flt_hits_fops);
return 0;
}
static int mvpp2_dbgfs_cls_init(struct dentry *parent, struct mvpp2 *priv)
{
struct dentry *cls_dir, *c2_dir, *flow_tbl_dir;
int i, ret;
cls_dir = debugfs_create_dir("classifier", parent);
if (!cls_dir)
return -ENOMEM;
c2_dir = debugfs_create_dir("c2", cls_dir);
if (!c2_dir)
return -ENOMEM;
for (i = 0; i < MVPP22_CLS_C2_N_ENTRIES; i++) {
ret = mvpp2_dbgfs_c2_entry_init(c2_dir, priv, i);
if (ret)
return ret;
}
flow_tbl_dir = debugfs_create_dir("flow_table", cls_dir);
if (!flow_tbl_dir)
return -ENOMEM;
for (i = 0; i < MVPP2_CLS_FLOWS_TBL_SIZE; i++) {
ret = mvpp2_dbgfs_flow_tbl_entry_init(flow_tbl_dir, priv, i);
if (ret)
return ret;
}
return 0;
}
static int mvpp2_dbgfs_port_init(struct dentry *parent,
struct mvpp2_port *port)
{
......@@ -648,21 +697,14 @@ static int mvpp2_dbgfs_port_init(struct dentry *parent,
debugfs_create_file("vid_filter", 0444, port_dir, port,
&mvpp2_dbgfs_port_vid_fops);
debugfs_create_file("c2_hits", 0444, port_dir, port,
&mvpp2_dbgfs_flow_c2_hits_fops);
debugfs_create_file("default_rxq", 0444, port_dir, port,
&mvpp2_dbgfs_flow_c2_rxq_fops);
debugfs_create_file("rss_enable", 0444, port_dir, port,
&mvpp2_dbgfs_flow_c2_enable_fops);
return 0;
}
void mvpp2_dbgfs_cleanup(struct mvpp2 *priv)
{
debugfs_remove_recursive(priv->dbgfs_dir);
kfree(priv->dbgfs_entries);
}
void mvpp2_dbgfs_init(struct mvpp2 *priv, const char *name)
......@@ -682,11 +724,18 @@ void mvpp2_dbgfs_init(struct mvpp2 *priv, const char *name)
return;
priv->dbgfs_dir = mvpp2_dir;
priv->dbgfs_entries = kzalloc(sizeof(*priv->dbgfs_entries), GFP_KERNEL);
if (!priv->dbgfs_entries)
goto err;
ret = mvpp2_dbgfs_prs_init(mvpp2_dir, priv);
if (ret)
goto err;
ret = mvpp2_dbgfs_cls_init(mvpp2_dir, priv);
if (ret)
goto err;
for (i = 0; i < priv->port_count; i++) {
ret = mvpp2_dbgfs_port_init(mvpp2_dir, priv->port_list[i]);
if (ret)
......
......@@ -3741,9 +3741,9 @@ static int mvpp2_set_features(struct net_device *dev,
if (changed & NETIF_F_RXHASH) {
if (features & NETIF_F_RXHASH)
mvpp22_rss_enable(port);
mvpp22_port_rss_enable(port);
else
mvpp22_rss_disable(port);
mvpp22_port_rss_disable(port);
}
return 0;
......@@ -4301,7 +4301,7 @@ static int mvpp2_port_init(struct mvpp2_port *port)
mvpp2_cls_port_config(port);
if (mvpp22_rss_is_supported())
mvpp22_rss_port_init(port);
mvpp22_port_rss_init(port);
/* Provide an initial Rx packet size */
port->pkt_size = MVPP2_RX_PKT_SIZE(port->dev->mtu);
......@@ -4848,6 +4848,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
struct mvpp2_port *port;
struct mvpp2_port_pcpu *port_pcpu;
struct device_node *port_node = to_of_node(port_fwnode);
netdev_features_t features;
struct net_device *dev;
struct resource *res;
struct phylink *phylink;
......@@ -4856,7 +4857,6 @@ static int mvpp2_port_probe(struct platform_device *pdev,
unsigned long flags = 0;
bool has_tx_irqs;
u32 id;
int features;
int phy_mode;
int err, i;
......
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