[PATCH 5/6] net: add MV88E61xx DSA driver

Tim Harvey tharvey at gateworks.com
Thu Apr 7 22:33:58 CEST 2022


On Sat, Apr 2, 2022 at 4:17 PM Vladimir Oltean <vladimir.oltean at nxp.com> wrote:
>
> On Fri, Apr 01, 2022 at 01:24:48PM -0700, Tim Harvey wrote:
> > > > > Why is mv88e61xx_dsa_xmit() no-op?
> > > >
> > > > For DSA dsa-uclass calls the switch master eth device send function
> > > > after calling the dsa_ops->xmit function so that a dsa driver can add
> > > > any header/footer if needed. The function is required but in my case I
> > > > don't care about header/footer tagging or vlan as only 1 port is
> > > > active at a time in U-Boot so I just return success.
> > >
> > > So if I make one port active, the other are completely disabled? They
> > > won't even switch? Is that how DSA uclass is supposed to work in U-Boot?
> > >
> > > I would think that it should be somehow configurable instead.
> >
> > Marek,
> >
> > I'll let Vladimir correct me if I'm wrong but my understanding is DSA
> > in U-Boot is not intended to allow switches to forward packets on
> > their own from port to port but instead just for forwarding packets
> > between the active port and the MAC connected to the CPU (at least
> > that's what I intended when I wrote the ksz9477 dsa driver
> > previously).
> >
> > In my opinion what a DSA driver provides is avoidance of putting
> > switches in forwarding mode having the potential of easily creating
> > bridge loops. With the existing mv88e61xx driver I've had users create
> > bridge loops often.
>
> DM_DSA follows the guiding principle that the user doesn't care about
> the switch more than being able to transfer a boot image through TFTP
> without causing switching loops in the network. The way this is achieved
> is by following the "port extender" model which is exactly the way in
> which Linux DSA was first introduced, prior to having support for L2
> bridging offloads via switchdev. For U-Boot, packet forwarding across
> front ports is effectively a non-goal. In fact, what we want to avoid is
> the proliferation of bloatware such as cmd/ethsw.c, which can and will
> be abused to preconfigure a switch from the bootloader so you won't have
> to manage it from Linux.

Vladimir,

I also want to avoid the proliferation of bloatware which is primarily
why I want to avoid having to muck with packets when there is only one
port active at a time which I feel is completely unnecessary.

