diff options
author | Codrin Ciubotariu <codrin.ciubotariu@freescale.com> | 2015-07-24 16:55:30 +0300 |
---|---|---|
committer | York Sun <yorksun@freescale.com> | 2015-09-21 08:29:47 -0700 |
commit | 68c929da6bf754ace639b2159e2d5b9e22323aaa (patch) | |
tree | 0c4be2ff82ca86a48eeaee9d330e5318202ad89a /drivers | |
parent | 86719f0cd55bc13186798217b08fa6a048eda27c (diff) |
drivers/net/vsc9953: Add commands to enable/disable HW learning
The command:
ethsw [port <port_no>] learning { [help] | show | auto | disable }
can be used to enable/disable HW learning on a port.
This patch also adds this command to the generic ethsw parser from
cmd_ethsw.
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/vsc9953.c | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/drivers/net/vsc9953.c b/drivers/net/vsc9953.c index 1dddb44c8bf..21b14e6a190 100644 --- a/drivers/net/vsc9953.c +++ b/drivers/net/vsc9953.c @@ -717,6 +717,72 @@ static void vsc9953_port_statistics_clear(int port_no) VSC9953_STAT_CLEAR_DR); } +enum port_learn_mode { + PORT_LEARN_NONE, + PORT_LEARN_AUTO +}; + +/* Set learning configuration for a VSC9953 port */ +static void vsc9953_port_learn_mode_set(int port_no, enum port_learn_mode mode) +{ + struct vsc9953_analyzer *l2ana_reg; + + /* Administrative down */ + if (!vsc9953_l2sw.port[port_no].enabled) { + printf("Port %d is administrative down\n", port_no); + return; + } + + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + + VSC9953_ANA_OFFSET); + + switch (mode) { + case PORT_LEARN_NONE: + clrbits_le32(&l2ana_reg->port[port_no].port_cfg, + VSC9953_PORT_CFG_LEARN_DROP | + VSC9953_PORT_CFG_LEARN_CPU | + VSC9953_PORT_CFG_LEARN_AUTO | + VSC9953_PORT_CFG_LEARN_ENA); + break; + case PORT_LEARN_AUTO: + clrsetbits_le32(&l2ana_reg->port[port_no].port_cfg, + VSC9953_PORT_CFG_LEARN_DROP | + VSC9953_PORT_CFG_LEARN_CPU, + VSC9953_PORT_CFG_LEARN_ENA | + VSC9953_PORT_CFG_LEARN_AUTO); + break; + default: + printf("Unknown learn mode for port %d\n", port_no); + } +} + +/* Get learning configuration for a VSC9953 port */ +static int vsc9953_port_learn_mode_get(int port_no, enum port_learn_mode *mode) +{ + u32 val; + struct vsc9953_analyzer *l2ana_reg; + + /* Administrative down */ + if (!vsc9953_l2sw.port[port_no].enabled) { + printf("Port %d is administrative down\n", port_no); + return -1; + } + + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + + VSC9953_ANA_OFFSET); + + /* For now we only support HW learning (auto) and no learning */ + val = in_le32(&l2ana_reg->port[port_no].port_cfg); + if ((val & (VSC9953_PORT_CFG_LEARN_ENA | + VSC9953_PORT_CFG_LEARN_AUTO)) == + (VSC9953_PORT_CFG_LEARN_ENA | VSC9953_PORT_CFG_LEARN_AUTO)) + *mode = PORT_LEARN_AUTO; + else + *mode = PORT_LEARN_NONE; + + return 0; +} + static int vsc9953_port_status_key_func(struct ethsw_command_def *parsed_cmd) { int i; @@ -810,6 +876,79 @@ static int vsc9953_port_stats_clear_key_func(struct ethsw_command_def return CMD_RET_SUCCESS; } +static int vsc9953_learn_show_key_func(struct ethsw_command_def *parsed_cmd) +{ + int i; + enum port_learn_mode 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; + } + if (vsc9953_port_learn_mode_get(parsed_cmd->port, &mode)) + return CMD_RET_FAILURE; + printf("%7s %11s\n", "Port", "Learn mode"); + switch (mode) { + case PORT_LEARN_NONE: + printf("%7d %11s\n", parsed_cmd->port, "disable"); + break; + case PORT_LEARN_AUTO: + printf("%7d %11s\n", parsed_cmd->port, "auto"); + break; + default: + printf("%7d %11s\n", parsed_cmd->port, "-"); + } + } else { + printf("%7s %11s\n", "Port", "Learn mode"); + for (i = 0; i < VSC9953_MAX_PORTS; i++) { + if (vsc9953_port_learn_mode_get(i, &mode)) + continue; + switch (mode) { + case PORT_LEARN_NONE: + printf("%7d %11s\n", i, "disable"); + break; + case PORT_LEARN_AUTO: + printf("%7d %11s\n", i, "auto"); + break; + default: + printf("%7d %11s\n", i, "-"); + } + } + } + + return CMD_RET_SUCCESS; +} + +static int vsc9953_learn_set_key_func(struct ethsw_command_def *parsed_cmd) +{ + int i; + enum port_learn_mode mode; + + /* Last keyword should tell us the learn mode */ + if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == + ethsw_id_auto) + mode = PORT_LEARN_AUTO; + else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == + ethsw_id_disable) + mode = PORT_LEARN_NONE; + 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_learn_mode_set(parsed_cmd->port, mode); + } else { + for (i = 0; i < VSC9953_MAX_PORTS; i++) + vsc9953_port_learn_mode_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, @@ -817,6 +956,8 @@ static struct ethsw_command_func vsc9953_cmd_func = { .port_show = &vsc9953_port_config_key_func, .port_stats = &vsc9953_port_stats_key_func, .port_stats_clear = &vsc9953_port_stats_clear_key_func, + .port_learn = &vsc9953_learn_set_key_func, + .port_learn_show = &vsc9953_learn_show_key_func, }; #endif /* CONFIG_CMD_ETHSW */ |