net: dsa: Add Lantiq / Intel GSWIP tag support
authorHauke Mehrtens <hauke@hauke-m.de>
Sun, 9 Sep 2018 20:16:43 +0000 (22:16 +0200)
committerDavid S. Miller <davem@davemloft.net>
Thu, 13 Sep 2018 15:14:33 +0000 (08:14 -0700)
This handles the tag added by the PMAC on the VRX200 SoC line.

The GSWIP uses internally a GSWIP special tag which is located after the
Ethernet header. The PMAC which connects the GSWIP to the CPU converts
this special tag used by the GSWIP into the PMAC special tag which is
added in front of the Ethernet header.

This was tested with GSWIP 2.1 found in the VRX200 SoCs, other GSWIP
versions use slightly different PMAC special tags.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
MAINTAINERS
include/net/dsa.h
net/dsa/Kconfig
net/dsa/Makefile
net/dsa/dsa.c
net/dsa/dsa_priv.h
net/dsa/tag_gswip.c [new file with mode: 0644]

index 0b2e27e8abefe10d2f70f4c9f54d15e38a97ebaa..a11fbbe2be73c0a0710a2afb984a742bdce7f9a7 100644 (file)
@@ -8167,6 +8167,12 @@ S:       Maintained
 F:     net/l3mdev
 F:     include/net/l3mdev.h
 
+LANTIQ / INTEL Ethernet drivers
+M:     Hauke Mehrtens <hauke@hauke-m.de>
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     net/dsa/tag_gswip.c
+
 LANTIQ MIPS ARCHITECTURE
 M:     John Crispin <john@phrozen.org>
 L:     linux-mips@linux-mips.org
