diff options
35 files changed, 2049 insertions, 437 deletions
diff --git a/arch/mips/boot/dts/mscc/ocelot.dtsi b/arch/mips/boot/dts/mscc/ocelot.dtsi index f94e8a02ed06..535a98284dcb 100644 --- a/arch/mips/boot/dts/mscc/ocelot.dtsi +++ b/arch/mips/boot/dts/mscc/ocelot.dtsi @@ -134,11 +134,13 @@ <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"; diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index ab3ee5c3fd02..da54363b5c92 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -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; diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h index cc3ec83a600a..d5f46784306e 100644 --- a/drivers/net/dsa/ocelot/felix.h +++ b/drivers/net/dsa/ocelot/felix.h @@ -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; diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index 2e9270c00096..738e61820ccb 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -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, diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c b/drivers/net/dsa/ocelot/seville_vsc9953.c index e28dd600f464..579eb7f2a71b 100644 --- a/drivers/net/dsa/ocelot/seville_vsc9953.c +++ b/drivers/net/dsa/ocelot/seville_vsc9953.c @@ -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, diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 4f1b41569260..3fd5c6cc23af 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -7,6 +7,7 @@ #ifndef _MACB_H #define _MACB_H +#include <linux/clk.h> #include <linux/phylink.h> #include <linux/ptp_clock_kernel.h> #include <linux/net_tstamp.h> @@ -1298,4 +1299,14 @@ static inline bool gem_has_ptp(struct macb *bp) return !!(bp->caps & MACB_CAPS_GEM_HAS_PTP); } +/** + * struct macb_platform_data - platform data for MACB Ethernet used for PCI registration + * @pclk: platform clock + * @hclk: AHB clock + */ +struct macb_platform_data { + struct clk *pclk; + struct clk *hclk; +}; + #endif /* _MACB_H */ diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index f00ad73ea8e3..4b42b2d6398c 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -23,7 +23,6 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/dma-mapping.h> -#include <linux/platform_data/macb.h> #include <linux/platform_device.h> #include <linux/phylink.h> #include <linux/of.h> diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c index 35316c91f523..353393dea639 100644 --- a/drivers/net/ethernet/cadence/macb_pci.c +++ b/drivers/net/ethernet/cadence/macb_pci.c @@ -13,7 +13,6 @@ #include <linux/etherdevice.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/platform_data/macb.h> #include <linux/platform_device.h> #include "macb.h" diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index b9375d96cdbc..974821b9cdc4 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -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" diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c index ec1b6e2572ba..0988bc9aaac5 100644 --- a/drivers/net/ethernet/mscc/ocelot_flower.c +++ b/drivers/net/ethernet/mscc/ocelot_flower.c @@ -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 @@ finished_key_parsing: } /* 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; } diff --git a/drivers/net/ethernet/mscc/ocelot_io.c b/drivers/net/ethernet/mscc/ocelot_io.c index d22711282183..0acb45948418 100644 --- a/drivers/net/ethernet/mscc/ocelot_io.c +++ b/drivers/net/ethernet/mscc/ocelot_io.c @@ -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) { diff --git a/drivers/net/ethernet/mscc/ocelot_s2.h b/drivers/net/ethernet/mscc/ocelot_s2.h deleted file mode 100644 index 80107bec2e45..000000000000 --- a/drivers/net/ethernet/mscc/ocelot_s2.h +++ /dev/null @@ -1,64 +0,0 @@ -/* 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_ */ diff --git a/drivers/net/ethernet/mscc/ocelot_vcap.c b/drivers/net/ethernet/mscc/ocelot_vcap.c index 3ef620faf995..75eca3457e6e 100644 --- a/drivers/net/ethernet/mscc/ocelot_vcap.c +++ b/drivers/net/ethernet/mscc/ocelot_vcap.c @@ -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; } diff --git a/drivers/net/ethernet/mscc/ocelot_vcap.h b/drivers/net/ethernet/mscc/ocelot_vcap.h index 0dfbfc011b2e..7db6da6e35b9 100644 --- a/drivers/net/ethernet/mscc/ocelot_vcap.h +++ b/drivers/net/ethernet/mscc/ocelot_vcap.h @@ -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, diff --git a/drivers/net/ethernet/mscc/ocelot_vsc7514.c b/drivers/net/ethernet/mscc/ocelot_vsc7514.c index d7aef2fb9848..086cddef319f 100644 --- a/drivers/net/ethernet/mscc/ocelot_vsc7514.c +++ b/drivers/net/ethernet/mscc/ocelot_vsc7514.c @@ -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; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c b/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c index d1d6fb6669e5..2749ce009ebc 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c @@ -350,7 +350,7 @@ err_out_port_reset: err_out_reset: ionic_reset(ionic); err_out_teardown: - ionic_dev_teardown(ionic); + del_timer_sync(&ionic->watchdog_timer); pci_clear_master(pdev); /* Don't fail the probe for these errors, keep * the hw interface around for inspection @@ -378,6 +378,8 @@ static void ionic_remove(struct pci_dev *pdev) if (!ionic) return; + del_timer_sync(&ionic->watchdog_timer); + if (ionic->lif) { ionic_devlink_unregister(ionic); ionic_lif_unregister(ionic->lif); @@ -389,7 +391,6 @@ static void ionic_remove(struct pci_dev *pdev) ionic_port_reset(ionic); ionic_reset(ionic); - ionic_dev_teardown(ionic); pci_clear_master(pdev); ionic_unmap_bars(ionic); pci_release_regions(pdev); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.c b/drivers/net/ethernet/pensando/ionic/ionic_dev.c index a02f710200da..545c99b15df8 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.c @@ -19,9 +19,12 @@ static void ionic_watchdog_cb(struct timer_list *t) mod_timer(&ionic->watchdog_timer, round_jiffies(jiffies + ionic->watchdog_period)); + if (!ionic->lif) + return; + hb = ionic_heartbeat_check(ionic); - if (hb >= 0 && ionic->lif) + if (hb >= 0) ionic_link_status_check_request(ionic->lif, false); } @@ -98,11 +101,6 @@ int ionic_dev_setup(struct ionic *ionic) return 0; } -void ionic_dev_teardown(struct ionic *ionic) -{ - del_timer_sync(&ionic->watchdog_timer); -} - /* Devcmd Interface */ int ionic_heartbeat_check(struct ionic *ionic) { diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h index 8842dc4a716f..c109cd5a0471 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h @@ -283,7 +283,6 @@ static inline bool ionic_q_has_space(struct ionic_queue *q, unsigned int want) void ionic_init_devinfo(struct ionic *ionic); int ionic_dev_setup(struct ionic *ionic); -void ionic_dev_teardown(struct ionic *ionic); void ionic_dev_cmd_go(struct ionic_dev *idev, union ionic_dev_cmd *cmd); u8 ionic_dev_cmd_status(struct ionic_dev *idev); diff --git a/include/linux/platform_data/macb.h b/include/linux/platform_data/macb.h deleted file mode 100644 index aa5b5562d6f7..000000000000 --- a/include/linux/platform_data/macb.h +++ /dev/null @@ -1,20 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2004-2006 Atmel Corporation - */ -#ifndef __MACB_PDATA_H__ -#define __MACB_PDATA_H__ - -#include <linux/clk.h> - -/** - * struct macb_platform_data - platform data for MACB Ethernet - * @pclk: platform clock - * @hclk: AHB clock - */ -struct macb_platform_data { - struct clk *pclk; - struct clk *hclk; -}; - -#endif /* __MACB_PDATA_H__ */ diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index dc763ca9413c..7338b3865a2a 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h @@ -110,7 +110,7 @@ struct inet_connection_sock { __u8 pending; /* ACK is pending */ __u8 quick; /* Scheduled number of quick acks */ __u8 pingpong; /* The session is interactive */ - __u8 blocked; /* Delayed ACK was blocked by socket lock */ + __u8 retry; /* Number of attempts */ __u32 ato; /* Predicted tick of soft clock */ unsigned long timeout; /* Currently scheduled timeout */ __u32 lrcvtime; /* timestamp of last received data packet */ @@ -198,7 +198,8 @@ static inline void inet_csk_clear_xmit_timer(struct sock *sk, const int what) sk_stop_timer(sk, &icsk->icsk_retransmit_timer); #endif } else if (what == ICSK_TIME_DACK) { - icsk->icsk_ack.blocked = icsk->icsk_ack.pending = 0; + icsk->icsk_ack.pending = 0; + icsk->icsk_ack.retry = 0; #ifdef INET_CSK_CLEAR_TIMERS sk_stop_timer(sk, &icsk->icsk_delack_timer); #endif diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h index 3093385f6147..0c40122dcb88 100644 --- a/include/soc/mscc/ocelot.h +++ b/include/soc/mscc/ocelot.h @@ -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, diff --git a/include/soc/mscc/ocelot_vcap.h b/include/soc/mscc/ocelot_vcap.h index 5748373ab4d3..96300adf3648 100644 --- a/include/soc/mscc/ocelot_vcap.h +++ b/include/soc/mscc/ocelot_vcap.h @@ -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_ */ diff --git a/net/dccp/timer.c b/net/dccp/timer.c index 927c796d7682..a934d2932373 100644 --- a/net/dccp/timer.c +++ b/net/dccp/timer.c @@ -176,7 +176,6 @@ static void dccp_delack_timer(struct timer_list *t) bh_lock_sock(sk); if (sock_owned_by_user(sk)) { /* Try again later. */ - icsk->icsk_ack.blocked = 1; __NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOCKED); sk_reset_timer(sk, &icsk->icsk_delack_timer, jiffies + TCP_DELACK_MIN); diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index b457dd2d6c75..4148f5f78f31 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -564,7 +564,7 @@ void inet_csk_clear_xmit_timers(struct sock *sk) { struct inet_connection_sock *icsk = inet_csk(sk); - icsk->icsk_pending = icsk->icsk_ack.pending = icsk->icsk_ack.blocked = 0; + icsk->icsk_pending = icsk->icsk_ack.pending = 0; sk_stop_timer(sk, &icsk->icsk_retransmit_timer); sk_stop_timer(sk, &icsk->icsk_delack_timer); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 2a8bfa89a515..ed2805564424 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1538,10 +1538,8 @@ void tcp_cleanup_rbuf(struct sock *sk, int copied) if (inet_csk_ack_scheduled(sk)) { const struct inet_connection_sock *icsk = inet_csk(sk); - /* Delayed ACKs frequently hit locked sockets during bulk - * receive. */ - if (icsk->icsk_ack.blocked || - /* Once-per-two-segments ACK was not sent by tcp_input.c */ + + if (/* Once-per-two-segments ACK was not sent by tcp_input.c */ tp->rcv_nxt - tp->rcv_wup > icsk->icsk_ack.rcv_mss || /* * If this read emptied read buffer, we send ACK, if diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 386978dcd318..bf48cd73e967 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -3911,11 +3911,8 @@ void tcp_send_delayed_ack(struct sock *sk) /* Use new timeout only if there wasn't a older one earlier. */ if (icsk->icsk_ack.pending & ICSK_ACK_TIMER) { - /* If delack timer was blocked or is about to expire, - * send ACK now. - */ - if (icsk->icsk_ack.blocked || - time_before_eq(icsk->icsk_ack.timeout, jiffies + (ato >> 2))) { + /* If delack timer is about to expire, send ACK now. */ + if (time_before_eq(icsk->icsk_ack.timeout, jiffies + (ato >> 2))) { tcp_send_ack(sk); return; } @@ -3944,10 +3941,15 @@ void __tcp_send_ack(struct sock *sk, u32 rcv_nxt) buff = alloc_skb(MAX_TCP_HEADER, sk_gfp_mask(sk, GFP_ATOMIC | __GFP_NOWARN)); if (unlikely(!buff)) { + struct inet_connection_sock *icsk = inet_csk(sk); + unsigned long delay; + + delay = TCP_DELACK_MAX << icsk->icsk_ack.retry; + if (delay < TCP_RTO_MAX) + icsk->icsk_ack.retry++; inet_csk_schedule_ack(sk); - inet_csk(sk)->icsk_ack.ato = TCP_ATO_MIN; - inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, - TCP_DELACK_MAX, TCP_RTO_MAX); + icsk->icsk_ack.ato = TCP_ATO_MIN; + inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, delay, TCP_RTO_MAX); return; } diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 0c08c420fbc2..6c62b9ea1320 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -331,7 +331,6 @@ static void tcp_delack_timer(struct timer_list *t) if (!sock_owned_by_user(sk)) { tcp_delack_timer_handler(sk); } else { - icsk->icsk_ack.blocked = 1; __NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOCKED); /* deleguate our work to tcp_release_cb() */ if (!test_and_set_bit(TCP_DELACK_TIMER_DEFERRED, &sk->sk_tsq_flags)) diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_ets_strict.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_ets_strict.sh index 6d1790b5de7a..e9f8718af979 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/qos_ets_strict.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/qos_ets_strict.sh @@ -147,17 +147,26 @@ switch_create() # Make sure that ingress quotas are smaller than egress so that there is # room for both streams of traffic to be admitted to shared buffer. + devlink_pool_size_thtype_save 0 devlink_pool_size_thtype_set 0 dynamic 10000000 + devlink_pool_size_thtype_save 4 devlink_pool_size_thtype_set 4 dynamic 10000000 + devlink_port_pool_th_save $swp1 0 devlink_port_pool_th_set $swp1 0 6 + devlink_tc_bind_pool_th_save $swp1 1 ingress devlink_tc_bind_pool_th_set $swp1 1 ingress 0 6 + devlink_port_pool_th_save $swp2 0 devlink_port_pool_th_set $swp2 0 6 + devlink_tc_bind_pool_th_save $swp2 2 ingress devlink_tc_bind_pool_th_set $swp2 2 ingress 0 6 + devlink_tc_bind_pool_th_save $swp3 1 egress devlink_tc_bind_pool_th_set $swp3 1 egress 4 7 + devlink_tc_bind_pool_th_save $swp3 2 egress devlink_tc_bind_pool_th_set $swp3 2 egress 4 7 + devlink_port_pool_th_save $swp3 4 devlink_port_pool_th_set $swp3 4 7 } diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_headroom.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_headroom.sh new file mode 100755 index 000000000000..27de3d9ed08e --- /dev/null +++ b/tools/testing/selftests/drivers/net/mlxsw/qos_headroom.sh @@ -0,0 +1,379 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +ALL_TESTS=" + test_defaults + test_dcb_ets + test_mtu + test_pfc + test_int_buf + test_tc_priomap + test_tc_mtu + test_tc_sizes + test_tc_int_buf +" + +lib_dir=$(dirname $0)/../../../net/forwarding + +NUM_NETIFS=0 +source $lib_dir/lib.sh +source $lib_dir/devlink_lib.sh +source qos_lib.sh + +swp=$NETIF_NO_CABLE + +cleanup() +{ + pre_cleanup +} + +get_prio_pg() +{ + __mlnx_qos -i $swp | sed -n '/^PFC/,/^[^[:space:]]/p' | + grep buffer | sed 's/ \+/ /g' | cut -d' ' -f 2- +} + +get_prio_pfc() +{ + __mlnx_qos -i $swp | sed -n '/^PFC/,/^[^[:space:]]/p' | + grep enabled | sed 's/ \+/ /g' | cut -d' ' -f 2- +} + +get_prio_tc() +{ + __mlnx_qos -i $swp | sed -n '/^tc/,$p' | + awk '/^tc/ { TC = $2 } + /priority:/ { PRIO[$2]=TC } + END { + for (i in PRIO) + printf("%d ", PRIO[i]) + }' +} + +get_buf_size() +{ + local idx=$1; shift + + __mlnx_qos -i $swp | grep Receive | sed 's/.*: //' | cut -d, -f $((idx + 1)) +} + +get_tot_size() +{ + __mlnx_qos -i $swp | grep Receive | sed 's/.*total_size=//' +} + +check_prio_pg() +{ + local expect=$1; shift + + local current=$(get_prio_pg) + test "$current" = "$expect" + check_err $? "prio2buffer is '$current', expected '$expect'" +} + +check_prio_pfc() +{ + local expect=$1; shift + + local current=$(get_prio_pfc) + test "$current" = "$expect" + check_err $? "prio PFC is '$current', expected '$expect'" +} + +check_prio_tc() +{ + local expect=$1; shift + + local current=$(get_prio_tc) + test "$current" = "$expect" + check_err $? "prio_tc is '$current', expected '$expect'" +} + +__check_buf_size() +{ + local idx=$1; shift + local expr=$1; shift + local what=$1; shift + + local current=$(get_buf_size $idx) + ((current $expr)) + check_err $? "${what}buffer $idx size is '$current', expected '$expr'" + echo $current +} + +check_buf_size() +{ + __check_buf_size "$@" > /dev/null +} + +test_defaults() +{ + RET=0 + + check_prio_pg "0 0 0 0 0 0 0 0 " + check_prio_tc "0 0 0 0 0 0 0 0 " + check_prio_pfc "0 0 0 0 0 0 0 0 " + + log_test "Default headroom configuration" +} + +test_dcb_ets() +{ + RET=0 + + __mlnx_qos -i $swp --prio_tc=0,2,4,6,1,3,5,7 > /dev/null + + check_prio_pg "0 2 4 6 1 3 5 7 " + check_prio_tc "0 2 4 6 1 3 5 7 " + check_prio_pfc "0 0 0 0 0 0 0 0 " + + __mlnx_qos -i $swp --prio_tc=0,0,0,0,0,0,0,0 > /dev/null + + check_prio_pg "0 0 0 0 0 0 0 0 " + check_prio_tc "0 0 0 0 0 0 0 0 " + + __mlnx_qos -i $swp --prio2buffer=1,3,5,7,0,2,4,6 &> /dev/null + check_fail $? "prio2buffer accepted in DCB mode" + + log_test "Configuring headroom through ETS" +} + +test_mtu() +{ + local what=$1; shift + local buf0size_2 + local buf0size + + RET=0 + buf0size=$(__check_buf_size 0 "> 0") + + mtu_set $swp 3000 + buf0size_2=$(__check_buf_size 0 "> $buf0size" "MTU 3000: ") + mtu_restore $swp + + mtu_set $swp 6000 + check_buf_size 0 "> $buf0size_2" "MTU 6000: " + mtu_restore $swp + + check_buf_size 0 "== $buf0size" + + log_test "${what}MTU impacts buffer size" +} + +test_tc_mtu() +{ + # In TC mode, MTU still impacts the threshold below which a buffer is + # not permitted to go. + + tc qdisc replace dev $swp root handle 1: bfifo limit 1.5M + test_mtu "TC: " + tc qdisc delete dev $swp root +} + +test_pfc() +{ + RET=0 + + __mlnx_qos -i $swp --prio_tc=0,0,0,0,0,1,2,3 > /dev/null + + local buf0size=$(get_buf_size 0) + local buf1size=$(get_buf_size 1) + local buf2size=$(get_buf_size 2) + local buf3size=$(get_buf_size 3) + check_buf_size 0 "> 0" + check_buf_size 1 "> 0" + check_buf_size 2 "> 0" + check_buf_size 3 "> 0" + check_buf_size 4 "== 0" + check_buf_size 5 "== 0" + check_buf_size 6 "== 0" + check_buf_size 7 "== 0" + + log_test "Buffer size sans PFC" + + RET=0 + + __mlnx_qos -i $swp --pfc=0,0,0,0,0,1,1,1 --cable_len=0 > /dev/null + + check_prio_pg "0 0 0 0 0 1 2 3 " + check_prio_pfc "0 0 0 0 0 1 1 1 " + check_buf_size 0 "== $buf0size" + check_buf_size 1 "> $buf1size" + check_buf_size 2 "> $buf2size" + check_buf_size 3 "> $buf3size" + + local buf1size=$(get_buf_size 1) + check_buf_size 2 "== $buf1size" + check_buf_size 3 "== $buf1size" + + log_test "PFC: Cable length 0" + + RET=0 + + __mlnx_qos -i $swp --pfc=0,0,0,0,0,1,1,1 --cable_len=1000 > /dev/null + + check_buf_size 0 "== $buf0size" + check_buf_size 1 "> $buf1size" + check_buf_size 2 "> $buf1size" + check_buf_size 3 "> $buf1size" + + log_test "PFC: Cable length 1000" + + RET=0 + + __mlnx_qos -i $swp --pfc=0,0,0,0,0,0,0,0 --cable_len=0 > /dev/null + __mlnx_qos -i $swp --prio_tc=0,0,0,0,0,0,0,0 > /dev/null + + check_prio_pg "0 0 0 0 0 0 0 0 " + check_prio_tc "0 0 0 0 0 0 0 0 " + check_buf_size 0 "> 0" + check_buf_size 1 "== 0" + check_buf_size 2 "== 0" + check_buf_size 3 "== 0" + check_buf_size 4 "== 0" + check_buf_size 5 "== 0" + check_buf_size 6 "== 0" + check_buf_size 7 "== 0" + + log_test "PFC: Restore defaults" +} + +test_tc_priomap() +{ + RET=0 + + __mlnx_qos -i $swp --prio_tc=0,1,2,3,4,5,6,7 > /dev/null + check_prio_pg "0 1 2 3 4 5 6 7 " + + tc qdisc replace dev $swp root handle 1: bfifo limit 1.5M + check_prio_pg "0 0 0 0 0 0 0 0 " + + __mlnx_qos -i $swp --prio2buffer=1,3,5,7,0,2,4,6 > /dev/null + check_prio_pg "1 3 5 7 0 2 4 6 " + + tc qdisc delete dev $swp root + check_prio_pg "0 1 2 3 4 5 6 7 " + + # Clean up. + tc qdisc replace dev $swp root handle 1: bfifo limit 1.5M + __mlnx_qos -i $swp --prio2buffer=0,0,0,0,0,0,0,0 > /dev/null + tc qdisc delete dev $swp root + __mlnx_qos -i $swp --prio_tc=0,0,0,0,0,0,0,0 > /dev/null + + log_test "TC: priomap" +} + +test_tc_sizes() +{ + local cell_size=$(devlink_cell_size_get) + local size=$((cell_size * 1000)) + + RET=0 + + __mlnx_qos -i $swp --buffer_size=$size,0,0,0,0,0,0,0 &> /dev/null + check_fail $? "buffer_size should fail before qdisc is added" + + tc qdisc replace dev $swp root handle 1: bfifo limit 1.5M + + __mlnx_qos -i $swp --buffer_size=$size,0,0,0,0,0,0,0 > /dev/null + check_err $? "buffer_size should pass after qdisc is added" + check_buf_size 0 "== $size" "set size: " + + mtu_set $swp 6000 + check_buf_size 0 "== $size" "set MTU: " + mtu_restore $swp + + __mlnx_qos -i $swp --buffer_size=0,0,0,0,0,0,0,0 > /dev/null + + # After replacing the qdisc for the same kind, buffer_size still has to + # work. + tc qdisc replace dev $swp root handle 1: bfifo limit 1M + + __mlnx_qos -i $swp --buffer_size=$size,0,0,0,0,0,0,0 > /dev/null + check_buf_size 0 "== $size" "post replace, set size: " + + __mlnx_qos -i $swp --buffer_size=0,0,0,0,0,0,0,0 > /dev/null + + # Likewise after replacing for a different kind. + tc qdisc replace dev $swp root handle 2: prio bands 8 + + __mlnx_qos -i $swp --buffer_size=$size,0,0,0,0,0,0,0 > /dev/null + check_buf_size 0 "== $size" "post replace different kind, set size: " + + tc qdisc delete dev $swp root + + __mlnx_qos -i $swp --buffer_size=$size,0,0,0,0,0,0,0 &> /dev/null + check_fail $? "buffer_size should fail after qdisc is deleted" + + log_test "TC: buffer size" +} + +test_int_buf() +{ + local what=$1; shift + + RET=0 + + local buf0size=$(get_buf_size 0) + local tot_size=$(get_tot_size) + + # Size of internal buffer and buffer 9. + local dsize=$((tot_size - buf0size)) + + tc qdisc add dev $swp clsact + tc filter add dev $swp egress matchall skip_sw action mirred egress mirror dev $swp + + local buf0size_2=$(get_buf_size 0) + local tot_size_2=$(get_tot_size) + local dsize_2=$((tot_size_2 - buf0size_2)) + + # Egress SPAN should have added to the "invisible" buffer configuration. + ((dsize_2 > dsize)) + check_err $? "Invisible buffers account for '$dsize_2', expected '> $dsize'" + + mtu_set $swp 3000 + + local buf0size_3=$(get_buf_size 0) + local tot_size_3=$(get_tot_size) + local dsize_3=$((tot_size_3 - buf0size_3)) + + # MTU change might change buffer 0, which will show at total, but the + # hidden buffers should stay the same size. + ((dsize_3 == dsize_2)) + check_err $? "MTU change: Invisible buffers account for '$dsize_3', expected '== $dsize_2'" + + mtu_restore $swp + tc qdisc del dev $swp clsact + + # After SPAN removal, hidden buffers should be back to the original sizes. + local buf0size_4=$(get_buf_size 0) + local tot_size_4=$(get_tot_size) + local dsize_4=$((tot_size_4 - buf0size_4)) + ((dsize_4 == dsize)) + check_err $? "SPAN removed: Invisible buffers account for '$dsize_4', expected '== $dsize'" + + log_test "${what}internal buffer size" +} + +test_tc_int_buf() +{ + local cell_size=$(devlink_cell_size_get) + local size=$((cell_size * 1000)) + + tc qdisc replace dev $swp root handle 1: bfifo limit 1.5M + test_int_buf "TC: " + + __mlnx_qos -i $swp --buffer_size=$size,0,0,0,0,0,0,0 > /dev/null + test_int_buf "TC+buffsize: " + + __mlnx_qos -i $swp --buffer_size=0,0,0,0,0,0,0,0 > /dev/null + tc qdisc delete dev $swp root +} + +trap cleanup EXIT + +bail_on_lldpad +setup_wait +tests_run + +exit $EXIT_STATUS diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_lib.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_lib.sh index faa51012cdac..0bf76f13c030 100644 --- a/tools/testing/selftests/drivers/net/mlxsw/qos_lib.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/qos_lib.sh @@ -82,3 +82,17 @@ bail_on_lldpad() fi fi } + +__mlnx_qos() +{ + local err + + mlnx_qos "$@" 2>/dev/null + err=$? + + if ((err)); then + echo "Error ($err) in mlnx_qos $@" >/dev/stderr + fi + + return $err +} diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh index b025daea062d..8f164c80e215 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh @@ -145,12 +145,17 @@ switch_create() # Make sure that ingress quotas are smaller than egress so that there is # room for both streams of traffic to be admitted to shared buffer. + devlink_port_pool_th_save $swp1 0 devlink_port_pool_th_set $swp1 0 5 + devlink_tc_bind_pool_th_save $swp1 0 ingress devlink_tc_bind_pool_th_set $swp1 0 ingress 0 5 + devlink_port_pool_th_save $swp2 0 devlink_port_pool_th_set $swp2 0 5 + devlink_tc_bind_pool_th_save $swp2 1 ingress devlink_tc_bind_pool_th_set $swp2 1 ingress 0 5 + devlink_port_pool_th_save $swp3 4 devlink_port_pool_th_set $swp3 4 12 } diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_pfc.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_pfc.sh new file mode 100755 index 000000000000..4d900bc1f76c --- /dev/null +++ b/tools/testing/selftests/drivers/net/mlxsw/qos_pfc.sh @@ -0,0 +1,403 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# This test injects a 10-MB burst of traffic with VLAN tag and 802.1p priority +# of 1. This stream is consistently prioritized as priority 1, is put to PG +# buffer 1, and scheduled at TC 1. +# +# - the stream first ingresses through $swp1, where it is forwarded to $swp3 +# +# - then it ingresses through $swp4. Here it is put to a lossless buffer and put +# to a small pool ("PFC pool"). The traffic is forwarded to $swp2, which is +# shaped, and thus the PFC pool eventually fills, therefore the headroom +# fills, and $swp3 is paused. +# +# - since $swp3 now can't send traffic, the traffic ingressing $swp1 is kept at +# a pool ("overflow pool"). The overflow pool needs to be large enough to +# contain the whole burst. +# +# - eventually the PFC pool gets some traffic out, headroom therefore gets some +# traffic to the pool, and $swp3 is unpaused again. This way the traffic is +# gradually forwarded from the overflow pool, through the PFC pool, out of +# $swp2, and eventually to $h2. +# +# - if PFC works, all lossless flow packets that ingress through $swp1 should +# also be seen ingressing $h2. If it doesn't, there will be drops due to +# discrepancy between the speeds of $swp1 and $h2. +# +# - it should all play out relatively quickly, so that SLL and HLL will not +# cause drops. +# +# +-----------------------+ +# | H1 | +# | + $h1.111 | +# | | 192.0.2.33/28 | +# | | | +# | + $h1 | +# +---|-------------------+ +--------------------+ +# | | | +# +---|----------------------|--------------------|---------------------------+ +# | + $swp1 $swp3 + + $swp4 | +# | | iPOOL1 iPOOL0 | | iPOOL2 | +# | | ePOOL4 ePOOL5 | | ePOOL4 | +# | | 1Gbps | | 1Gbps | +# | | PFC:enabled=1 | | PFC:enabled=1 | +# | +-|----------------------|-+ +-|------------------------+ | +# | | + $swp1.111 $swp3.111 + | | + $swp4.111 | | +# | | | | | | +# | | BR1 | | BR2 | | +# | | | | | | +# | | | | + $swp2.111 | | +# | +--------------------------+ +---------|----------------+ | +# | | | +# | iPOOL0: 500KB dynamic | | +# | iPOOL1: 10MB static | | +# | iPOOL2: 1MB static + $swp2 | +# | ePOOL4: 500KB dynamic | iPOOL0 | +# | ePOOL5: 10MB static | ePOOL6 | +# | ePOOL6: "infinite" static | 200Mbps shaper | +# +-------------------------------------------------------|-------------------+ +# | +# +---|-------------------+ +# | + $h2 H2 | +# | | | +# | + $h2.111 | +# | 192.0.2.34/28 | +# +-----------------------+ +# +# iPOOL0+ePOOL4 is a helper pool for control traffic etc. +# iPOOL1+ePOOL5 are overflow pools. +# iPOOL2+ePOOL6 are PFC pools. + +ALL_TESTS=" + ping_ipv4 + test_qos_pfc +" + +lib_dir=$(dirname $0)/../../../net/forwarding + +NUM_NETIFS=6 +source $lib_dir/lib.sh +source $lib_dir/devlink_lib.sh +source qos_lib.sh + +_1KB=1000 +_100KB=$((100 * _1KB)) +_500KB=$((500 * _1KB)) +_1MB=$((1000 * _1KB)) +_10MB=$((10 * _1MB)) + +h1_create() +{ + simple_if_init $h1 + mtu_set $h1 10000 + + vlan_create $h1 111 v$h1 192.0.2.33/28 +} + +h1_destroy() +{ + vlan_destroy $h1 111 + + mtu_restore $h1 + simple_if_fini $h1 +} + +h2_create() +{ + simple_if_init $h2 + mtu_set $h2 10000 + + vlan_create $h2 111 v$h2 192.0.2.34/28 +} + +h2_destroy() +{ + vlan_destroy $h2 111 + + mtu_restore $h2 + simple_if_fini $h2 +} + +switch_create() +{ + # pools + # ----- + + devlink_pool_size_thtype_save 0 + devlink_pool_size_thtype_save 4 + devlink_pool_size_thtype_save 1 + devlink_pool_size_thtype_save 5 + devlink_pool_size_thtype_save 2 + devlink_pool_size_thtype_save 6 + + devlink_port_pool_th_save $swp1 1 + devlink_port_pool_th_save $swp2 6 + devlink_port_pool_th_save $swp3 5 + devlink_port_pool_th_save $swp4 2 + + devlink_tc_bind_pool_th_save $swp1 1 ingress + devlink_tc_bind_pool_th_save $swp2 1 egress + devlink_tc_bind_pool_th_save $swp3 1 egress + devlink_tc_bind_pool_th_save $swp4 1 ingress + + # Control traffic pools. Just reduce the size. Keep them dynamic so that + # we don't need to change all the uninteresting quotas. + devlink_pool_size_thtype_set 0 dynamic $_500KB + devlink_pool_size_thtype_set 4 dynamic $_500KB + + # Overflow pools. + devlink_pool_size_thtype_set 1 static $_10MB + devlink_pool_size_thtype_set 5 static $_10MB + + # PFC pools. As per the writ, the size of egress PFC pool should be + # infinice, but actually it just needs to be large enough to not matter + # in practice, so reuse the 10MB limit. + devlink_pool_size_thtype_set 2 static $_1MB + devlink_pool_size_thtype_set 6 static $_10MB + + # $swp1 + # ----- + + ip link set dev $swp1 up + mtu_set $swp1 10000 + vlan_create $swp1 111 + ip link set dev $swp1.111 type vlan ingress-qos-map 0:0 1:1 + + devlink_port_pool_th_set $swp1 1 $_10MB + devlink_tc_bind_pool_th_set $swp1 1 ingress 1 $_10MB + + # Configure qdisc so that we can configure PG and therefore pool + # assignment. + tc qdisc replace dev $swp1 root handle 1: \ + ets bands 8 strict 8 priomap 7 6 + __mlnx_qos -i $swp1 --prio2buffer=0,1,0,0,0,0,0,0 >/dev/null + + # $swp2 + # ----- + + ip link set dev $swp2 up + mtu_set $swp2 10000 + vlan_create $swp2 111 + ip link set dev $swp2.111 type vlan egress-qos-map 0:0 1:1 + + devlink_port_pool_th_set $swp2 6 $_10MB + devlink_tc_bind_pool_th_set $swp2 1 egress 6 $_10MB + + # prio 0->TC0 (band 7), 1->TC1 (band 6). TC1 is shaped. + tc qdisc replace dev $swp2 root handle 1: \ + ets bands 8 strict 8 priomap 7 6 + tc qdisc replace dev $swp2 parent 1:7 handle 17: \ + tbf rate 200Mbit burst 131072 limit 1M + + # $swp3 + # ----- + + ip link set dev $swp3 up + mtu_set $swp3 10000 + vlan_create $swp3 111 + ip link set dev $swp3.111 type vlan egress-qos-map 0:0 1:1 + + devlink_port_pool_th_set $swp3 5 $_10MB + devlink_tc_bind_pool_th_set $swp3 1 egress 5 $_10MB + + # prio 0->TC0 (band 7), 1->TC1 (band 6) + tc qdisc replace dev $swp3 root handle 1: \ + ets bands 8 strict 8 priomap 7 6 + + # Need to enable PFC so that PAUSE takes effect. Therefore need to put + # the lossless prio into a buffer of its own. Don't bother with buffer + # sizes though, there is not going to be any pressure in the "backward" + # direction. + __mlnx_qos -i $swp3 --prio2buffer=0,1,0,0,0,0,0,0 >/dev/null + __mlnx_qos -i $swp3 --pfc=0,1,0,0,0,0,0,0 >/dev/null + + # $swp4 + # ----- + + ip link set dev $swp4 up + mtu_set $swp4 10000 + vlan_create $swp4 111 + ip link set dev $swp4.111 type vlan ingress-qos-map 0:0 1:1 + + devlink_port_pool_th_set $swp4 2 $_1MB + devlink_tc_bind_pool_th_set $swp4 1 ingress 2 $_1MB + + # Configure qdisc so that we can hand-tune headroom. + tc qdisc replace dev $swp4 root handle 1: \ + ets bands 8 strict 8 priomap 7 6 + __mlnx_qos -i $swp4 --prio2buffer=0,1,0,0,0,0,0,0 >/dev/null + __mlnx_qos -i $swp4 --pfc=0,1,0,0,0,0,0,0 >/dev/null + # PG0 will get autoconfigured to Xoff, give PG1 arbitrarily 100K, which + # is (-2*MTU) about 80K of delay provision. + __mlnx_qos -i $swp3 --buffer_size=0,$_100KB,0,0,0,0,0,0 >/dev/null + + # bridges + # ------- + + ip link add name br1 type bridge vlan_filtering 0 + ip link set dev $swp1.111 master br1 + ip link set dev $swp3.111 master br1 + ip link set dev br1 up + + ip link add name br2 type bridge vlan_filtering 0 + ip link set dev $swp2.111 master br2 + ip link set dev $swp4.111 master br2 + ip link set dev br2 up +} + +switch_destroy() +{ + # Do this first so that we can reset the limits to values that are only + # valid for the original static / dynamic setting. + devlink_pool_size_thtype_restore 6 + devlink_pool_size_thtype_restore 5 + devlink_pool_size_thtype_restore 4 + devlink_pool_size_thtype_restore 2 + devlink_pool_size_thtype_restore 1 + devlink_pool_size_thtype_restore 0 + + # bridges + # ------- + + ip link set dev br2 down + ip link set dev $swp4.111 nomaster + ip link set dev $swp2.111 nomaster + ip link del dev br2 + + ip link set dev br1 down + ip link set dev $swp3.111 nomaster + ip link set dev $swp1.111 nomaster + ip link del dev br1 + + # $swp4 + # ----- + + __mlnx_qos -i $swp4 --buffer_size=0,0,0,0,0,0,0,0 >/dev/null + __mlnx_qos -i $swp4 --pfc=0,0,0,0,0,0,0,0 >/dev/null + __mlnx_qos -i $swp4 --prio2buffer=0,0,0,0,0,0,0,0 >/dev/null + tc qdisc del dev $swp4 root + + devlink_tc_bind_pool_th_restore $swp4 1 ingress + devlink_port_pool_th_restore $swp4 2 + + vlan_destroy $swp4 111 + mtu_restore $swp4 + ip link set dev $swp4 down + + # $swp3 + # ----- + + __mlnx_qos -i $swp3 --pfc=0,0,0,0,0,0,0,0 >/dev/null + __mlnx_qos -i $swp3 --prio2buffer=0,0,0,0,0,0,0,0 >/dev/null + tc qdisc del dev $swp3 root + + devlink_tc_bind_pool_th_restore $swp3 1 egress + devlink_port_pool_th_restore $swp3 5 + + vlan_destroy $swp3 111 + mtu_restore $swp3 + ip link set dev $swp3 down + + # $swp2 + # ----- + + tc qdisc del dev $swp2 parent 1:7 + tc qdisc del dev $swp2 root + + devlink_tc_bind_pool_th_restore $swp2 1 egress + devlink_port_pool_th_restore $swp2 6 + + vlan_destroy $swp2 111 + mtu_restore $swp2 + ip link set dev $swp2 down + + # $swp1 + # ----- + + __mlnx_qos -i $swp1 --prio2buffer=0,0,0,0,0,0,0,0 >/dev/null + tc qdisc del dev $swp1 root + + devlink_tc_bind_pool_th_restore $swp1 1 ingress + devlink_port_pool_th_restore $swp1 1 + + vlan_destroy $swp1 111 + mtu_restore $swp1 + ip link set dev $swp1 down +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + swp3=${NETIFS[p5]} + swp4=${NETIFS[p6]} + + h2mac=$(mac_get $h2) + + vrf_prepare + + h1_create + h2_create + switch_create +} + +cleanup() +{ + pre_cleanup + + switch_destroy + h2_destroy + h1_destroy + + vrf_cleanup +} + +ping_ipv4() +{ + ping_test $h1 192.0.2.34 +} + +test_qos_pfc() +{ + RET=0 + + # 10M pool, each packet is 8K of payload + headers + local pkts=$((_10MB / 8050)) + local size=$((pkts * 8050)) + local in0=$(ethtool_stats_get $swp1 rx_octets_prio_1) + local out0=$(ethtool_stats_get $swp2 tx_octets_prio_1) + + $MZ $h1 -p 8000 -Q 1:111 -A 192.0.2.33 -B 192.0.2.34 \ + -a own -b $h2mac -c $pkts -t udp -q + sleep 2 + + local in1=$(ethtool_stats_get $swp1 rx_octets_prio_1) + local out1=$(ethtool_stats_get $swp2 tx_octets_prio_1) + + local din=$((in1 - in0)) + local dout=$((out1 - out0)) + + local pct_in=$((din * 100 / size)) + + ((pct_in > 95 && pct_in < 105)) + check_err $? "Relative ingress out of expected bounds, $pct_in% should be 100%" + + ((dout == din)) + check_err $? "$((din - dout)) bytes out of $din ingressed got lost" + + log_test "PFC" +} + +trap cleanup EXIT + +bail_on_lldpad +setup_prepare +setup_wait +tests_run + +exit $EXIT_STATUS diff --git a/tools/testing/selftests/drivers/net/mlxsw/sch_ets.sh b/tools/testing/selftests/drivers/net/mlxsw/sch_ets.sh index 94c37124a840..af64bc9ea8ab 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/sch_ets.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/sch_ets.sh @@ -27,11 +27,17 @@ switch_create() # amount of traffic that is admitted to the shared buffers. This makes # sure that there is always enough traffic of all types to select from # for the DWRR process. + devlink_port_pool_th_save $swp1 0 devlink_port_pool_th_set $swp1 0 12 + devlink_tc_bind_pool_th_save $swp1 0 ingress devlink_tc_bind_pool_th_set $swp1 0 ingress 0 12 + devlink_port_pool_th_save $swp2 4 devlink_port_pool_th_set $swp2 4 12 + devlink_tc_bind_pool_th_save $swp2 7 egress devlink_tc_bind_pool_th_set $swp2 7 egress 4 5 + devlink_tc_bind_pool_th_save $swp2 6 egress devlink_tc_bind_pool_th_set $swp2 6 egress 4 5 + devlink_tc_bind_pool_th_save $swp2 5 egress devlink_tc_bind_pool_th_set $swp2 5 egress 4 5 # Note: sch_ets_core.sh uses VLAN ingress-qos-map to assign packet diff --git a/tools/testing/selftests/drivers/net/mlxsw/sch_red_core.sh b/tools/testing/selftests/drivers/net/mlxsw/sch_red_core.sh index 517297a14ecf..b0cb1aaffdda 100644 --- a/tools/testing/selftests/drivers/net/mlxsw/sch_red_core.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/sch_red_core.sh @@ -208,6 +208,7 @@ switch_create() ip link set dev br2_11 up local size=$(devlink_pool_size_thtype 0 | cut -d' ' -f 1) + devlink_port_pool_th_save $swp3 8 devlink_port_pool_th_set $swp3 8 $size } diff --git a/tools/testing/selftests/net/forwarding/devlink_lib.sh b/tools/testing/selftests/net/forwarding/devlink_lib.sh index 75fe24bcb9cd..9c12c4fd3afc 100644 --- a/tools/testing/selftests/net/forwarding/devlink_lib.sh +++ b/tools/testing/selftests/net/forwarding/devlink_lib.sh @@ -5,7 +5,7 @@ # Defines if [[ ! -v DEVLINK_DEV ]]; then - DEVLINK_DEV=$(devlink port show "${NETIFS[p1]}" -j \ + DEVLINK_DEV=$(devlink port show "${NETIFS[p1]:-$NETIF_NO_CABLE}" -j \ | jq -r '.port | keys[]' | cut -d/ -f-2) if [ -z "$DEVLINK_DEV" ]; then echo "SKIP: ${NETIFS[p1]} has no devlink device registered for it" @@ -117,6 +117,12 @@ devlink_reload() declare -A DEVLINK_ORIG +# Changing pool type from static to dynamic causes reinterpretation of threshold +# values. They therefore need to be saved before pool type is changed, then the +# pool type can be changed, and then the new values need to be set up. Therefore +# instead of saving the current state implicitly in the _set call, provide +# functions for all three primitives: save, set, and restore. + devlink_port_pool_threshold() { local port=$1; shift @@ -126,14 +132,21 @@ devlink_port_pool_threshold() | jq '.port_pool."'"$port"'"[].threshold' } -devlink_port_pool_th_set() +devlink_port_pool_th_save() { local port=$1; shift local pool=$1; shift - local th=$1; shift local key="port_pool($port,$pool).threshold" DEVLINK_ORIG[$key]=$(devlink_port_pool_threshold $port $pool) +} + +devlink_port_pool_th_set() +{ + local port=$1; shift + local pool=$1; shift + local th=$1; shift + devlink sb port pool set $port pool $pool th $th } @@ -142,8 +155,13 @@ devlink_port_pool_th_restore() local port=$1; shift local pool=$1; shift local key="port_pool($port,$pool).threshold" + local -a orig=(${DEVLINK_ORIG[$key]}) - devlink sb port pool set $port pool $pool th ${DEVLINK_ORIG[$key]} + if [[ -z $orig ]]; then + echo "WARNING: Mismatched devlink_port_pool_th_restore" + else + devlink sb port pool set $port pool $pool th $orig + fi } devlink_pool_size_thtype() @@ -154,14 +172,20 @@ devlink_pool_size_thtype() | jq -r '.pool[][] | (.size, .thtype)' } +devlink_pool_size_thtype_save() +{ + local pool=$1; shift + local key="pool($pool).size_thtype" + + DEVLINK_ORIG[$key]=$(devlink_pool_size_thtype $pool) +} + devlink_pool_size_thtype_set() { local pool=$1; shift local thtype=$1; shift local size=$1; shift - local key="pool($pool).size_thtype" - DEVLINK_ORIG[$key]=$(devlink_pool_size_thtype $pool) devlink sb pool set "$DEVLINK_DEV" pool $pool size $size thtype $thtype } @@ -171,8 +195,12 @@ devlink_pool_size_thtype_restore() local key="pool($pool).size_thtype" local -a orig=(${DEVLINK_ORIG[$key]}) - devlink sb pool set "$DEVLINK_DEV" pool $pool \ - size ${orig[0]} thtype ${orig[1]} + if [[ -z ${orig[0]} ]]; then + echo "WARNING: Mismatched devlink_pool_size_thtype_restore" + else + devlink sb pool set "$DEVLINK_DEV" pool $pool \ + size ${orig[0]} thtype ${orig[1]} + fi } devlink_tc_bind_pool_th() @@ -185,6 +213,16 @@ devlink_tc_bind_pool_th() | jq -r '.tc_bind[][] | (.pool, .threshold)' } +devlink_tc_bind_pool_th_save() +{ + local port=$1; shift + local tc=$1; shift + local dir=$1; shift + local key="tc_bind($port,$dir,$tc).pool_th" + + DEVLINK_ORIG[$key]=$(devlink_tc_bind_pool_th $port $tc $dir) +} + devlink_tc_bind_pool_th_set() { local port=$1; shift @@ -192,9 +230,7 @@ devlink_tc_bind_pool_th_set() local dir=$1; shift local pool=$1; shift local th=$1; shift - local key="tc_bind($port,$dir,$tc).pool_th" - DEVLINK_ORIG[$key]=$(devlink_tc_bind_pool_th $port $tc $dir) devlink sb tc bind set $port tc $tc type $dir pool $pool th $th } @@ -206,8 +242,12 @@ devlink_tc_bind_pool_th_restore() local key="tc_bind($port,$dir,$tc).pool_th" local -a orig=(${DEVLINK_ORIG[$key]}) - devlink sb tc bind set $port tc $tc type $dir \ - pool ${orig[0]} th ${orig[1]} + if [[ -z ${orig[0]} ]]; then + echo "WARNING: Mismatched devlink_tc_bind_pool_th_restore" + else + devlink sb tc bind set $port tc $tc type $dir \ + pool ${orig[0]} th ${orig[1]} + fi } devlink_traps_num_get() @@ -509,3 +549,9 @@ devlink_cpu_port_get() echo "$DEVLINK_DEV/$cpu_dl_port_num" } + +devlink_cell_size_get() +{ + devlink sb pool show "$DEVLINK_DEV" pool 0 -j \ + | jq '.pool[][].cell_size' +} |