
Hi Codrin,
On Tue, Jun 23, 2015 at 11:48 AM, Codrin Ciubotariu codrin.ciubotariu@freescale.com wrote:
The new command: ethsw [port <port_no>] [vlan <vid>] fdb { [help] | show | flush | { add | del } <mac> }
Can be used to add and delete FDB entries. Also, the command can be used to show entries from the FDB tables. When used with [port <port_no>] and [vlan <vid>], only the matching the FDB entries can be seen or flushed.
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 | 635 +++++++++++++++++++++++++++++++++++++++++++++++++- include/vsc9953.h | 28 +++ 2 files changed, 662 insertions(+), 1 deletion(-)
diff --git a/drivers/net/vsc9953.c b/drivers/net/vsc9953.c index 1936c4a..ef7b50c 100644 --- a/drivers/net/vsc9953.c +++ b/drivers/net/vsc9953.c @@ -12,6 +12,7 @@ #include <fsl_memac.h> #include <errno.h> #include <vsc9953.h> +#include <linux/ctype.h>
static struct vsc9953_info vsc9953_l2sw = { .port[0] = VSC9953_PORT_INFO_INITIALIZER(0), @@ -579,6 +580,7 @@ void vsc9953_init(bd_t *bis)
#define VSC9953_MAX_CMD_PARAMS 20 #define VSC9953_CMD_PORT_ALL -1 +#define VSC9953_CMD_VLAN_ALL -1
/* Enable/disable status of a VSC9953 port */ static void vsc9953_port_status_set(int port_no, u8 enabled) @@ -952,6 +954,365 @@ static void vsc9953_port_statistics_clear(int port_no) CONFIG_VSC9953_STAT_CLEAR_DR); }
+/* wait for FDB to become available */ +static int vsc9953_mac_table_poll_idle(void) +{
struct vsc9953_analyzer *l2ana_reg;
u32 timeout;
Use a single space.
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
VSC9953_ANA_OFFSET);
timeout = 50000;
while (((in_le32(&l2ana_reg->ana_tables.mac_access) &
CONFIG_VSC9953_MAC_CMD_MASK) !=
CONFIG_VSC9953_MAC_CMD_IDLE) && --timeout)
udelay(1);
return !!timeout;
Maybe return -EBUSY like suggested in previous patch.
+}
+/* enum describing available commands for the MAC table */ +enum mac_table_cmd {
MAC_TABLE_READ_DIRECT,
MAC_TABLE_READ_INDIRECT,
MAC_TABLE_WRITE,
MAC_TABLE_LEARN,
MAC_TABLE_FORGET,
MAC_TABLE_GET_NEXT,
MAC_TABLE_AGE,
+};
+/* Issues a command to the FDB table */ +static int vsc9953_mac_table_cmd(enum mac_table_cmd cmd) +{
struct vsc9953_analyzer *l2ana_reg;
Use a single space.
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
VSC9953_ANA_OFFSET);
switch (cmd) {
case MAC_TABLE_READ_DIRECT:
clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
CONFIG_VSC9953_MAC_CMD_MASK |
CONFIG_VSC9953_MAC_CMD_VALID,
CONFIG_VSC9953_MAC_CMD_READ);
break;
case MAC_TABLE_READ_INDIRECT:
clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
CONFIG_VSC9953_MAC_CMD_MASK,
CONFIG_VSC9953_MAC_CMD_READ |
CONFIG_VSC9953_MAC_CMD_VALID);
break;
case MAC_TABLE_WRITE:
clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
CONFIG_VSC9953_MAC_CMD_MASK |
CONFIG_VSC9953_MAC_ENTRYTYPE_MASK,
CONFIG_VSC9953_MAC_CMD_WRITE |
CONFIG_VSC9953_MAC_ENTRYTYPE_LOCKED);
break;
case MAC_TABLE_LEARN:
clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
CONFIG_VSC9953_MAC_CMD_MASK |
CONFIG_VSC9953_MAC_ENTRYTYPE_MASK,
CONFIG_VSC9953_MAC_CMD_LEARN |
CONFIG_VSC9953_MAC_ENTRYTYPE_LOCKED |
CONFIG_VSC9953_MAC_CMD_VALID);
break;
case MAC_TABLE_FORGET:
clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
CONFIG_VSC9953_MAC_CMD_MASK |
CONFIG_VSC9953_MAC_ENTRYTYPE_MASK,
CONFIG_VSC9953_MAC_CMD_FORGET);
break;
case MAC_TABLE_GET_NEXT:
clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
CONFIG_VSC9953_MAC_CMD_MASK |
CONFIG_VSC9953_MAC_ENTRYTYPE_MASK,
CONFIG_VSC9953_MAC_CMD_NEXT);
break;
case MAC_TABLE_AGE:
clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
CONFIG_VSC9953_MAC_CMD_MASK |
CONFIG_VSC9953_MAC_ENTRYTYPE_MASK,
CONFIG_VSC9953_MAC_CMD_AGE);
break;
default:
printf("Unknown MAC table command\n");
}
if (!vsc9953_mac_table_poll_idle()) {
debug("MAC table timeout\n");
return -1;
}
/* For some commands we might have a way to
* detect if the command succeeded
*/
if ((cmd == MAC_TABLE_GET_NEXT || cmd == MAC_TABLE_READ_DIRECT ||
MAC_TABLE_READ_INDIRECT) &&
!(in_le32(&l2ana_reg->ana_tables.mac_access) &
CONFIG_VSC9953_MAC_CMD_VALID))
return -1;
return 0;
+}
+/* show the FDB entries that correspond to a port and a VLAN */ +static void vsc9953_mac_table_show(int port_no, int vid) +{
int i, rc[VSC9953_MAX_PORTS];
u32 val, vlan, mach, macl, dest_indx;
Use a separate line for each variable.
enum port_learn_mode mode[VSC9953_MAX_PORTS];
struct vsc9953_analyzer *l2ana_reg;
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
VSC9953_ANA_OFFSET);
/* disable auto learning */
if (port_no == VSC9953_CMD_PORT_ALL) {
for (i = 0; i < VSC9953_MAX_PORTS; i++) {
rc[i] = vsc9953_port_learn_mode_get(i, &mode[i]);
if (!rc[i] && mode[i] != PORT_LEARN_NONE)
vsc9953_port_learn_mode_set(i,
PORT_LEARN_NONE);
}
} else {
rc[port_no] = vsc9953_port_learn_mode_get(port_no,
&mode[port_no]);
if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE)
vsc9953_port_learn_mode_set(port_no, PORT_LEARN_NONE);
}
/* write port and vid to get selected FDB entries */
val = in_le32(&l2ana_reg->ana.anag_efil);
if (port_no != VSC9953_CMD_PORT_ALL) {
val = (val & ~CONFIG_VSC9953_AGE_PORT_MASK) |
CONFIG_VSC9953_AGE_PORT_EN |
field_set(port_no,
CONFIG_VSC9953_AGE_PORT_MASK);
Seems like a good place to use bitfield_replace() from include/bitfield.h (or a new one that you add that uses the mask for the shift).
}
if (vid != VSC9953_CMD_VLAN_ALL) {
val = (val & ~CONFIG_VSC9953_AGE_VID_MASK) |
CONFIG_VSC9953_AGE_VID_EN |
field_set(vid, CONFIG_VSC9953_AGE_VID_MASK);
Same here.
}
out_le32(&l2ana_reg->ana.anag_efil, val);
/* set MAC and VLAN to 0 to look from beginning */
clrbits_le32(&l2ana_reg->ana_tables.mach_data,
CONFIG_VSC9953_MAC_VID_MASK |
CONFIG_VSC9953_MAC_MACH_MASK);
out_le32(&l2ana_reg->ana_tables.macl_data, 0);
/* get entries */
printf("%10s %17s %5s %4s\n", "EntryType", "MAC", "PORT", "VID");
do {
/* get out when an invalid entry is found */
if (vsc9953_mac_table_cmd(MAC_TABLE_GET_NEXT))
break;
val = in_le32(&l2ana_reg->ana_tables.mac_access);
switch (val & CONFIG_VSC9953_MAC_ENTRYTYPE_MASK) {
case CONFIG_VSC9953_MAC_ENTRYTYPE_NORMAL:
printf("%10s ", "Dynamic");
break;
case CONFIG_VSC9953_MAC_ENTRYTYPE_LOCKED:
printf("%10s ", "Static");
break;
case CONFIG_VSC9953_MAC_ENTRYTYPE_IPV4MCAST:
printf("%10s ", "IPv4 Mcast");
break;
case CONFIG_VSC9953_MAC_ENTRYTYPE_IPV6MCAST:
printf("%10s ", "IPv6 Mcast");
break;
default:
printf("%10s ", "Unknown");
}
dest_indx = field_get(val & CONFIG_VSC9953_MAC_DESTIDX_MASK,
CONFIG_VSC9953_MAC_DESTIDX_MASK);
val = in_le32(&l2ana_reg->ana_tables.mach_data);
vlan = field_get(val & CONFIG_VSC9953_MAC_VID_MASK,
CONFIG_VSC9953_MAC_VID_MASK);
It seems like masking off the val before shifting it would be better implemented inside the field_get function (renamed and moved to include/bitfield.h) instead of on each use.
mach = field_get(val & CONFIG_VSC9953_MAC_MACH_MASK,
CONFIG_VSC9953_MAC_MACH_MASK);
macl = in_le32(&l2ana_reg->ana_tables.macl_data);
printf("%02x:%02x:%02x:%02x:%02x:%02x ", (mach >> 8) & 0xff,
mach & 0xff, (macl >> 24) & 0xff, (macl >> 16) & 0xff,
(macl >> 8) & 0xff, macl & 0xff);
printf("%5d ", dest_indx);
printf("%4d\n", vlan);
} while (1);
/* set learning mode to previous value */
if (port_no == VSC9953_CMD_PORT_ALL) {
for (i = 0; i < VSC9953_MAX_PORTS; i++) {
if (!rc[i] && mode[i] != PORT_LEARN_NONE)
vsc9953_port_learn_mode_set(i, mode[i]);
}
} else {
/* If administrative down, skip */
if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE)
vsc9953_port_learn_mode_set(port_no, mode[port_no]);
}
/* reset FDB port and VLAN FDB selection */
clrbits_le32(&l2ana_reg->ana.anag_efil, CONFIG_VSC9953_AGE_PORT_EN |
CONFIG_VSC9953_AGE_PORT_MASK | CONFIG_VSC9953_AGE_VID_EN |
CONFIG_VSC9953_AGE_VID_MASK);
+}
+/* Add a static FDB entry */ +static int vsc9953_mac_table_add(u8 port_no, uchar mac[6], int vid) +{
u32 val;
struct vsc9953_analyzer *l2ana_reg;
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
VSC9953_ANA_OFFSET);
out_le32(&l2ana_reg->ana_tables.mach_data,
(mac[0] << 8) | (mac[1] << 0) |
(field_set(vid, CONFIG_VSC9953_MACHDATA_VID_MASK) &
CONFIG_VSC9953_MACHDATA_VID_MASK));
Why do you need to & with the mask again after field_set()?
out_le32(&l2ana_reg->ana_tables.macl_data,
(mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) |
(mac[5] << 0));
/* set on which port is the MAC address added */
clrsetbits_le32(&l2ana_reg->ana_tables.mac_access,
CONFIG_VSC9953_MAC_DESTIDX_MASK,
field_set(port_no, CONFIG_VSC9953_MAC_DESTIDX_MASK));
if (vsc9953_mac_table_cmd(MAC_TABLE_LEARN))
return -1;
/* check if the MAC address was indeed added */
out_le32(&l2ana_reg->ana_tables.mach_data,
(mac[0] << 8) | (mac[1] << 0) |
(field_set(vid, CONFIG_VSC9953_MACHDATA_VID_MASK) &
CONFIG_VSC9953_MACHDATA_VID_MASK));
Why do you need to & with the mask again after field_set()?
out_le32(&l2ana_reg->ana_tables.macl_data,
(mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) |
(mac[5] << 0));
if (vsc9953_mac_table_cmd(MAC_TABLE_READ_DIRECT))
return -1;
val = in_le32(&l2ana_reg->ana_tables.mac_access);
if ((port_no != field_get(val & CONFIG_VSC9953_MAC_DESTIDX_MASK,
CONFIG_VSC9953_MAC_DESTIDX_MASK))) {
printf("Failed to add MAC address\n");
return -1;
}
return 0;
+}
+/* Delete a FDB entry */ +static int vsc9953_mac_table_del(uchar mac[6], u16 vid) +{
struct vsc9953_analyzer *l2ana_reg;
Use a single space.
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
VSC9953_ANA_OFFSET);
/* check first if MAC entry is present */
out_le32(&l2ana_reg->ana_tables.mach_data,
(mac[0] << 8) | (mac[1] << 0) |
(field_set(vid, CONFIG_VSC9953_MACHDATA_VID_MASK) &
CONFIG_VSC9953_MACHDATA_VID_MASK));
Why do you need to & with the mask again after field_set()?
out_le32(&l2ana_reg->ana_tables.macl_data,
(mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) |
(mac[5] << 0));
if (vsc9953_mac_table_cmd(MAC_TABLE_READ_INDIRECT)) {
printf("The MAC address: %02x:%02x:%02x:%02x:%02x:%02x ",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
printf("VLAN: %d does not exist.\n", vid);
return -1;
}
/* FDB entry found, proceed to delete */
out_le32(&l2ana_reg->ana_tables.mach_data, (mac[0] << 8) |
(mac[1] << 0) |
(field_set(vid, CONFIG_VSC9953_MACHDATA_VID_MASK) &
CONFIG_VSC9953_MACHDATA_VID_MASK));
Why do you need to & with the mask again after field_set()?
out_le32(&l2ana_reg->ana_tables.macl_data, (mac[2] << 24) |
(mac[3] << 16) | (mac[4] << 8) | (mac[5] << 0));
if (vsc9953_mac_table_cmd(MAC_TABLE_FORGET))
return -1;
/* check if the MAC entry is still in FDB */
out_le32(&l2ana_reg->ana_tables.mach_data, (mac[0] << 8) |
(mac[1] << 0) |
(field_set(vid, CONFIG_VSC9953_MACHDATA_VID_MASK) &
CONFIG_VSC9953_MACHDATA_VID_MASK));
Why do you need to & with the mask again after field_set()?
out_le32(&l2ana_reg->ana_tables.macl_data, (mac[2] << 24) |
(mac[3] << 16) | (mac[4] << 8) | (mac[5] << 0));
if (vsc9953_mac_table_cmd(MAC_TABLE_READ_INDIRECT)) {
printf("Failed to delete MAC address\n");
return -1;
}
return 0;
+}
+/* age the unlocked entries in FDB */ +static void vsc9953_mac_table_age(int port_no, int vid) +{
int rc;
u32 val;
struct vsc9953_analyzer *l2ana_reg;
enum port_learn_mode mode;
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
VSC9953_ANA_OFFSET);
/* disable auto learning */
rc = vsc9953_port_learn_mode_get(port_no, &mode);
if (!rc && mode != PORT_LEARN_NONE)
vsc9953_port_learn_mode_set(port_no, PORT_LEARN_NONE);
/* set port and VID for selective aging */
val = in_le32(&l2ana_reg->ana.anag_efil);
if (port_no != VSC9953_CMD_PORT_ALL) {
val = (val & ~CONFIG_VSC9953_AGE_PORT_MASK) |
CONFIG_VSC9953_AGE_PORT_EN |
field_set(port_no, CONFIG_VSC9953_AGE_PORT_MASK);
Seems like a good place to use bitfield_replace() from include/bitfield.h (or a new one that you add that uses the mask for the shift).
}
if (vid != VSC9953_CMD_VLAN_ALL) {
val = (val & ~CONFIG_VSC9953_AGE_VID_MASK) |
CONFIG_VSC9953_AGE_VID_EN |
field_set(vid, CONFIG_VSC9953_AGE_VID_MASK);
Same here.
}
out_le32(&l2ana_reg->ana.anag_efil, val);
/* age the dynamic FDB entries */
vsc9953_mac_table_cmd(MAC_TABLE_AGE);
/* clear previously set port and VID */
clrbits_le32(&l2ana_reg->ana.anag_efil, CONFIG_VSC9953_AGE_PORT_EN |
CONFIG_VSC9953_AGE_PORT_MASK | CONFIG_VSC9953_AGE_VID_EN |
CONFIG_VSC9953_AGE_VID_MASK);
if (!rc && mode != PORT_LEARN_NONE)
vsc9953_port_learn_mode_set(port_no, mode);
+}
+/* Delete all the dynamic FDB entries */ +static void vsc9953_mac_table_flush(int port, int vid) +{
vsc9953_mac_table_age(port, vid);
vsc9953_mac_table_age(port, vid);
+}
/* IDs used to track keywords in a command */ enum keyword_id { id_key_end = -1, @@ -964,11 +1325,19 @@ enum keyword_id { id_clear, id_learning, id_auto,
id_vlan,
id_fdb,
id_add,
id_del,
id_flush, id_count, /* keep last */
};
enum keyword_opt_id { id_port_no = id_count + 1,
id_vlan_no,
id_add_del_no,
id_add_del_mac, id_count_all, /* keep last */
};
@@ -977,6 +1346,8 @@ struct command_def { int cmd_keywords_nr; int port; int err;
int vid;
uchar *mac_addr;
Use this: + uchar ethaddr[6]; I recently made a pass through U-Boot trying to standardize on that naming. Also, don't make it a pointer that has to be allocated. It is small and of known size.
int (*cmd_function)(struct command_def *parsed_cmd);
};
@@ -1149,6 +1520,77 @@ static int vsc9953_learn_set_key_func(struct command_def *parsed_cmd) 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; " \ +"if vlan <vid> is missing, will be used VID 1"
Please use this: +"if vlan <vid> is missing, VID 1 will be used"
+static int vsc9953_fdb_help_key_func(struct command_def *parsed_cmd) +{
printf(VSC9953_FDB_HELP"\n");
return 0;
Please use: + return CMD_RET_SUCCESS;
+}
+static int vsc9953_fdb_show_key_func(struct command_def *parsed_cmd) +{
vsc9953_mac_table_show(parsed_cmd->port, parsed_cmd->vid);
return 0;
Please use: + return CMD_RET_SUCCESS;
+}
+static int vsc9953_fdb_flush_key_func(struct command_def *parsed_cmd) +{
vsc9953_mac_table_flush(parsed_cmd->port, parsed_cmd->vid);
return 0;
Please use: + return CMD_RET_SUCCESS;
+}
+static int vsc9953_fdb_entry_add_key_func(struct command_def *parsed_cmd) +{
int vid;
/* check if MAC address is present */
if (!parsed_cmd->mac_addr) {
Use this: + if (is_valid_ethaddr(parsed_cmd->mac_addr)) {
printf("Please use a valid MAC address\n");
return -EINVAL;
Please use: + return CMD_RET_USAGE;
}
/* a port number must be present */
if (parsed_cmd->port == VSC9953_CMD_PORT_ALL) {
printf("Please specify a port\n");
return -EINVAL;
Please use: + return CMD_RET_USAGE;
}
/* Use VLAN 1 if VID is not set */
vid = (parsed_cmd->vid == VSC9953_CMD_VLAN_ALL ? 1 : parsed_cmd->vid);
if (vsc9953_mac_table_add(parsed_cmd->port, parsed_cmd->mac_addr, vid))
return -1;
Please use: + return CMD_RET_FAILURE;
return 0;
Please use: + return CMD_RET_SUCCESS;
+}
+static int vsc9953_fdb_entry_del_key_func(struct command_def *parsed_cmd) +{
int vid;
/* check if MAC address is present */
if (!parsed_cmd->mac_addr) {
Use this: + if (is_valid_ethaddr(parsed_cmd->mac_addr)) {
printf("Please use a valid MAC address\n");
return -EINVAL;
Please use: + return CMD_RET_USAGE;
}
/* Use VLAN 1 if VID is not set */
vid = (parsed_cmd->vid == VSC9953_CMD_VLAN_ALL ?
1 : parsed_cmd->vid);
if (vsc9953_mac_table_del(parsed_cmd->mac_addr, vid))
return -1;
Please use: + return CMD_RET_FAILURE;
return 0;
Please use: + return CMD_RET_SUCCESS;
+}
struct keywords_to_function { enum keyword_id cmd_keyword[VSC9953_MAX_CMD_PARAMS]; int (*keyword_function)(struct command_def *parsed_cmd); @@ -1225,6 +1667,49 @@ struct keywords_to_function { id_key_end, }, .keyword_function = &vsc9953_learn_set_key_func,
}, {
.cmd_keyword = {
id_fdb,
id_key_end,
},
.keyword_function = &vsc9953_fdb_help_key_func,
}, {
.cmd_keyword = {
id_fdb,
id_help,
id_key_end,
},
.keyword_function = &vsc9953_fdb_help_key_func,
}, {
.cmd_keyword = {
id_fdb,
id_show,
id_key_end,
},
.keyword_function = &vsc9953_fdb_show_key_func,
}, {
.cmd_keyword = {
id_fdb,
id_flush,
id_key_end,
},
.keyword_function = &vsc9953_fdb_flush_key_func,
}, {
.cmd_keyword = {
id_fdb,
id_add,
id_add_del_mac,
id_key_end,
},
.keyword_function = &vsc9953_fdb_entry_add_key_func,
}, {
.cmd_keyword = {
id_fdb,
id_del,
id_add_del_mac,
id_key_end,
},
.keyword_function = &vsc9953_fdb_entry_del_key_func, },
};
@@ -1237,6 +1722,20 @@ struct keywords_optional { id_port_no, id_key_end, },
}, {
.cmd_keyword = {
id_vlan,
id_vlan_no,
id_key_end,
},
}, {
.cmd_keyword = {
id_port,
id_port_no,
id_vlan,
id_vlan_no,
id_key_end,
}, },
};
@@ -1246,6 +1745,12 @@ static int keyword_match_gen(enum keyword_id key_id, int argc, static int keyword_match_port(enum keyword_id key_id, int argc, char *const argv[], int *argc_nr, struct command_def *parsed_cmd); +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_mac_addr(enum keyword_id key_id, int argc,
char *const argv[], int *argc_nr,
struct command_def *parsed_cmd);
/* Define properties for each keyword;
- keep the order synced with enum keyword_id
@@ -1282,6 +1787,21 @@ struct keyword_def { }, { .keyword_name = "auto", .match = &keyword_match_gen,
}, {
.keyword_name = "vlan",
.match = &keyword_match_vlan,
}, {
.keyword_name = "fdb",
.match = &keyword_match_gen,
}, {
.keyword_name = "add",
.match = &keyword_match_mac_addr,
}, {
.keyword_name = "del",
.match = &keyword_match_mac_addr,
}, {
.keyword_name = "flush",
.match = &keyword_match_gen, },
};
@@ -1325,6 +1845,112 @@ static int keyword_match_port(enum keyword_id key_id, int argc, return 0; }
+/* Function used to match the command's vlan */ +static int keyword_match_vlan(enum keyword_id key_id, int argc,
char *const argv[], int *argc_nr,
struct command_def *parsed_cmd)
+{
unsigned long val;
int aux;
Use a single space.
if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
return 0;
if (*argc_nr + 1 >= argc)
return 0;
if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) {
if (!VSC9953_VLAN_CHECK(val)) {
printf("Invalid vlan number: %lu\n", val);
return 0;
}
parsed_cmd->vid = val;
(*argc_nr)++;
parsed_cmd->cmd_to_keywords[*argc_nr] = id_vlan_no;
return 1;
}
aux = *argc_nr + 1;
if (keyword_match_gen(id_add, argc, argv, &aux, parsed_cmd))
parsed_cmd->cmd_to_keywords[*argc_nr + 1] = id_add;
else if (keyword_match_gen(id_del, argc, argv, &aux, parsed_cmd))
parsed_cmd->cmd_to_keywords[*argc_nr + 1] = id_del;
else
return 0;
if (*argc_nr + 2 >= argc)
return 0;
if (strict_strtoul(argv[*argc_nr + 2], 10, &val) != -EINVAL) {
if (!VSC9953_VLAN_CHECK(val)) {
printf("Invalid vlan number: %lu\n", val);
return 0;
}
parsed_cmd->vid = val;
(*argc_nr) += 2;
parsed_cmd->cmd_to_keywords[*argc_nr] = id_add_del_no;
return 1;
}
return 0;
+}
+/* check if the string has the format for a MAC address */ +static int string_is_mac_addr(const char *mac) +{
int i;
if (!mac)
return 0;
for (i = 0; i < 6; i++) {
if (!isxdigit(*mac) || !isxdigit(*(mac + 1)))
return 0;
mac += 2;
if (i != 5) {
if (*mac != ':' && *mac != '-')
return 0;
mac++;
}
}
if (*mac != '\0')
return 0;
return 1;
This functionality is already implemented in common/env_flags.c in the _env_flags_validate_type() function. Maybe that implementation should be extracted. Another option is to make the eth_parse_enetaddr() in net/eth.c return a status and then it can be used. Either way I don't think it should be re-implemented here.
+}
+/* Function used to match the command's MAC address */ +static int keyword_match_mac_addr(enum keyword_id key_id, int argc,
char *const argv[], int *argc_nr,
struct command_def *parsed_cmd)
+{
if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
return 0;
if ((*argc_nr + 1 >= argc) || parsed_cmd->mac_addr)
return 1;
if (!string_is_mac_addr(argv[*argc_nr + 1])) {
printf("Invalid mac address: %s\n", argv[*argc_nr + 1]);
return 0;
}
parsed_cmd->mac_addr = malloc(6);
Why malloc this? It is small and known size.
eth_parse_enetaddr(argv[*argc_nr + 1], parsed_cmd->mac_addr);
if (is_broadcast_ethaddr(parsed_cmd->mac_addr)) {
free(parsed_cmd->mac_addr);
parsed_cmd->mac_addr = NULL;
Drop these two lines.
return 0;
}
parsed_cmd->cmd_to_keywords[*argc_nr + 1] = id_add_del_mac;
return 1;
+}
/* match optional keywords */ static void cmd_keywords_opt_check(struct command_def *parsed_cmd, int *argc_val) @@ -1414,13 +2040,19 @@ static void command_def_init(struct command_def *parsed_cmd) parsed_cmd->cmd_to_keywords[i] = -1;
parsed_cmd->port = VSC9953_CMD_PORT_ALL;
parsed_cmd->vid = VSC9953_CMD_VLAN_ALL; parsed_cmd->err = 0;
parsed_cmd->mac_addr = NULL;
Drop this.
parsed_cmd->cmd_function = NULL;
}
static void command_def_cleanup(struct command_def *parsed_cmd) {
/* Nothing to do for now */
/* free MAC address */
if (parsed_cmd->mac_addr) {
free(parsed_cmd->mac_addr);
parsed_cmd->mac_addr = NULL;
}
Don't malloc, and you don't need free.
}
/* function to interpret commands starting with "ethsw " */ @@ -1461,6 +2093,7 @@ U_BOOT_CMD(ethsw, VSC9953_MAX_CMD_PARAMS, 0, do_ethsw, VSC9953_PORT_CONF_HELP"\n" VSC9953_PORT_STATS_HELP"\n" VSC9953_LEARN_HELP"\n"
VSC9953_FDB_HELP"\n"
);
#endif /* CONFIG_VSC9953_CMD */ diff --git a/include/vsc9953.h b/include/vsc9953.h index 59c85c3..051c24e 100644 --- a/include/vsc9953.h +++ b/include/vsc9953.h @@ -93,6 +93,25 @@ #define CONFIG_VSC9953_VCAP_MV_CFG 0x0000ffff #define CONFIG_VSC9953_VCAP_UPDATE_CTRL 0x01000004
+/* Macros for register vsc9953_ana_ana_tables.mac_access register */ +#define CONFIG_VSC9953_MAC_CMD_IDLE 0x00000000 +#define CONFIG_VSC9953_MAC_CMD_LEARN 0x00000001 +#define CONFIG_VSC9953_MAC_CMD_FORGET 0x00000002 +#define CONFIG_VSC9953_MAC_CMD_AGE 0x00000003 +#define CONFIG_VSC9953_MAC_CMD_NEXT 0x00000004 +#define CONFIG_VSC9953_MAC_CMD_READ 0x00000006 +#define CONFIG_VSC9953_MAC_CMD_WRITE 0x00000007 +#define CONFIG_VSC9953_MAC_CMD_MASK 0x00000007 +#define CONFIG_VSC9953_MAC_CMD_VALID 0x00000800 +#define CONFIG_VSC9953_MAC_ENTRYTYPE_NORMAL 0x00000000 +#define CONFIG_VSC9953_MAC_ENTRYTYPE_LOCKED 0x00000200 +#define CONFIG_VSC9953_MAC_ENTRYTYPE_IPV4MCAST 0x00000400 +#define CONFIG_VSC9953_MAC_ENTRYTYPE_IPV6MCAST 0x00000600 +#define CONFIG_VSC9953_MAC_ENTRYTYPE_MASK 0x00000600 +#define CONFIG_VSC9953_MAC_DESTIDX_MASK 0x000001f8 +#define CONFIG_VSC9953_MAC_VID_MASK 0x1fff0000 +#define CONFIG_VSC9953_MAC_MACH_MASK 0x0000ffff
/* 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 @@ -131,6 +150,15 @@ #define CONFIG_VSC9953_TAG_CFG_ALL_ZERO 0x00000100 #define CONFIG_VSC9953_TAG_CFG_ALL 0x00000180
+/* Macros for vsc9953_ana_ana.anag_efil register */ +#define CONFIG_VSC9953_AGE_PORT_EN 0x00080000 +#define CONFIG_VSC9953_AGE_PORT_MASK 0x0007c000 +#define CONFIG_VSC9953_AGE_VID_EN 0x00002000 +#define CONFIG_VSC9953_AGE_VID_MASK 0x00001fff
+/* Macros for vsc9953_ana_ana_tables.mach_data register */ +#define CONFIG_VSC9953_MACHDATA_VID_MASK 0x1fff0000
Drop "CONFIG_" from all these.
#define VSC9953_MAX_PORTS 10 #define VSC9953_PORT_CHECK(port) \ (((port) < 0 || (port) >= VSC9953_MAX_PORTS) ? 0 : 1) -- 1.9.3
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot