On Mon, Mar 15, 2021 at 10:13:59PM +0100, Tobias Waldekranz wrote:
> Allow a user to control automatic learning per port.
> 
> Many chips have an explicit "LearningDisable"-bit that can be used for
> this, but we opt for setting/clearing the PAV instead, as it works on
> all devices at least as far back as 6083.
> 
> Signed-off-by: Tobias Waldekranz <tob...@waldekranz.com>
> ---
>  drivers/net/dsa/mv88e6xxx/chip.c | 29 +++++++++++++++++++++--------
>  drivers/net/dsa/mv88e6xxx/port.c | 21 +++++++++++++++++++++
>  drivers/net/dsa/mv88e6xxx/port.h |  2 ++
>  3 files changed, 44 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/net/dsa/mv88e6xxx/chip.c 
> b/drivers/net/dsa/mv88e6xxx/chip.c
> index 01e4ac32d1e5..48e65f22641e 100644
> --- a/drivers/net/dsa/mv88e6xxx/chip.c
> +++ b/drivers/net/dsa/mv88e6xxx/chip.c
> @@ -2689,15 +2689,20 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip 
> *chip, int port)
>                       return err;
>       }
>  
> -     /* Port Association Vector: when learning source addresses
> -      * of packets, add the address to the address database using
> -      * a port bitmap that has only the bit for this port set and
> -      * the other bits clear.
> +     /* Port Association Vector: disable automatic address learning
> +      * on all user ports since they start out in standalone
> +      * mode. When joining a bridge, learning will be configured to
> +      * match the bridge port settings. Enable learning on all
> +      * DSA/CPU ports. NOTE: FROM_CPU frames always bypass the
> +      * learning process.
> +      *
> +      * Disable HoldAt1, IntOnAgeOut, LockedPort, IgnoreWrongData,
> +      * and RefreshLocked. I.e. setup standard automatic learning.
>        */
> -     reg = 1 << port;
> -     /* Disable learning for CPU port */
> -     if (dsa_is_cpu_port(ds, port))
> +     if (dsa_is_user_port(ds, port))
>               reg = 0;
> +     else
> +             reg = 1 << port;
>  
>       err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
>                                  reg);

Can this be refactored to use mv88e6xxx_port_set_assoc_vector too?

> @@ -5426,7 +5431,7 @@ static int mv88e6xxx_port_pre_bridge_flags(struct 
> dsa_switch *ds, int port,
>       struct mv88e6xxx_chip *chip = ds->priv;
>       const struct mv88e6xxx_ops *ops;
>  
> -     if (flags.mask & ~(BR_FLOOD | BR_MCAST_FLOOD))
> +     if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD))
>               return -EINVAL;
>  
>       ops = chip->info->ops;
> @@ -5449,6 +5454,14 @@ static int mv88e6xxx_port_bridge_flags(struct 
> dsa_switch *ds, int port,
>  
>       mv88e6xxx_reg_lock(chip);
>  
> +     if (flags.mask & BR_LEARNING) {
> +             u16 pav = (flags.val & BR_LEARNING) ? (1 << port) : 0;
> +
> +             err = mv88e6xxx_port_set_assoc_vector(chip, port, pav);
> +             if (err)
> +                     goto out;
> +     }
> +
>       if (flags.mask & BR_FLOOD) {
>               bool unicast = !!(flags.val & BR_FLOOD);
>  
> diff --git a/drivers/net/dsa/mv88e6xxx/port.c 
> b/drivers/net/dsa/mv88e6xxx/port.c
> index 4561f289ab76..d716cd61b6c6 100644
> --- a/drivers/net/dsa/mv88e6xxx/port.c
> +++ b/drivers/net/dsa/mv88e6xxx/port.c
> @@ -1171,6 +1171,27 @@ int mv88e6097_port_egress_rate_limiting(struct 
> mv88e6xxx_chip *chip, int port)
>                                   0x0001);
>  }
>  
> +/* Offset 0x0B: Port Association Vector */
> +
> +int mv88e6xxx_port_set_assoc_vector(struct mv88e6xxx_chip *chip, int port,
> +                                 u16 pav)
> +{
> +     u16 reg, mask;
> +     int err;
> +
> +     err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
> +                               &reg);
> +     if (err)
> +             return err;
> +
> +     mask = GENMASK(mv88e6xxx_num_ports(chip), 0);

mv88e6xxx_num_ports(chip) - 1, maybe?

> +     reg &= ~mask;
> +     reg |= pav & mask;
> +
> +     return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR,
> +                                 reg);
> +}
> +
>  /* Offset 0x0C: Port ATU Control */
>  
>  int mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip *chip, int port)
> diff --git a/drivers/net/dsa/mv88e6xxx/port.h 
> b/drivers/net/dsa/mv88e6xxx/port.h
> index e6d0eaa6aa1d..635b6571a0e9 100644
> --- a/drivers/net/dsa/mv88e6xxx/port.h
> +++ b/drivers/net/dsa/mv88e6xxx/port.h
> @@ -361,6 +361,8 @@ int mv88e6165_port_set_jumbo_size(struct mv88e6xxx_chip 
> *chip, int port,
>                                 size_t size);
>  int mv88e6095_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int 
> port);
>  int mv88e6097_port_egress_rate_limiting(struct mv88e6xxx_chip *chip, int 
> port);
> +int mv88e6xxx_port_set_assoc_vector(struct mv88e6xxx_chip *chip, int port,
> +                                 u16 pav);
>  int mv88e6097_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
>                              u8 out);
>  int mv88e6390_port_pause_limit(struct mv88e6xxx_chip *chip, int port, u8 in,
> -- 
> 2.25.1
> 

Reply via email to