@ -783,6 +783,45 @@ ar8327_atu_flush_port(struct ar8xxx_priv *priv, int port)
return ret ;
}
static int
ar8327_get_port_igmp ( struct ar8xxx_priv * priv , int port )
{
u32 fwd_ctrl , frame_ack ;
fwd_ctrl = ( BIT ( port ) < < AR8327_FWD_CTRL1_IGMP_S ) ;
frame_ack = ( ( AR8327_FRAME_ACK_CTRL_IGMP_MLD |
AR8327_FRAME_ACK_CTRL_IGMP_JOIN |
AR8327_FRAME_ACK_CTRL_IGMP_LEAVE ) < <
AR8327_FRAME_ACK_CTRL_S ( port ) ) ;
return ( ar8xxx_read ( priv , AR8327_REG_FWD_CTRL1 ) &
fwd_ctrl ) = = fwd_ctrl & &
( ar8xxx_read ( priv , AR8327_REG_FRAME_ACK_CTRL ( port ) ) &
frame_ack ) = = frame_ack ;
}
static void
ar8327_set_port_igmp ( struct ar8xxx_priv * priv , int port , int enable )
{
int reg_frame_ack = AR8327_REG_FRAME_ACK_CTRL ( port ) ;
u32 val_frame_ack = ( AR8327_FRAME_ACK_CTRL_IGMP_MLD |
AR8327_FRAME_ACK_CTRL_IGMP_JOIN |
AR8327_FRAME_ACK_CTRL_IGMP_LEAVE ) < <
AR8327_FRAME_ACK_CTRL_S ( port ) ;
if ( enable ) {
ar8xxx_rmw ( priv , AR8327_REG_FWD_CTRL1 ,
BIT ( port ) < < AR8327_FWD_CTRL1_MC_FLOOD_S ,
BIT ( port ) < < AR8327_FWD_CTRL1_IGMP_S ) ;
ar8xxx_reg_set ( priv , reg_frame_ack , val_frame_ack ) ;
} else {
ar8xxx_rmw ( priv , AR8327_REG_FWD_CTRL1 ,
BIT ( port ) < < AR8327_FWD_CTRL1_IGMP_S ,
BIT ( port ) < < AR8327_FWD_CTRL1_MC_FLOOD_S ) ;
ar8xxx_reg_clear ( priv , reg_frame_ack , val_frame_ack ) ;
}
}
static void
ar8327_vtu_op ( struct ar8xxx_priv * priv , u32 op , u32 val )
{
@ -1084,6 +1123,110 @@ ar8327_sw_hw_apply(struct switch_dev *dev)
return 0 ;
}
int
ar8327_sw_get_port_igmp_snooping ( struct switch_dev * dev ,
const struct switch_attr * attr ,
struct switch_val * val )
{
struct ar8xxx_priv * priv = swdev_to_ar8xxx ( dev ) ;
int port = val - > port_vlan ;
if ( port > = dev - > ports )
return - EINVAL ;
mutex_lock ( & priv - > reg_mutex ) ;
val - > value . i = ar8327_get_port_igmp ( priv , port ) ;
mutex_unlock ( & priv - > reg_mutex ) ;
return 0 ;
}
int
ar8327_sw_set_port_igmp_snooping ( struct switch_dev * dev ,
const struct switch_attr * attr ,
struct switch_val * val )
{
struct ar8xxx_priv * priv = swdev_to_ar8xxx ( dev ) ;
int port = val - > port_vlan ;
if ( port > = dev - > ports )
return - EINVAL ;
mutex_lock ( & priv - > reg_mutex ) ;
ar8327_set_port_igmp ( priv , port , val - > value . i ) ;
mutex_unlock ( & priv - > reg_mutex ) ;
return 0 ;
}
int
ar8327_sw_get_igmp_snooping ( struct switch_dev * dev ,
const struct switch_attr * attr ,
struct switch_val * val )
{
int port ;
for ( port = 0 ; port < dev - > ports ; port + + ) {
val - > port_vlan = port ;
if ( ar8327_sw_get_port_igmp_snooping ( dev , attr , val ) | |
! val - > value . i )
break ;
}
return 0 ;
}
int
ar8327_sw_set_igmp_snooping ( struct switch_dev * dev ,
const struct switch_attr * attr ,
struct switch_val * val )
{
int port ;
for ( port = 0 ; port < dev - > ports ; port + + ) {
val - > port_vlan = port ;
if ( ar8327_sw_set_port_igmp_snooping ( dev , attr , val ) )
break ;
}
return 0 ;
}
int
ar8327_sw_get_igmp_v3 ( struct switch_dev * dev ,
const struct switch_attr * attr ,
struct switch_val * val )
{
struct ar8xxx_priv * priv = swdev_to_ar8xxx ( dev ) ;
u32 val_reg ;
mutex_lock ( & priv - > reg_mutex ) ;
val_reg = ar8xxx_read ( priv , AR8327_REG_FRAME_ACK_CTRL1 ) ;
val - > value . i = ( ( val_reg & AR8327_FRAME_ACK_CTRL_IGMP_V3_EN ) ! = 0 ) ;
mutex_unlock ( & priv - > reg_mutex ) ;
return 0 ;
}
int
ar8327_sw_set_igmp_v3 ( struct switch_dev * dev ,
const struct switch_attr * attr ,
struct switch_val * val )
{
struct ar8xxx_priv * priv = swdev_to_ar8xxx ( dev ) ;
mutex_lock ( & priv - > reg_mutex ) ;
if ( val - > value . i )
ar8xxx_reg_set ( priv , AR8327_REG_FRAME_ACK_CTRL1 ,
AR8327_FRAME_ACK_CTRL_IGMP_V3_EN ) ;
else
ar8xxx_reg_clear ( priv , AR8327_REG_FRAME_ACK_CTRL1 ,
AR8327_FRAME_ACK_CTRL_IGMP_V3_EN ) ;
mutex_unlock ( & priv - > reg_mutex ) ;
return 0 ;
}
static const struct switch_attr ar8327_sw_attr_globals [ ] = {
{
. type = SWITCH_TYPE_INT ,
@ -1144,6 +1287,22 @@ static const struct switch_attr ar8327_sw_attr_globals[] = {
. description = " Flush ARL table " ,
. set = ar8xxx_sw_set_flush_arl_table ,
} ,
{
. type = SWITCH_TYPE_INT ,
. name = " igmp_snooping " ,
. description = " Enable IGMP Snooping " ,
. set = ar8327_sw_set_igmp_snooping ,
. get = ar8327_sw_get_igmp_snooping ,
. max = 1
} ,
{
. type = SWITCH_TYPE_INT ,
. name = " igmp_v3 " ,
. description = " Enable IGMPv3 support " ,
. set = ar8327_sw_set_igmp_v3 ,
. get = ar8327_sw_get_igmp_v3 ,
. max = 1
} ,
} ;
static const struct switch_attr ar8327_sw_attr_port [ ] = {
@ -1174,6 +1333,14 @@ static const struct switch_attr ar8327_sw_attr_port[] = {
. description = " Flush port's ARL table entries " ,
. set = ar8xxx_sw_set_flush_port_arl_table ,
} ,
{
. type = SWITCH_TYPE_INT ,
. name = " igmp_snooping " ,
. description = " Enable port's IGMP Snooping " ,
. set = ar8327_sw_set_port_igmp_snooping ,
. get = ar8327_sw_get_port_igmp_snooping ,
. max = 1
} ,
} ;
static const struct switch_dev_ops ar8327_sw_ops = {