drivers/net/vsc9953: Add VLAN commands for VSC9953
The new added commands can be used to configure VLANs for a port
on both ingress and egress.
The new commands are:
ethsw [port <port_no>] pvid { [help] | show | <pvid> }
- set/show PVID (ingress and egress VLAN tagging) for a port;
ethsw [port <port_no>] vlan { [help] | show | add <vid> | del <vid> }
- add a VLAN to a port (VLAN members);
ethsw [port <port_no>] untagged { [help] | show | all | none | pvid }
- set egress tagging mod for a port"
ethsw [port <port_no>] egress tag { [help] | show | pvid | classified }
- Configure VID source for egress tag. Tag's VID could be the
frame's classified VID or the PVID of the port
These commands have also been added to the ethsw generic parser from
common/cmd_ethsw.c
Signed-off-by: Johnson Leung <johnson.leung@freescale.com>
Signed-off-by: Codrin Ciubotariu <codrin.ciubotariu@freescale.com>
Acked-by: Joe Hershberger <joe.hershberger@ni.com>
Reviewed-by: York Sun <yorksun@freescale.com>
diff --git a/common/cmd_ethsw.c b/common/cmd_ethsw.c
index 9ba680a..1fa93ef 100644
--- a/common/cmd_ethsw.c
+++ b/common/cmd_ethsw.c
@@ -47,6 +47,51 @@
return CMD_RET_SUCCESS;
}
+#define ETHSW_PVID_HELP "ethsw [port <port_no>] " \
+"pvid { [help] | show | <pvid> } " \
+"- set/show PVID (ingress and egress VLAN tagging) for a port"
+
+static int ethsw_pvid_help_key_func(struct ethsw_command_def *parsed_cmd)
+{
+ printf(ETHSW_PVID_HELP"\n");
+
+ return CMD_RET_SUCCESS;
+}
+
+#define ETHSW_VLAN_HELP "ethsw [port <port_no>] vlan " \
+"{ [help] | show | add <vid> | del <vid> } " \
+"- add a VLAN to a port (VLAN members)"
+
+static int ethsw_vlan_help_key_func(struct ethsw_command_def *parsed_cmd)
+{
+ printf(ETHSW_VLAN_HELP"\n");
+
+ return CMD_RET_SUCCESS;
+}
+
+#define ETHSW_PORT_UNTAG_HELP "ethsw [port <port_no>] untagged " \
+"{ [help] | show | all | none | pvid } " \
+" - set egress tagging mod for a port"
+
+static int ethsw_port_untag_help_key_func(struct ethsw_command_def *parsed_cmd)
+{
+ printf(ETHSW_PORT_UNTAG_HELP"\n");
+
+ return CMD_RET_SUCCESS;
+}
+
+#define ETHSW_EGR_VLAN_TAG_HELP "ethsw [port <port_no>] egress tag " \
+"{ [help] | show | pvid | classified } " \
+"- Configure VID source for egress tag. " \
+"Tag's VID could be the frame's classified VID or the PVID of the port"
+
+static int ethsw_egr_tag_help_key_func(struct ethsw_command_def *parsed_cmd)
+{
+ printf(ETHSW_EGR_VLAN_TAG_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;
@@ -196,6 +241,181 @@
.cmd_func_offset = offsetof(struct ethsw_command_func,
fdb_entry_del),
.keyword_function = NULL,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_pvid,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = -1,
+ .keyword_function = ðsw_pvid_help_key_func,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_pvid,
+ ethsw_id_help,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = -1,
+ .keyword_function = ðsw_pvid_help_key_func,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_pvid,
+ ethsw_id_show,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = offsetof(struct ethsw_command_func,
+ pvid_show),
+ .keyword_function = NULL,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_pvid,
+ ethsw_id_pvid_no,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = offsetof(struct ethsw_command_func,
+ pvid_set),
+ .keyword_function = NULL,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_vlan,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = -1,
+ .keyword_function = ðsw_vlan_help_key_func,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_vlan,
+ ethsw_id_help,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = -1,
+ .keyword_function = ðsw_vlan_help_key_func,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_vlan,
+ ethsw_id_show,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = offsetof(struct ethsw_command_func,
+ vlan_show),
+ .keyword_function = NULL,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_vlan,
+ ethsw_id_add,
+ ethsw_id_add_del_no,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = offsetof(struct ethsw_command_func,
+ vlan_set),
+ .keyword_function = NULL,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_vlan,
+ ethsw_id_del,
+ ethsw_id_add_del_no,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = offsetof(struct ethsw_command_func,
+ vlan_set),
+ .keyword_function = NULL,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_untagged,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = -1,
+ .keyword_function = ðsw_port_untag_help_key_func,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_untagged,
+ ethsw_id_help,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = -1,
+ .keyword_function = ðsw_port_untag_help_key_func,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_untagged,
+ ethsw_id_show,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = offsetof(struct ethsw_command_func,
+ port_untag_show),
+ .keyword_function = NULL,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_untagged,
+ ethsw_id_all,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = offsetof(struct ethsw_command_func,
+ port_untag_set),
+ .keyword_function = NULL,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_untagged,
+ ethsw_id_none,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = offsetof(struct ethsw_command_func,
+ port_untag_set),
+ .keyword_function = NULL,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_untagged,
+ ethsw_id_pvid,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = offsetof(struct ethsw_command_func,
+ port_untag_set),
+ .keyword_function = NULL,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_egress,
+ ethsw_id_tag,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = -1,
+ .keyword_function = ðsw_egr_tag_help_key_func,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_egress,
+ ethsw_id_tag,
+ ethsw_id_help,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = -1,
+ .keyword_function = ðsw_egr_tag_help_key_func,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_egress,
+ ethsw_id_tag,
+ ethsw_id_show,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = offsetof(struct ethsw_command_func,
+ port_egr_vlan_show),
+ .keyword_function = NULL,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_egress,
+ ethsw_id_tag,
+ ethsw_id_pvid,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = offsetof(struct ethsw_command_func,
+ port_egr_vlan_set),
+ .keyword_function = NULL,
+ }, {
+ .cmd_keyword = {
+ ethsw_id_egress,
+ ethsw_id_tag,
+ ethsw_id_classified,
+ ethsw_id_key_end,
+ },
+ .cmd_func_offset = offsetof(struct ethsw_command_func,
+ port_egr_vlan_set),
+ .keyword_function = NULL,
},
};
@@ -234,6 +454,9 @@
static int keyword_match_vlan(enum ethsw_keyword_id key_id, int argc,
char *const argv[], int *argc_nr,
struct ethsw_command_def *parsed_cmd);
+static int keyword_match_pvid(enum ethsw_keyword_id key_id, int argc,
+ char *const argv[], int *argc_nr,
+ struct ethsw_command_def *parsed_cmd);
static int keyword_match_mac_addr(enum ethsw_keyword_id key_id, int argc,
char *const argv[], int *argc_nr,
struct ethsw_command_def *parsed_cmd);
@@ -289,6 +512,27 @@
}, {
.keyword_name = "flush",
.match = &keyword_match_gen,
+ }, {
+ .keyword_name = "pvid",
+ .match = &keyword_match_pvid,
+ }, {
+ .keyword_name = "untagged",
+ .match = &keyword_match_gen,
+ }, {
+ .keyword_name = "all",
+ .match = &keyword_match_gen,
+ }, {
+ .keyword_name = "none",
+ .match = &keyword_match_gen,
+ }, {
+ .keyword_name = "egress",
+ .match = &keyword_match_gen,
+ }, {
+ .keyword_name = "tag",
+ .match = &keyword_match_gen,
+ }, {
+ .keyword_name = "classified",
+ .match = &keyword_match_gen,
},
};
@@ -403,6 +647,28 @@
return 0;
}
+/* Function used to match the command's pvid */
+static int keyword_match_pvid(enum ethsw_keyword_id key_id, int argc,
+ char *const argv[], int *argc_nr,
+ struct ethsw_command_def *parsed_cmd)
+{
+ unsigned long val;
+
+ if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
+ return 0;
+
+ if (*argc_nr + 1 >= argc)
+ return 1;
+
+ if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) {
+ parsed_cmd->vid = val;
+ (*argc_nr)++;
+ parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_pvid_no;
+ }
+
+ return 1;
+}
+
/* Function used to match the command's MAC address */
static int keyword_match_mac_addr(enum ethsw_keyword_id key_id, int argc,
char *const argv[], int *argc_nr,
@@ -624,4 +890,8 @@
ETHSW_PORT_STATS_HELP"\n"
ETHSW_LEARN_HELP"\n"
ETHSW_FDB_HELP"\n"
+ ETHSW_PVID_HELP"\n"
+ ETHSW_VLAN_HELP"\n"
+ ETHSW_PORT_UNTAG_HELP"\n"
+ ETHSW_EGR_VLAN_TAG_HELP"\n"
);
diff --git a/drivers/net/vsc9953.c b/drivers/net/vsc9953.c
index 071906c..c5c0e5c 100644
--- a/drivers/net/vsc9953.c
+++ b/drivers/net/vsc9953.c
@@ -196,6 +196,100 @@
return timeout ? 0 : -EBUSY;
}
+#ifdef CONFIG_CMD_ETHSW
+/* Add/remove a port to/from a VLAN */
+static void vsc9953_vlan_table_membership_set(int vid, u32 port_no, u8 add)
+{
+ u32 val;
+ struct vsc9953_analyzer *l2ana_reg;
+
+ l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+ VSC9953_ANA_OFFSET);
+
+ if (vsc9953_vlan_table_poll_idle() < 0) {
+ debug("VLAN table timeout\n");
+ return;
+ }
+
+ val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
+ val = bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid);
+ out_le32(&l2ana_reg->ana_tables.vlan_tidx, val);
+
+ clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
+ VSC9953_VLAN_CMD_MASK, VSC9953_VLAN_CMD_READ);
+
+ if (vsc9953_vlan_table_poll_idle() < 0) {
+ debug("VLAN table timeout\n");
+ return;
+ }
+
+ val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
+ val = bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid);
+ out_le32(&l2ana_reg->ana_tables.vlan_tidx, val);
+
+ val = in_le32(&l2ana_reg->ana_tables.vlan_access);
+ if (!add) {
+ val = bitfield_replace_by_mask(val, VSC9953_VLAN_CMD_MASK,
+ VSC9953_VLAN_CMD_WRITE) &
+ ~(bitfield_replace_by_mask(0, VSC9953_VLAN_PORT_MASK,
+ (1 << port_no)));
+ ;
+ } else {
+ val = bitfield_replace_by_mask(val, VSC9953_VLAN_CMD_MASK,
+ VSC9953_VLAN_CMD_WRITE) |
+ bitfield_replace_by_mask(0, VSC9953_VLAN_PORT_MASK,
+ (1 << port_no));
+ }
+ out_le32(&l2ana_reg->ana_tables.vlan_access, val);
+
+ /* wait for VLAN table command to flush */
+ if (vsc9953_vlan_table_poll_idle() < 0) {
+ debug("VLAN table timeout\n");
+ return;
+ }
+}
+
+/* show VLAN membership for a port */
+static void vsc9953_vlan_membership_show(int port_no)
+{
+ u32 val;
+ struct vsc9953_analyzer *l2ana_reg;
+ u32 vid;
+
+ l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+ VSC9953_ANA_OFFSET);
+
+ printf("Port %d VLAN membership: ", port_no);
+
+ for (vid = 0; vid < VSC9953_MAX_VLAN; vid++) {
+ if (vsc9953_vlan_table_poll_idle() < 0) {
+ debug("VLAN table timeout\n");
+ return;
+ }
+
+ val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
+ val = bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK,
+ vid);
+ out_le32(&l2ana_reg->ana_tables.vlan_tidx, val);
+
+ clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
+ VSC9953_VLAN_CMD_MASK, VSC9953_VLAN_CMD_READ);
+
+ if (vsc9953_vlan_table_poll_idle() < 0) {
+ debug("VLAN table timeout\n");
+ return;
+ }
+
+ val = in_le32(&l2ana_reg->ana_tables.vlan_access);
+
+ if (bitfield_extract_by_mask(val, VSC9953_VLAN_PORT_MASK) &
+ (1 << port_no))
+ printf("%d ", vid);
+ }
+ printf("\n");
+}
+#endif
+
/* vlan table set/clear all membership of vid */
static void vsc9953_vlan_table_membership_all_set(int vid, int set_member)
{
@@ -233,6 +327,30 @@
(set_member ? VSC9953_VLAN_PORT_MASK : 0));
}
+#ifdef CONFIG_CMD_ETHSW
+/* Get PVID of a VSC9953 port */
+static int vsc9953_port_vlan_pvid_get(int port_nr, int *pvid)
+{
+ u32 val;
+ struct vsc9953_analyzer *l2ana_reg;
+
+ /* Administrative down */
+ if (vsc9953_l2sw.port[port_nr].enabled) {
+ printf("Port %d is administrative down\n", port_nr);
+ return -1;
+ }
+
+ l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+ VSC9953_ANA_OFFSET);
+
+ /* Get ingress PVID */
+ val = in_le32(&l2ana_reg->port[port_nr].vlan_cfg);
+ *pvid = bitfield_extract_by_mask(val, VSC9953_VLAN_CFG_VID_MASK);
+
+ return 0;
+}
+#endif
+
/* Set PVID for a VSC9953 port */
static void vsc9953_port_vlan_pvid_set(int port_no, int pvid)
{
@@ -359,6 +477,75 @@
EGRESS_UNTAG_NONE,
};
+#ifdef CONFIG_CMD_ETHSW
+/* Get egress tagging configuration for a VSC9953 port */
+static int vsc9953_port_vlan_egr_untag_get(int port_no,
+ enum egress_untag_mode *mode)
+{
+ u32 val;
+ struct vsc9953_rew_reg *l2rew_reg;
+
+ /* Administrative down */
+ if (!vsc9953_l2sw.port[port_no].enabled) {
+ printf("Port %d is administrative down\n", port_no);
+ return -1;
+ }
+
+ l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
+ VSC9953_REW_OFFSET);
+
+ val = in_le32(&l2rew_reg->port[port_no].port_tag_cfg);
+
+ switch (val & VSC9953_TAG_CFG_MASK) {
+ case VSC9953_TAG_CFG_NONE:
+ *mode = EGRESS_UNTAG_ALL;
+ return 0;
+ case VSC9953_TAG_CFG_ALL_BUT_PVID_ZERO:
+ *mode = EGRESS_UNTAG_PVID_AND_ZERO;
+ return 0;
+ case VSC9953_TAG_CFG_ALL_BUT_ZERO:
+ *mode = EGRESS_UNTAG_ZERO;
+ return 0;
+ case VSC9953_TAG_CFG_ALL:
+ *mode = EGRESS_UNTAG_NONE;
+ return 0;
+ default:
+ printf("Unknown egress tagging configuration for port %d\n",
+ port_no);
+ return -1;
+ }
+}
+
+/* Show egress tagging configuration for a VSC9953 port */
+static void vsc9953_port_vlan_egr_untag_show(int port_no)
+{
+ enum egress_untag_mode mode;
+
+ if (vsc9953_port_vlan_egr_untag_get(port_no, &mode)) {
+ printf("%7d\t%17s\n", port_no, "-");
+ return;
+ }
+
+ printf("%7d\t", port_no);
+ switch (mode) {
+ case EGRESS_UNTAG_ALL:
+ printf("%17s\n", "all");
+ break;
+ case EGRESS_UNTAG_NONE:
+ printf("%17s\n", "none");
+ break;
+ case EGRESS_UNTAG_PVID_AND_ZERO:
+ printf("%17s\n", "PVID and 0");
+ break;
+ case EGRESS_UNTAG_ZERO:
+ printf("%17s\n", "0");
+ break;
+ default:
+ printf("%17s\n", "-");
+ }
+}
+#endif
+
static void vsc9953_port_vlan_egr_untag_set(int port_no,
enum egress_untag_mode mode)
{
@@ -1166,6 +1353,51 @@
vsc9953_mac_table_age(port, vid);
}
+enum egress_vlan_tag {
+ EGR_TAG_CLASS = 0,
+ EGR_TAG_PVID,
+};
+
+/* Set egress tag mode for a VSC9953 port */
+static void vsc9953_port_vlan_egress_tag_set(int port_no,
+ enum egress_vlan_tag mode)
+{
+ struct vsc9953_rew_reg *l2rew_reg;
+
+ l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
+ VSC9953_REW_OFFSET);
+
+ switch (mode) {
+ case EGR_TAG_CLASS:
+ clrbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
+ VSC9953_TAG_VID_PVID);
+ break;
+ case EGR_TAG_PVID:
+ setbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
+ VSC9953_TAG_VID_PVID);
+ break;
+ default:
+ printf("Unknown egress VLAN tag mode for port %d\n", port_no);
+ }
+}
+
+/* Get egress tag mode for a VSC9953 port */
+static void vsc9953_port_vlan_egress_tag_get(int port_no,
+ enum egress_vlan_tag *mode)
+{
+ u32 val;
+ struct vsc9953_rew_reg *l2rew_reg;
+
+ l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
+ VSC9953_REW_OFFSET);
+
+ val = in_le32(&l2rew_reg->port[port_no].port_tag_cfg);
+ if (val & VSC9953_TAG_VID_PVID)
+ *mode = EGR_TAG_PVID;
+ else
+ *mode = EGR_TAG_CLASS;
+}
+
static int vsc9953_port_status_key_func(struct ethsw_command_def *parsed_cmd)
{
int i;
@@ -1417,6 +1649,244 @@
return CMD_RET_SUCCESS;
}
+static int vsc9953_pvid_show_key_func(struct ethsw_command_def *parsed_cmd)
+{
+ int i;
+ int pvid;
+
+ if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
+ if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
+ printf("Invalid port number: %d\n", parsed_cmd->port);
+ return CMD_RET_FAILURE;
+ }
+
+ if (vsc9953_port_vlan_pvid_get(parsed_cmd->port, &pvid))
+ return CMD_RET_FAILURE;
+ printf("%7s %7s\n", "Port", "PVID");
+ printf("%7d %7d\n", parsed_cmd->port, pvid);
+ } else {
+ printf("%7s %7s\n", "Port", "PVID");
+ for (i = 0; i < VSC9953_MAX_PORTS; i++) {
+ if (vsc9953_port_vlan_pvid_get(i, &pvid))
+ continue;
+ printf("%7d %7d\n", i, pvid);
+ }
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+static int vsc9953_pvid_set_key_func(struct ethsw_command_def *parsed_cmd)
+{
+ /* PVID number should be set in parsed_cmd->vid */
+ if (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL) {
+ printf("Please set a pvid value\n");
+ return CMD_RET_FAILURE;
+ }
+
+ if (!VSC9953_VLAN_CHECK(parsed_cmd->vid)) {
+ printf("Invalid VID number: %d\n", parsed_cmd->vid);
+ return CMD_RET_FAILURE;
+ }
+
+ if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
+ if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
+ printf("Invalid port number: %d\n", parsed_cmd->port);
+ return CMD_RET_FAILURE;
+ }
+ vsc9953_port_vlan_pvid_set(parsed_cmd->port, parsed_cmd->vid);
+ } else {
+ vsc9953_port_all_vlan_pvid_set(parsed_cmd->vid);
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+static int vsc9953_vlan_show_key_func(struct ethsw_command_def *parsed_cmd)
+{
+ int i;
+
+ if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
+ if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
+ printf("Invalid port number: %d\n", parsed_cmd->port);
+ return CMD_RET_FAILURE;
+ }
+ vsc9953_vlan_membership_show(parsed_cmd->port);
+ } else {
+ for (i = 0; i < VSC9953_MAX_PORTS; i++)
+ vsc9953_vlan_membership_show(i);
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+static int vsc9953_vlan_set_key_func(struct ethsw_command_def *parsed_cmd)
+{
+ int i;
+ int add;
+
+ /* VLAN should be set in parsed_cmd->vid */
+ if (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL) {
+ printf("Please set a vlan value\n");
+ return CMD_RET_FAILURE;
+ }
+
+ if (!VSC9953_VLAN_CHECK(parsed_cmd->vid)) {
+ printf("Invalid VID number: %d\n", parsed_cmd->vid);
+ return CMD_RET_FAILURE;
+ }
+
+ /* keywords add/delete should be the last but one in array */
+ if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 2] ==
+ ethsw_id_add)
+ add = 1;
+ else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 2] ==
+ ethsw_id_del)
+ add = 0;
+ else
+ return CMD_RET_USAGE;
+
+ if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
+ if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
+ printf("Invalid port number: %d\n", parsed_cmd->port);
+ return CMD_RET_FAILURE;
+ }
+ vsc9953_vlan_table_membership_set(parsed_cmd->vid,
+ parsed_cmd->port, add);
+ } else {
+ for (i = 0; i < VSC9953_MAX_PORTS; i++)
+ vsc9953_vlan_table_membership_set(parsed_cmd->vid, i,
+ add);
+ }
+
+ return CMD_RET_SUCCESS;
+}
+static int vsc9953_port_untag_show_key_func(
+ struct ethsw_command_def *parsed_cmd)
+{
+ int i;
+
+ printf("%7s\t%17s\n", "Port", "Untag");
+ if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
+ if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
+ printf("Invalid port number: %d\n", parsed_cmd->port);
+ return CMD_RET_FAILURE;
+ }
+ vsc9953_port_vlan_egr_untag_show(parsed_cmd->port);
+ } else {
+ for (i = 0; i < VSC9953_MAX_PORTS; i++)
+ vsc9953_port_vlan_egr_untag_show(i);
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+static int vsc9953_port_untag_set_key_func(struct ethsw_command_def *parsed_cmd)
+{
+ int i;
+ enum egress_untag_mode mode;
+
+ /* keywords for the untagged mode are the last in the array */
+ if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
+ ethsw_id_all)
+ mode = EGRESS_UNTAG_ALL;
+ else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
+ ethsw_id_none)
+ mode = EGRESS_UNTAG_NONE;
+ else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
+ ethsw_id_pvid)
+ mode = EGRESS_UNTAG_PVID_AND_ZERO;
+ else
+ return CMD_RET_USAGE;
+
+ if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
+ if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
+ printf("Invalid port number: %d\n", parsed_cmd->port);
+ return CMD_RET_FAILURE;
+ }
+ vsc9953_port_vlan_egr_untag_set(parsed_cmd->port, mode);
+ } else {
+ for (i = 0; i < VSC9953_MAX_PORTS; i++)
+ vsc9953_port_vlan_egr_untag_set(i, mode);
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+static int vsc9953_egr_vlan_tag_show_key_func(
+ struct ethsw_command_def *parsed_cmd)
+{
+ int i;
+ enum egress_vlan_tag mode;
+
+ if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
+ if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
+ printf("Invalid port number: %d\n", parsed_cmd->port);
+ return CMD_RET_FAILURE;
+ }
+ vsc9953_port_vlan_egress_tag_get(parsed_cmd->port, &mode);
+ printf("%7s\t%12s\n", "Port", "Egress VID");
+ printf("%7d\t", parsed_cmd->port);
+ switch (mode) {
+ case EGR_TAG_CLASS:
+ printf("%12s\n", "classified");
+ break;
+ case EGR_TAG_PVID:
+ printf("%12s\n", "pvid");
+ break;
+ default:
+ printf("%12s\n", "-");
+ }
+ } else {
+ printf("%7s\t%12s\n", "Port", "Egress VID");
+ for (i = 0; i < VSC9953_MAX_PORTS; i++) {
+ vsc9953_port_vlan_egress_tag_get(i, &mode);
+ switch (mode) {
+ case EGR_TAG_CLASS:
+ printf("%7d\t%12s\n", i, "classified");
+ break;
+ case EGR_TAG_PVID:
+ printf("%7d\t%12s\n", i, "pvid");
+ break;
+ default:
+ printf("%7d\t%12s\n", i, "-");
+ }
+ }
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+static int vsc9953_egr_vlan_tag_set_key_func(
+ struct ethsw_command_def *parsed_cmd)
+{
+ int i;
+ enum egress_vlan_tag mode;
+
+ /* keywords for the egress vlan tag mode are the last in the array */
+ if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
+ ethsw_id_pvid)
+ mode = EGR_TAG_PVID;
+ else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] ==
+ ethsw_id_classified)
+ mode = EGR_TAG_CLASS;
+ else
+ return CMD_RET_USAGE;
+
+ if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
+ if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
+ printf("Invalid port number: %d\n", parsed_cmd->port);
+ return CMD_RET_FAILURE;
+ }
+ vsc9953_port_vlan_egress_tag_set(parsed_cmd->port, mode);
+ } else {
+ for (i = 0; i < VSC9953_MAX_PORTS; i++)
+ vsc9953_port_vlan_egress_tag_set(i, 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,
@@ -1430,6 +1900,14 @@
.fdb_flush = &vsc9953_fdb_flush_key_func,
.fdb_entry_add = &vsc9953_fdb_entry_add_key_func,
.fdb_entry_del = &vsc9953_fdb_entry_del_key_func,
+ .pvid_show = &vsc9953_pvid_show_key_func,
+ .pvid_set = &vsc9953_pvid_set_key_func,
+ .vlan_show = &vsc9953_vlan_show_key_func,
+ .vlan_set = &vsc9953_vlan_set_key_func,
+ .port_untag_show = &vsc9953_port_untag_show_key_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,
};
#endif /* CONFIG_CMD_ETHSW */
diff --git a/include/ethsw.h b/include/ethsw.h
index 5159031..cc9708e 100644
--- a/include/ethsw.h
+++ b/include/ethsw.h
@@ -30,12 +30,20 @@
ethsw_id_add,
ethsw_id_del,
ethsw_id_flush,
+ ethsw_id_pvid,
+ ethsw_id_untagged,
+ ethsw_id_all,
+ ethsw_id_none,
+ ethsw_id_egress,
+ ethsw_id_tag,
+ ethsw_id_classified,
ethsw_id_count, /* keep last */
};
enum ethsw_keyword_opt_id {
ethsw_id_port_no = ethsw_id_count + 1,
ethsw_id_vlan_no,
+ ethsw_id_pvid_no,
ethsw_id_add_del_no,
ethsw_id_add_del_mac,
ethsw_id_count_all, /* keep last */
@@ -64,6 +72,14 @@
int (*fdb_flush)(struct ethsw_command_def *parsed_cmd);
int (*fdb_entry_add)(struct ethsw_command_def *parsed_cmd);
int (*fdb_entry_del)(struct ethsw_command_def *parsed_cmd);
+ int (*pvid_show)(struct ethsw_command_def *parsed_cmd);
+ int (*pvid_set)(struct ethsw_command_def *parsed_cmd);
+ int (*vlan_show)(struct ethsw_command_def *parsed_cmd);
+ int (*vlan_set)(struct ethsw_command_def *parsed_cmd);
+ int (*port_untag_show)(struct ethsw_command_def *parsed_cmd);
+ 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 ethsw_define_functions(const struct ethsw_command_func *cmd_func);
diff --git a/include/vsc9953.h b/include/vsc9953.h
index df1c709..12b7ace 100644
--- a/include/vsc9953.h
+++ b/include/vsc9953.h
@@ -108,6 +108,8 @@
/* Macros for vsc9953_ana_port.vlan_cfg register */
#define VSC9953_VLAN_CFG_AWARE_ENA 0x00100000
#define VSC9953_VLAN_CFG_POP_CNT_MASK 0x000c0000
+#define VSC9953_VLAN_CFG_POP_CNT_NONE 0x00000000
+#define VSC9953_VLAN_CFG_POP_CNT_ONE 0x00040000
#define VSC9953_VLAN_CFG_VID_MASK 0x00000fff
/* Macros for vsc9953_rew_port.port_vlan_cfg register */
@@ -142,6 +144,7 @@
#define VSC9953_TAG_CFG_ALL_BUT_PVID_ZERO 0x00000080
#define VSC9953_TAG_CFG_ALL_BUT_ZERO 0x00000100
#define VSC9953_TAG_CFG_ALL 0x00000180
+#define VSC9953_TAG_VID_PVID 0x00000010
/* Macros for vsc9953_ana_ana.anag_efil register */
#define VSC9953_AGE_PORT_EN 0x00080000