Commit 85ee9874 authored by Daniel Golle's avatar Daniel Golle Committed by Paolo Abeni
Browse files

net: dsa: add tag format for MxL862xx switches



Add proprietary special tag format for the MaxLinear MXL862xx family of
switches. While using the same Ethertype as MaxLinear's GSW1xx switches,
the actual tag format differs significantly, hence we need a dedicated
tag driver for that.

Signed-off-by: default avatarDaniel Golle <daniel@makrotopia.org>
Link: https://patch.msgid.link/c64e6ddb6c93a4fac39f9ab9b2d8bf551a2b118d.1770433307.git.daniel@makrotopia.org


Reviewed-by: default avatarVladimir Oltean <olteanv@gmail.com>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 4ccc9851
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -15631,6 +15631,7 @@ M: Daniel Golle <daniel@makrotopia.org>
L:	netdev@vger.kernel.org
S:	Maintained
F:	Documentation/devicetree/bindings/net/dsa/maxlinear,mxl862xx.yaml
F:	net/dsa/tag_mxl862xx.c
MCAN DEVICE DRIVER
M:	Markus Schneider-Pargmann <msp@baylibre.com>
+2 −0
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ struct tc_action;
#define DSA_TAG_PROTO_BRCM_LEGACY_FCS_VALUE	29
#define DSA_TAG_PROTO_YT921X_VALUE		30
#define DSA_TAG_PROTO_MXL_GSW1XX_VALUE		31
#define DSA_TAG_PROTO_MXL862_VALUE		32

enum dsa_tag_protocol {
	DSA_TAG_PROTO_NONE		= DSA_TAG_PROTO_NONE_VALUE,
@@ -91,6 +92,7 @@ enum dsa_tag_protocol {
	DSA_TAG_PROTO_VSC73XX_8021Q	= DSA_TAG_PROTO_VSC73XX_8021Q_VALUE,
	DSA_TAG_PROTO_YT921X		= DSA_TAG_PROTO_YT921X_VALUE,
	DSA_TAG_PROTO_MXL_GSW1XX	= DSA_TAG_PROTO_MXL_GSW1XX_VALUE,
	DSA_TAG_PROTO_MXL862		= DSA_TAG_PROTO_MXL862_VALUE,
};

struct dsa_switch;
+7 −0
Original line number Diff line number Diff line
@@ -104,6 +104,13 @@ config NET_DSA_TAG_MTK
	  Say Y or M if you want to enable support for tagging frames for
	  Mediatek switches.

config NET_DSA_TAG_MXL_862XX
	tristate "Tag driver for MaxLinear MxL862xx switches"
	help
	  Say Y or M if you want to enable support for tagging frames for the
	  MaxLinear MxL86252 and MxL86282 switches using their native 8-byte
	  tagging protocol.

config NET_DSA_TAG_MXL_GSW1XX
	tristate "Tag driver for MaxLinear GSW1xx switches"
	help
+1 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ obj-$(CONFIG_NET_DSA_TAG_HELLCREEK) += tag_hellcreek.o
obj-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o
obj-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o
obj-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o
obj-$(CONFIG_NET_DSA_TAG_MXL_862XX) += tag_mxl862xx.o
obj-$(CONFIG_NET_DSA_TAG_MXL_GSW1XX) += tag_mxl-gsw1xx.o
obj-$(CONFIG_NET_DSA_TAG_NONE) += tag_none.o
obj-$(CONFIG_NET_DSA_TAG_OCELOT) += tag_ocelot.o

net/dsa/tag_mxl862xx.c

0 → 100644
+110 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * DSA Special Tag for MaxLinear 862xx switch chips
 *
 * Copyright (C) 2025 Daniel Golle <daniel@makrotopia.org>
 * Copyright (C) 2024 MaxLinear Inc.
 */

#include <linux/bitops.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <net/dsa.h>
#include "tag.h"

#define MXL862_NAME	"mxl862xx"

#define MXL862_HEADER_LEN	8

/* Word 0 -> EtherType */

/* Word 2 */
#define MXL862_SUBIF_ID		GENMASK(4, 0)

/* Word 3 */
#define MXL862_IGP_EGP		GENMASK(3, 0)

static struct sk_buff *mxl862_tag_xmit(struct sk_buff *skb,
				       struct net_device *dev)
{
	struct dsa_port *dp = dsa_user_to_port(dev);
	struct dsa_port *cpu_dp = dp->cpu_dp;
	unsigned int cpu_port, sub_interface;
	__be16 *mxl862_tag;

	cpu_port = cpu_dp->index;

	/* target port sub-interface ID relative to the CPU port */
	sub_interface = dp->index + 16 - cpu_port;

	/* provide additional space 'MXL862_HEADER_LEN' bytes */
	skb_push(skb, MXL862_HEADER_LEN);

	/* shift MAC address to the beginning of the enlarged buffer,
	 * releasing the space required for DSA tag (between MAC address and
	 * Ethertype)
	 */
	dsa_alloc_etype_header(skb, MXL862_HEADER_LEN);

	/* special tag ingress (from the perspective of the switch) */
	mxl862_tag = dsa_etype_header_pos_tx(skb);
	mxl862_tag[0] = htons(ETH_P_MXLGSW);
	mxl862_tag[1] = 0;
	mxl862_tag[2] = htons(FIELD_PREP(MXL862_SUBIF_ID, sub_interface));
	mxl862_tag[3] = htons(FIELD_PREP(MXL862_IGP_EGP, cpu_port));

	return skb;
}

static struct sk_buff *mxl862_tag_rcv(struct sk_buff *skb,
				      struct net_device *dev)
{
	__be16 *mxl862_tag;
	int port;

	if (unlikely(!pskb_may_pull(skb, MXL862_HEADER_LEN))) {
		dev_warn_ratelimited(&dev->dev, "Cannot pull SKB, packet dropped\n");
		return NULL;
	}

	mxl862_tag = dsa_etype_header_pos_rx(skb);

	if (unlikely(mxl862_tag[0] != htons(ETH_P_MXLGSW))) {
		dev_warn_ratelimited(&dev->dev,
				     "Invalid special tag marker, packet dropped, tag: %8ph\n",
				     mxl862_tag);
		return NULL;
	}

	/* Get source port information */
	port = FIELD_GET(MXL862_IGP_EGP, ntohs(mxl862_tag[3]));
	skb->dev = dsa_conduit_find_user(dev, 0, port);
	if (unlikely(!skb->dev)) {
		dev_warn_ratelimited(&dev->dev,
				     "Invalid source port, packet dropped, tag: %8ph\n",
				     mxl862_tag);
		return NULL;
	}

	/* remove the MxL862xx special tag between the MAC addresses and the
	 * current ethertype field.
	 */
	skb_pull_rcsum(skb, MXL862_HEADER_LEN);
	dsa_strip_etype_header(skb, MXL862_HEADER_LEN);

	return skb;
}

static const struct dsa_device_ops mxl862_netdev_ops = {
	.name = MXL862_NAME,
	.proto = DSA_TAG_PROTO_MXL862,
	.xmit = mxl862_tag_xmit,
	.rcv = mxl862_tag_rcv,
	.needed_headroom = MXL862_HEADER_LEN,
};

MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_MXL862, MXL862_NAME);
MODULE_DESCRIPTION("DSA tag driver for MaxLinear MxL862xx switches");
MODULE_LICENSE("GPL");

module_dsa_tag_driver(mxl862_netdev_ops);