index 461e8a7661b7855ca2ee7bec2e4ffb7e9bb2bc2a..23690c44e167c689a34b6fbda2cd98a18247dc04 100644 (file)
@@ -35,6 +35,7 @@ enum dsa_tag_protocol {
        DSA_TAG_PROTO_BRCM_PREPEND,
        DSA_TAG_PROTO_DSA,
        DSA_TAG_PROTO_EDSA,
+       DSA_TAG_PROTO_GSWIP,
        DSA_TAG_PROTO_KSZ,
        DSA_TAG_PROTO_LAN9303,
        DSA_TAG_PROTO_MTK,
index 4183e4ba27a50c3cf52bff9756d0552da612d619..48c41918fb35605d63ca2b48f16e341d7d68a900 100644 (file)
@@ -38,6 +38,9 @@ config NET_DSA_TAG_DSA
 config NET_DSA_TAG_EDSA
        bool
 
+config NET_DSA_TAG_GSWIP
+       bool
+
 config NET_DSA_TAG_KSZ
        bool
 
index 9e4d3536f977e2a2f4c95219274b5e49ae93865d..6e721f7a2947f1a48716f1cff04b394c04658c2b 100644 (file)
@@ -9,6 +9,7 @@ dsa_core-$(CONFIG_NET_DSA_TAG_BRCM) += tag_brcm.o
 dsa_core-$(CONFIG_NET_DSA_TAG_BRCM_PREPEND) += tag_brcm.o
 dsa_core-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o
 dsa_core-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
+dsa_core-$(CONFIG_NET_DSA_TAG_GSWIP) += tag_gswip.o
 dsa_core-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o
 dsa_core-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o
 dsa_core-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o
index 45f70859f550a2b03bbac51c9f3f3e1cec121b5a..5f73e96cc9e65b4ed84e52aafed72e7212865000 100644 (file)
@@ -52,6 +52,9 @@ const struct dsa_device_ops *dsa_device_ops[DSA_TAG_LAST] = {
 #ifdef CONFIG_NET_DSA_TAG_EDSA
        [DSA_TAG_PROTO_EDSA] = &edsa_netdev_ops,
 #endif
+#ifdef CONFIG_NET_DSA_TAG_GSWIP
+       [DSA_TAG_PROTO_GSWIP] = &gswip_netdev_ops,
+#endif
 #ifdef CONFIG_NET_DSA_TAG_KSZ
        [DSA_TAG_PROTO_KSZ] = &ksz_netdev_ops,
 #endif
index 2868b5bb7e7de1e1fbf4678c9f9c29b04ec58bee..9e4fd04ab53c81947db2525e1c5121f3769e14fc 100644 (file)
@@ -206,6 +206,9 @@ extern const struct dsa_device_ops dsa_netdev_ops;
 /* tag_edsa.c */
 extern const struct dsa_device_ops edsa_netdev_ops;
 
+/* tag_gswip.c */
+extern const struct dsa_device_ops gswip_netdev_ops;
+
 /* tag_ksz.c */
 extern const struct dsa_device_ops ksz_netdev_ops;
 
diff --git a/net/dsa/tag_gswip.c b/net/dsa/tag_gswip.c
new file mode 100644 (file)
index 0000000..49e9b73
--- /dev/null
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel / Lantiq GSWIP V2.0 PMAC tag support
+ *
+ * Copyright (C) 2017 - 2018 Hauke Mehrtens <hauke@hauke-m.de>
+ */
+
+#include <linux/bitops.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <net/dsa.h>
+
+#include "dsa_priv.h"
+
+#define GSWIP_TX_HEADER_LEN            4
+
+/* special tag in TX path header */
+/* Byte 0 */
+#define GSWIP_TX_SLPID_SHIFT           0       /* source port ID */
+#define  GSWIP_TX_SLPID_CPU            2
+#define  GSWIP_TX_SLPID_APP1           3
+#define  GSWIP_TX_SLPID_APP2           4
+#define  GSWIP_TX_SLPID_APP3           5
+#define  GSWIP_TX_SLPID_APP4           6
+#define  GSWIP_TX_SLPID_APP5           7
+
+/* Byte 1 */
+#define GSWIP_TX_CRCGEN_DIS            BIT(7)
+#define GSWIP_TX_DPID_SHIFT            0       /* destination group ID */
+#define  GSWIP_TX_DPID_ELAN            0
+#define  GSWIP_TX_DPID_EWAN            1
+#define  GSWIP_TX_DPID_CPU             2
+#define  GSWIP_TX_DPID_APP1            3
+#define  GSWIP_TX_DPID_APP2            4
+#define  GSWIP_TX_DPID_APP3            5
+#define  GSWIP_TX_DPID_APP4            6
+#define  GSWIP_TX_DPID_APP5            7
+
+/* Byte 2 */
+#define GSWIP_TX_PORT_MAP_EN           BIT(7)
+#define GSWIP_TX_PORT_MAP_SEL          BIT(6)
+#define GSWIP_TX_LRN_DIS               BIT(5)
+#define GSWIP_TX_CLASS_EN              BIT(4)
+#define GSWIP_TX_CLASS_SHIFT           0
+#define GSWIP_TX_CLASS_MASK            GENMASK(3, 0)
+
+/* Byte 3 */
+#define GSWIP_TX_DPID_EN               BIT(0)
+#define GSWIP_TX_PORT_MAP_SHIFT                1
+#define GSWIP_TX_PORT_MAP_MASK         GENMASK(6, 1)
+
+#define GSWIP_RX_HEADER_LEN    8
+
+/* special tag in RX path header */
+/* Byte 7 */
+#define GSWIP_RX_SPPID_SHIFT           4
+#define GSWIP_RX_SPPID_MASK            GENMASK(6, 4)
+
+static struct sk_buff *gswip_tag_xmit(struct sk_buff *skb,
+                                     struct net_device *dev)
+{
+       struct dsa_port *dp = dsa_slave_to_port(dev);
+       int err;
+       u8 *gswip_tag;
+
+       err = skb_cow_head(skb, GSWIP_TX_HEADER_LEN);
+       if (err)
+               return NULL;
+
+       skb_push(skb, GSWIP_TX_HEADER_LEN);
+
+       gswip_tag = skb->data;
+       gswip_tag[0] = GSWIP_TX_SLPID_CPU;
+       gswip_tag[1] = GSWIP_TX_DPID_ELAN;
+       gswip_tag[2] = GSWIP_TX_PORT_MAP_EN | GSWIP_TX_PORT_MAP_SEL;
+       gswip_tag[3] = BIT(dp->index + GSWIP_TX_PORT_MAP_SHIFT) & GSWIP_TX_PORT_MAP_MASK;
+       gswip_tag[3] |= GSWIP_TX_DPID_EN;
+
+       return skb;
+}
+
+static struct sk_buff *gswip_tag_rcv(struct sk_buff *skb,
+                                    struct net_device *dev,
+                                    struct packet_type *pt)
+{
+       int port;
+       u8 *gswip_tag;
+
+       if (unlikely(!pskb_may_pull(skb, GSWIP_RX_HEADER_LEN)))
+               return NULL;
+
+       gswip_tag = skb->data - ETH_HLEN;
+
+       /* Get source port information */
+       port = (gswip_tag[7] & GSWIP_RX_SPPID_MASK) >> GSWIP_RX_SPPID_SHIFT;
+       skb->dev = dsa_master_find_slave(dev, 0, port);
+       if (!skb->dev)
+               return NULL;
+
+       /* remove GSWIP tag */
+       skb_pull_rcsum(skb, GSWIP_RX_HEADER_LEN);
+
+       return skb;
+}
+
+const struct dsa_device_ops gswip_netdev_ops = {
+       .xmit = gswip_tag_xmit,
+       .rcv = gswip_tag_rcv,
+};