>
> Tim, I accept that U-Boot's Ethernet usage model (a single device active
> at a time, with RX in synchronous poll mode) simplifies DM_DSA to the
> point that creating/parsing DSA tags (which serve the purpose of
> multiplexing/demultiplexing packets to/from switch ports) on the CPU is
> more or less redundant when said multiplexing can be achieved on a time
> basis by disabling all the ports except the required source/destination
> switch port and the CPU port. This holds true even when DM_DSA gains
> support for multi-switch setups.
>
> What I would like, however, is to avoid driver code putting pressure on
> the DSA uclass code. I don't really like the tracking of the priv->active_port
> as being the port on which ->port_enable was last called. The only reason
> this is done is to appease the "port_index != port_pdata->index" check
> from dsa_port_recv(). In turn, this is because the ->xmit() and ->rcv()
> DSA ops are not optional. Let's make them optional instead, instead of
> adding code to a C file that indirectly depends on the code structure
> from another C file.
>
> But ->port_enable() and ->port_disable() are optional too, and that's
> not okay, because if the driver doesn't provide a way to enable/disable
> ports, packets can flow anywhere.
>
> I suggest making it clear to driver writers that it has to be one or the
> other by sanitizing the ops:
>
> diff --git a/net/dsa-uclass.c b/net/dsa-uclass.c
> index 9ff55a02fb23..ea860fa715bb 100644
> --- a/net/dsa-uclass.c
> +++ b/net/dsa-uclass.c
> @@ -342,6 +342,19 @@ U_BOOT_DRIVER(dsa_port) = {
>         .plat_auto = sizeof(struct eth_pdata),
>  };
>
> +static int dsa_sanitize_ops(struct udevice *dev)
> +{
> +       struct dsa_ops *ops = dsa_get_ops(dev);
> +
> +       if ((!ops->xmit || !ops->rcv) &&
> +           (!ops->port_enable && !ops->port_disable)) {
> +               dev_err(dev, "Packets cannot be steered to ports\n");
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
>  /*
>   * This function mostly deals with pulling information out of the device tree
>   * into the pdata structure.
> @@ -358,6 +371,10 @@ static int dsa_post_bind(struct udevice *dev)
>         if (!ofnode_valid(node))
>                 return -ENODEV;
>
> +       err = dsa_sanitize_ops(dev);
> +       if (err)
> +               return err;
> +
>         pdata->master_node = ofnode_null();
>
>         node = ofnode_find_subnode(node, "ports");
>
>
> Then we can properly make rcv() and xmit() optional at the level of the
> DSA uclass. This way we avoid the tail chasing approach of pretending
> that "return priv->active_port" _is_ the way to decode a packet for a
> certain driver. It isn't, and it should just be DSA's fallback if no
> such method is known. I'd like to preserve the option to implement a
> rcv() and xmit() procedure, because it offers one extra layer of safety
> that the CPU is really talking to the switch port it thinks it's
> talking, plus inter-switch traffic is reduced in cross-chip topologies
> (which are not supported now, but maybe they will be).
>
> I think that fallback could look like this:
>
> diff --git a/net/dsa-uclass.c b/net/dsa-uclass.c
> index ea860fa715bb..64654ec1ad72 100644
> --- a/net/dsa-uclass.c
> +++ b/net/dsa-uclass.c
> @@ -131,16 +131,15 @@ static void dsa_port_stop(struct udevice *pdev)
>   * We copy the frame to a stack buffer where we have reserved headroom and
>   * tailroom space.  Headroom and tailroom are set to 0.
>   */
> -static int dsa_port_send(struct udevice *pdev, void *packet, int length)
> +static int dsa_port_mangle_packet(struct udevice *pdev, void *packet,
> +                                 int length)
>  {
> +       struct dsa_port_pdata *port_pdata = dev_get_parent_plat(pdev);
>         struct udevice *dev = dev_get_parent(pdev);
>         struct dsa_priv *priv = dev_get_uclass_priv(dev);
>         int head = priv->headroom, tail = priv->tailroom;
> -       struct udevice *master = dsa_get_master(dev);
>         struct dsa_ops *ops = dsa_get_ops(dev);
>         uchar dsa_packet_tmp[PKTSIZE_ALIGN];
> -       struct dsa_port_pdata *port_pdata;
> -       int err;
>
>         if (length + head + tail > PKTSIZE_ALIGN)
>                 return -EINVAL;
> @@ -152,10 +151,21 @@ static int dsa_port_send(struct udevice *pdev, void *packet, int length)
>         /* copy back to preserve original buffer alignment */
>         memcpy(packet, dsa_packet_tmp, length);
>
> -       port_pdata = dev_get_parent_plat(pdev);
> -       err = ops->xmit(dev, port_pdata->index, packet, length);
> -       if (err)
> -               return err;
> +       return ops->xmit(dev, port_pdata->index, packet, length);
> +}
> +
> +static int dsa_port_send(struct udevice *pdev, void *packet, int length)
> +{
> +       struct udevice *dev = dev_get_parent(pdev);
> +       struct udevice *master = dsa_get_master(dev);
> +       struct dsa_ops *ops = dsa_get_ops(dev);
> +       int err;
> +
> +       if (ops->xmit) {
> +               err = dsa_port_mangle_packet(pdev, packet, length);
> +               if (err)
> +                       return err;
> +       }
>
>         return eth_get_ops(master)->send(master, packet, length);
>  }
> @@ -172,7 +182,7 @@ static int dsa_port_recv(struct udevice *pdev, int flags, uchar **packetp)
>         int length, port_index, err;
>
>         length = eth_get_ops(master)->recv(master, flags, packetp);
> -       if (length <= 0)
> +       if (length <= 0 || !ops->rcv)
>                 return length;
>
>         /*
>

I can add this to my series if I submit a follow-up.

> I think part of the reason for which Tim is actively trying to avoid DSA
> tag inserting and parsing is because fec_mxc.c refuses to send packets
> larger than 1500 bytes. As a side note, I do think that limitation
> should be lifted and do allow for a reasonable amount of extra bytes,
> because as things stand, if somebody will want to implement rcv() and

> xmit() for either the mv88e6xxx or ksz9477 drivers, they'll involuntarily
> break the boards where fec is a DSA master, which isn't really very fair.

Very likely.

I guess I'll have to invest in tagging packets if you won't accept the
simplistic approach of not having to tag frames knowing that only one
port is active at a time.

That said, I have no idea if or when I will re-visit this. Adding a
DSA version of this driver was something on my personal wish list and
not something that was necessary by any means by my employer so I may
have to just drop it as I don't have the personal time to work through
this part of it or unravelling the mii bus mess in the fec_mxc driver.
It seems to me there is an issue with trying to create DM_MDIO drivers
in general as most dt's I've seen wouldn't support the requirements
yet configure DM_MDIO anyway (meaning if you implemented it you would
break those boards as I found).

Best Regards,

Tim


More information about the U-Boot mailing list