Commit 611ba753 authored by David S. Miller's avatar David S. Miller

Merge branch 'HW-support-for-VCAP-IS1-and-ES0-in-mscc_ocelot'

Vladimir Oltean says:

====================
HW support for VCAP IS1 and ES0 in mscc_ocelot

The patches from RFC series "Offload tc-flower to mscc_ocelot switch
using VCAP chains" have been split into 2:
https://patchwork.ozlabs.org/project/netdev/list/?series=204810&state=*

This is the boring part, that deals with the prerequisites, and not with
tc-flower integration. Apart from the initialization of some hardware
blocks, which at this point still don't do anything, no new
functionality is introduced.

- Key and action field offsets are defined for the supported switches.
- VCAP properties are added to the driver for the new TCAM blocks. But
  instead of adding them manually as was done for IS2, which is error
  prone, the driver is refactored to read these parameters from
  hardware, which is possible.
- Some improvements regarding the processing of struct ocelot_vcap_filter.
- Extending the code to be compatible with full and quarter keys.

This series was tested, along with other patches not yet submitted, on
the Felix and Seville switches.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 879456be 98642d1a
......@@ -134,11 +134,13 @@ switch@1010000 {
<0x1280000 0x100>,
<0x1800000 0x80000>,
<0x1880000 0x10000>,
<0x1040000 0x10000>,
<0x1050000 0x10000>,
<0x1060000 0x10000>;
reg-names = "sys", "rew", "qs", "ptp", "port0", "port1",
"port2", "port3", "port4", "port5", "port6",
"port7", "port8", "port9", "port10", "qsys",
"ana", "s2";
"ana", "s0", "s1", "s2";
interrupts = <18 21 22>;
interrupt-names = "ptp_rdy", "xtr", "inj";
......
......@@ -435,8 +435,6 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports)
ocelot->num_stats = felix->info->num_stats;
ocelot->shared_queue_sz = felix->info->shared_queue_sz;
ocelot->num_mact_rows = felix->info->num_mact_rows;
ocelot->vcap_is2_keys = felix->info->vcap_is2_keys;
ocelot->vcap_is2_actions= felix->info->vcap_is2_actions;
ocelot->vcap = felix->info->vcap;
ocelot->ops = felix->info->ops;
ocelot->inj_prefix = OCELOT_TAG_PREFIX_SHORT;
......
......@@ -21,9 +21,7 @@ struct felix_info {
unsigned int num_stats;
int num_ports;
int num_tx_queues;
struct vcap_field *vcap_is2_keys;
struct vcap_field *vcap_is2_actions;
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[] = {
......@@ -138,14 +135,27 @@ static const u32 vsc9959_qs_regmap[] = {
REG_RESERVED(QS_INH_DBG),
};
static const u32 vsc9959_s2_regmap[] = {
REG(S2_CORE_UPDATE_CTRL, 0x000000),
REG(S2_CORE_MV_CFG, 0x000004),
REG(S2_CACHE_ENTRY_DAT, 0x000008),
REG(S2_CACHE_MASK_DAT, 0x000108),
REG(S2_CACHE_ACTION_DAT, 0x000208),
REG(S2_CACHE_CNT_DAT, 0x000308),
REG(S2_CACHE_TG_DAT, 0x000388),
static const u32 vsc9959_vcap_regmap[] = {
/* VCAP_CORE_CFG */
REG(VCAP_CORE_UPDATE_CTRL, 0x000000),
REG(VCAP_CORE_MV_CFG, 0x000004),
/* VCAP_CORE_CACHE */
REG(VCAP_CACHE_ENTRY_DAT, 0x000008),
REG(VCAP_CACHE_MASK_DAT, 0x000108),
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[] = {
......@@ -359,7 +369,9 @@ static const u32 *vsc9959_regmap[TARGET_MAX] = {
[QSYS] = vsc9959_qsys_regmap,
[REW] = vsc9959_rew_regmap,
[SYS] = vsc9959_sys_regmap,
[S2] = vsc9959_s2_regmap,
[S0] = vsc9959_vcap_regmap,
[S1] = vsc9959_vcap_regmap,
[S2] = vsc9959_vcap_regmap,
[PTP] = vsc9959_ptp_regmap,
[GCB] = vsc9959_gcb_regmap,
[DEV_GMII] = vsc9959_dev_gmii_regmap,
......@@ -392,6 +404,16 @@ static const struct resource vsc9959_target_io_res[TARGET_MAX] = {
.end = 0x001ffff,
.name = "sys",
},
[S0] = {
.start = 0x0040000,
.end = 0x00403ff,
.name = "s0",
},
[S1] = {
.start = 0x0050000,
.end = 0x00503ff,
.name = "s1",
},
[S2] = {
.start = 0x0060000,
.end = 0x00603ff,
......@@ -596,6 +618,112 @@ static const struct ocelot_stat_layout vsc9959_stats_layout[] = {
{ .offset = 0x111, .name = "drop_green_prio_7", },
};
static const struct vcap_field vsc9959_vcap_es0_keys[] = {
[VCAP_ES0_EGR_PORT] = { 0, 3},
[VCAP_ES0_IGR_PORT] = { 3, 3},
[VCAP_ES0_RSV] = { 6, 2},
[VCAP_ES0_L2_MC] = { 8, 1},
[VCAP_ES0_L2_BC] = { 9, 1},
[VCAP_ES0_VID] = { 10, 12},
[VCAP_ES0_DP] = { 22, 1},
[VCAP_ES0_PCP] = { 23, 3},
};
static const struct vcap_field vsc9959_vcap_es0_actions[] = {
[VCAP_ES0_ACT_PUSH_OUTER_TAG] = { 0, 2},
[VCAP_ES0_ACT_PUSH_INNER_TAG] = { 2, 1},
[VCAP_ES0_ACT_TAG_A_TPID_SEL] = { 3, 2},
[VCAP_ES0_ACT_TAG_A_VID_SEL] = { 5, 1},
[VCAP_ES0_ACT_TAG_A_PCP_SEL] = { 6, 2},
[VCAP_ES0_ACT_TAG_A_DEI_SEL] = { 8, 2},
[VCAP_ES0_ACT_TAG_B_TPID_SEL] = { 10, 2},
[VCAP_ES0_ACT_TAG_B_VID_SEL] = { 12, 1},
[VCAP_ES0_ACT_TAG_B_PCP_SEL] = { 13, 2},
[VCAP_ES0_ACT_TAG_B_DEI_SEL] = { 15, 2},
[VCAP_ES0_ACT_VID_A_VAL] = { 17, 12},
[VCAP_ES0_ACT_PCP_A_VAL] = { 29, 3},
[VCAP_ES0_ACT_DEI_A_VAL] = { 32, 1},
[VCAP_ES0_ACT_VID_B_VAL] = { 33, 12},
[VCAP_ES0_ACT_PCP_B_VAL] = { 45, 3},
[VCAP_ES0_ACT_DEI_B_VAL] = { 48, 1},
[VCAP_ES0_ACT_RSV] = { 49, 23},
[VCAP_ES0_ACT_HIT_STICKY] = { 72, 1},
};
static const struct vcap_field vsc9959_vcap_is1_keys[] = {
[VCAP_IS1_HK_TYPE] = { 0, 1},
[VCAP_IS1_HK_LOOKUP] = { 1, 2},
[VCAP_IS1_HK_IGR_PORT_MASK] = { 3, 7},
[VCAP_IS1_HK_RSV] = { 10, 9},
[VCAP_IS1_HK_OAM_Y1731] = { 19, 1},
[VCAP_IS1_HK_L2_MC] = { 20, 1},
[VCAP_IS1_HK_L2_BC] = { 21, 1},
[VCAP_IS1_HK_IP_MC] = { 22, 1},
[VCAP_IS1_HK_VLAN_TAGGED] = { 23, 1},
[VCAP_IS1_HK_VLAN_DBL_TAGGED] = { 24, 1},
[VCAP_IS1_HK_TPID] = { 25, 1},
[VCAP_IS1_HK_VID] = { 26, 12},
[VCAP_IS1_HK_DEI] = { 38, 1},
[VCAP_IS1_HK_PCP] = { 39, 3},
/* Specific Fields for IS1 Half Key S1_NORMAL */
[VCAP_IS1_HK_L2_SMAC] = { 42, 48},
[VCAP_IS1_HK_ETYPE_LEN] = { 90, 1},
[VCAP_IS1_HK_ETYPE] = { 91, 16},
[VCAP_IS1_HK_IP_SNAP] = {107, 1},
[VCAP_IS1_HK_IP4] = {108, 1},
/* Layer-3 Information */
[VCAP_IS1_HK_L3_FRAGMENT] = {109, 1},
[VCAP_IS1_HK_L3_FRAG_OFS_GT0] = {110, 1},
[VCAP_IS1_HK_L3_OPTIONS] = {111, 1},
[VCAP_IS1_HK_L3_DSCP] = {112, 6},
[VCAP_IS1_HK_L3_IP4_SIP] = {118, 32},
/* Layer-4 Information */
[VCAP_IS1_HK_TCP_UDP] = {150, 1},
[VCAP_IS1_HK_TCP] = {151, 1},
[VCAP_IS1_HK_L4_SPORT] = {152, 16},
[VCAP_IS1_HK_L4_RNG] = {168, 8},
/* Specific Fields for IS1 Half Key S1_5TUPLE_IP4 */
[VCAP_IS1_HK_IP4_INNER_TPID] = { 42, 1},
[VCAP_IS1_HK_IP4_INNER_VID] = { 43, 12},
[VCAP_IS1_HK_IP4_INNER_DEI] = { 55, 1},
[VCAP_IS1_HK_IP4_INNER_PCP] = { 56, 3},
[VCAP_IS1_HK_IP4_IP4] = { 59, 1},
[VCAP_IS1_HK_IP4_L3_FRAGMENT] = { 60, 1},
[VCAP_IS1_HK_IP4_L3_FRAG_OFS_GT0] = { 61, 1},
[VCAP_IS1_HK_IP4_L3_OPTIONS] = { 62, 1},
[VCAP_IS1_HK_IP4_L3_DSCP] = { 63, 6},
[VCAP_IS1_HK_IP4_L3_IP4_DIP] = { 69, 32},
[VCAP_IS1_HK_IP4_L3_IP4_SIP] = {101, 32},
[VCAP_IS1_HK_IP4_L3_PROTO] = {133, 8},
[VCAP_IS1_HK_IP4_TCP_UDP] = {141, 1},
[VCAP_IS1_HK_IP4_TCP] = {142, 1},
[VCAP_IS1_HK_IP4_L4_RNG] = {143, 8},
[VCAP_IS1_HK_IP4_IP_PAYLOAD_S1_5TUPLE] = {151, 32},
};
static const struct vcap_field vsc9959_vcap_is1_actions[] = {
[VCAP_IS1_ACT_DSCP_ENA] = { 0, 1},
[VCAP_IS1_ACT_DSCP_VAL] = { 1, 6},
[VCAP_IS1_ACT_QOS_ENA] = { 7, 1},
[VCAP_IS1_ACT_QOS_VAL] = { 8, 3},
[VCAP_IS1_ACT_DP_ENA] = { 11, 1},
[VCAP_IS1_ACT_DP_VAL] = { 12, 1},
[VCAP_IS1_ACT_PAG_OVERRIDE_MASK] = { 13, 8},
[VCAP_IS1_ACT_PAG_VAL] = { 21, 8},
[VCAP_IS1_ACT_RSV] = { 29, 9},
[VCAP_IS1_ACT_VID_REPLACE_ENA] = { 38, 1},
[VCAP_IS1_ACT_VID_ADD_VAL] = { 39, 12},
[VCAP_IS1_ACT_FID_SEL] = { 51, 2},
[VCAP_IS1_ACT_FID_VAL] = { 53, 13},
[VCAP_IS1_ACT_PCP_DEI_ENA] = { 66, 1},
[VCAP_IS1_ACT_PCP_VAL] = { 67, 3},
[VCAP_IS1_ACT_DEI_VAL] = { 70, 1},
[VCAP_IS1_ACT_VLAN_POP_CNT_ENA] = { 71, 1},
[VCAP_IS1_ACT_VLAN_POP_CNT] = { 72, 2},
[VCAP_IS1_ACT_CUSTOM_ACE_TYPE_ENA] = { 74, 4},
[VCAP_IS1_ACT_HIT_STICKY] = { 78, 1},
};
static struct vcap_field vsc9959_vcap_is2_keys[] = {
/* Common: 41 bits */
[VCAP_IS2_TYPE] = { 0, 4},
......@@ -694,15 +822,32 @@ 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 = {
[ES0_ACTION_TYPE_NORMAL] = {
.width = 72, /* HIT_STICKY not included */
.count = 1,
},
},
.target = S0,
.keys = vsc9959_vcap_es0_keys,
.actions = vsc9959_vcap_es0_actions,
},
[VCAP_IS1] = {
.action_type_width = 0,
.action_table = {
[IS1_ACTION_TYPE_NORMAL] = {
.width = 78, /* HIT_STICKY not included */
.count = 4,
},
},
.target = S1,
.keys = vsc9959_vcap_is1_keys,
.actions = vsc9959_vcap_is1_actions,
},
[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] = {
......@@ -714,8 +859,9 @@ 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,
},
};
......@@ -1184,8 +1330,6 @@ static const struct felix_info felix_info_vsc9959 = {
.ops = &vsc9959_ops,
.stats_layout = vsc9959_stats_layout,
.num_stats = ARRAY_SIZE(vsc9959_stats_layout),
.vcap_is2_keys = vsc9959_vcap_is2_keys,
.vcap_is2_actions = vsc9959_vcap_is2_actions,
.vcap = vsc9959_vcap_props,
.shared_queue_sz = 128 * 1024,
.num_mact_rows = 2048,
......
......@@ -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
......@@ -140,14 +136,27 @@ static const u32 vsc9953_qs_regmap[] = {
REG_RESERVED(QS_INH_DBG),
};
static const u32 vsc9953_s2_regmap[] = {
REG(S2_CORE_UPDATE_CTRL, 0x000000),
REG(S2_CORE_MV_CFG, 0x000004),
REG(S2_CACHE_ENTRY_DAT, 0x000008),
REG(S2_CACHE_MASK_DAT, 0x000108),
REG(S2_CACHE_ACTION_DAT, 0x000208),
REG(S2_CACHE_CNT_DAT, 0x000308),
REG(S2_CACHE_TG_DAT, 0x000388),
static const u32 vsc9953_vcap_regmap[] = {
/* VCAP_CORE_CFG */
REG(VCAP_CORE_UPDATE_CTRL, 0x000000),
REG(VCAP_CORE_MV_CFG, 0x000004),
/* VCAP_CORE_CACHE */
REG(VCAP_CACHE_ENTRY_DAT, 0x000008),
REG(VCAP_CACHE_MASK_DAT, 0x000108),
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[] = {
......@@ -352,7 +361,9 @@ static const u32 *vsc9953_regmap[TARGET_MAX] = {
[QSYS] = vsc9953_qsys_regmap,
[REW] = vsc9953_rew_regmap,
[SYS] = vsc9953_sys_regmap,
[S2] = vsc9953_s2_regmap,
[S0] = vsc9953_vcap_regmap,
[S1] = vsc9953_vcap_regmap,
[S2] = vsc9953_vcap_regmap,
[GCB] = vsc9953_gcb_regmap,
[DEV_GMII] = vsc9953_dev_gmii_regmap,
};
......@@ -384,6 +395,16 @@ static const struct resource vsc9953_target_io_res[TARGET_MAX] = {
.end = 0x001ffff,
.name = "sys",
},
[S0] = {
.start = 0x0040000,
.end = 0x00403ff,
.name = "s0",
},
[S1] = {
.start = 0x0050000,
.end = 0x00503ff,
.name = "s1",
},
[S2] = {
.start = 0x0060000,
.end = 0x00603ff,
......@@ -599,6 +620,112 @@ static const struct ocelot_stat_layout vsc9953_stats_layout[] = {
{ .offset = 0x91, .name = "drop_green_prio_7", },
};
static const struct vcap_field vsc9953_vcap_es0_keys[] = {
[VCAP_ES0_EGR_PORT] = { 0, 4},
[VCAP_ES0_IGR_PORT] = { 4, 4},
[VCAP_ES0_RSV] = { 8, 2},
[VCAP_ES0_L2_MC] = { 10, 1},
[VCAP_ES0_L2_BC] = { 11, 1},
[VCAP_ES0_VID] = { 12, 12},
[VCAP_ES0_DP] = { 24, 1},
[VCAP_ES0_PCP] = { 25, 3},
};
static const struct vcap_field vsc9953_vcap_es0_actions[] = {
[VCAP_ES0_ACT_PUSH_OUTER_TAG] = { 0, 2},
[VCAP_ES0_ACT_PUSH_INNER_TAG] = { 2, 1},
[VCAP_ES0_ACT_TAG_A_TPID_SEL] = { 3, 2},
[VCAP_ES0_ACT_TAG_A_VID_SEL] = { 5, 1},
[VCAP_ES0_ACT_TAG_A_PCP_SEL] = { 6, 2},
[VCAP_ES0_ACT_TAG_A_DEI_SEL] = { 8, 2},
[VCAP_ES0_ACT_TAG_B_TPID_SEL] = { 10, 2},
[VCAP_ES0_ACT_TAG_B_VID_SEL] = { 12, 1},
[VCAP_ES0_ACT_TAG_B_PCP_SEL] = { 13, 2},
[VCAP_ES0_ACT_TAG_B_DEI_SEL] = { 15, 2},
[VCAP_ES0_ACT_VID_A_VAL] = { 17, 12},
[VCAP_ES0_ACT_PCP_A_VAL] = { 29, 3},
[VCAP_ES0_ACT_DEI_A_VAL] = { 32, 1},
[VCAP_ES0_ACT_VID_B_VAL] = { 33, 12},
[VCAP_ES0_ACT_PCP_B_VAL] = { 45, 3},
[VCAP_ES0_ACT_DEI_B_VAL] = { 48, 1},
[VCAP_ES0_ACT_RSV] = { 49, 24},
[VCAP_ES0_ACT_HIT_STICKY] = { 73, 1},
};
static const struct vcap_field vsc9953_vcap_is1_keys[] = {
[VCAP_IS1_HK_TYPE] = { 0, 1},
[VCAP_IS1_HK_LOOKUP] = { 1, 2},
[VCAP_IS1_HK_IGR_PORT_MASK] = { 3, 11},
[VCAP_IS1_HK_RSV] = { 14, 10},
/* VCAP_IS1_HK_OAM_Y1731 not supported */
[VCAP_IS1_HK_L2_MC] = { 24, 1},
[VCAP_IS1_HK_L2_BC] = { 25, 1},
[VCAP_IS1_HK_IP_MC] = { 26, 1},
[VCAP_IS1_HK_VLAN_TAGGED] = { 27, 1},
[VCAP_IS1_HK_VLAN_DBL_TAGGED] = { 28, 1},
[VCAP_IS1_HK_TPID] = { 29, 1},
[VCAP_IS1_HK_VID] = { 30, 12},
[VCAP_IS1_HK_DEI] = { 42, 1},
[VCAP_IS1_HK_PCP] = { 43, 3},
/* Specific Fields for IS1 Half Key S1_NORMAL */
[VCAP_IS1_HK_L2_SMAC] = { 46, 48},
[VCAP_IS1_HK_ETYPE_LEN] = { 94, 1},
[VCAP_IS1_HK_ETYPE] = { 95, 16},
[VCAP_IS1_HK_IP_SNAP] = {111, 1},
[VCAP_IS1_HK_IP4] = {112, 1},
/* Layer-3 Information */
[VCAP_IS1_HK_L3_FRAGMENT] = {113, 1},
[VCAP_IS1_HK_L3_FRAG_OFS_GT0] = {114, 1},
[VCAP_IS1_HK_L3_OPTIONS] = {115, 1},
[VCAP_IS1_HK_L3_DSCP] = {116, 6},
[VCAP_IS1_HK_L3_IP4_SIP] = {122, 32},
/* Layer-4 Information */
[VCAP_IS1_HK_TCP_UDP] = {154, 1},
[VCAP_IS1_HK_TCP] = {155, 1},
[VCAP_IS1_HK_L4_SPORT] = {156, 16},
[VCAP_IS1_HK_L4_RNG] = {172, 8},
/* Specific Fields for IS1 Half Key S1_5TUPLE_IP4 */
[VCAP_IS1_HK_IP4_INNER_TPID] = { 46, 1},
[VCAP_IS1_HK_IP4_INNER_VID] = { 47, 12},
[VCAP_IS1_HK_IP4_INNER_DEI] = { 59, 1},
[VCAP_IS1_HK_IP4_INNER_PCP] = { 60, 3},
[VCAP_IS1_HK_IP4_IP4] = { 63, 1},
[VCAP_IS1_HK_IP4_L3_FRAGMENT] = { 64, 1},
[VCAP_IS1_HK_IP4_L3_FRAG_OFS_GT0] = { 65, 1},
[VCAP_IS1_HK_IP4_L3_OPTIONS] = { 66, 1},
[VCAP_IS1_HK_IP4_L3_DSCP] = { 67, 6},
[VCAP_IS1_HK_IP4_L3_IP4_DIP] = { 73, 32},
[VCAP_IS1_HK_IP4_L3_IP4_SIP] = {105, 32},
[VCAP_IS1_HK_IP4_L3_PROTO] = {137, 8},
[VCAP_IS1_HK_IP4_TCP_UDP] = {145, 1},
[VCAP_IS1_HK_IP4_TCP] = {146, 1},
[VCAP_IS1_HK_IP4_L4_RNG] = {147, 8},
[VCAP_IS1_HK_IP4_IP_PAYLOAD_S1_5TUPLE] = {155, 32},
};
static const struct vcap_field vsc9953_vcap_is1_actions[] = {
[VCAP_IS1_ACT_DSCP_ENA] = { 0, 1},
[VCAP_IS1_ACT_DSCP_VAL] = { 1, 6},
[VCAP_IS1_ACT_QOS_ENA] = { 7, 1},
[VCAP_IS1_ACT_QOS_VAL] = { 8, 3},
[VCAP_IS1_ACT_DP_ENA] = { 11, 1},
[VCAP_IS1_ACT_DP_VAL] = { 12, 1},
[VCAP_IS1_ACT_PAG_OVERRIDE_MASK] = { 13, 8},
[VCAP_IS1_ACT_PAG_VAL] = { 21, 8},
[VCAP_IS1_ACT_RSV] = { 29, 11},
[VCAP_IS1_ACT_VID_REPLACE_ENA] = { 40, 1},
[VCAP_IS1_ACT_VID_ADD_VAL] = { 41, 12},
[VCAP_IS1_ACT_FID_SEL] = { 53, 2},
[VCAP_IS1_ACT_FID_VAL] = { 55, 13},
[VCAP_IS1_ACT_PCP_DEI_ENA] = { 68, 1},
[VCAP_IS1_ACT_PCP_VAL] = { 69, 3},
[VCAP_IS1_ACT_DEI_VAL] = { 72, 1},
[VCAP_IS1_ACT_VLAN_POP_CNT_ENA] = { 73, 1},
[VCAP_IS1_ACT_VLAN_POP_CNT] = { 74, 2},
[VCAP_IS1_ACT_CUSTOM_ACE_TYPE_ENA] = { 76, 4},
[VCAP_IS1_ACT_HIT_STICKY] = { 80, 1},
};
static struct vcap_field vsc9953_vcap_is2_keys[] = {
/* Common: 41 bits */
[VCAP_IS2_TYPE] = { 0, 4},
......@@ -684,15 +811,32 @@ 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 = {
[ES0_ACTION_TYPE_NORMAL] = {
.width = 73, /* HIT_STICKY not included */
.count = 1,
},
},
.target = S0,
.keys = vsc9953_vcap_es0_keys,
.actions = vsc9953_vcap_es0_actions,
},
[VCAP_IS1] = {
.action_type_width = 0,
.action_table = {
[IS1_ACTION_TYPE_NORMAL] = {
.width = 80, /* HIT_STICKY not included */
.count = 4,
},
},
.target = S1,
.keys = vsc9953_vcap_is1_keys,
.actions = vsc9953_vcap_is1_actions,
},
[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] = {
......@@ -704,8 +848,9 @@ 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,
},
};
......@@ -1031,8 +1176,6 @@ static const struct felix_info seville_info_vsc9953 = {
.ops = &vsc9953_ops,
.stats_layout = vsc9953_stats_layout,
.num_stats = ARRAY_SIZE(vsc9953_stats_layout),
.vcap_is2_keys = vsc9953_vcap_is2_keys,
.vcap_is2_actions = vsc9953_vcap_is2_actions,
.vcap = vsc9953_vcap_props,
.shared_queue_sz = 2048 * 1024,
.num_mact_rows = 2048,
......
......@@ -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"
......
......@@ -44,8 +44,8 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f,
return 0;
}
static int ocelot_flower_parse(struct flow_cls_offload *f,
struct ocelot_vcap_filter *filter)
static int ocelot_flower_parse_key(struct flow_cls_offload *f,
struct ocelot_vcap_filter *filter)
{
struct flow_rule *rule = flow_cls_offload_flow_rule(f);
struct flow_dissector *dissector = rule->match.dissector;
......@@ -179,9 +179,22 @@ static int ocelot_flower_parse(struct flow_cls_offload *f,
}
/* else, a filter of type OCELOT_VCAP_KEY_ANY is implicitly added */
return 0;
}
static int ocelot_flower_parse(struct flow_cls_offload *f,
struct ocelot_vcap_filter *filter)
{
int ret;
filter->prio = f->common.prio;
filter->id = f->cookie;
return ocelot_flower_parse_action(f, filter);
ret = ocelot_flower_parse_action(f, filter);
if (ret)
return ret;
return ocelot_flower_parse_key(f, filter);
}
static struct ocelot_vcap_filter
......@@ -221,28 +234,33 @@ EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
struct flow_cls_offload *f, bool ingress)
{
struct ocelot_vcap_filter filter;
struct ocelot_vcap_block *block = &ocelot->block;
struct ocelot_vcap_filter *filter;
filter.prio = f->common.prio;
filter.id = f->cookie;
filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie);
if (!filter)
return 0;
return ocelot_vcap_filter_del(ocelot, &filter);
return ocelot_vcap_filter_del(ocelot, filter);
}
EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy);
int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
struct flow_cls_offload *f, bool ingress)
{
struct ocelot_vcap_filter filter;
struct ocelot_vcap_block *block = &ocelot->block;
struct ocelot_vcap_filter *filter;
int ret;
filter.prio = f->common.prio;
filter.id = f->cookie;
ret = ocelot_vcap_filter_stats_update(ocelot, &filter);
filter = ocelot_vcap_block_find_filter_by_id(block, f->cookie);
if (!filter)
return 0;
ret = ocelot_vcap_filter_stats_update(ocelot, filter);
if (ret)
return ret;
flow_stats_update(&f->stats, 0x0, filter.stats.pkts, 0, 0x0,
flow_stats_update(&f->stats, 0x0, filter->stats.pkts, 0, 0x0,
FLOW_ACTION_HW_STATS_IMMEDIATE);
return 0;
}
......
......@@ -71,6 +71,23 @@ void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg)
}
EXPORT_SYMBOL(ocelot_port_writel);
u32 __ocelot_target_read_ix(struct ocelot *ocelot, enum ocelot_target target,
u32 reg, u32 offset)
{
u32 val;
regmap_read(ocelot->targets[target],
ocelot->map[target][reg] + offset, &val);
return val;
}
void __ocelot_target_write_ix(struct ocelot *ocelot, enum ocelot_target target,
u32 val, u32 reg, u32 offset)
{
regmap_write(ocelot->targets[target],
ocelot->map[target][reg] + offset, val);
}
int ocelot_regfields_init(struct ocelot *ocelot,
const struct reg_field *const regfields)
{
......
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
/* Microsemi Ocelot Switch driver
* Copyright (c) 2018 Microsemi Corporation
*/
#ifndef _OCELOT_S2_CORE_H_
#define _OCELOT_S2_CORE_H_
#define S2_CORE_UPDATE_CTRL_UPDATE_CMD(x) (((x) << 22) & GENMASK(24, 22))
#define S2_CORE_UPDATE_CTRL_UPDATE_CMD_M GENMASK(24, 22)
#define S2_CORE_UPDATE_CTRL_UPDATE_CMD_X(x) (((x) & GENMASK(24, 22)) >> 22)
#define S2_CORE_UPDATE_CTRL_UPDATE_ENTRY_DIS BIT(21)
#define S2_CORE_UPDATE_CTRL_UPDATE_ACTION_DIS BIT(20)
#define S2_CORE_UPDATE_CTRL_UPDATE_CNT_DIS BIT(19)
#define S2_CORE_UPDATE_CTRL_UPDATE_ADDR(x) (((x) << 3) & GENMASK(18, 3))
#define S2_CORE_UPDATE_CTRL_UPDATE_ADDR_M GENMASK(18, 3)
#define S2_CORE_UPDATE_CTRL_UPDATE_ADDR_X(x) (((x) & GENMASK(18, 3)) >> 3)
#define S2_CORE_UPDATE_CTRL_UPDATE_SHOT BIT(2)
#define S2_CORE_UPDATE_CTRL_CLEAR_CACHE BIT(1)
#define S2_CORE_UPDATE_CTRL_MV_TRAFFIC_IGN BIT(0)
#define S2_CORE_MV_CFG_MV_NUM_POS(x) (((x) << 16) & GENMASK(31, 16))
#define S2_CORE_MV_CFG_MV_NUM_POS_M GENMASK(31, 16)
#define S2_CORE_MV_CFG_MV_NUM_POS_X(x) (((x) & GENMASK(31, 16)) >> 16)
#define S2_CORE_MV_CFG_MV_SIZE(x) ((x) & GENMASK(15, 0))
#define S2_CORE_MV_CFG_MV_SIZE_M GENMASK(15, 0)
#define S2_CACHE_ENTRY_DAT_RSZ 0x4
#define S2_CACHE_MASK_DAT_RSZ 0x4
#define S2_CACHE_ACTION_DAT_RSZ 0x4
#define S2_CACHE_CNT_DAT_RSZ 0x4
#define S2_STICKY_VCAP_ROW_DELETED_STICKY BIT(0)
#define S2_BIST_CTRL_TCAM_BIST BIT(1)
#define S2_BIST_CTRL_TCAM_INIT BIT(0)
#define S2_BIST_CFG_TCAM_BIST_SOE_ENA BIT(8)
#define S2_BIST_CFG_TCAM_HCG_DIS BIT(7)
#define S2_BIST_CFG_TCAM_CG_DIS BIT(6)
#define S2_BIST_CFG_TCAM_BIAS(x) ((x) & GENMASK(5, 0))
#define S2_BIST_CFG_TCAM_BIAS_M GENMASK(5, 0)
#define S2_BIST_STAT_BIST_RT_ERR BIT(15)
#define S2_BIST_STAT_BIST_PENC_ERR BIT(14)
#define S2_BIST_STAT_BIST_COMP_ERR BIT(13)
#define S2_BIST_STAT_BIST_ADDR_ERR BIT(12)
#define S2_BIST_STAT_BIST_BL1E_ERR BIT(11)
#define S2_BIST_STAT_BIST_BL1_ERR BIT(10)
#define S2_BIST_STAT_BIST_BL0E_ERR BIT(9)
#define S2_BIST_STAT_BIST_BL0_ERR BIT(8)
#define S2_BIST_STAT_BIST_PH1_ERR BIT(7)
#define S2_BIST_STAT_BIST_PH0_ERR BIT(6)
#define S2_BIST_STAT_BIST_PV1_ERR BIT(5)
#define S2_BIST_STAT_BIST_PV0_ERR BIT(4)
#define S2_BIST_STAT_BIST_RUN BIT(3)
#define S2_BIST_STAT_BIST_ERR BIT(2)
#define S2_BIST_STAT_BIST_BUSY BIT(1)
#define S2_BIST_STAT_TCAM_RDY BIT(0)
#endif /* _OCELOT_S2_CORE_H_ */
......@@ -9,7 +9,6 @@
#include <soc/mscc/ocelot_vcap.h>
#include "ocelot_police.h"
#include "ocelot_vcap.h"
#include "ocelot_s2.h"
#define OCELOT_POLICER_DISCARD 0x17f
#define ENTRY_WIDTH 32
......@@ -48,145 +47,174 @@ struct vcap_data {
u32 tg_mask; /* Current type-group mask */
};
static u32 vcap_s2_read_update_ctrl(struct ocelot *ocelot)
static u32 vcap_read_update_ctrl(struct ocelot *ocelot,
const struct vcap_props *vcap)
{
return ocelot_read(ocelot, S2_CORE_UPDATE_CTRL);
return ocelot_target_read(ocelot, vcap->target, VCAP_CORE_UPDATE_CTRL);
}
static void vcap_cmd(struct ocelot *ocelot, u16 ix, int cmd, int sel)
static void vcap_cmd(struct ocelot *ocelot, const struct vcap_props *vcap,
u16 ix, int cmd, int sel)
{
const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
u32 value = (VCAP_CORE_UPDATE_CTRL_UPDATE_CMD(cmd) |
VCAP_CORE_UPDATE_CTRL_UPDATE_ADDR(ix) |
VCAP_CORE_UPDATE_CTRL_UPDATE_SHOT);
u32 value = (S2_CORE_UPDATE_CTRL_UPDATE_CMD(cmd) |
S2_CORE_UPDATE_CTRL_UPDATE_ADDR(ix) |
S2_CORE_UPDATE_CTRL_UPDATE_SHOT);
if ((sel & VCAP_SEL_ENTRY) && ix >= vcap_is2->entry_count)
if ((sel & VCAP_SEL_ENTRY) && ix >= vcap->entry_count)
return;
if (!(sel & VCAP_SEL_ENTRY))
value |= S2_CORE_UPDATE_CTRL_UPDATE_ENTRY_DIS;
value |= VCAP_CORE_UPDATE_CTRL_UPDATE_ENTRY_DIS;
if (!(sel & VCAP_SEL_ACTION))
value |= S2_CORE_UPDATE_CTRL_UPDATE_ACTION_DIS;
value |= VCAP_CORE_UPDATE_CTRL_UPDATE_ACTION_DIS;
if (!(sel & VCAP_SEL_COUNTER))
value |= S2_CORE_UPDATE_CTRL_UPDATE_CNT_DIS;
value |= VCAP_CORE_UPDATE_CTRL_UPDATE_CNT_DIS;
ocelot_target_write(ocelot, vcap->target, value, VCAP_CORE_UPDATE_CTRL);
ocelot_write(ocelot, value, S2_CORE_UPDATE_CTRL);
readx_poll_timeout(vcap_s2_read_update_ctrl, ocelot, value,
(value & S2_CORE_UPDATE_CTRL_UPDATE_SHOT) == 0,
10, 100000);
read_poll_timeout(vcap_read_update_ctrl, value,
(value & VCAP_CORE_UPDATE_CTRL_UPDATE_SHOT) == 0,
10, 100000, false, ocelot, vcap);
}
/* Convert from 0-based row to VCAP entry row and run command */
static void vcap_row_cmd(struct ocelot *ocelot, u32 row, int cmd, int sel)
static void vcap_row_cmd(struct ocelot *ocelot, const struct vcap_props *vcap,
u32 row, int cmd, int sel)
{
const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
vcap_cmd(ocelot, vcap_is2->entry_count - row - 1, cmd, sel);
vcap_cmd(ocelot, vcap, vcap->entry_count - row - 1, cmd, sel);
}
static void vcap_entry2cache(struct ocelot *ocelot, struct vcap_data *data)
static void vcap_entry2cache(struct ocelot *ocelot,
const struct vcap_props *vcap,
struct vcap_data *data)
{
const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
u32 entry_words, i;
entry_words = DIV_ROUND_UP(vcap_is2->entry_width, ENTRY_WIDTH);
entry_words = DIV_ROUND_UP(vcap->entry_width, ENTRY_WIDTH);
for (i = 0; i < entry_words; i++) {
ocelot_write_rix(ocelot, data->entry[i], S2_CACHE_ENTRY_DAT, i);
ocelot_write_rix(ocelot, ~data->mask[i], S2_CACHE_MASK_DAT, i);
ocelot_target_write_rix(ocelot, vcap->target, data->entry[i],
VCAP_CACHE_ENTRY_DAT, i);
ocelot_target_write_rix(ocelot, vcap->target, ~data->mask[i],
VCAP_CACHE_MASK_DAT, i);
}
ocelot_write(ocelot, data->tg, S2_CACHE_TG_DAT);
ocelot_target_write(ocelot, vcap->target, data->tg, VCAP_CACHE_TG_DAT);
}
static void vcap_cache2entry(struct ocelot *ocelot, struct vcap_data *data)
static void vcap_cache2entry(struct ocelot *ocelot,
const struct vcap_props *vcap,
struct vcap_data *data)
{
const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
u32 entry_words, i;
entry_words = DIV_ROUND_UP(vcap_is2->entry_width, ENTRY_WIDTH);
entry_words = DIV_ROUND_UP(vcap->entry_width, ENTRY_WIDTH);
for (i = 0; i < entry_words; i++) {
data->entry[i] = ocelot_read_rix(ocelot, S2_CACHE_ENTRY_DAT, i);
data->entry[i] = ocelot_target_read_rix(ocelot, vcap->target,
VCAP_CACHE_ENTRY_DAT, i);
// Invert mask
data->mask[i] = ~ocelot_read_rix(ocelot, S2_CACHE_MASK_DAT, i);
data->mask[i] = ~ocelot_target_read_rix(ocelot, vcap->target,
VCAP_CACHE_MASK_DAT, i);
}
data->tg = ocelot_read(ocelot, S2_CACHE_TG_DAT);
data->tg = ocelot_target_read(ocelot, vcap->target, VCAP_CACHE_TG_DAT);
}
static void vcap_action2cache(struct ocelot *ocelot, struct vcap_data *data)
static void vcap_action2cache(struct ocelot *ocelot,
const struct vcap_props *vcap,
struct vcap_data *data)
{
const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
u32 action_words, mask;
int i, width;
/* Encode action type */
width = vcap_is2->action_type_width;
width = vcap->action_type_width;
if (width) {
mask = GENMASK(width, 0);
data->action[0] = ((data->action[0] & ~mask) | data->type);
}
action_words = DIV_ROUND_UP(vcap_is2->action_width, ENTRY_WIDTH);
action_words = DIV_ROUND_UP(vcap->action_width, ENTRY_WIDTH);
for (i = 0; i < action_words; i++)
ocelot_write_rix(ocelot, data->action[i], S2_CACHE_ACTION_DAT,
i);
ocelot_target_write_rix(ocelot, vcap->target, data->action[i],
VCAP_CACHE_ACTION_DAT, i);
for (i = 0; i < vcap_is2->counter_words; i++)
ocelot_write_rix(ocelot, data->counter[i], S2_CACHE_CNT_DAT, i);
for (i = 0; i < vcap->counter_words; i++)
ocelot_target_write_rix(ocelot, vcap->target, data->counter[i],
VCAP_CACHE_CNT_DAT, i);
}
static void vcap_cache2action(struct ocelot *ocelot, struct vcap_data *data)
static void vcap_cache2action(struct ocelot *ocelot,
const struct vcap_props *vcap,
struct vcap_data *data)
{
const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
u32 action_words;
int i, width;
action_words = DIV_ROUND_UP(vcap_is2->action_width, ENTRY_WIDTH);
action_words = DIV_ROUND_UP(vcap->action_width, ENTRY_WIDTH);
for (i = 0; i < action_words; i++)
data->action[i] = ocelot_read_rix(ocelot, S2_CACHE_ACTION_DAT,
i);
data->action[i] = ocelot_target_read_rix(ocelot, vcap->target,
VCAP_CACHE_ACTION_DAT,
i);
for (i = 0; i < vcap_is2->counter_words; i++)
data->counter[i] = ocelot_read_rix(ocelot, S2_CACHE_CNT_DAT, i);
for (i = 0; i < vcap->counter_words; i++)
data->counter[i] = ocelot_target_read_rix(ocelot, vcap->target,
VCAP_CACHE_CNT_DAT,
i);
/* Extract action type */
width = vcap_is2->action_type_width;
width = vcap->action_type_width;
data->type = (width ? (data->action[0] & GENMASK(width, 0)) : 0);
}
/* Calculate offsets for entry */
static void is2_data_get(struct ocelot *ocelot, struct vcap_data *data, int ix)
static void vcap_data_offset_get(const struct vcap_props *vcap,
struct vcap_data *data, int ix)
{
const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
int i, col, offset, count, cnt, base;
int width = vcap_is2->tg_width;
int num_subwords_per_entry, num_subwords_per_action;
int i, col, offset, num_entries_per_row, base;
u32 width = vcap->tg_width;
count = (data->tg_sw == VCAP_TG_HALF ? 2 : 4);
col = (ix % 2);
cnt = (vcap_is2->sw_count / count);
base = (vcap_is2->sw_count - col * cnt - cnt);
switch (data->tg_sw) {
case VCAP_TG_FULL:
num_entries_per_row = 1;
break;
case VCAP_TG_HALF:
num_entries_per_row = 2;
break;
case VCAP_TG_QUARTER:
num_entries_per_row = 4;
break;
default:
return;
}
col = (ix % num_entries_per_row);
num_subwords_per_entry = (vcap->sw_count / num_entries_per_row);
base = (vcap->sw_count - col * num_subwords_per_entry -
num_subwords_per_entry);
data->tg_value = 0;
data->tg_mask = 0;
for (i = 0; i < cnt; i++) {
for (i = 0; i < num_subwords_per_entry; i++) {
offset = ((base + i) * width);
data->tg_value |= (data->tg_sw << offset);
data->tg_mask |= GENMASK(offset + width - 1, offset);
}
/* Calculate key/action/counter offsets */
col = (count - col - 1);
data->key_offset = (base * vcap_is2->entry_width) / vcap_is2->sw_count;
data->counter_offset = (cnt * col * vcap_is2->counter_width);
col = (num_entries_per_row - col - 1);
data->key_offset = (base * vcap->entry_width) / vcap->sw_count;
data->counter_offset = (num_subwords_per_entry * col *
vcap->counter_width);
i = data->type;
width = vcap_is2->action_table[i].width;
cnt = vcap_is2->action_table[i].count;
data->action_offset =
(((cnt * col * width) / count) + vcap_is2->action_type_width);
width = vcap->action_table[i].width;
num_subwords_per_action = vcap->action_table[i].count;
data->action_offset = ((num_subwords_per_action * col * width) /
num_entries_per_row);
data->action_offset += vcap->action_type_width;
}
static void vcap_data_set(u32 *data, u32 offset, u32 len, u32 value)
......@@ -224,22 +252,21 @@ static void vcap_key_field_set(struct vcap_data *data, u32 offset, u32 width,
vcap_data_set(data->mask, offset + data->key_offset, width, mask);
}
static void vcap_key_set(struct ocelot *ocelot, struct vcap_data *data,
enum vcap_is2_half_key_field field,
u32 value, u32 mask)
static void vcap_key_set(const struct vcap_props *vcap, struct vcap_data *data,
int field, u32 value, u32 mask)
{
u32 offset = ocelot->vcap_is2_keys[field].offset;
u32 length = ocelot->vcap_is2_keys[field].length;
u32 offset = vcap->keys[field].offset;
u32 length = vcap->keys[field].length;
vcap_key_field_set(data, offset, length, value, mask);
}
static void vcap_key_bytes_set(struct ocelot *ocelot, struct vcap_data *data,
enum vcap_is2_half_key_field field,
static void vcap_key_bytes_set(const struct vcap_props *vcap,
struct vcap_data *data, int field,
u8 *val, u8 *msk)
{
u32 offset = ocelot->vcap_is2_keys[field].offset;
u32 count = ocelot->vcap_is2_keys[field].length;
u32 offset = vcap->keys[field].offset;
u32 count = vcap->keys[field].length;
u32 i, j, n = 0, value = 0, mask = 0;
WARN_ON(count % 8);
......@@ -265,37 +292,37 @@ static void vcap_key_bytes_set(struct ocelot *ocelot, struct vcap_data *data,
}
}
static void vcap_key_l4_port_set(struct ocelot *ocelot, struct vcap_data *data,
enum vcap_is2_half_key_field field,
static void vcap_key_l4_port_set(const struct vcap_props *vcap,
struct vcap_data *data, int field,
struct ocelot_vcap_udp_tcp *port)
{
u32 offset = ocelot->vcap_is2_keys[field].offset;
u32 length = ocelot->vcap_is2_keys[field].length;
u32 offset = vcap->keys[field].offset;
u32 length = vcap->keys[field].length;
WARN_ON(length != 16);
vcap_key_field_set(data, offset, length, port->value, port->mask);
}
static void vcap_key_bit_set(struct ocelot *ocelot, struct vcap_data *data,
enum vcap_is2_half_key_field field,
static void vcap_key_bit_set(const struct vcap_props *vcap,
struct vcap_data *data, int field,
enum ocelot_vcap_bit val)
{
u32 offset = ocelot->vcap_is2_keys[field].offset;
u32 length = ocelot->vcap_is2_keys[field].length;
u32 value = (val == OCELOT_VCAP_BIT_1 ? 1 : 0);
u32 msk = (val == OCELOT_VCAP_BIT_ANY ? 0 : 1);
u32 offset = vcap->keys[field].offset;
u32 length = vcap->keys[field].length;
WARN_ON(length != 1);
vcap_key_field_set(data, offset, length, value, msk);
}
static void vcap_action_set(struct ocelot *ocelot, struct vcap_data *data,
enum vcap_is2_action_field field, u32 value)
static void vcap_action_set(const struct vcap_props *vcap,
struct vcap_data *data, int field, u32 value)
{
int offset = ocelot->vcap_is2_actions[field].offset;
int length = ocelot->vcap_is2_actions[field].length;
int offset = vcap->actions[field].offset;
int length = vcap->actions[field].length;
vcap_data_set(data->action, offset + data->action_offset, length,
value);
......@@ -304,32 +331,34 @@ static void vcap_action_set(struct ocelot *ocelot, struct vcap_data *data,
static void is2_action_set(struct ocelot *ocelot, struct vcap_data *data,
struct ocelot_vcap_filter *filter)
{
const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS2];
switch (filter->action) {
case OCELOT_VCAP_ACTION_DROP:
vcap_action_set(ocelot, data, VCAP_IS2_ACT_PORT_MASK, 0);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_MASK_MODE, 1);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_POLICE_ENA, 1);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_POLICE_IDX,
vcap_action_set(vcap, data, VCAP_IS2_ACT_PORT_MASK, 0);
vcap_action_set(vcap, data, VCAP_IS2_ACT_MASK_MODE, 1);
vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_ENA, 1);
vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_IDX,
OCELOT_POLICER_DISCARD);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_QU_NUM, 0);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_COPY_ENA, 0);
vcap_action_set(vcap, data, VCAP_IS2_ACT_CPU_QU_NUM, 0);
vcap_action_set(vcap, data, VCAP_IS2_ACT_CPU_COPY_ENA, 0);
break;
case OCELOT_VCAP_ACTION_TRAP:
vcap_action_set(ocelot, data, VCAP_IS2_ACT_PORT_MASK, 0);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_MASK_MODE, 1);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_POLICE_ENA, 0);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_POLICE_IDX, 0);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_QU_NUM, 0);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_COPY_ENA, 1);
vcap_action_set(vcap, data, VCAP_IS2_ACT_PORT_MASK, 0);
vcap_action_set(vcap, data, VCAP_IS2_ACT_MASK_MODE, 1);
vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_ENA, 0);
vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_IDX, 0);
vcap_action_set(vcap, data, VCAP_IS2_ACT_CPU_QU_NUM, 0);
vcap_action_set(vcap, data, VCAP_IS2_ACT_CPU_COPY_ENA, 1);
break;
case OCELOT_VCAP_ACTION_POLICE:
vcap_action_set(ocelot, data, VCAP_IS2_ACT_PORT_MASK, 0);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_MASK_MODE, 0);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_POLICE_ENA, 1);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_POLICE_IDX,
vcap_action_set(vcap, data, VCAP_IS2_ACT_PORT_MASK, 0);
vcap_action_set(vcap, data, VCAP_IS2_ACT_MASK_MODE, 0);
vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_ENA, 1);
vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_IDX,
filter->pol_ix);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_QU_NUM, 0);
vcap_action_set(ocelot, data, VCAP_IS2_ACT_CPU_COPY_ENA, 0);
vcap_action_set(vcap, data, VCAP_IS2_ACT_CPU_QU_NUM, 0);
vcap_action_set(vcap, data, VCAP_IS2_ACT_CPU_COPY_ENA, 0);
break;
}
}
......@@ -337,7 +366,7 @@ static void is2_action_set(struct ocelot *ocelot, struct vcap_data *data,
static void is2_entry_set(struct ocelot *ocelot, int ix,
struct ocelot_vcap_filter *filter)
{
const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS2];
struct ocelot_vcap_key_vlan *tag = &filter->vlan;
u32 val, msk, type, type_mask = 0xf, i, count;
struct ocelot_vcap_u64 payload;
......@@ -348,52 +377,52 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
memset(&data, 0, sizeof(data));
/* Read row */
vcap_row_cmd(ocelot, row, VCAP_CMD_READ, VCAP_SEL_ALL);
vcap_cache2entry(ocelot, &data);
vcap_cache2action(ocelot, &data);
vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_READ, VCAP_SEL_ALL);
vcap_cache2entry(ocelot, vcap, &data);
vcap_cache2action(ocelot, vcap, &data);
data.tg_sw = VCAP_TG_HALF;
is2_data_get(ocelot, &data, ix);
vcap_data_offset_get(vcap, &data, ix);
data.tg = (data.tg & ~data.tg_mask);
if (filter->prio != 0)
data.tg |= data.tg_value;
data.type = IS2_ACTION_TYPE_NORMAL;
vcap_key_set(ocelot, &data, VCAP_IS2_HK_PAG, 0, 0);
vcap_key_set(ocelot, &data, VCAP_IS2_HK_IGR_PORT_MASK, 0,
vcap_key_set(vcap, &data, VCAP_IS2_HK_PAG, 0, 0);
vcap_key_set(vcap, &data, VCAP_IS2_HK_IGR_PORT_MASK, 0,
~filter->ingress_port_mask);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_FIRST, OCELOT_VCAP_BIT_1);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_HOST_MATCH,
vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_FIRST, OCELOT_VCAP_BIT_ANY);
vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_HOST_MATCH,
OCELOT_VCAP_BIT_ANY);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L2_MC, filter->dmac_mc);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L2_BC, filter->dmac_bc);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_VLAN_TAGGED, tag->tagged);
vcap_key_set(ocelot, &data, VCAP_IS2_HK_VID,
vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L2_MC, filter->dmac_mc);
vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L2_BC, filter->dmac_bc);
vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_VLAN_TAGGED, tag->tagged);
vcap_key_set(vcap, &data, VCAP_IS2_HK_VID,
tag->vid.value, tag->vid.mask);
vcap_key_set(ocelot, &data, VCAP_IS2_HK_PCP,
vcap_key_set(vcap, &data, VCAP_IS2_HK_PCP,
tag->pcp.value[0], tag->pcp.mask[0]);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_DEI, tag->dei);
vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_DEI, tag->dei);
switch (filter->key_type) {
case OCELOT_VCAP_KEY_ETYPE: {
struct ocelot_vcap_key_etype *etype = &filter->key.etype;
type = IS2_TYPE_ETYPE;
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L2_DMAC,
vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L2_DMAC,
etype->dmac.value, etype->dmac.mask);
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L2_SMAC,
vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L2_SMAC,
etype->smac.value, etype->smac.mask);
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_MAC_ETYPE_ETYPE,
vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_MAC_ETYPE_ETYPE,
etype->etype.value, etype->etype.mask);
/* Clear unused bits */
vcap_key_set(ocelot, &data, VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD0,
vcap_key_set(vcap, &data, VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD0,
0, 0);
vcap_key_set(ocelot, &data, VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD1,
vcap_key_set(vcap, &data, VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD1,
0, 0);
vcap_key_set(ocelot, &data, VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD2,
vcap_key_set(vcap, &data, VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD2,
0, 0);
vcap_key_bytes_set(ocelot, &data,
vcap_key_bytes_set(vcap, &data,
VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD0,
etype->data.value, etype->data.mask);
break;
......@@ -402,15 +431,15 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
struct ocelot_vcap_key_llc *llc = &filter->key.llc;
type = IS2_TYPE_LLC;
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L2_DMAC,
vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L2_DMAC,
llc->dmac.value, llc->dmac.mask);
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L2_SMAC,
vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L2_SMAC,
llc->smac.value, llc->smac.mask);
for (i = 0; i < 4; i++) {
payload.value[i] = llc->llc.value[i];
payload.mask[i] = llc->llc.mask[i];
}
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_MAC_LLC_L2_LLC,
vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_MAC_LLC_L2_LLC,
payload.value, payload.mask);
break;
}
......@@ -418,11 +447,11 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
struct ocelot_vcap_key_snap *snap = &filter->key.snap;
type = IS2_TYPE_SNAP;
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L2_DMAC,
vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L2_DMAC,
snap->dmac.value, snap->dmac.mask);
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L2_SMAC,
vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L2_SMAC,
snap->smac.value, snap->smac.mask);
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_MAC_SNAP_L2_SNAP,
vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_MAC_SNAP_L2_SNAP,
filter->key.snap.snap.value,
filter->key.snap.snap.mask);
break;
......@@ -431,24 +460,24 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
struct ocelot_vcap_key_arp *arp = &filter->key.arp;
type = IS2_TYPE_ARP;
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_MAC_ARP_SMAC,
vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_MAC_ARP_SMAC,
arp->smac.value, arp->smac.mask);
vcap_key_bit_set(ocelot, &data,
vcap_key_bit_set(vcap, &data,
VCAP_IS2_HK_MAC_ARP_ADDR_SPACE_OK,
arp->ethernet);
vcap_key_bit_set(ocelot, &data,
vcap_key_bit_set(vcap, &data,
VCAP_IS2_HK_MAC_ARP_PROTO_SPACE_OK,
arp->ip);
vcap_key_bit_set(ocelot, &data,
vcap_key_bit_set(vcap, &data,
VCAP_IS2_HK_MAC_ARP_LEN_OK,
arp->length);
vcap_key_bit_set(ocelot, &data,
vcap_key_bit_set(vcap, &data,
VCAP_IS2_HK_MAC_ARP_TARGET_MATCH,
arp->dmac_match);
vcap_key_bit_set(ocelot, &data,
vcap_key_bit_set(vcap, &data,
VCAP_IS2_HK_MAC_ARP_SENDER_MATCH,
arp->smac_match);
vcap_key_bit_set(ocelot, &data,
vcap_key_bit_set(vcap, &data,
VCAP_IS2_HK_MAC_ARP_OPCODE_UNKNOWN,
arp->unknown);
......@@ -457,15 +486,15 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
(arp->arp == OCELOT_VCAP_BIT_0 ? 2 : 0));
msk = ((arp->req == OCELOT_VCAP_BIT_ANY ? 0 : 1) |
(arp->arp == OCELOT_VCAP_BIT_ANY ? 0 : 2));
vcap_key_set(ocelot, &data, VCAP_IS2_HK_MAC_ARP_OPCODE,
vcap_key_set(vcap, &data, VCAP_IS2_HK_MAC_ARP_OPCODE,
val, msk);
vcap_key_bytes_set(ocelot, &data,
vcap_key_bytes_set(vcap, &data,
VCAP_IS2_HK_MAC_ARP_L3_IP4_DIP,
arp->dip.value.addr, arp->dip.mask.addr);
vcap_key_bytes_set(ocelot, &data,
vcap_key_bytes_set(vcap, &data,
VCAP_IS2_HK_MAC_ARP_L3_IP4_SIP,
arp->sip.value.addr, arp->sip.mask.addr);
vcap_key_set(ocelot, &data, VCAP_IS2_HK_MAC_ARP_DIP_EQ_SIP,
vcap_key_set(vcap, &data, VCAP_IS2_HK_MAC_ARP_DIP_EQ_SIP,
0, 0);
break;
}
......@@ -534,22 +563,22 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
seq_zero = ipv6->seq_zero;
}
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_IP4,
vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_IP4,
ipv4 ? OCELOT_VCAP_BIT_1 : OCELOT_VCAP_BIT_0);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L3_FRAGMENT,
vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L3_FRAGMENT,
fragment);
vcap_key_set(ocelot, &data, VCAP_IS2_HK_L3_FRAG_OFS_GT0, 0, 0);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L3_OPTIONS,
vcap_key_set(vcap, &data, VCAP_IS2_HK_L3_FRAG_OFS_GT0, 0, 0);
vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L3_OPTIONS,
options);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_IP4_L3_TTL_GT0,
vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_IP4_L3_TTL_GT0,
ttl);
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L3_TOS,
vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L3_TOS,
ds.value, ds.mask);
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L3_IP4_DIP,
vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L3_IP4_DIP,
dip.value.addr, dip.mask.addr);
vcap_key_bytes_set(ocelot, &data, VCAP_IS2_HK_L3_IP4_SIP,
vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L3_IP4_SIP,
sip.value.addr, sip.mask.addr);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_DIP_EQ_SIP,
vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_DIP_EQ_SIP,
sip_eq_dip);
val = proto.value[0];
msk = proto.mask[0];
......@@ -558,33 +587,33 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
/* UDP/TCP protocol match */
tcp = (val == 6 ?
OCELOT_VCAP_BIT_1 : OCELOT_VCAP_BIT_0);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_TCP, tcp);
vcap_key_l4_port_set(ocelot, &data,
vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_TCP, tcp);
vcap_key_l4_port_set(vcap, &data,
VCAP_IS2_HK_L4_DPORT, dport);
vcap_key_l4_port_set(ocelot, &data,
vcap_key_l4_port_set(vcap, &data,
VCAP_IS2_HK_L4_SPORT, sport);
vcap_key_set(ocelot, &data, VCAP_IS2_HK_L4_RNG, 0, 0);
vcap_key_bit_set(ocelot, &data,
vcap_key_set(vcap, &data, VCAP_IS2_HK_L4_RNG, 0, 0);
vcap_key_bit_set(vcap, &data,
VCAP_IS2_HK_L4_SPORT_EQ_DPORT,
sport_eq_dport);
vcap_key_bit_set(ocelot, &data,
vcap_key_bit_set(vcap, &data,
VCAP_IS2_HK_L4_SEQUENCE_EQ0,
seq_zero);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L4_FIN,
vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L4_FIN,
tcp_fin);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L4_SYN,
vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L4_SYN,
tcp_syn);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L4_RST,
vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L4_RST,
tcp_rst);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L4_PSH,
vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L4_PSH,
tcp_psh);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L4_ACK,
vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L4_ACK,
tcp_ack);
vcap_key_bit_set(ocelot, &data, VCAP_IS2_HK_L4_URG,
vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L4_URG,
tcp_urg);
vcap_key_set(ocelot, &data, VCAP_IS2_HK_L4_1588_DOM,
vcap_key_set(vcap, &data, VCAP_IS2_HK_L4_1588_DOM,
0, 0);
vcap_key_set(ocelot, &data, VCAP_IS2_HK_L4_1588_VER,
vcap_key_set(vcap, &data, VCAP_IS2_HK_L4_1588_VER,
0, 0);
} else {
if (msk == 0) {
......@@ -598,10 +627,10 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
payload.mask[i] = ip_data->mask[i];
}
}
vcap_key_bytes_set(ocelot, &data,
vcap_key_bytes_set(vcap, &data,
VCAP_IS2_HK_IP4_L3_PROTO,
proto.value, proto.mask);
vcap_key_bytes_set(ocelot, &data,
vcap_key_bytes_set(vcap, &data,
VCAP_IS2_HK_L3_PAYLOAD,
payload.value, payload.mask);
}
......@@ -611,42 +640,44 @@ static void is2_entry_set(struct ocelot *ocelot, int ix,
default:
type = 0;
type_mask = 0;
count = vcap_is2->entry_width / 2;
count = vcap->entry_width / 2;
/* Iterate over the non-common part of the key and
* clear entry data
*/
for (i = ocelot->vcap_is2_keys[VCAP_IS2_HK_L2_DMAC].offset;
for (i = vcap->keys[VCAP_IS2_HK_L2_DMAC].offset;
i < count; i += ENTRY_WIDTH) {
vcap_key_field_set(&data, i, min(32u, count - i), 0, 0);
}
break;
}
vcap_key_set(ocelot, &data, VCAP_IS2_TYPE, type, type_mask);
vcap_key_set(vcap, &data, VCAP_IS2_TYPE, type, type_mask);
is2_action_set(ocelot, &data, filter);
vcap_data_set(data.counter, data.counter_offset,
vcap_is2->counter_width, filter->stats.pkts);
vcap->counter_width, filter->stats.pkts);
/* Write row */
vcap_entry2cache(ocelot, &data);
vcap_action2cache(ocelot, &data);
vcap_row_cmd(ocelot, row, VCAP_CMD_WRITE, VCAP_SEL_ALL);
vcap_entry2cache(ocelot, vcap, &data);
vcap_action2cache(ocelot, vcap, &data);
vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_WRITE, VCAP_SEL_ALL);
}
static void is2_entry_get(struct ocelot *ocelot, struct ocelot_vcap_filter *filter,
int ix)
static void
vcap_entry_get(struct ocelot *ocelot, struct ocelot_vcap_filter *filter, int ix)
{
const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS2];
struct vcap_data data;
int row = (ix / 2);
int row, count;
u32 cnt;
vcap_row_cmd(ocelot, row, VCAP_CMD_READ, VCAP_SEL_COUNTER);
vcap_cache2action(ocelot, &data);
data.tg_sw = VCAP_TG_HALF;
is2_data_get(ocelot, &data, ix);
count = (1 << (data.tg_sw - 1));
row = (ix / count);
vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_READ, VCAP_SEL_COUNTER);
vcap_cache2action(ocelot, vcap, &data);
vcap_data_offset_get(vcap, &data, ix);
cnt = vcap_data_get(data.counter, data.counter_offset,
vcap_is2->counter_width);
vcap->counter_width);
filter->stats.pkts = cnt;
}
......@@ -726,19 +757,20 @@ static int ocelot_vcap_block_get_filter_index(struct ocelot_vcap_block *block,
struct ocelot_vcap_filter *filter)
{
struct ocelot_vcap_filter *tmp;
int index = -1;
int index = 0;
list_for_each_entry(tmp, &block->rules, list) {
++index;
if (filter->id == tmp->id)
break;
return index;
index++;
}
return index;
return -ENOENT;
}
static struct ocelot_vcap_filter*
ocelot_vcap_block_find_filter(struct ocelot_vcap_block *block,
int index)
ocelot_vcap_block_find_filter_by_index(struct ocelot_vcap_block *block,
int index)
{
struct ocelot_vcap_filter *tmp;
int i = 0;
......@@ -752,6 +784,18 @@ ocelot_vcap_block_find_filter(struct ocelot_vcap_block *block,
return NULL;
}
struct ocelot_vcap_filter *
ocelot_vcap_block_find_filter_by_id(struct ocelot_vcap_block *block, int id)
{
struct ocelot_vcap_filter *filter;
list_for_each_entry(filter, &block->rules, list)
if (filter->id == id)
return filter;
return NULL;
}
/* If @on=false, then SNAP, ARP, IP and OAM frames will not match on keys based
* on destination and source MAC addresses, but only on higher-level protocol
* information. The only frame types to match on keys containing MAC addresses
......@@ -833,7 +877,7 @@ ocelot_exclusive_mac_etype_filter_rules(struct ocelot *ocelot,
if (ocelot_vcap_is_problematic_mac_etype(filter)) {
/* Search for any non-MAC_ETYPE rules on the port */
for (i = 0; i < block->count; i++) {
tmp = ocelot_vcap_block_find_filter(block, i);
tmp = ocelot_vcap_block_find_filter_by_index(block, i);
if (tmp->ingress_port_mask & filter->ingress_port_mask &&
ocelot_vcap_is_problematic_non_mac_etype(tmp))
return false;
......@@ -845,7 +889,7 @@ ocelot_exclusive_mac_etype_filter_rules(struct ocelot *ocelot,
} else if (ocelot_vcap_is_problematic_non_mac_etype(filter)) {
/* Search for any MAC_ETYPE rules on the port */
for (i = 0; i < block->count; i++) {
tmp = ocelot_vcap_block_find_filter(block, i);
tmp = ocelot_vcap_block_find_filter_by_index(block, i);
if (tmp->ingress_port_mask & filter->ingress_port_mask &&
ocelot_vcap_is_problematic_mac_etype(tmp))
return false;
......@@ -877,12 +921,14 @@ int ocelot_vcap_filter_add(struct ocelot *ocelot,
/* Get the index of the inserted filter */
index = ocelot_vcap_block_get_filter_index(block, filter);
if (index < 0)
return index;
/* Move down the rules to make place for the new filter */
for (i = block->count - 1; i > index; i--) {
struct ocelot_vcap_filter *tmp;
tmp = ocelot_vcap_block_find_filter(block, i);
tmp = ocelot_vcap_block_find_filter_by_index(block, i);
is2_entry_set(ocelot, i, tmp);
}
......@@ -924,6 +970,8 @@ int ocelot_vcap_filter_del(struct ocelot *ocelot,
/* Gets index of the filter */
index = ocelot_vcap_block_get_filter_index(block, filter);
if (index < 0)
return index;
/* Delete filter */
ocelot_vcap_block_remove_filter(ocelot, block, filter);
......@@ -932,7 +980,7 @@ int ocelot_vcap_filter_del(struct ocelot *ocelot,
for (i = index; i < block->count; i++) {
struct ocelot_vcap_filter *tmp;
tmp = ocelot_vcap_block_find_filter(block, i);
tmp = ocelot_vcap_block_find_filter_by_index(block, i);
is2_entry_set(ocelot, i, tmp);
}
......@@ -946,36 +994,115 @@ int ocelot_vcap_filter_stats_update(struct ocelot *ocelot,
struct ocelot_vcap_filter *filter)
{
struct ocelot_vcap_block *block = &ocelot->block;
struct ocelot_vcap_filter *tmp;
struct ocelot_vcap_filter tmp;
int index;
index = ocelot_vcap_block_get_filter_index(block, filter);
is2_entry_get(ocelot, filter, index);
if (index < 0)
return index;
vcap_entry_get(ocelot, filter, index);
/* After we get the result we need to clear the counters */
tmp = ocelot_vcap_block_find_filter(block, index);
tmp->stats.pkts = 0;
is2_entry_set(ocelot, index, tmp);
tmp = *filter;
tmp.stats.pkts = 0;
is2_entry_set(ocelot, index, &tmp);
return 0;
}
int ocelot_vcap_init(struct ocelot *ocelot)
static void ocelot_vcap_init_one(struct ocelot *ocelot,
const struct vcap_props *vcap)
{
const struct vcap_props *vcap_is2 = &ocelot->vcap[VCAP_IS2];
struct ocelot_vcap_block *block = &ocelot->block;
struct vcap_data data;
memset(&data, 0, sizeof(data));
vcap_entry2cache(ocelot, &data);
ocelot_write(ocelot, vcap_is2->entry_count, S2_CORE_MV_CFG);
vcap_cmd(ocelot, 0, VCAP_CMD_INITIALIZE, VCAP_SEL_ENTRY);
vcap_entry2cache(ocelot, vcap, &data);
ocelot_target_write(ocelot, vcap->target, vcap->entry_count,
VCAP_CORE_MV_CFG);
vcap_cmd(ocelot, vcap, 0, VCAP_CMD_INITIALIZE, VCAP_SEL_ENTRY);
vcap_action2cache(ocelot, &data);
ocelot_write(ocelot, vcap_is2->action_count, S2_CORE_MV_CFG);
vcap_cmd(ocelot, 0, VCAP_CMD_INITIALIZE,
vcap_action2cache(ocelot, vcap, &data);
ocelot_target_write(ocelot, vcap->target, vcap->action_count,
VCAP_CORE_MV_CFG);
vcap_cmd(ocelot, vcap, 0, VCAP_CMD_INITIALIZE,
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;
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
......@@ -992,9 +1119,16 @@ 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(&ocelot->block.rules);
INIT_LIST_HEAD(&block->rules);
return 0;
}
......@@ -221,7 +221,10 @@ int ocelot_vcap_filter_del(struct ocelot *ocelot,
struct ocelot_vcap_filter *rule);
int ocelot_vcap_filter_stats_update(struct ocelot *ocelot,
struct ocelot_vcap_filter *rule);
struct ocelot_vcap_filter *
ocelot_vcap_block_find_filter_by_id(struct ocelot_vcap_block *block, int id);
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,
......
......@@ -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),
......@@ -241,14 +237,27 @@ static const u32 ocelot_sys_regmap[] = {
REG(SYS_PTP_CFG, 0x0006c4),
};
static const u32 ocelot_s2_regmap[] = {
REG(S2_CORE_UPDATE_CTRL, 0x000000),
REG(S2_CORE_MV_CFG, 0x000004),
REG(S2_CACHE_ENTRY_DAT, 0x000008),
REG(S2_CACHE_MASK_DAT, 0x000108),
REG(S2_CACHE_ACTION_DAT, 0x000208),
REG(S2_CACHE_CNT_DAT, 0x000308),
REG(S2_CACHE_TG_DAT, 0x000388),
static const u32 ocelot_vcap_regmap[] = {
/* VCAP_CORE_CFG */
REG(VCAP_CORE_UPDATE_CTRL, 0x000000),
REG(VCAP_CORE_MV_CFG, 0x000004),
/* VCAP_CORE_CACHE */
REG(VCAP_CACHE_ENTRY_DAT, 0x000008),
REG(VCAP_CACHE_MASK_DAT, 0x000108),
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[] = {
......@@ -311,7 +320,7 @@ static const u32 *ocelot_regmap[TARGET_MAX] = {
[QSYS] = ocelot_qsys_regmap,
[REW] = ocelot_rew_regmap,
[SYS] = ocelot_sys_regmap,
[S2] = ocelot_s2_regmap,
[S2] = ocelot_vcap_regmap,
[PTP] = ocelot_ptp_regmap,
[DEV_GMII] = ocelot_dev_gmii_regmap,
};
......@@ -756,6 +765,113 @@ static const struct ocelot_ops ocelot_ops = {
.wm_enc = ocelot_wm_enc,
};
static const struct vcap_field vsc7514_vcap_es0_keys[] = {
[VCAP_ES0_EGR_PORT] = { 0, 4},
[VCAP_ES0_IGR_PORT] = { 4, 4},
[VCAP_ES0_RSV] = { 8, 2},
[VCAP_ES0_L2_MC] = { 10, 1},
[VCAP_ES0_L2_BC] = { 11, 1},
[VCAP_ES0_VID] = { 12, 12},
[VCAP_ES0_DP] = { 24, 1},
[VCAP_ES0_PCP] = { 25, 3},
};
static const struct vcap_field vsc7514_vcap_es0_actions[] = {
[VCAP_ES0_ACT_PUSH_OUTER_TAG] = { 0, 2},
[VCAP_ES0_ACT_PUSH_INNER_TAG] = { 2, 1},
[VCAP_ES0_ACT_TAG_A_TPID_SEL] = { 3, 2},
[VCAP_ES0_ACT_TAG_A_VID_SEL] = { 5, 1},
[VCAP_ES0_ACT_TAG_A_PCP_SEL] = { 6, 2},
[VCAP_ES0_ACT_TAG_A_DEI_SEL] = { 8, 2},
[VCAP_ES0_ACT_TAG_B_TPID_SEL] = { 10, 2},
[VCAP_ES0_ACT_TAG_B_VID_SEL] = { 12, 1},
[VCAP_ES0_ACT_TAG_B_PCP_SEL] = { 13, 2},
[VCAP_ES0_ACT_TAG_B_DEI_SEL] = { 15, 2},
[VCAP_ES0_ACT_VID_A_VAL] = { 17, 12},
[VCAP_ES0_ACT_PCP_A_VAL] = { 29, 3},
[VCAP_ES0_ACT_DEI_A_VAL] = { 32, 1},
[VCAP_ES0_ACT_VID_B_VAL] = { 33, 12},
[VCAP_ES0_ACT_PCP_B_VAL] = { 45, 3},
[VCAP_ES0_ACT_DEI_B_VAL] = { 48, 1},
[VCAP_ES0_ACT_RSV] = { 49, 24},
[VCAP_ES0_ACT_HIT_STICKY] = { 73, 1},
};
static const struct vcap_field vsc7514_vcap_is1_keys[] = {
[VCAP_IS1_HK_TYPE] = { 0, 1},
[VCAP_IS1_HK_LOOKUP] = { 1, 2},
[VCAP_IS1_HK_IGR_PORT_MASK] = { 3, 12},
[VCAP_IS1_HK_RSV] = { 15, 9},
[VCAP_IS1_HK_OAM_Y1731] = { 24, 1},
[VCAP_IS1_HK_L2_MC] = { 25, 1},
[VCAP_IS1_HK_L2_BC] = { 26, 1},
[VCAP_IS1_HK_IP_MC] = { 27, 1},
[VCAP_IS1_HK_VLAN_TAGGED] = { 28, 1},
[VCAP_IS1_HK_VLAN_DBL_TAGGED] = { 29, 1},
[VCAP_IS1_HK_TPID] = { 30, 1},
[VCAP_IS1_HK_VID] = { 31, 12},
[VCAP_IS1_HK_DEI] = { 43, 1},
[VCAP_IS1_HK_PCP] = { 44, 3},
/* Specific Fields for IS1 Half Key S1_NORMAL */
[VCAP_IS1_HK_L2_SMAC] = { 47, 48},
[VCAP_IS1_HK_ETYPE_LEN] = { 95, 1},
[VCAP_IS1_HK_ETYPE] = { 96, 16},
[VCAP_IS1_HK_IP_SNAP] = {112, 1},
[VCAP_IS1_HK_IP4] = {113, 1},
/* Layer-3 Information */
[VCAP_IS1_HK_L3_FRAGMENT] = {114, 1},
[VCAP_IS1_HK_L3_FRAG_OFS_GT0] = {115, 1},
[VCAP_IS1_HK_L3_OPTIONS] = {116, 1},
[VCAP_IS1_HK_L3_DSCP] = {117, 6},
[VCAP_IS1_HK_L3_IP4_SIP] = {123, 32},
/* Layer-4 Information */
[VCAP_IS1_HK_TCP_UDP] = {155, 1},
[VCAP_IS1_HK_TCP] = {156, 1},
[VCAP_IS1_HK_L4_SPORT] = {157, 16},
[VCAP_IS1_HK_L4_RNG] = {173, 8},
/* Specific Fields for IS1 Half Key S1_5TUPLE_IP4 */
[VCAP_IS1_HK_IP4_INNER_TPID] = { 47, 1},
[VCAP_IS1_HK_IP4_INNER_VID] = { 48, 12},
[VCAP_IS1_HK_IP4_INNER_DEI] = { 60, 1},
[VCAP_IS1_HK_IP4_INNER_PCP] = { 61, 3},
[VCAP_IS1_HK_IP4_IP4] = { 64, 1},
[VCAP_IS1_HK_IP4_L3_FRAGMENT] = { 65, 1},
[VCAP_IS1_HK_IP4_L3_FRAG_OFS_GT0] = { 66, 1},
[VCAP_IS1_HK_IP4_L3_OPTIONS] = { 67, 1},
[VCAP_IS1_HK_IP4_L3_DSCP] = { 68, 6},
[VCAP_IS1_HK_IP4_L3_IP4_DIP] = { 74, 32},
[VCAP_IS1_HK_IP4_L3_IP4_SIP] = {106, 32},
[VCAP_IS1_HK_IP4_L3_PROTO] = {138, 8},
[VCAP_IS1_HK_IP4_TCP_UDP] = {146, 1},
[VCAP_IS1_HK_IP4_TCP] = {147, 1},
[VCAP_IS1_HK_IP4_L4_RNG] = {148, 8},
[VCAP_IS1_HK_IP4_IP_PAYLOAD_S1_5TUPLE] = {156, 32},
};
static const struct vcap_field vsc7514_vcap_is1_actions[] = {
[VCAP_IS1_ACT_DSCP_ENA] = { 0, 1},
[VCAP_IS1_ACT_DSCP_VAL] = { 1, 6},
[VCAP_IS1_ACT_QOS_ENA] = { 7, 1},
[VCAP_IS1_ACT_QOS_VAL] = { 8, 3},
[VCAP_IS1_ACT_DP_ENA] = { 11, 1},
[VCAP_IS1_ACT_DP_VAL] = { 12, 1},
[VCAP_IS1_ACT_PAG_OVERRIDE_MASK] = { 13, 8},
[VCAP_IS1_ACT_PAG_VAL] = { 21, 8},
[VCAP_IS1_ACT_RSV] = { 29, 9},
/* The fields below are incorrectly shifted by 2 in the manual */
[VCAP_IS1_ACT_VID_REPLACE_ENA] = { 38, 1},
[VCAP_IS1_ACT_VID_ADD_VAL] = { 39, 12},
[VCAP_IS1_ACT_FID_SEL] = { 51, 2},
[VCAP_IS1_ACT_FID_VAL] = { 53, 13},
[VCAP_IS1_ACT_PCP_DEI_ENA] = { 66, 1},
[VCAP_IS1_ACT_PCP_VAL] = { 67, 3},
[VCAP_IS1_ACT_DEI_VAL] = { 70, 1},
[VCAP_IS1_ACT_VLAN_POP_CNT_ENA] = { 71, 1},
[VCAP_IS1_ACT_VLAN_POP_CNT] = { 72, 2},
[VCAP_IS1_ACT_CUSTOM_ACE_TYPE_ENA] = { 74, 4},
[VCAP_IS1_ACT_HIT_STICKY] = { 78, 1},
};
static const struct vcap_field vsc7514_vcap_is2_keys[] = {
/* Common: 46 bits */
[VCAP_IS2_TYPE] = { 0, 4},
......@@ -854,15 +970,32 @@ 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 = {
[ES0_ACTION_TYPE_NORMAL] = {
.width = 73, /* HIT_STICKY not included */
.count = 1,
},
},
.target = S0,
.keys = vsc7514_vcap_es0_keys,
.actions = vsc7514_vcap_es0_actions,
},
[VCAP_IS1] = {
.action_type_width = 0,
.action_table = {
[IS1_ACTION_TYPE_NORMAL] = {
.width = 78, /* HIT_STICKY not included */
.count = 4,
},
},
.target = S1,
.keys = vsc7514_vcap_is1_keys,
.actions = vsc7514_vcap_is1_actions,
},
[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] = {
......@@ -874,8 +1007,9 @@ 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,
},
};
......@@ -1037,6 +1171,8 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
{ QSYS, "qsys" },
{ ANA, "ana" },
{ QS, "qs" },
{ S0, "s0" },
{ S1, "s1" },
{ S2, "s2" },
{ PTP, "ptp", 1 },
};
......@@ -1113,8 +1249,6 @@ static int mscc_ocelot_probe(struct platform_device *pdev)
ocelot->num_phys_ports = of_get_child_count(ports);
ocelot->vcap_is2_keys = vsc7514_vcap_is2_keys;
ocelot->vcap_is2_actions = vsc7514_vcap_is2_actions;
ocelot->vcap = vsc7514_vcap_props;
ocelot->inj_prefix = OCELOT_TAG_PREFIX_NONE;
ocelot->xtr_prefix = OCELOT_TAG_PREFIX_NONE;
......
......@@ -123,6 +123,8 @@ enum ocelot_target {
QSYS,
REW,
SYS,
S0,
S1,
S2,
HSIO,
PTP,
......@@ -393,13 +395,6 @@ enum ocelot_reg {
SYS_CM_DATA_RD,
SYS_CM_OP,
SYS_CM_DATA,
S2_CORE_UPDATE_CTRL = S2 << TARGET_OFFSET,
S2_CORE_MV_CFG,
S2_CACHE_ENTRY_DAT,
S2_CACHE_MASK_DAT,
S2_CACHE_ACTION_DAT,
S2_CACHE_CNT_DAT,
S2_CACHE_TG_DAT,
PTP_PIN_CFG = PTP << TARGET_OFFSET,
PTP_PIN_TOD_SEC_MSB,
PTP_PIN_TOD_SEC_LSB,
......@@ -518,6 +513,29 @@ enum ocelot_regfield {
REGFIELD_MAX
};
enum {
/* VCAP_CORE_CFG */
VCAP_CORE_UPDATE_CTRL,
VCAP_CORE_MV_CFG,
/* VCAP_CORE_CACHE */
VCAP_CACHE_ENTRY_DAT,
VCAP_CACHE_MASK_DAT,
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 {
PTP_PIN_0,
PTP_PIN_1,
......@@ -614,10 +632,7 @@ struct ocelot {
struct list_head multicast;
struct ocelot_vcap_block block;
const struct vcap_field *vcap_is2_keys;
const struct vcap_field *vcap_is2_actions;
const struct vcap_props *vcap;
struct vcap_props *vcap;
/* Workqueue to check statistics for overflow with its lock */
struct mutex stats_lock;
......@@ -661,6 +676,24 @@ struct ocelot_policer {
#define ocelot_fields_write(ocelot, id, reg, val) regmap_fields_write((ocelot)->regfields[(reg)], (id), (val))
#define ocelot_fields_read(ocelot, id, reg, val) regmap_fields_read((ocelot)->regfields[(reg)], (id), (val))
#define ocelot_target_read_ix(ocelot, target, reg, gi, ri) \
__ocelot_target_read_ix(ocelot, target, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri))
#define ocelot_target_read_gix(ocelot, target, reg, gi) \
__ocelot_target_read_ix(ocelot, target, reg, reg##_GSZ * (gi))
#define ocelot_target_read_rix(ocelot, target, reg, ri) \
__ocelot_target_read_ix(ocelot, target, reg, reg##_RSZ * (ri))
#define ocelot_target_read(ocelot, target, reg) \
__ocelot_target_read_ix(ocelot, target, reg, 0)
#define ocelot_target_write_ix(ocelot, target, val, reg, gi, ri) \
__ocelot_target_write_ix(ocelot, target, val, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri))
#define ocelot_target_write_gix(ocelot, target, val, reg, gi) \
__ocelot_target_write_ix(ocelot, target, val, reg, reg##_GSZ * (gi))
#define ocelot_target_write_rix(ocelot, target, val, reg, ri) \
__ocelot_target_write_ix(ocelot, target, val, reg, reg##_RSZ * (ri))
#define ocelot_target_write(ocelot, target, val, reg) \
__ocelot_target_write_ix(ocelot, target, val, reg, 0)
/* I/O */
u32 ocelot_port_readl(struct ocelot_port *port, u32 reg);
void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg);
......@@ -668,6 +701,10 @@ u32 __ocelot_read_ix(struct ocelot *ocelot, u32 reg, u32 offset);
void __ocelot_write_ix(struct ocelot *ocelot, u32 val, u32 reg, u32 offset);
void __ocelot_rmw_ix(struct ocelot *ocelot, u32 val, u32 mask, u32 reg,
u32 offset);
u32 __ocelot_target_read_ix(struct ocelot *ocelot, enum ocelot_target target,
u32 reg, u32 offset);
void __ocelot_target_write_ix(struct ocelot *ocelot, enum ocelot_target target,
u32 val, u32 reg, u32 offset);
/* Hardware initialization */
int ocelot_regfields_init(struct ocelot *ocelot,
......
......@@ -6,17 +6,22 @@
#ifndef _OCELOT_VCAP_H_
#define _OCELOT_VCAP_H_
#include <soc/mscc/ocelot.h>
/* =================================================================
* VCAP Common
* =================================================================
*/
enum {
/* VCAP_IS1, */
VCAP_ES0,
VCAP_IS1,
VCAP_IS2,
/* VCAP_ES0, */
__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 */
......@@ -33,6 +38,11 @@ struct vcap_props {
} action_table[2];
u16 counter_words; /* Number of counter words */
u16 counter_width; /* Counter width (in bits) */
enum ocelot_target target;
const struct vcap_field *keys;
const struct vcap_field *actions;
};
/* VCAP Type-Group values */
......@@ -41,6 +51,61 @@ struct vcap_props {
#define VCAP_TG_HALF 2 /* Half entry */
#define VCAP_TG_QUARTER 3 /* Quarter entry */
#define VCAP_CORE_UPDATE_CTRL_UPDATE_CMD(x) (((x) << 22) & GENMASK(24, 22))
#define VCAP_CORE_UPDATE_CTRL_UPDATE_CMD_M GENMASK(24, 22)
#define VCAP_CORE_UPDATE_CTRL_UPDATE_CMD_X(x) (((x) & GENMASK(24, 22)) >> 22)
#define VCAP_CORE_UPDATE_CTRL_UPDATE_ENTRY_DIS BIT(21)
#define VCAP_CORE_UPDATE_CTRL_UPDATE_ACTION_DIS BIT(20)
#define VCAP_CORE_UPDATE_CTRL_UPDATE_CNT_DIS BIT(19)
#define VCAP_CORE_UPDATE_CTRL_UPDATE_ADDR(x) (((x) << 3) & GENMASK(18, 3))
#define VCAP_CORE_UPDATE_CTRL_UPDATE_ADDR_M GENMASK(18, 3)
#define VCAP_CORE_UPDATE_CTRL_UPDATE_ADDR_X(x) (((x) & GENMASK(18, 3)) >> 3)
#define VCAP_CORE_UPDATE_CTRL_UPDATE_SHOT BIT(2)
#define VCAP_CORE_UPDATE_CTRL_CLEAR_CACHE BIT(1)
#define VCAP_CORE_UPDATE_CTRL_MV_TRAFFIC_IGN BIT(0)
#define VCAP_CORE_MV_CFG_MV_NUM_POS(x) (((x) << 16) & GENMASK(31, 16))
#define VCAP_CORE_MV_CFG_MV_NUM_POS_M GENMASK(31, 16)
#define VCAP_CORE_MV_CFG_MV_NUM_POS_X(x) (((x) & GENMASK(31, 16)) >> 16)
#define VCAP_CORE_MV_CFG_MV_SIZE(x) ((x) & GENMASK(15, 0))
#define VCAP_CORE_MV_CFG_MV_SIZE_M GENMASK(15, 0)
#define VCAP_CACHE_ENTRY_DAT_RSZ 0x4
#define VCAP_CACHE_MASK_DAT_RSZ 0x4
#define VCAP_CACHE_ACTION_DAT_RSZ 0x4
#define VCAP_CACHE_CNT_DAT_RSZ 0x4
#define VCAP_STICKY_VCAP_ROW_DELETED_STICKY BIT(0)
#define TCAM_BIST_CTRL_TCAM_BIST BIT(1)
#define TCAM_BIST_CTRL_TCAM_INIT BIT(0)
#define TCAM_BIST_CFG_TCAM_BIST_SOE_ENA BIT(8)
#define TCAM_BIST_CFG_TCAM_HCG_DIS BIT(7)
#define TCAM_BIST_CFG_TCAM_CG_DIS BIT(6)
#define TCAM_BIST_CFG_TCAM_BIAS(x) ((x) & GENMASK(5, 0))
#define TCAM_BIST_CFG_TCAM_BIAS_M GENMASK(5, 0)
#define TCAM_BIST_STAT_BIST_RT_ERR BIT(15)
#define TCAM_BIST_STAT_BIST_PENC_ERR BIT(14)
#define TCAM_BIST_STAT_BIST_COMP_ERR BIT(13)
#define TCAM_BIST_STAT_BIST_ADDR_ERR BIT(12)
#define TCAM_BIST_STAT_BIST_BL1E_ERR BIT(11)
#define TCAM_BIST_STAT_BIST_BL1_ERR BIT(10)
#define TCAM_BIST_STAT_BIST_BL0E_ERR BIT(9)
#define TCAM_BIST_STAT_BIST_BL0_ERR BIT(8)
#define TCAM_BIST_STAT_BIST_PH1_ERR BIT(7)
#define TCAM_BIST_STAT_BIST_PH0_ERR BIT(6)
#define TCAM_BIST_STAT_BIST_PV1_ERR BIT(5)
#define TCAM_BIST_STAT_BIST_PV0_ERR BIT(4)
#define TCAM_BIST_STAT_BIST_RUN BIT(3)
#define TCAM_BIST_STAT_BIST_ERR BIT(2)
#define TCAM_BIST_STAT_BIST_BUSY BIT(1)
#define TCAM_BIST_STAT_TCAM_RDY BIT(0)
/* =================================================================
* VCAP IS2
* =================================================================
......@@ -202,4 +267,137 @@ enum vcap_is2_action_field {
VCAP_IS2_ACT_HIT_CNT,
};
/* =================================================================
* VCAP IS1
* =================================================================
*/
/* IS1 half key types */
#define IS1_TYPE_S1_NORMAL 0
#define IS1_TYPE_S1_5TUPLE_IP4 1
/* IS1 full key types */
#define IS1_TYPE_S1_NORMAL_IP6 0
#define IS1_TYPE_S1_7TUPLE 1
#define IS2_TYPE_S1_5TUPLE_IP6 2
enum {
IS1_ACTION_TYPE_NORMAL,
IS1_ACTION_TYPE_MAX,
};
enum vcap_is1_half_key_field {
VCAP_IS1_HK_TYPE,
VCAP_IS1_HK_LOOKUP,
VCAP_IS1_HK_IGR_PORT_MASK,
VCAP_IS1_HK_RSV,
VCAP_IS1_HK_OAM_Y1731,
VCAP_IS1_HK_L2_MC,
VCAP_IS1_HK_L2_BC,
VCAP_IS1_HK_IP_MC,
VCAP_IS1_HK_VLAN_TAGGED,
VCAP_IS1_HK_VLAN_DBL_TAGGED,
VCAP_IS1_HK_TPID,
VCAP_IS1_HK_VID,
VCAP_IS1_HK_DEI,
VCAP_IS1_HK_PCP,
/* Specific Fields for IS1 Half Key S1_NORMAL */
VCAP_IS1_HK_L2_SMAC,
VCAP_IS1_HK_ETYPE_LEN,
VCAP_IS1_HK_ETYPE,
VCAP_IS1_HK_IP_SNAP,
VCAP_IS1_HK_IP4,
VCAP_IS1_HK_L3_FRAGMENT,
VCAP_IS1_HK_L3_FRAG_OFS_GT0,
VCAP_IS1_HK_L3_OPTIONS,
VCAP_IS1_HK_L3_DSCP,
VCAP_IS1_HK_L3_IP4_SIP,
VCAP_IS1_HK_TCP_UDP,
VCAP_IS1_HK_TCP,
VCAP_IS1_HK_L4_SPORT,
VCAP_IS1_HK_L4_RNG,
/* Specific Fields for IS1 Half Key S1_5TUPLE_IP4 */
VCAP_IS1_HK_IP4_INNER_TPID,
VCAP_IS1_HK_IP4_INNER_VID,
VCAP_IS1_HK_IP4_INNER_DEI,
VCAP_IS1_HK_IP4_INNER_PCP,
VCAP_IS1_HK_IP4_IP4,
VCAP_IS1_HK_IP4_L3_FRAGMENT,
VCAP_IS1_HK_IP4_L3_FRAG_OFS_GT0,
VCAP_IS1_HK_IP4_L3_OPTIONS,
VCAP_IS1_HK_IP4_L3_DSCP,
VCAP_IS1_HK_IP4_L3_IP4_DIP,
VCAP_IS1_HK_IP4_L3_IP4_SIP,
VCAP_IS1_HK_IP4_L3_PROTO,
VCAP_IS1_HK_IP4_TCP_UDP,
VCAP_IS1_HK_IP4_TCP,
VCAP_IS1_HK_IP4_L4_RNG,
VCAP_IS1_HK_IP4_IP_PAYLOAD_S1_5TUPLE,
};
enum vcap_is1_action_field {
VCAP_IS1_ACT_DSCP_ENA,
VCAP_IS1_ACT_DSCP_VAL,
VCAP_IS1_ACT_QOS_ENA,
VCAP_IS1_ACT_QOS_VAL,
VCAP_IS1_ACT_DP_ENA,
VCAP_IS1_ACT_DP_VAL,
VCAP_IS1_ACT_PAG_OVERRIDE_MASK,
VCAP_IS1_ACT_PAG_VAL,
VCAP_IS1_ACT_RSV,
VCAP_IS1_ACT_VID_REPLACE_ENA,
VCAP_IS1_ACT_VID_ADD_VAL,
VCAP_IS1_ACT_FID_SEL,
VCAP_IS1_ACT_FID_VAL,
VCAP_IS1_ACT_PCP_DEI_ENA,
VCAP_IS1_ACT_PCP_VAL,
VCAP_IS1_ACT_DEI_VAL,
VCAP_IS1_ACT_VLAN_POP_CNT_ENA,
VCAP_IS1_ACT_VLAN_POP_CNT,
VCAP_IS1_ACT_CUSTOM_ACE_TYPE_ENA,
VCAP_IS1_ACT_HIT_STICKY,
};
/* =================================================================
* VCAP ES0
* =================================================================
*/
enum {
ES0_ACTION_TYPE_NORMAL,
ES0_ACTION_TYPE_MAX,
};
enum vcap_es0_key_field {
VCAP_ES0_EGR_PORT,
VCAP_ES0_IGR_PORT,
VCAP_ES0_RSV,
VCAP_ES0_L2_MC,
VCAP_ES0_L2_BC,
VCAP_ES0_VID,
VCAP_ES0_DP,
VCAP_ES0_PCP,
};
enum vcap_es0_action_field {
VCAP_ES0_ACT_PUSH_OUTER_TAG,
VCAP_ES0_ACT_PUSH_INNER_TAG,
VCAP_ES0_ACT_TAG_A_TPID_SEL,
VCAP_ES0_ACT_TAG_A_VID_SEL,
VCAP_ES0_ACT_TAG_A_PCP_SEL,
VCAP_ES0_ACT_TAG_A_DEI_SEL,
VCAP_ES0_ACT_TAG_B_TPID_SEL,
VCAP_ES0_ACT_TAG_B_VID_SEL,
VCAP_ES0_ACT_TAG_B_PCP_SEL,
VCAP_ES0_ACT_TAG_B_DEI_SEL,
VCAP_ES0_ACT_VID_A_VAL,
VCAP_ES0_ACT_PCP_A_VAL,
VCAP_ES0_ACT_DEI_A_VAL,
VCAP_ES0_ACT_VID_B_VAL,
VCAP_ES0_ACT_PCP_B_VAL,
VCAP_ES0_ACT_DEI_B_VAL,
VCAP_ES0_ACT_RSV,
VCAP_ES0_ACT_HIT_STICKY,
};
#endif /* _OCELOT_VCAP_H_ */
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