Message ID | 1435078136-22809-9-git-send-email-codrin.ciubotariu@freescale.com |
---|---|
State | Changes Requested |
Headers | show |
Hi Codrin, On Tue, Jun 23, 2015 at 11:48 AM, Codrin Ciubotariu <codrin.ciubotariu@freescale.com> wrote: > 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 > > Signed-off-by: Johnson Leung <johnson.leung@freescale.com> > Signed-off-by: Codrin Ciubotariu <codrin.ciubotariu@freescale.com> > --- > Changes for v2: > - removed Change-id field; > > drivers/net/vsc9953.c | 678 +++++++++++++++++++++++++++++++++++++++++++++++++- > include/vsc9953.h | 3 + > 2 files changed, 680 insertions(+), 1 deletion(-) > > diff --git a/drivers/net/vsc9953.c b/drivers/net/vsc9953.c > index ef7b50c..b78a941 100644 > --- a/drivers/net/vsc9953.c > +++ b/drivers/net/vsc9953.c > @@ -270,6 +270,31 @@ static void vsc9953_port_vlan_pvid_set(int port_no, int pvid) > field_set(pvid, CONFIG_VSC9953_PORT_VLAN_CFG_VID_MASK)); > } > > +#ifdef CONFIG_VSC9953_CMD Why does this need to be defined outside of the #ifdef already at the bottom of the file? > +/* Set PVID for a VSC9953 port */ > +static int vsc9953_port_vlan_pvid_get(int port_nr, int *pvid) > +{ > + u32 val; Use a single space. > + struct vsc9953_analyzer *l2ana_reg; > + > + /* Administrative down */ > + if ((!vsc9953_l2sw.port[port_nr].enabled)) { Why do you have double "((" and "))"? > + 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 = field_get(val & CONFIG_VSC9953_VLAN_CFG_VID_MASK, > + CONFIG_VSC9953_VLAN_CFG_VID_MASK); > + > + return 0; > +} > +#endif > + > static void vsc9953_port_all_vlan_pvid_set(int pvid) > { > int i; > @@ -407,6 +432,75 @@ static void vsc9953_port_vlan_egr_untag_set(int port_no, > } > } > > +#ifdef CONFIG_VSC9953_CMD Why does this need to be defined outside of the #ifdef already at the bottom of the file? > +/* 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)) { Why do you have double "((" and "))"? > + 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 & CONFIG_VSC9953_TAG_CFG_MASK) { > + case CONFIG_VSC9953_TAG_CFG_NONE: > + *mode = EGRESS_UNTAG_ALL; > + return 0; > + case CONFIG_VSC9953_TAG_CFG_ALL_PVID_ZERO: > + *mode = EGRESS_UNTAG_PVID_AND_ZERO; > + return 0; > + case CONFIG_VSC9953_TAG_CFG_ALL_ZERO: > + *mode = EGRESS_UNTAG_ZERO; > + return 0; > + case CONFIG_VSC9953_TAG_CFG_ALL: > + *mode = EGRESS_UNTAG_NONE; > + return 0; > + default: > + printf("Unknown egress tagging configuration for port %d\n", > + port_no); > + return -1; > + } > +} > + > +/* Shiw egress tagging configuration for a VSC9953 port */ Shiw -> Show > +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", "none"); > + break; > + case EGRESS_UNTAG_NONE: > + printf("%17s\n", "all"); > + break; > + case EGRESS_UNTAG_PVID_AND_ZERO: > + printf("%17s\n", "all but PVID and 0"); > + break; > + case EGRESS_UNTAG_ZERO: > + printf("%17s\n", "all but 0"); > + break; > + default: > + printf("%17s\n", "-"); > + } > +} > +#endif > + > static void vsc9953_port_all_vlan_egress_untagged_set( > enum egress_untag_mode mode) > { > @@ -954,6 +1048,102 @@ static void vsc9953_port_statistics_clear(int port_no) > CONFIG_VSC9953_STAT_CLEAR_DR); > } > > +/* Add/remove a port to/from a VLAN */ > +static void vsc9953_vlan_table_membership_set(int vid, u32 port_no, u8 add) > +{ > + struct vsc9953_analyzer *l2ana_reg; > + > + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + > + VSC9953_ANA_OFFSET); > + > + if (!vsc9953_vlan_table_poll_idle()) { > + debug("VLAN table timeout\n"); > + return; > + } > + > + clrsetbits_le32(&l2ana_reg->ana_tables.vlan_tidx, > + CONFIG_VSC9953_ANA_TBL_VID_MASK, > + field_set(vid, CONFIG_VSC9953_ANA_TBL_VID_MASK)); > + clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access, > + CONFIG_VSC9953_VLAN_CMD_MASK, > + field_set(CONFIG_VSC9953_VLAN_CMD_READ, > + CONFIG_VSC9953_VLAN_CMD_MASK)); > + > + if (!vsc9953_vlan_table_poll_idle()) { > + debug("VLAN table timeout\n"); > + return; > + } > + > + clrsetbits_le32(&l2ana_reg->ana_tables.vlan_tidx, > + CONFIG_VSC9953_ANA_TBL_VID_MASK, > + field_set(vid, CONFIG_VSC9953_ANA_TBL_VID_MASK)); > + > + if (!add) { > + clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access, > + CONFIG_VSC9953_VLAN_CMD_MASK | > + (field_set((1 << port_no), > + CONFIG_VSC9953_VLAN_PORT_MASK) & > + CONFIG_VSC9953_VLAN_PORT_MASK), > + field_set(CONFIG_VSC9953_VLAN_CMD_WRITE, > + CONFIG_VSC9953_VLAN_CMD_MASK)); > + } else { > + clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access, > + CONFIG_VSC9953_VLAN_CMD_MASK, > + field_set(CONFIG_VSC9953_VLAN_CMD_WRITE, > + CONFIG_VSC9953_VLAN_CMD_MASK) | > + (field_set((1 << port_no), > + CONFIG_VSC9953_VLAN_PORT_MASK) & > + CONFIG_VSC9953_VLAN_PORT_MASK)); > + } > + > + /* wait for VLAN table command to flush */ > + if (!vsc9953_vlan_table_poll_idle()) { > + 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()) { > + debug("VLAN table timeout\n"); > + return; > + } > + > + clrsetbits_le32(&l2ana_reg->ana_tables.vlan_tidx, > + CONFIG_VSC9953_ANA_TBL_VID_MASK, > + field_set(vid, > + CONFIG_VSC9953_ANA_TBL_VID_MASK)); > + clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access, > + CONFIG_VSC9953_VLAN_CMD_MASK, > + field_set(CONFIG_VSC9953_VLAN_CMD_READ, > + CONFIG_VSC9953_VLAN_CMD_MASK)); > + > + if (!vsc9953_vlan_table_poll_idle()) { > + debug("VLAN table timeout\n"); > + return; > + } > + > + val = in_le32(&l2ana_reg->ana_tables.vlan_access); > + > + if (!!(val & (field_set((1 << port_no), > + CONFIG_VSC9953_VLAN_PORT_MASK)))) There is no need for "!!" in an if statement. Drop it and the extra parenthesis. > + printf("%d ", vid); > + } > + printf("\n"); > +} > + > /* wait for FDB to become available */ > static int vsc9953_mac_table_poll_idle(void) > { > @@ -965,7 +1155,7 @@ static int vsc9953_mac_table_poll_idle(void) > > timeout = 50000; > while (((in_le32(&l2ana_reg->ana_tables.mac_access) & > - CONFIG_VSC9953_MAC_CMD_MASK) != > + CONFIG_VSC9953_MAC_CMD_MASK) != > CONFIG_VSC9953_MAC_CMD_IDLE) && --timeout) > udelay(1); > > @@ -1313,6 +1503,51 @@ static void vsc9953_mac_table_flush(int port, int vid) > 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; Use a single space. > + > + 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, > + CONFIG_VSC9953_TAG_VID_PVID); > + break; > + case EGR_TAG_PVID: > + setbits_le32(&l2rew_reg->port[port_no].port_tag_cfg, > + CONFIG_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 & CONFIG_VSC9953_TAG_VID_PVID) > + *mode = EGR_TAG_PVID; > + else > + *mode = EGR_TAG_CLASS; > +} > + > /* IDs used to track keywords in a command */ > enum keyword_id { > id_key_end = -1, > @@ -1330,12 +1565,20 @@ enum keyword_id { > id_add, > id_del, > id_flush, > + id_pvid, > + id_untagged, > + id_all, > + id_none, > + id_egress, > + id_tag, > + id_classified, > id_count, /* keep last */ > }; > > enum keyword_opt_id { > id_port_no = id_count + 1, > id_vlan_no, > + id_pvid_no, > id_add_del_no, > id_add_del_mac, > id_count_all, /* keep last */ > @@ -1520,6 +1763,241 @@ static int vsc9953_learn_set_key_func(struct command_def *parsed_cmd) > return 0; > } > > +#define VSC9953_PVID_HELP "ethsw [port <port_no>] " \ > +"pvid { [help] | show | <pvid> } " \ > +"- set/show PVID (ingress and egress VLAN tagging) for a port" > + > +static int vsc9953_pvid_help_key_func(struct command_def *parsed_cmd) > +{ > + printf(VSC9953_PVID_HELP"\n"); > + > + return 0; Please use: + return CMD_RET_SUCCESS; > +} > + > +static int vsc9953_pvid_show_key_func(struct command_def *parsed_cmd) > +{ > + int i, pvid; > + > + if (parsed_cmd->port != VSC9953_CMD_PORT_ALL) { > + if (vsc9953_port_vlan_pvid_get(parsed_cmd->port, &pvid)) > + return -1; Please use: + 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 0; Please use: + return CMD_RET_SUCCESS; > +} > + > +static int vsc9953_pvid_set_key_func(struct command_def *parsed_cmd) > +{ > + /* PVID number should be set in parsed_cmd->vid */ > + if (parsed_cmd->vid == VSC9953_CMD_VLAN_ALL) { > + printf("Please set a vlan value\n"); > + return -1; Please use: + return CMD_RET_USAGE; > + } > + > + if (parsed_cmd->port != VSC9953_CMD_PORT_ALL) > + vsc9953_port_vlan_pvid_set(parsed_cmd->port, parsed_cmd->vid); > + else > + vsc9953_port_all_vlan_pvid_set(parsed_cmd->vid); > + > + return 0; Please use: + return CMD_RET_SUCCESS; > +} > + > +#define VSC9953_VLAN_HELP "ethsw [port <port_no>] vlan " \ > +"{ [help] | show | add <vid> | del <vid> } " \ > +"- add a VLAN to a port (VLAN members)" > + > +static int vsc9953_vlan_help_key_func(struct command_def *parsed_cmd) > +{ > + printf(VSC9953_VLAN_HELP"\n"); > + > + return 0; Please use: + return CMD_RET_SUCCESS; > +} > + > +static int vsc9953_vlan_show_key_func(struct command_def *parsed_cmd) > +{ > + int i; Use a single space. > + > + if (parsed_cmd->port != VSC9953_CMD_PORT_ALL) { > + vsc9953_vlan_membership_show(parsed_cmd->port); > + } else { > + for (i = 0; i < VSC9953_MAX_PORTS; i++) > + vsc9953_vlan_membership_show(i); > + } > + > + return 0; Please use: + return CMD_RET_SUCCESS; > +} > + > +static int vsc9953_vlan_set_key_func(struct command_def *parsed_cmd) > +{ > + int i, add; > + > + /* VLAN should be set in parsed_cmd->vid */ > + if (parsed_cmd->vid == VSC9953_CMD_VLAN_ALL) { > + printf("Please set a vlan value\n"); > + return -1; Please use: + return CMD_RET_USAGE; > + } > + > + /* keywords add/delete should be the last but one in array */ > + if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 2] == > + id_add) > + add = 1; > + else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 2] == > + id_del) > + add = 0; > + else > + return -1; Please use: + return CMD_RET_USAGE; > + > + if (parsed_cmd->port != VSC9953_CMD_PORT_ALL) { > + 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 0; Please use: + return CMD_RET_SUCCESS; > +} > + > +#define VSC9953_PORT_UNTAG_HELP "ethsw [port <port_no>] untagged " \ > +"{ [help] | show | all | none | pvid } " \ > +" - set egress tagging mod for a port" > + > +static int vsc9953_port_untag_help_key_func(struct command_def *parsed_cmd) > +{ > + printf(VSC9953_PORT_UNTAG_HELP"\n"); > + > + return 0; Please use: + return CMD_RET_SUCCESS; > +} > + > +static int vsc9953_port_untag_show_key_func(struct command_def *parsed_cmd) > +{ > + int i; Use a single space. > + > + printf("%7s\t%17s\n", "Port", "Egress VLAN tag"); > + if (parsed_cmd->port != VSC9953_CMD_PORT_ALL) { > + 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 0; Please use: + return CMD_RET_SUCCESS; > +} > + > +static int vsc9953_port_untag_set_key_func(struct command_def *parsed_cmd) > +{ > + int i; > + enum egress_untag_mode mode; Use a single space. > + > + /* keywords for the untagged mode are the last in the array */ > + if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == > + id_all) > + mode = EGRESS_UNTAG_ALL; > + else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == > + id_none) > + mode = EGRESS_UNTAG_NONE; > + else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == > + id_pvid) > + mode = EGRESS_UNTAG_PVID_AND_ZERO; > + else > + return -1; Please use: + return CMD_RET_USAGE; > + > + if (parsed_cmd->port != VSC9953_CMD_PORT_ALL) { > + 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 0; Please use: + return CMD_RET_SUCCESS; > +} > + > +#define VSC9953_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 vsc9953_egr_tag_help_key_func(struct command_def *parsed_cmd) > +{ > + printf(VSC9953_EGR_VLAN_TAG_HELP"\n"); > + > + return 0; Please use: + return CMD_RET_SUCCESS; > +} > + > +static int vsc9953_egr_vlan_tag_show_key_func(struct command_def *parsed_cmd) > +{ > + int i; > + enum egress_vlan_tag mode; > + > + if (parsed_cmd->port != VSC9953_CMD_PORT_ALL) { > + 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 0; Please use: + return CMD_RET_SUCCESS; > +} > + > +static int vsc9953_egr_vlan_tag_set_key_func(struct 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] == > + id_pvid) > + mode = EGR_TAG_PVID; > + else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == > + id_classified) > + mode = EGR_TAG_CLASS; > + else > + return -1; Please use: + return CMD_RET_USAGE; > + > + if (parsed_cmd->port != VSC9953_CMD_PORT_ALL) { > + 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 0; Please use: + return CMD_RET_SUCCESS; > +} > + > #define VSC9953_FDB_HELP "ethsw [port <port_no>] [vlan <vid>] fdb " \ > "{ [help] | show | flush | { add | del } <mac> } " \ > "- Add/delete a mac entry in FDB; use show to see FDB entries; " \ > @@ -1669,6 +2147,149 @@ struct keywords_to_function { > .keyword_function = &vsc9953_learn_set_key_func, > }, { > .cmd_keyword = { > + id_pvid, > + id_key_end, > + }, > + .keyword_function = &vsc9953_pvid_help_key_func, > + }, { > + .cmd_keyword = { > + id_pvid, > + id_help, > + id_key_end, > + }, > + .keyword_function = &vsc9953_pvid_help_key_func, > + }, { > + .cmd_keyword = { > + id_pvid, > + id_show, > + id_key_end, > + }, > + .keyword_function = &vsc9953_pvid_show_key_func, > + }, { > + .cmd_keyword = { > + id_pvid, > + id_pvid_no, > + id_key_end, > + }, > + .keyword_function = &vsc9953_pvid_set_key_func, > + }, { > + .cmd_keyword = { > + id_vlan, > + id_key_end, > + }, > + .keyword_function = &vsc9953_vlan_help_key_func, > + }, { > + .cmd_keyword = { > + id_vlan, > + id_help, > + id_key_end, > + }, > + .keyword_function = &vsc9953_vlan_help_key_func, > + }, { > + .cmd_keyword = { > + id_vlan, > + id_show, > + id_key_end, > + }, > + .keyword_function = &vsc9953_vlan_show_key_func, > + }, { > + .cmd_keyword = { > + id_vlan, > + id_add, > + id_add_del_no, > + id_key_end, > + }, > + .keyword_function = &vsc9953_vlan_set_key_func, > + }, { > + .cmd_keyword = { > + id_vlan, > + id_del, > + id_add_del_no, > + id_key_end, > + }, > + .keyword_function = &vsc9953_vlan_set_key_func, > + }, { > + .cmd_keyword = { > + id_untagged, > + id_key_end, > + }, > + .keyword_function = &vsc9953_port_untag_help_key_func, > + }, { > + .cmd_keyword = { > + id_untagged, > + id_help, > + id_key_end, > + }, > + .keyword_function = &vsc9953_port_untag_help_key_func, > + }, { > + .cmd_keyword = { > + id_untagged, > + id_show, > + id_key_end, > + }, > + .keyword_function = &vsc9953_port_untag_show_key_func, > + }, { > + .cmd_keyword = { > + id_untagged, > + id_all, > + id_key_end, > + }, > + .keyword_function = &vsc9953_port_untag_set_key_func, > + }, { > + .cmd_keyword = { > + id_untagged, > + id_none, > + id_key_end, > + }, > + .keyword_function = &vsc9953_port_untag_set_key_func, > + }, { > + .cmd_keyword = { > + id_untagged, > + id_pvid, > + id_key_end, > + }, > + .keyword_function = &vsc9953_port_untag_set_key_func, > + }, { > + .cmd_keyword = { > + id_egress, > + id_tag, > + id_key_end, > + }, > + .keyword_function = &vsc9953_egr_tag_help_key_func, > + }, { > + .cmd_keyword = { > + id_egress, > + id_tag, > + id_help, > + id_key_end, > + }, > + .keyword_function = &vsc9953_egr_tag_help_key_func, > + }, { > + .cmd_keyword = { > + id_egress, > + id_tag, > + id_show, > + id_key_end, > + }, > + .keyword_function = &vsc9953_egr_vlan_tag_show_key_func, > + }, { > + .cmd_keyword = { > + id_egress, > + id_tag, > + id_pvid, > + id_key_end, > + }, > + .keyword_function = &vsc9953_egr_vlan_tag_set_key_func, > + }, { > + .cmd_keyword = { > + id_egress, > + id_tag, > + id_classified, > + id_key_end, > + }, > + .keyword_function = &vsc9953_egr_vlan_tag_set_key_func, > + }, { > + .cmd_keyword = { > id_fdb, > id_key_end, > }, > @@ -1748,6 +2369,9 @@ static int keyword_match_port(enum keyword_id key_id, int argc, > static int keyword_match_vlan(enum keyword_id key_id, int argc, > char *const argv[], int *argc_nr, > struct command_def *parsed_cmd); > +static int keyword_match_pvid(enum keyword_id key_id, int argc, > + char *const argv[], int *argc_nr, > + struct command_def *parsed_cmd); > static int keyword_match_mac_addr(enum keyword_id key_id, int argc, > char *const argv[], int *argc_nr, > struct command_def *parsed_cmd); > @@ -1802,6 +2426,27 @@ struct keyword_def { > }, { > .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, > }, > }; > > @@ -1896,6 +2541,33 @@ static int keyword_match_vlan(enum keyword_id key_id, int argc, > return 0; > } > > +/* Function used to match the command's pvid */ > +static int keyword_match_pvid(enum keyword_id key_id, int argc, > + char *const argv[], int *argc_nr, > + struct 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) { > + if (!VSC9953_VLAN_CHECK(val)) { > + printf("Invalid pvid number: %lu\n", val); > + return 0; > + } > + parsed_cmd->vid = val; > + (*argc_nr)++; > + parsed_cmd->cmd_to_keywords[*argc_nr] = id_pvid_no; > + return 1; > + } > + > + return 1; > +} > + > /* check if the string has the format for a MAC address */ > static int string_is_mac_addr(const char *mac) > { > @@ -2094,6 +2766,10 @@ U_BOOT_CMD(ethsw, VSC9953_MAX_CMD_PARAMS, 0, do_ethsw, > VSC9953_PORT_STATS_HELP"\n" > VSC9953_LEARN_HELP"\n" > VSC9953_FDB_HELP"\n" > + VSC9953_VLAN_HELP"\n" > + VSC9953_PVID_HELP"\n" > + VSC9953_PORT_UNTAG_HELP"\n" > + VSC9953_EGR_VLAN_TAG_HELP"\n" > ); > > #endif /* CONFIG_VSC9953_CMD */ > diff --git a/include/vsc9953.h b/include/vsc9953.h > index 051c24e..6eb22a9 100644 > --- a/include/vsc9953.h > +++ b/include/vsc9953.h > @@ -115,6 +115,8 @@ > /* Macros for vsc9953_ana_port.vlan_cfg register */ > #define CONFIG_VSC9953_VLAN_CFG_AWARE_ENA 0x00100000 > #define CONFIG_VSC9953_VLAN_CFG_POP_CNT_MASK 0x000c0000 > +#define CONFIG_VSC9953_VLAN_CFG_POP_CNT_NONE 0x00000000 > +#define CONFIG_VSC9953_VLAN_CFG_POP_CNT_ONE 0x00040000 > #define CONFIG_VSC9953_VLAN_CFG_VID_MASK 0x00000fff > > /* Macros for vsc9953_rew_port.port_vlan_cfg register */ > @@ -149,6 +151,7 @@ > #define CONFIG_VSC9953_TAG_CFG_ALL_PVID_ZERO 0x00000080 > #define CONFIG_VSC9953_TAG_CFG_ALL_ZERO 0x00000100 > #define CONFIG_VSC9953_TAG_CFG_ALL 0x00000180 > +#define CONFIG_VSC9953_TAG_VID_PVID 0x00000010 > > /* Macros for vsc9953_ana_ana.anag_efil register */ > #define CONFIG_VSC9953_AGE_PORT_EN 0x00080000 > -- > 1.9.3 > > _______________________________________________ > U-Boot mailing list > U-Boot@lists.denx.de > http://lists.denx.de/mailman/listinfo/u-boot
Hi Joe, > -----Original Message----- > From: Joe Hershberger [mailto:joe.hershberger@gmail.com] > Sent: Friday, June 26, 2015 1:41 AM > To: Ciubotariu Codrin Constantin-B43658 > Cc: u-boot; Joe Hershberger; Sun York-R58495 > Subject: Re: [U-Boot] [PATCH 08/11 v2] drivers/net/vsc9953: Add VLAN commands > for VSC9953 > > > @@ -270,6 +270,31 @@ static void vsc9953_port_vlan_pvid_set(int port_no, int > pvid) > > field_set(pvid, > CONFIG_VSC9953_PORT_VLAN_CFG_VID_MASK)); > > } > > > > +#ifdef CONFIG_VSC9953_CMD > > Why does this need to be defined outside of the #ifdef already at the > bottom of the file? I added it here so that vsc9953_port_vlan_pvid_get() could be next to its pair, vsc9953_port_vlan_pvid_set(). If you think that it should be at the bottom of the file I can move it. > > + /* Administrative down */ > > + if ((!vsc9953_l2sw.port[port_nr].enabled)) { > > Why do you have double "((" and "))"? By mistake, I will remove one pair. > > +#ifdef CONFIG_VSC9953_CMD > > Why does this need to be defined outside of the #ifdef already at the > bottom of the file? I did this so that similar get/set() functions to be close to one another. Also, the functions guarded by CONFIG_VSC9953_CMD are used only when the ethsw commands are enabled (CONFIG_VSC9953_CMD defined). If a user decides to use the driver for VSC9953, with the switch working in unmanaged state and he doesn't need the commands to configure the switch, he could compile u-boot with CONFIG_VSC9953_CMD undefined. In this case, some warnings will appear at compile time suggesting that functions like vsc9953_port_vlan_egr_untag_get() are defined but not used. > > + /* Administrative down */ > > + if ((!vsc9953_l2sw.port[port_no].enabled)) { > > Why do you have double "((" and "))"? By mistake, I will remove one pair. > > +/* Shiw egress tagging configuration for a VSC9953 port */ > > Shiw -> Show Yes, it's a typo. > > + if (!!(val & (field_set((1 << port_no), > > + CONFIG_VSC9953_VLAN_PORT_MASK)))) > > There is no need for "!!" in an if statement. Drop it and the extra parenthesis. Ok. Thanks and best regards, Codrin
Hi Codrin, On Tue, Jun 30, 2015 at 9:02 AM, Codrin Constantin Ciubotariu <codrin.ciubotariu@freescale.com> wrote: > Hi Joe, > >> -----Original Message----- >> From: Joe Hershberger [mailto:joe.hershberger@gmail.com] >> Sent: Friday, June 26, 2015 1:41 AM >> To: Ciubotariu Codrin Constantin-B43658 >> Cc: u-boot; Joe Hershberger; Sun York-R58495 >> Subject: Re: [U-Boot] [PATCH 08/11 v2] drivers/net/vsc9953: Add VLAN commands >> for VSC9953 >> >> > @@ -270,6 +270,31 @@ static void vsc9953_port_vlan_pvid_set(int port_no, int >> pvid) >> > field_set(pvid, >> CONFIG_VSC9953_PORT_VLAN_CFG_VID_MASK)); >> > } >> > >> > +#ifdef CONFIG_VSC9953_CMD >> >> Why does this need to be defined outside of the #ifdef already at the >> bottom of the file? > > I added it here so that vsc9953_port_vlan_pvid_get() could be next to its pair, vsc9953_port_vlan_pvid_set(). If you think that it should be at the bottom of the file I can move it. OK, I think that makes sense the way you had it. Also, it wouldn't make sense to move out of drivers/net/vsc9953.c, so leave it here. >> > + /* Administrative down */ >> > + if ((!vsc9953_l2sw.port[port_nr].enabled)) { >> >> Why do you have double "((" and "))"? > > By mistake, I will remove one pair. > >> > +#ifdef CONFIG_VSC9953_CMD >> >> Why does this need to be defined outside of the #ifdef already at the >> bottom of the file? > > I did this so that similar get/set() functions to be close to one another. Also, the functions guarded by CONFIG_VSC9953_CMD are used only when the ethsw commands are enabled (CONFIG_VSC9953_CMD defined). If a user decides to use the driver for VSC9953, with the switch working in unmanaged state and he doesn't need the commands to configure the switch, he could compile u-boot with CONFIG_VSC9953_CMD undefined. In this case, some warnings will appear at compile time suggesting that functions like vsc9953_port_vlan_egr_untag_get() are defined but not used. Sounds good. You can leave this here. Thanks, -Joe
diff --git a/drivers/net/vsc9953.c b/drivers/net/vsc9953.c index ef7b50c..b78a941 100644 --- a/drivers/net/vsc9953.c +++ b/drivers/net/vsc9953.c @@ -270,6 +270,31 @@ static void vsc9953_port_vlan_pvid_set(int port_no, int pvid) field_set(pvid, CONFIG_VSC9953_PORT_VLAN_CFG_VID_MASK)); } +#ifdef CONFIG_VSC9953_CMD +/* Set PVID for 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 = field_get(val & CONFIG_VSC9953_VLAN_CFG_VID_MASK, + CONFIG_VSC9953_VLAN_CFG_VID_MASK); + + return 0; +} +#endif + static void vsc9953_port_all_vlan_pvid_set(int pvid) { int i; @@ -407,6 +432,75 @@ static void vsc9953_port_vlan_egr_untag_set(int port_no, } } +#ifdef CONFIG_VSC9953_CMD +/* 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 & CONFIG_VSC9953_TAG_CFG_MASK) { + case CONFIG_VSC9953_TAG_CFG_NONE: + *mode = EGRESS_UNTAG_ALL; + return 0; + case CONFIG_VSC9953_TAG_CFG_ALL_PVID_ZERO: + *mode = EGRESS_UNTAG_PVID_AND_ZERO; + return 0; + case CONFIG_VSC9953_TAG_CFG_ALL_ZERO: + *mode = EGRESS_UNTAG_ZERO; + return 0; + case CONFIG_VSC9953_TAG_CFG_ALL: + *mode = EGRESS_UNTAG_NONE; + return 0; + default: + printf("Unknown egress tagging configuration for port %d\n", + port_no); + return -1; + } +} + +/* Shiw 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", "none"); + break; + case EGRESS_UNTAG_NONE: + printf("%17s\n", "all"); + break; + case EGRESS_UNTAG_PVID_AND_ZERO: + printf("%17s\n", "all but PVID and 0"); + break; + case EGRESS_UNTAG_ZERO: + printf("%17s\n", "all but 0"); + break; + default: + printf("%17s\n", "-"); + } +} +#endif + static void vsc9953_port_all_vlan_egress_untagged_set( enum egress_untag_mode mode) { @@ -954,6 +1048,102 @@ static void vsc9953_port_statistics_clear(int port_no) CONFIG_VSC9953_STAT_CLEAR_DR); } +/* Add/remove a port to/from a VLAN */ +static void vsc9953_vlan_table_membership_set(int vid, u32 port_no, u8 add) +{ + struct vsc9953_analyzer *l2ana_reg; + + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + + VSC9953_ANA_OFFSET); + + if (!vsc9953_vlan_table_poll_idle()) { + debug("VLAN table timeout\n"); + return; + } + + clrsetbits_le32(&l2ana_reg->ana_tables.vlan_tidx, + CONFIG_VSC9953_ANA_TBL_VID_MASK, + field_set(vid, CONFIG_VSC9953_ANA_TBL_VID_MASK)); + clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access, + CONFIG_VSC9953_VLAN_CMD_MASK, + field_set(CONFIG_VSC9953_VLAN_CMD_READ, + CONFIG_VSC9953_VLAN_CMD_MASK)); + + if (!vsc9953_vlan_table_poll_idle()) { + debug("VLAN table timeout\n"); + return; + } + + clrsetbits_le32(&l2ana_reg->ana_tables.vlan_tidx, + CONFIG_VSC9953_ANA_TBL_VID_MASK, + field_set(vid, CONFIG_VSC9953_ANA_TBL_VID_MASK)); + + if (!add) { + clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access, + CONFIG_VSC9953_VLAN_CMD_MASK | + (field_set((1 << port_no), + CONFIG_VSC9953_VLAN_PORT_MASK) & + CONFIG_VSC9953_VLAN_PORT_MASK), + field_set(CONFIG_VSC9953_VLAN_CMD_WRITE, + CONFIG_VSC9953_VLAN_CMD_MASK)); + } else { + clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access, + CONFIG_VSC9953_VLAN_CMD_MASK, + field_set(CONFIG_VSC9953_VLAN_CMD_WRITE, + CONFIG_VSC9953_VLAN_CMD_MASK) | + (field_set((1 << port_no), + CONFIG_VSC9953_VLAN_PORT_MASK) & + CONFIG_VSC9953_VLAN_PORT_MASK)); + } + + /* wait for VLAN table command to flush */ + if (!vsc9953_vlan_table_poll_idle()) { + 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()) { + debug("VLAN table timeout\n"); + return; + } + + clrsetbits_le32(&l2ana_reg->ana_tables.vlan_tidx, + CONFIG_VSC9953_ANA_TBL_VID_MASK, + field_set(vid, + CONFIG_VSC9953_ANA_TBL_VID_MASK)); + clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access, + CONFIG_VSC9953_VLAN_CMD_MASK, + field_set(CONFIG_VSC9953_VLAN_CMD_READ, + CONFIG_VSC9953_VLAN_CMD_MASK)); + + if (!vsc9953_vlan_table_poll_idle()) { + debug("VLAN table timeout\n"); + return; + } + + val = in_le32(&l2ana_reg->ana_tables.vlan_access); + + if (!!(val & (field_set((1 << port_no), + CONFIG_VSC9953_VLAN_PORT_MASK)))) + printf("%d ", vid); + } + printf("\n"); +} + /* wait for FDB to become available */ static int vsc9953_mac_table_poll_idle(void) { @@ -965,7 +1155,7 @@ static int vsc9953_mac_table_poll_idle(void) timeout = 50000; while (((in_le32(&l2ana_reg->ana_tables.mac_access) & - CONFIG_VSC9953_MAC_CMD_MASK) != + CONFIG_VSC9953_MAC_CMD_MASK) != CONFIG_VSC9953_MAC_CMD_IDLE) && --timeout) udelay(1); @@ -1313,6 +1503,51 @@ static void vsc9953_mac_table_flush(int port, int vid) 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, + CONFIG_VSC9953_TAG_VID_PVID); + break; + case EGR_TAG_PVID: + setbits_le32(&l2rew_reg->port[port_no].port_tag_cfg, + CONFIG_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 & CONFIG_VSC9953_TAG_VID_PVID) + *mode = EGR_TAG_PVID; + else + *mode = EGR_TAG_CLASS; +} + /* IDs used to track keywords in a command */ enum keyword_id { id_key_end = -1, @@ -1330,12 +1565,20 @@ enum keyword_id { id_add, id_del, id_flush, + id_pvid, + id_untagged, + id_all, + id_none, + id_egress, + id_tag, + id_classified, id_count, /* keep last */ }; enum keyword_opt_id { id_port_no = id_count + 1, id_vlan_no, + id_pvid_no, id_add_del_no, id_add_del_mac, id_count_all, /* keep last */ @@ -1520,6 +1763,241 @@ static int vsc9953_learn_set_key_func(struct command_def *parsed_cmd) return 0; } +#define VSC9953_PVID_HELP "ethsw [port <port_no>] " \ +"pvid { [help] | show | <pvid> } " \ +"- set/show PVID (ingress and egress VLAN tagging) for a port" + +static int vsc9953_pvid_help_key_func(struct command_def *parsed_cmd) +{ + printf(VSC9953_PVID_HELP"\n"); + + return 0; +} + +static int vsc9953_pvid_show_key_func(struct command_def *parsed_cmd) +{ + int i, pvid; + + if (parsed_cmd->port != VSC9953_CMD_PORT_ALL) { + if (vsc9953_port_vlan_pvid_get(parsed_cmd->port, &pvid)) + return -1; + 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 0; +} + +static int vsc9953_pvid_set_key_func(struct command_def *parsed_cmd) +{ + /* PVID number should be set in parsed_cmd->vid */ + if (parsed_cmd->vid == VSC9953_CMD_VLAN_ALL) { + printf("Please set a vlan value\n"); + return -1; + } + + if (parsed_cmd->port != VSC9953_CMD_PORT_ALL) + vsc9953_port_vlan_pvid_set(parsed_cmd->port, parsed_cmd->vid); + else + vsc9953_port_all_vlan_pvid_set(parsed_cmd->vid); + + return 0; +} + +#define VSC9953_VLAN_HELP "ethsw [port <port_no>] vlan " \ +"{ [help] | show | add <vid> | del <vid> } " \ +"- add a VLAN to a port (VLAN members)" + +static int vsc9953_vlan_help_key_func(struct command_def *parsed_cmd) +{ + printf(VSC9953_VLAN_HELP"\n"); + + return 0; +} + +static int vsc9953_vlan_show_key_func(struct command_def *parsed_cmd) +{ + int i; + + if (parsed_cmd->port != VSC9953_CMD_PORT_ALL) { + vsc9953_vlan_membership_show(parsed_cmd->port); + } else { + for (i = 0; i < VSC9953_MAX_PORTS; i++) + vsc9953_vlan_membership_show(i); + } + + return 0; +} + +static int vsc9953_vlan_set_key_func(struct command_def *parsed_cmd) +{ + int i, add; + + /* VLAN should be set in parsed_cmd->vid */ + if (parsed_cmd->vid == VSC9953_CMD_VLAN_ALL) { + printf("Please set a vlan value\n"); + return -1; + } + + /* keywords add/delete should be the last but one in array */ + if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 2] == + id_add) + add = 1; + else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 2] == + id_del) + add = 0; + else + return -1; + + if (parsed_cmd->port != VSC9953_CMD_PORT_ALL) { + 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 0; +} + +#define VSC9953_PORT_UNTAG_HELP "ethsw [port <port_no>] untagged " \ +"{ [help] | show | all | none | pvid } " \ +" - set egress tagging mod for a port" + +static int vsc9953_port_untag_help_key_func(struct command_def *parsed_cmd) +{ + printf(VSC9953_PORT_UNTAG_HELP"\n"); + + return 0; +} + +static int vsc9953_port_untag_show_key_func(struct command_def *parsed_cmd) +{ + int i; + + printf("%7s\t%17s\n", "Port", "Egress VLAN tag"); + if (parsed_cmd->port != VSC9953_CMD_PORT_ALL) { + 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 0; +} + +static int vsc9953_port_untag_set_key_func(struct 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] == + id_all) + mode = EGRESS_UNTAG_ALL; + else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == + id_none) + mode = EGRESS_UNTAG_NONE; + else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == + id_pvid) + mode = EGRESS_UNTAG_PVID_AND_ZERO; + else + return -1; + + if (parsed_cmd->port != VSC9953_CMD_PORT_ALL) { + 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 0; +} + +#define VSC9953_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 vsc9953_egr_tag_help_key_func(struct command_def *parsed_cmd) +{ + printf(VSC9953_EGR_VLAN_TAG_HELP"\n"); + + return 0; +} + +static int vsc9953_egr_vlan_tag_show_key_func(struct command_def *parsed_cmd) +{ + int i; + enum egress_vlan_tag mode; + + if (parsed_cmd->port != VSC9953_CMD_PORT_ALL) { + 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 0; +} + +static int vsc9953_egr_vlan_tag_set_key_func(struct 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] == + id_pvid) + mode = EGR_TAG_PVID; + else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == + id_classified) + mode = EGR_TAG_CLASS; + else + return -1; + + if (parsed_cmd->port != VSC9953_CMD_PORT_ALL) { + 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 0; +} + #define VSC9953_FDB_HELP "ethsw [port <port_no>] [vlan <vid>] fdb " \ "{ [help] | show | flush | { add | del } <mac> } " \ "- Add/delete a mac entry in FDB; use show to see FDB entries; " \ @@ -1669,6 +2147,149 @@ struct keywords_to_function { .keyword_function = &vsc9953_learn_set_key_func, }, { .cmd_keyword = { + id_pvid, + id_key_end, + }, + .keyword_function = &vsc9953_pvid_help_key_func, + }, { + .cmd_keyword = { + id_pvid, + id_help, + id_key_end, + }, + .keyword_function = &vsc9953_pvid_help_key_func, + }, { + .cmd_keyword = { + id_pvid, + id_show, + id_key_end, + }, + .keyword_function = &vsc9953_pvid_show_key_func, + }, { + .cmd_keyword = { + id_pvid, + id_pvid_no, + id_key_end, + }, + .keyword_function = &vsc9953_pvid_set_key_func, + }, { + .cmd_keyword = { + id_vlan, + id_key_end, + }, + .keyword_function = &vsc9953_vlan_help_key_func, + }, { + .cmd_keyword = { + id_vlan, + id_help, + id_key_end, + }, + .keyword_function = &vsc9953_vlan_help_key_func, + }, { + .cmd_keyword = { + id_vlan, + id_show, + id_key_end, + }, + .keyword_function = &vsc9953_vlan_show_key_func, + }, { + .cmd_keyword = { + id_vlan, + id_add, + id_add_del_no, + id_key_end, + }, + .keyword_function = &vsc9953_vlan_set_key_func, + }, { + .cmd_keyword = { + id_vlan, + id_del, + id_add_del_no, + id_key_end, + }, + .keyword_function = &vsc9953_vlan_set_key_func, + }, { + .cmd_keyword = { + id_untagged, + id_key_end, + }, + .keyword_function = &vsc9953_port_untag_help_key_func, + }, { + .cmd_keyword = { + id_untagged, + id_help, + id_key_end, + }, + .keyword_function = &vsc9953_port_untag_help_key_func, + }, { + .cmd_keyword = { + id_untagged, + id_show, + id_key_end, + }, + .keyword_function = &vsc9953_port_untag_show_key_func, + }, { + .cmd_keyword = { + id_untagged, + id_all, + id_key_end, + }, + .keyword_function = &vsc9953_port_untag_set_key_func, + }, { + .cmd_keyword = { + id_untagged, + id_none, + id_key_end, + }, + .keyword_function = &vsc9953_port_untag_set_key_func, + }, { + .cmd_keyword = { + id_untagged, + id_pvid, + id_key_end, + }, + .keyword_function = &vsc9953_port_untag_set_key_func, + }, { + .cmd_keyword = { + id_egress, + id_tag, + id_key_end, + }, + .keyword_function = &vsc9953_egr_tag_help_key_func, + }, { + .cmd_keyword = { + id_egress, + id_tag, + id_help, + id_key_end, + }, + .keyword_function = &vsc9953_egr_tag_help_key_func, + }, { + .cmd_keyword = { + id_egress, + id_tag, + id_show, + id_key_end, + }, + .keyword_function = &vsc9953_egr_vlan_tag_show_key_func, + }, { + .cmd_keyword = { + id_egress, + id_tag, + id_pvid, + id_key_end, + }, + .keyword_function = &vsc9953_egr_vlan_tag_set_key_func, + }, { + .cmd_keyword = { + id_egress, + id_tag, + id_classified, + id_key_end, + }, + .keyword_function = &vsc9953_egr_vlan_tag_set_key_func, + }, { + .cmd_keyword = { id_fdb, id_key_end, }, @@ -1748,6 +2369,9 @@ static int keyword_match_port(enum keyword_id key_id, int argc, static int keyword_match_vlan(enum keyword_id key_id, int argc, char *const argv[], int *argc_nr, struct command_def *parsed_cmd); +static int keyword_match_pvid(enum keyword_id key_id, int argc, + char *const argv[], int *argc_nr, + struct command_def *parsed_cmd); static int keyword_match_mac_addr(enum keyword_id key_id, int argc, char *const argv[], int *argc_nr, struct command_def *parsed_cmd); @@ -1802,6 +2426,27 @@ struct keyword_def { }, { .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, }, }; @@ -1896,6 +2541,33 @@ static int keyword_match_vlan(enum keyword_id key_id, int argc, return 0; } +/* Function used to match the command's pvid */ +static int keyword_match_pvid(enum keyword_id key_id, int argc, + char *const argv[], int *argc_nr, + struct 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) { + if (!VSC9953_VLAN_CHECK(val)) { + printf("Invalid pvid number: %lu\n", val); + return 0; + } + parsed_cmd->vid = val; + (*argc_nr)++; + parsed_cmd->cmd_to_keywords[*argc_nr] = id_pvid_no; + return 1; + } + + return 1; +} + /* check if the string has the format for a MAC address */ static int string_is_mac_addr(const char *mac) { @@ -2094,6 +2766,10 @@ U_BOOT_CMD(ethsw, VSC9953_MAX_CMD_PARAMS, 0, do_ethsw, VSC9953_PORT_STATS_HELP"\n" VSC9953_LEARN_HELP"\n" VSC9953_FDB_HELP"\n" + VSC9953_VLAN_HELP"\n" + VSC9953_PVID_HELP"\n" + VSC9953_PORT_UNTAG_HELP"\n" + VSC9953_EGR_VLAN_TAG_HELP"\n" ); #endif /* CONFIG_VSC9953_CMD */ diff --git a/include/vsc9953.h b/include/vsc9953.h index 051c24e..6eb22a9 100644 --- a/include/vsc9953.h +++ b/include/vsc9953.h @@ -115,6 +115,8 @@ /* Macros for vsc9953_ana_port.vlan_cfg register */ #define CONFIG_VSC9953_VLAN_CFG_AWARE_ENA 0x00100000 #define CONFIG_VSC9953_VLAN_CFG_POP_CNT_MASK 0x000c0000 +#define CONFIG_VSC9953_VLAN_CFG_POP_CNT_NONE 0x00000000 +#define CONFIG_VSC9953_VLAN_CFG_POP_CNT_ONE 0x00040000 #define CONFIG_VSC9953_VLAN_CFG_VID_MASK 0x00000fff /* Macros for vsc9953_rew_port.port_vlan_cfg register */ @@ -149,6 +151,7 @@ #define CONFIG_VSC9953_TAG_CFG_ALL_PVID_ZERO 0x00000080 #define CONFIG_VSC9953_TAG_CFG_ALL_ZERO 0x00000100 #define CONFIG_VSC9953_TAG_CFG_ALL 0x00000180 +#define CONFIG_VSC9953_TAG_VID_PVID 0x00000010 /* Macros for vsc9953_ana_ana.anag_efil register */ #define CONFIG_VSC9953_AGE_PORT_EN 0x00080000