@@ -91,6 +91,17 @@ static int ethsw_egr_tag_help_key_func(struct ethsw_command_def *parsed_cmd)
return CMD_RET_SUCCESS;
}
+#define ETHSW_VLAN_FDB_HELP "ethsw vlan fdb " \
+"{ [help] | show | shared | private } " \
+"- make VLAN learning shared or private"
+
+static int ethsw_vlan_learn_help_key_func(struct ethsw_command_def *parsed_cmd)
+{
+ printf(ETHSW_VLAN_FDB_HELP"\n");
+
+ return CMD_RET_SUCCESS;
+}
+
static struct keywords_to_function {
enum ethsw_keyword_id cmd_keyword[ETHSW_MAX_CMD_PARAMS];
int cmd_func_offset;
@@ -415,6 +426,53 @@ static struct keywords_to_function {
.cmd_func_offset = offsetof(struct ethsw_command_func,
port_egr_vlan_set),
.keyword_function = NULL,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_vlan,
+ ethsw_id_fdb,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = -1,
+ .keyword_function = ðsw_vlan_learn_help_key_func,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_vlan,
+ ethsw_id_fdb,
+ ethsw_id_help,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = -1,
+ .keyword_function = ðsw_vlan_learn_help_key_func,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_vlan,
+ ethsw_id_fdb,
+ ethsw_id_show,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = offsetof(struct ethsw_command_func,
+ vlan_learn_show),
+ .keyword_function = NULL,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_vlan,
+ ethsw_id_fdb,
+ ethsw_id_shared,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = offsetof(struct ethsw_command_func,
+ vlan_learn_set),
+ .keyword_function = NULL,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_vlan,
+ ethsw_id_fdb,
+ ethsw_id_private,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = offsetof(struct ethsw_command_func,
+ vlan_learn_set),
+ .keyword_function = NULL,
},
};
@@ -532,6 +590,12 @@ struct keyword_def {
}, {
.keyword_name = "classified",
.match = &keyword_match_gen,
+ }, {
+ .keyword_name = "shared",
+ .match = &keyword_match_gen,
+ }, {
+ .keyword_name = "private",
+ .match = &keyword_match_gen,
},
};
@@ -892,4 +956,5 @@ U_BOOT_CMD(ethsw, ETHSW_MAX_CMD_PARAMS, 0, do_ethsw,
ETHSW_VLAN_HELP"\n"
ETHSW_PORT_UNTAG_HELP"\n"
ETHSW_EGR_VLAN_TAG_HELP"\n"
+ ETHSW_VLAN_FDB_HELP"\n"
);
@@ -1399,6 +1399,55 @@ static void vsc9953_port_vlan_egress_tag_get(int port_no,
*mode = EGR_TAG_CLASS;
}
+/* VSC9953 VLAN learning modes */
+enum vlan_learning_mode {
+ SHARED_VLAN_LEARNING,
+ PRIVATE_VLAN_LEARNING,
+};
+
+/* Set VLAN learning mode for VSC9953 */
+static void vsc9953_vlan_learning_set(enum vlan_learning_mode lrn_mode)
+{
+ struct vsc9953_analyzer *l2ana_reg;
+
+ l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+ VSC9953_ANA_OFFSET);
+
+ switch (lrn_mode) {
+ case SHARED_VLAN_LEARNING:
+ setbits_le32(&l2ana_reg->ana.agen_ctrl, VSC9953_FID_MASK_ALL);
+ break;
+ case PRIVATE_VLAN_LEARNING:
+ clrbits_le32(&l2ana_reg->ana.agen_ctrl, VSC9953_FID_MASK_ALL);
+ break;
+ default:
+ printf("Unknown VLAN learn mode\n");
+ }
+}
+
+/* Get VLAN learning mode for VSC9953 */
+static int vsc9953_vlan_learning_get(enum vlan_learning_mode *lrn_mode)
+{
+ u32 val;
+ struct vsc9953_analyzer *l2ana_reg;
+
+ l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+ VSC9953_ANA_OFFSET);
+
+ val = in_le32(&l2ana_reg->ana.agen_ctrl);
+
+ if (!(val & VSC9953_FID_MASK_ALL)) {
+ *lrn_mode = PRIVATE_VLAN_LEARNING;
+ } else if ((val & VSC9953_FID_MASK_ALL) == VSC9953_FID_MASK_ALL) {
+ *lrn_mode = SHARED_VLAN_LEARNING;
+ } else {
+ printf("Unknown VLAN learning mode\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int vsc9953_port_status_key_func(struct ethsw_command_def *parsed_cmd)
{
int i;
@@ -1888,6 +1937,50 @@ static int vsc9953_egr_vlan_tag_set_key_func(
return CMD_RET_SUCCESS;
}
+static int vsc9953_vlan_learn_show_key_func(
+ struct ethsw_command_def *parsed_cmd)
+{
+ int rc;
+ enum vlan_learning_mode mode;
+
+ rc = vsc9953_vlan_learning_get(&mode);
+ if (rc)
+ return CMD_RET_FAILURE;
+
+ switch (mode) {
+ case SHARED_VLAN_LEARNING:
+ printf("VLAN learning mode: shared\n");
+ break;
+ case PRIVATE_VLAN_LEARNING:
+ printf("VLAN learning mode: private\n");
+ break;
+ default:
+ printf("Unknown VLAN learning mode\n");
+ rc = CMD_RET_FAILURE;
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+static int vsc9953_vlan_learn_set_key_func(struct ethsw_command_def *parsed_cmd)
+{
+ enum vlan_learning_mode mode;
+
+ /* keywords for shared/private are the last in the array */
+ if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
+ ethsw_id_shared)
+ mode = SHARED_VLAN_LEARNING;
+ else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
+ ethsw_id_private)
+ mode = PRIVATE_VLAN_LEARNING;
+ else
+ return CMD_RET_USAGE;
+
+ vsc9953_vlan_learning_set(mode);
+
+ return CMD_RET_SUCCESS;
+}
+
static struct ethsw_command_func vsc9953_cmd_func = {
.ethsw_name = "L2 Switch VSC9953",
.port_enable = &vsc9953_port_status_key_func,
@@ -1909,6 +2002,8 @@ static struct ethsw_command_func vsc9953_cmd_func = {
.port_untag_set = &vsc9953_port_untag_set_key_func,
.port_egr_vlan_show = &vsc9953_egr_vlan_tag_show_key_func,
.port_egr_vlan_set = &vsc9953_egr_vlan_tag_set_key_func,
+ .vlan_learn_show = &vsc9953_vlan_learn_show_key_func,
+ .vlan_learn_set = &vsc9953_vlan_learn_set_key_func,
};
#endif /* CONFIG_CMD_ETHSW */
@@ -37,6 +37,8 @@ enum ethsw_keyword_id {
ethsw_id_egress,
ethsw_id_tag,
ethsw_id_classified,
+ ethsw_id_shared,
+ ethsw_id_private,
ethsw_id_count, /* keep last */
};
@@ -80,6 +82,8 @@ struct ethsw_command_func {
int (*port_untag_set)(struct ethsw_command_def *parsed_cmd);
int (*port_egr_vlan_show)(struct ethsw_command_def *parsed_cmd);
int (*port_egr_vlan_set)(struct ethsw_command_def *parsed_cmd);
+ int (*vlan_learn_show)(struct ethsw_command_def *parsed_cmd);
+ int (*vlan_learn_set)(struct ethsw_command_def *parsed_cmd);
};
int ethsw_define_functions(const struct ethsw_command_func *cmd_func);
@@ -135,6 +135,9 @@
/* Macros for vsc9953_qsys_sys.switch_port_mode register */
#define VSC9953_PORT_ENA 0x00002000
+/* Macros for vsc9953_ana_ana.agen_ctrl register */
+#define VSC9953_FID_MASK_ALL 0x00fff000
+
/* Macros for vsc9953_ana_ana.adv_learn register */
#define VSC9953_VLAN_CHK 0x00000400