@ -196,6 +196,100 @@ static int vsc9953_vlan_table_poll_idle(void)
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 @@ static void vsc9953_vlan_table_membership_all_set(int vid, int set_member)
( 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 @@ enum egress_untag_mode {
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 @@ 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 ,
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 @@ static int vsc9953_fdb_entry_del_key_func(struct ethsw_command_def *parsed_cmd)
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 @@ static struct ethsw_command_func vsc9953_cmd_func = {
. 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 */