On 04/12/2020 19:54:16+0200, Vladimir Oltean wrote:
> The current assumption is that the felix DSA driver has flooding knobs
> per traffic class, while ocelot switchdev has a single flooding knob.
> This was correct for felix VSC9959 and ocelot VSC7514, but with the
> introduction of seville VSC9953, we see a switch driven by felix.c which
> has a single flooding knob.
> 
> So it is clear that we must do what should have been done from the
> beginning, which is not to overwrite the configuration done by ocelot.c
> in felix, but instead to teach the common ocelot library about the
> differences in our switches, and set up the flooding PGIDs centrally.
> 
> The effect that the bogus iteration through FELIX_NUM_TC has upon
> seville is quite dramatic. ANA_FLOODING is located at 0x00b548, and
> ANA_FLOODING_IPMC is located at 0x00b54c. So the bogus iteration will
> actually overwrite ANA_FLOODING_IPMC when attempting to write
> ANA_FLOODING[1]. There is no ANA_FLOODING[1] in sevile, just ANA_FLOODING.
> 
> And when ANA_FLOODING_IPMC is overwritten with a bogus value, the effect
> is that ANA_FLOODING_IPMC gets the value of 0x0003CF7D:
>       MC6_DATA = 61,
>       MC6_CTRL = 61,
>       MC4_DATA = 60,
>       MC4_CTRL = 0.
> Because MC4_CTRL is zero, this means that IPv4 multicast control packets
> are not flooded, but dropped. An invalid configuration, and this is how
> the issue was actually spotted.
> 
> Reported-by: Eldar Gasanov <eldargasan...@gmail.com>
> Reported-by: Maxim Kochetkov <fido_...@inbox.ru>
> Tested-by: Eldar Gasanov <eldargasan...@gmail.com>
> Fixes: 84705fc16552 ("net: dsa: felix: introduce support for Seville VSC9953 
> switch")
> Fixes: 3c7b51bd39b2 ("net: dsa: felix: allow flooding for all traffic 
> classes")
> Signed-off-by: Vladimir Oltean <vladimir.olt...@nxp.com>
Reviewed-by: Alexandre Belloni <alexandre.bell...@bootlin.com>

> ---
>  drivers/net/dsa/ocelot/felix.c             | 7 -------
>  drivers/net/dsa/ocelot/felix_vsc9959.c     | 1 +
>  drivers/net/dsa/ocelot/seville_vsc9953.c   | 1 +
>  drivers/net/ethernet/mscc/ocelot.c         | 9 +++++----
>  drivers/net/ethernet/mscc/ocelot_vsc7514.c | 1 +
>  include/soc/mscc/ocelot.h                  | 3 +++
>  6 files changed, 11 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
> index ada75fa15861..7dc230677b78 100644
> --- a/drivers/net/dsa/ocelot/felix.c
> +++ b/drivers/net/dsa/ocelot/felix.c
> @@ -588,7 +588,6 @@ static int felix_setup(struct dsa_switch *ds)
>       struct ocelot *ocelot = ds->priv;
>       struct felix *felix = ocelot_to_felix(ocelot);
>       int port, err;
> -     int tc;
>  
>       err = felix_init_structs(felix, ds->num_ports);
>       if (err)
> @@ -627,12 +626,6 @@ static int felix_setup(struct dsa_switch *ds)
>       ocelot_write_rix(ocelot,
>                        ANA_PGID_PGID_PGID(GENMASK(ocelot->num_phys_ports, 0)),
>                        ANA_PGID_PGID, PGID_UC);
> -     /* Setup the per-traffic class flooding PGIDs */
> -     for (tc = 0; tc < FELIX_NUM_TC; tc++)
> -             ocelot_write_rix(ocelot, ANA_FLOODING_FLD_MULTICAST(PGID_MC) |
> -                              ANA_FLOODING_FLD_BROADCAST(PGID_MC) |
> -                              ANA_FLOODING_FLD_UNICAST(PGID_UC),
> -                              ANA_FLOODING, tc);
>  
>       ds->mtu_enforcement_ingress = true;
>       ds->configure_vlan_while_not_filtering = true;
> diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c 
> b/drivers/net/dsa/ocelot/felix_vsc9959.c
> index 3e925b8d5306..2e5bbdca5ea4 100644
> --- a/drivers/net/dsa/ocelot/felix_vsc9959.c
> +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
> @@ -1429,6 +1429,7 @@ static int felix_pci_probe(struct pci_dev *pdev,
>       pci_set_drvdata(pdev, felix);
>       ocelot = &felix->ocelot;
>       ocelot->dev = &pdev->dev;
> +     ocelot->num_flooding_pgids = FELIX_NUM_TC;
>       felix->info = &felix_info_vsc9959;
>       felix->switch_base = pci_resource_start(pdev,
>                                               felix->info->switch_pci_bar);
> diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c 
> b/drivers/net/dsa/ocelot/seville_vsc9953.c
> index 1d420c4a2f0f..ebbaf6817ec8 100644
> --- a/drivers/net/dsa/ocelot/seville_vsc9953.c
> +++ b/drivers/net/dsa/ocelot/seville_vsc9953.c
> @@ -1210,6 +1210,7 @@ static int seville_probe(struct platform_device *pdev)
>  
>       ocelot = &felix->ocelot;
>       ocelot->dev = &pdev->dev;
> +     ocelot->num_flooding_pgids = 1;
>       felix->info = &seville_info_vsc9953;
>  
>       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> diff --git a/drivers/net/ethernet/mscc/ocelot.c 
> b/drivers/net/ethernet/mscc/ocelot.c
> index 2632fe2d2448..abea8dd2b0cb 100644
> --- a/drivers/net/ethernet/mscc/ocelot.c
> +++ b/drivers/net/ethernet/mscc/ocelot.c
> @@ -1551,10 +1551,11 @@ int ocelot_init(struct ocelot *ocelot)
>                    SYS_FRM_AGING_MAX_AGE(307692), SYS_FRM_AGING);
>  
>       /* Setup flooding PGIDs */
> -     ocelot_write_rix(ocelot, ANA_FLOODING_FLD_MULTICAST(PGID_MC) |
> -                      ANA_FLOODING_FLD_BROADCAST(PGID_MC) |
> -                      ANA_FLOODING_FLD_UNICAST(PGID_UC),
> -                      ANA_FLOODING, 0);
> +     for (i = 0; i < ocelot->num_flooding_pgids; i++)
> +             ocelot_write_rix(ocelot, ANA_FLOODING_FLD_MULTICAST(PGID_MC) |
> +                              ANA_FLOODING_FLD_BROADCAST(PGID_MC) |
> +                              ANA_FLOODING_FLD_UNICAST(PGID_UC),
> +                              ANA_FLOODING, i);
>       ocelot_write(ocelot, ANA_FLOODING_IPMC_FLD_MC6_DATA(PGID_MCIPV6) |
>                    ANA_FLOODING_IPMC_FLD_MC6_CTRL(PGID_MC) |
>                    ANA_FLOODING_IPMC_FLD_MC4_DATA(PGID_MCIPV4) |
> diff --git a/drivers/net/ethernet/mscc/ocelot_vsc7514.c 
> b/drivers/net/ethernet/mscc/ocelot_vsc7514.c
> index dc00772950e5..1e7729421a82 100644
> --- a/drivers/net/ethernet/mscc/ocelot_vsc7514.c
> +++ b/drivers/net/ethernet/mscc/ocelot_vsc7514.c
> @@ -1254,6 +1254,7 @@ static int mscc_ocelot_probe(struct platform_device 
> *pdev)
>       }
>  
>       ocelot->num_phys_ports = of_get_child_count(ports);
> +     ocelot->num_flooding_pgids = 1;
>  
>       ocelot->vcap = vsc7514_vcap_props;
>       ocelot->inj_prefix = OCELOT_TAG_PREFIX_NONE;
> diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
> index ea1de185f2e4..731116611390 100644
> --- a/include/soc/mscc/ocelot.h
> +++ b/include/soc/mscc/ocelot.h
> @@ -621,6 +621,9 @@ struct ocelot {
>       /* Keep track of the vlan port masks */
>       u32                             vlan_mask[VLAN_N_VID];
>  
> +     /* Switches like VSC9959 have flooding per traffic class */
> +     int                             num_flooding_pgids;
> +
>       /* In tables like ANA:PORT and the ANA:PGID:PGID mask,
>        * the CPU is located after the physical ports (at the
>        * num_phys_ports index).
> -- 
> 2.25.1
> 

-- 
Alexandre Belloni, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

Reply via email to