@@ -20,7 +20,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;
@@ -16,9 +16,6 @@
#include <linux/pci.h>
#include "felix.h"
-#define VSC9959_VCAP_IS2_CNT 1024
-#define VSC9959_VCAP_IS2_ENTRY_WIDTH 376
-#define VSC9959_VCAP_PORT_CNT 6
#define VSC9959_TAS_GCL_ENTRY_MAX 63
static const u32 vsc9959_ana_regmap[] = {
@@ -148,6 +145,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[] = {
@@ -696,15 +704,8 @@ 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_IS2] = {
- .tg_width = 2,
- .sw_count = 4,
- .entry_count = VSC9959_VCAP_IS2_CNT,
- .entry_width = VSC9959_VCAP_IS2_ENTRY_WIDTH,
- .action_count = VSC9959_VCAP_IS2_CNT +
- VSC9959_VCAP_PORT_CNT + 2,
- .action_width = 89,
.action_type_width = 1,
.action_table = {
[IS2_ACTION_TYPE_NORMAL] = {
@@ -716,8 +717,6 @@ static const struct vcap_props vsc9959_vcap_props[] = {
.count = 4
},
},
- .counter_words = 4,
- .counter_width = 32,
.target = S2,
.keys = vsc9959_vcap_is2_keys,
.actions = vsc9959_vcap_is2_actions,
@@ -12,10 +12,6 @@
#include <linux/iopoll.h>
#include "felix.h"
-#define VSC9953_VCAP_IS2_CNT 1024
-#define VSC9953_VCAP_IS2_ENTRY_WIDTH 376
-#define VSC9953_VCAP_PORT_CNT 10
-
#define MSCC_MIIM_CMD_OPR_WRITE BIT(1)
#define MSCC_MIIM_CMD_OPR_READ BIT(2)
#define MSCC_MIIM_CMD_WRDATA_SHIFT 4
@@ -150,6 +146,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[] = {
@@ -686,15 +693,8 @@ 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_IS2] = {
- .tg_width = 2,
- .sw_count = 4,
- .entry_count = VSC9953_VCAP_IS2_CNT,
- .entry_width = VSC9953_VCAP_IS2_ENTRY_WIDTH,
- .action_count = VSC9953_VCAP_IS2_CNT +
- VSC9953_VCAP_PORT_CNT + 2,
- .action_width = 101,
.action_type_width = 1,
.action_table = {
[IS2_ACTION_TYPE_NORMAL] = {
@@ -706,8 +706,6 @@ static const struct vcap_props vsc9953_vcap_props[] = {
.count = 4
},
},
- .counter_words = 4,
- .counter_width = 32,
.target = S2,
.keys = vsc9953_vcap_is2_keys,
.actions = vsc9953_vcap_is2_actions,
@@ -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"
@@ -1380,6 +1381,75 @@ static void ocelot_cpu_port_init(struct ocelot *ocelot)
ANA_PORT_VLAN_CFG, cpu);
}
+static void ocelot_detect_vcap_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;
+}
+
static void ocelot_detect_features(struct ocelot *ocelot)
{
int mmgt, eq_ctrl;
@@ -1396,6 +1466,8 @@ static void ocelot_detect_features(struct ocelot *ocelot)
dev_info(ocelot->dev,
"Detected %d bytes of packet buffer and %d frame references\n",
ocelot->packet_buffer_size, ocelot->num_frame_refs);
+
+ ocelot_detect_vcap_constants(ocelot, &ocelot->vcap[VCAP_IS2]);
}
int ocelot_init(struct ocelot *ocelot)
@@ -19,10 +19,6 @@
#include "ocelot.h"
#define IFH_EXTRACT_BITFIELD64(x, o, w) (((x) >> (o)) & GENMASK_ULL((w) - 1, 0))
-#define VSC7514_VCAP_IS2_CNT 64
-#define VSC7514_VCAP_IS2_ENTRY_WIDTH 376
-#define VSC7514_VCAP_IS2_ACTION_WIDTH 99
-#define VSC7514_VCAP_PORT_CNT 11
static const u32 ocelot_ana_regmap[] = {
REG(ANA_ADVLEARN, 0x009000),
@@ -251,6 +247,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[] = {
@@ -855,15 +862,8 @@ 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_IS2] = {
- .tg_width = 2,
- .sw_count = 4,
- .entry_count = VSC7514_VCAP_IS2_CNT,
- .entry_width = VSC7514_VCAP_IS2_ENTRY_WIDTH,
- .action_count = VSC7514_VCAP_IS2_CNT +
- VSC7514_VCAP_PORT_CNT + 2,
- .action_width = 99,
.action_type_width = 1,
.action_table = {
[IS2_ACTION_TYPE_NORMAL] = {
@@ -875,8 +875,6 @@ static const struct vcap_props vsc7514_vcap_props[] = {
.count = 4
},
},
- .counter_words = 4,
- .counter_width = 32,
.target = S2,
.keys = vsc7514_vcap_is2_keys,
.actions = vsc7514_vcap_is2_actions,
@@ -521,6 +521,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 {
@@ -620,7 +631,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;
The numbers in struct vcap_props may be fun to look at, but they are not fun to derive, especially since they are not a straightforward copy-and-paste from the reference manual. 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. This patch only refactors the constants that already exist, aka those for VCAP IS2. For IS1 and ES0, detection will be done in another patch. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> --- Changes in v2: Patch is new. drivers/net/dsa/ocelot/felix.h | 2 +- drivers/net/dsa/ocelot/felix_vsc9959.c | 25 ++++---- drivers/net/dsa/ocelot/seville_vsc9953.c | 26 ++++---- drivers/net/ethernet/mscc/ocelot.c | 72 ++++++++++++++++++++++ drivers/net/ethernet/mscc/ocelot_vsc7514.c | 26 ++++---- include/soc/mscc/ocelot.h | 13 +++- 6 files changed, 121 insertions(+), 43 deletions(-)