net: mscc: ocelot: automatically detect VCAP constants
authorVladimir Oltean <vladimir.oltean@nxp.com>
Tue, 29 Sep 2020 22:27:26 +0000 (01:27 +0300)
committerDavid S. Miller <davem@davemloft.net>
Wed, 30 Sep 2020 01:26:24 +0000 (18:26 -0700)
The numbers in struct vcap_props are not intuitive to derive, because
they are not a straightforward copy-and-paste from the reference manual
but instead rely on a fairly detailed level of understanding of the
layout of an entry in the TCAM and in the action RAM. For this reason,
bugs are very easy to introduce here.

Ease the work of hardware porters and read from hardware the constants
that were exported for this particular purpose. Note that this implies
that struct vcap_props can no longer be const.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/ocelot/felix.h
drivers/net/dsa/ocelot/felix_vsc9959.c
drivers/net/dsa/ocelot/seville_vsc9953.c
drivers/net/ethernet/mscc/ocelot.c
drivers/net/ethernet/mscc/ocelot_vcap.c
drivers/net/ethernet/mscc/ocelot_vcap.h
drivers/net/ethernet/mscc/ocelot_vsc7514.c
include/soc/mscc/ocelot.h
include/soc/mscc/ocelot_vcap.h

index ec4a8e939bcd9b8fa65c71ef31baf0d43861b43a..d5f46784306e21523a0f77ade38c7d1fdeb747e9 100644 (file)
@@ -21,7 +21,7 @@ struct felix_info {
        unsigned int                    num_stats;
        int                             num_ports;
        int                             num_tx_queues;
-       const struct vcap_props         *vcap;
+       struct vcap_props               *vcap;
        int                             switch_pci_bar;
        int                             imdio_pci_bar;
        const struct ptp_clock_info     *ptp_caps;
index e3e961e299c43449d5d451736ef8ec90687973fe..eef056b35523e28280e24b8d909bab4f6a97cc04 100644 (file)
@@ -148,6 +148,17 @@ static const u32 vsc9959_vcap_regmap[] = {
        REG(VCAP_CACHE_ACTION_DAT,              0x000208),
        REG(VCAP_CACHE_CNT_DAT,                 0x000308),
        REG(VCAP_CACHE_TG_DAT,                  0x000388),
+       /* VCAP_CONST */
+       REG(VCAP_CONST_VCAP_VER,                0x000398),
+       REG(VCAP_CONST_ENTRY_WIDTH,             0x00039c),
+       REG(VCAP_CONST_ENTRY_CNT,               0x0003a0),
+       REG(VCAP_CONST_ENTRY_SWCNT,             0x0003a4),
+       REG(VCAP_CONST_ENTRY_TG_WIDTH,          0x0003a8),
+       REG(VCAP_CONST_ACTION_DEF_CNT,          0x0003ac),
+       REG(VCAP_CONST_ACTION_WIDTH,            0x0003b0),
+       REG(VCAP_CONST_CNT_WIDTH,               0x0003b4),
+       REG(VCAP_CONST_CORE_CNT,                0x0003b8),
+       REG(VCAP_CONST_IF_CNT,                  0x0003bc),
 };
 
 static const u32 vsc9959_qsys_regmap[] = {
@@ -814,7 +825,7 @@ static struct vcap_field vsc9959_vcap_is2_actions[] = {
        [VCAP_IS2_ACT_HIT_CNT]                  = { 49, 32},
 };
 
-static const struct vcap_props vsc9959_vcap_props[] = {
+static struct vcap_props vsc9959_vcap_props[] = {
        [VCAP_ES0] = {
                .action_type_width = 0,
                .action_table = {
index 67336a59ee8e792ec788bc9bd9e153cfba059459..97e3a0f83429b16e02f39d1f75154a11efe85528 100644 (file)
@@ -150,6 +150,17 @@ static const u32 vsc9953_vcap_regmap[] = {
        REG(VCAP_CACHE_ACTION_DAT,              0x000208),
        REG(VCAP_CACHE_CNT_DAT,                 0x000308),
        REG(VCAP_CACHE_TG_DAT,                  0x000388),
+       /* VCAP_CONST */
+       REG(VCAP_CONST_VCAP_VER,                0x000398),
+       REG(VCAP_CONST_ENTRY_WIDTH,             0x00039c),
+       REG(VCAP_CONST_ENTRY_CNT,               0x0003a0),
+       REG(VCAP_CONST_ENTRY_SWCNT,             0x0003a4),
+       REG(VCAP_CONST_ENTRY_TG_WIDTH,          0x0003a8),
+       REG(VCAP_CONST_ACTION_DEF_CNT,          0x0003ac),
+       REG(VCAP_CONST_ACTION_WIDTH,            0x0003b0),
+       REG(VCAP_CONST_CNT_WIDTH,               0x0003b4),
+       REG_RESERVED(VCAP_CONST_CORE_CNT),
+       REG_RESERVED(VCAP_CONST_IF_CNT),
 };
 
 static const u32 vsc9953_qsys_regmap[] = {
@@ -804,7 +815,7 @@ static struct vcap_field vsc9953_vcap_is2_actions[] = {
        [VCAP_IS2_ACT_HIT_CNT]                  = { 50, 32},
 };
 
-static const struct vcap_props vsc9953_vcap_props[] = {
+static struct vcap_props vsc9953_vcap_props[] = {
        [VCAP_ES0] = {
                .action_type_width = 0,
                .action_table = {
index b9375d96cdbc178881184ff8b9787ae83e3ce4ff..974821b9cdc4d51f3705e4847b36651a4d65fd43 100644 (file)
@@ -5,6 +5,7 @@
  * Copyright (c) 2017 Microsemi Corporation
  */
 #include <linux/if_bridge.h>
+#include <soc/mscc/ocelot_vcap.h>
 #include "ocelot.h"
 #include "ocelot_vcap.h"
 
index 1755979e3f36f11e0c091f5890f7f2c15952572b..b736c3d3df2f9c738213ee2234627f7728d2539f 100644 (file)
@@ -1001,11 +1001,79 @@ static void ocelot_vcap_init_one(struct ocelot *ocelot,
                 VCAP_SEL_ACTION | VCAP_SEL_COUNTER);
 }
 
+static void ocelot_vcap_detect_constants(struct ocelot *ocelot,
+                                        struct vcap_props *vcap)
+{
+       int counter_memory_width;
+       int num_default_actions;
+       int version;
+
+       version = ocelot_target_read(ocelot, vcap->target,
+                                    VCAP_CONST_VCAP_VER);
+       /* Only version 0 VCAP supported for now */
+       if (WARN_ON(version != 0))
+               return;
+
+       /* Width in bits of type-group field */
+       vcap->tg_width = ocelot_target_read(ocelot, vcap->target,
+                                           VCAP_CONST_ENTRY_TG_WIDTH);
+       /* Number of subwords per TCAM row */
+       vcap->sw_count = ocelot_target_read(ocelot, vcap->target,
+                                           VCAP_CONST_ENTRY_SWCNT);
+       /* Number of rows in TCAM. There can be this many full keys, or double
+        * this number half keys, or 4 times this number quarter keys.
+        */
+       vcap->entry_count = ocelot_target_read(ocelot, vcap->target,
+                                              VCAP_CONST_ENTRY_CNT);
+       /* Assuming there are 4 subwords per TCAM row, their layout in the
+        * actual TCAM (not in the cache) would be:
+        *
+        * |  SW 3  | TG 3 |  SW 2  | TG 2 |  SW 1  | TG 1 |  SW 0  | TG 0 |
+        *
+        * (where SW=subword and TG=Type-Group).
+        *
+        * What VCAP_CONST_ENTRY_CNT is giving us is the width of one full TCAM
+        * row. But when software accesses the TCAM through the cache
+        * registers, the Type-Group values are written through another set of
+        * registers VCAP_TG_DAT, and therefore, it appears as though the 4
+        * subwords are contiguous in the cache memory.
+        * Important mention: regardless of the number of key entries per row
+        * (and therefore of key size: 1 full key or 2 half keys or 4 quarter
+        * keys), software always has to configure 4 Type-Group values. For
+        * example, in the case of 1 full key, the driver needs to set all 4
+        * Type-Group to be full key.
+        *
+        * For this reason, we need to fix up the value that the hardware is
+        * giving us. We don't actually care about the width of the entry in
+        * the TCAM. What we care about is the width of the entry in the cache
+        * registers, which is how we get to interact with it. And since the
+        * VCAP_ENTRY_DAT cache registers access only the subwords and not the
+        * Type-Groups, this means we need to subtract the width of the
+        * Type-Groups when packing and unpacking key entry data in a TCAM row.
+        */
+       vcap->entry_width = ocelot_target_read(ocelot, vcap->target,
+                                              VCAP_CONST_ENTRY_WIDTH);
+       vcap->entry_width -= vcap->tg_width * vcap->sw_count;
+       num_default_actions = ocelot_target_read(ocelot, vcap->target,
+                                                VCAP_CONST_ACTION_DEF_CNT);
+       vcap->action_count = vcap->entry_count + num_default_actions;
+       vcap->action_width = ocelot_target_read(ocelot, vcap->target,
+                                               VCAP_CONST_ACTION_WIDTH);
+       /* The width of the counter memory, this is the complete width of all
+        * counter-fields associated with one full-word entry. There is one
+        * counter per entry sub-word (see CAP_CORE::ENTRY_SWCNT for number of
+        * subwords.)
+        */
+       vcap->counter_words = vcap->sw_count;
+       counter_memory_width = ocelot_target_read(ocelot, vcap->target,
+                                                 VCAP_CONST_CNT_WIDTH);
+       vcap->counter_width = counter_memory_width / vcap->counter_words;
+}
+
 int ocelot_vcap_init(struct ocelot *ocelot)
 {
        struct ocelot_vcap_block *block = &ocelot->block;
-
-       ocelot_vcap_init_one(ocelot, &ocelot->vcap[VCAP_IS2]);
+       int i;
 
        /* Create a policer that will drop the frames for the cpu.
         * This policer will be used as action in the acl rules to drop
@@ -1022,6 +1090,13 @@ int ocelot_vcap_init(struct ocelot *ocelot)
        ocelot_write_gix(ocelot, 0x3fffff, ANA_POL_CIR_STATE,
                         OCELOT_POLICER_DISCARD);
 
+       for (i = 0; i < OCELOT_NUM_VCAP_BLOCKS; i++) {
+               struct vcap_props *vcap = &ocelot->vcap[i];
+
+               ocelot_vcap_detect_constants(ocelot, vcap);
+               ocelot_vcap_init_one(ocelot, vcap);
+       }
+
        block->pol_lpr = OCELOT_POLICER_DISCARD - 1;
 
        INIT_LIST_HEAD(&block->rules);
index 0dfbfc011b2e4cd8ea606d802f5b06b56a1e4070..50742d13c01a164b4f8d8f6be29a537b458b2e45 100644 (file)
@@ -222,6 +222,7 @@ int ocelot_vcap_filter_del(struct ocelot *ocelot,
 int ocelot_vcap_filter_stats_update(struct ocelot *ocelot,
                                    struct ocelot_vcap_filter *rule);
 
+void ocelot_detect_vcap_constants(struct ocelot *ocelot);
 int ocelot_vcap_init(struct ocelot *ocelot);
 
 int ocelot_setup_tc_cls_flower(struct ocelot_port_private *priv,
index 86f8b77decf5e35e21924ada68fed7567b094315..36332bc9af3b2a93ee15876314b306e9d173d5e3 100644 (file)
@@ -251,6 +251,17 @@ static const u32 ocelot_vcap_regmap[] = {
        REG(VCAP_CACHE_ACTION_DAT,                      0x000208),
        REG(VCAP_CACHE_CNT_DAT,                         0x000308),
        REG(VCAP_CACHE_TG_DAT,                          0x000388),
+       /* VCAP_CONST */
+       REG(VCAP_CONST_VCAP_VER,                        0x000398),
+       REG(VCAP_CONST_ENTRY_WIDTH,                     0x00039c),
+       REG(VCAP_CONST_ENTRY_CNT,                       0x0003a0),
+       REG(VCAP_CONST_ENTRY_SWCNT,                     0x0003a4),
+       REG(VCAP_CONST_ENTRY_TG_WIDTH,                  0x0003a8),
+       REG(VCAP_CONST_ACTION_DEF_CNT,                  0x0003ac),
+       REG(VCAP_CONST_ACTION_WIDTH,                    0x0003b0),
+       REG(VCAP_CONST_CNT_WIDTH,                       0x0003b4),
+       REG(VCAP_CONST_CORE_CNT,                        0x0003b8),
+       REG(VCAP_CONST_IF_CNT,                          0x0003bc),
 };
 
 static const u32 ocelot_ptp_regmap[] = {
@@ -963,7 +974,7 @@ static const struct vcap_field vsc7514_vcap_is2_actions[] = {
        [VCAP_IS2_ACT_HIT_CNT]                  = { 49, 32},
 };
 
-static const struct vcap_props vsc7514_vcap_props[] = {
+static struct vcap_props vsc7514_vcap_props[] = {
        [VCAP_ES0] = {
                .action_type_width = 0,
                .action_table = {
index b0a9efce8813b32e41342d7c76fd56c09bd3dc00..0c40122dcb88d1451e48807eaeebac8aac32e353 100644 (file)
@@ -523,6 +523,17 @@ enum {
        VCAP_CACHE_ACTION_DAT,
        VCAP_CACHE_CNT_DAT,
        VCAP_CACHE_TG_DAT,
+       /* VCAP_CONST */
+       VCAP_CONST_VCAP_VER,
+       VCAP_CONST_ENTRY_WIDTH,
+       VCAP_CONST_ENTRY_CNT,
+       VCAP_CONST_ENTRY_SWCNT,
+       VCAP_CONST_ENTRY_TG_WIDTH,
+       VCAP_CONST_ACTION_DEF_CNT,
+       VCAP_CONST_ACTION_WIDTH,
+       VCAP_CONST_CNT_WIDTH,
+       VCAP_CONST_CORE_CNT,
+       VCAP_CONST_IF_CNT,
 };
 
 enum ocelot_ptp_pins {
@@ -621,7 +632,7 @@ struct ocelot {
        struct list_head                multicast;
 
        struct ocelot_vcap_block        block;
-       const struct vcap_props         *vcap;
+       struct vcap_props               *vcap;
 
        /* Workqueue to check statistics for overflow with its lock */
        struct mutex                    stats_lock;
index 707e609ec9197890ceb2c0f3465e2ec0d53eb1e4..96300adf36481757c7954d6ae0bec7d420a187bd 100644 (file)
@@ -17,8 +17,11 @@ enum {
        VCAP_ES0,
        VCAP_IS1,
        VCAP_IS2,
+       __VCAP_COUNT,
 };
 
+#define OCELOT_NUM_VCAP_BLOCKS         __VCAP_COUNT
+
 struct vcap_props {
        u16 tg_width; /* Type-group width (in bits) */
        u16 sw_count; /* Sub word count */