layerscape: add patches-5.4
[openwrt/staging/wigyori.git] / target / linux / layerscape / patches-5.4 / 701-net-0262-net-dsa-ocelot-add-tagger-for-Ocelot-Felix-switches.patch
diff --git a/target/linux/layerscape/patches-5.4/701-net-0262-net-dsa-ocelot-add-tagger-for-Ocelot-Felix-switches.patch b/target/linux/layerscape/patches-5.4/701-net-0262-net-dsa-ocelot-add-tagger-for-Ocelot-Felix-switches.patch
new file mode 100644 (file)
index 0000000..f268500
--- /dev/null
@@ -0,0 +1,331 @@
+From 0254efd8d7e8f533b57bdf8665991fd5548c65a8 Mon Sep 17 00:00:00 2001
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+Date: Thu, 14 Nov 2019 17:03:29 +0200
+Subject: [PATCH] net: dsa: ocelot: add tagger for Ocelot/Felix switches
+
+While it is entirely possible that this tagger format is in fact more
+generic than just these 2 switch families, I don't have that knowledge.
+The Seville switch in NXP T1040 has a similar frame format, but there
+are enough differences (e.g. DEST field starts at bit 57 instead of 56)
+that calling this file tag_vitesse.c is a bit of a stretch at the
+moment. The frame format has been listed in a comment so that people who
+add support for further Vitesse switches can rework this tagger while
+keeping compatibility with Felix.
+
+The "ocelot" name was chosen instead of "felix" because even the Ocelot
+switch can act as a DSA device when it is used in NPI mode, and the Felix
+tagger format is almost identical. Currently it is only used for the
+Felix switch embedded in the NXP LS1028A chip.
+
+The ABI for this tagger should be considered "not stable" at the moment.
+The DSA tag is always placed before the Ethernet header and therefore,
+we are using the long prefix for RX tags to avoid putting the DSA master
+port in promiscuous mode. Once there will be an API in DSA for drivers
+to request DSA masters to be in promiscuous mode unconditionally, we
+will switch to the "no prefix" extraction frame header, which will save
+16 padding bytes for each RX frame.
+
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ MAINTAINERS          |   7 ++
+ include/net/dsa.h    |   2 +
+ net/dsa/Kconfig      |   7 ++
+ net/dsa/Makefile     |   1 +
+ net/dsa/tag_ocelot.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 246 insertions(+)
+ create mode 100644 net/dsa/tag_ocelot.c
+
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -17354,6 +17354,13 @@ S:    Maintained
+ F:    drivers/input/serio/userio.c
+ F:    include/uapi/linux/userio.h
++VITESSE FELIX ETHERNET SWITCH DRIVER
++M:    Vladimir Oltean <vladimir.oltean@nxp.com>
++M:    Claudiu Manoil <claudiu.manoil@nxp.com>
++L:    netdev@vger.kernel.org
++S:    Maintained
++F:    net/dsa/tag_ocelot.c
++
+ VIVID VIRTUAL VIDEO DRIVER
+ M:    Hans Verkuil <hverkuil@xs4all.nl>
+ L:    linux-media@vger.kernel.org
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -42,6 +42,7 @@ struct phylink_link_state;
+ #define DSA_TAG_PROTO_8021Q_VALUE             12
+ #define DSA_TAG_PROTO_SJA1105_VALUE           13
+ #define DSA_TAG_PROTO_KSZ8795_VALUE           14
++#define DSA_TAG_PROTO_OCELOT_VALUE            15
+ enum dsa_tag_protocol {
+       DSA_TAG_PROTO_NONE              = DSA_TAG_PROTO_NONE_VALUE,
+@@ -59,6 +60,7 @@ enum dsa_tag_protocol {
+       DSA_TAG_PROTO_8021Q             = DSA_TAG_PROTO_8021Q_VALUE,
+       DSA_TAG_PROTO_SJA1105           = DSA_TAG_PROTO_SJA1105_VALUE,
+       DSA_TAG_PROTO_KSZ8795           = DSA_TAG_PROTO_KSZ8795_VALUE,
++      DSA_TAG_PROTO_OCELOT            = DSA_TAG_PROTO_OCELOT_VALUE,
+ };
+ struct packet_type;
+--- a/net/dsa/Kconfig
++++ b/net/dsa/Kconfig
+@@ -79,6 +79,13 @@ config NET_DSA_TAG_KSZ
+         Say Y if you want to enable support for tagging frames for the
+         Microchip 8795/9477/9893 families of switches.
++config NET_DSA_TAG_OCELOT
++      tristate "Tag driver for Ocelot family of switches"
++      select PACKING
++      help
++        Say Y or M if you want to enable support for tagging frames for the
++        Ocelot switches (VSC7511, VSC7512, VSC7513, VSC7514, VSC9959).
++
+ config NET_DSA_TAG_QCA
+       tristate "Tag driver for Qualcomm Atheros QCA8K switches"
+       help
+--- a/net/dsa/Makefile
++++ b/net/dsa/Makefile
+@@ -12,6 +12,7 @@ obj-$(CONFIG_NET_DSA_TAG_GSWIP) += tag_g
+ 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_OCELOT) += tag_ocelot.o
+ obj-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o
+ obj-$(CONFIG_NET_DSA_TAG_SJA1105) += tag_sja1105.o
+ obj-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
+--- /dev/null
++++ b/net/dsa/tag_ocelot.c
+@@ -0,0 +1,229 @@
++// SPDX-License-Identifier: GPL-2.0
++/* Copyright 2019 NXP Semiconductors
++ */
++#include <soc/mscc/ocelot.h>
++#include <linux/packing.h>
++#include "dsa_priv.h"
++
++/* The CPU injection header and the CPU extraction header can have 3 types of
++ * prefixes: long, short and no prefix. The format of the header itself is the
++ * same in all 3 cases.
++ *
++ * Extraction with long prefix:
++ *
++ * +-------------------+-------------------+------+------+------------+-------+
++ * | ff:ff:ff:ff:ff:ff | ff:ff:ff:ff:ff:ff | 8880 | 000a | extraction | frame |
++ * |                   |                   |      |      |   header   |       |
++ * +-------------------+-------------------+------+------+------------+-------+
++ *        48 bits             48 bits      16 bits 16 bits  128 bits
++ *
++ * Extraction with short prefix:
++ *
++ *                                         +------+------+------------+-------+
++ *                                         | 8880 | 000a | extraction | frame |
++ *                                         |      |      |   header   |       |
++ *                                         +------+------+------------+-------+
++ *                                         16 bits 16 bits  128 bits
++ *
++ * Extraction with no prefix:
++ *
++ *                                                       +------------+-------+
++ *                                                       | extraction | frame |
++ *                                                       |   header   |       |
++ *                                                       +------------+-------+
++ *                                                          128 bits
++ *
++ *
++ * Injection with long prefix:
++ *
++ * +-------------------+-------------------+------+------+------------+-------+
++ * |      any dmac     |      any smac     | 8880 | 000a | injection  | frame |
++ * |                   |                   |      |      |   header   |       |
++ * +-------------------+-------------------+------+------+------------+-------+
++ *        48 bits             48 bits      16 bits 16 bits  128 bits
++ *
++ * Injection with short prefix:
++ *
++ *                                         +------+------+------------+-------+
++ *                                         | 8880 | 000a | injection  | frame |
++ *                                         |      |      |   header   |       |
++ *                                         +------+------+------------+-------+
++ *                                         16 bits 16 bits  128 bits
++ *
++ * Injection with no prefix:
++ *
++ *                                                       +------------+-------+
++ *                                                       | injection  | frame |
++ *                                                       |   header   |       |
++ *                                                       +------------+-------+
++ *                                                          128 bits
++ *
++ * The injection header looks like this (network byte order, bit 127
++ * is part of lowest address byte in memory, bit 0 is part of highest
++ * address byte):
++ *
++ *         +------+------+------+------+------+------+------+------+
++ * 127:120 |BYPASS| MASQ |          MASQ_PORT        |REW_OP|REW_OP|
++ *         +------+------+------+------+------+------+------+------+
++ * 119:112 |                         REW_OP                        |
++ *         +------+------+------+------+------+------+------+------+
++ * 111:104 |                         REW_VAL                       |
++ *         +------+------+------+------+------+------+------+------+
++ * 103: 96 |                         REW_VAL                       |
++ *         +------+------+------+------+------+------+------+------+
++ *  95: 88 |                         REW_VAL                       |
++ *         +------+------+------+------+------+------+------+------+
++ *  87: 80 |                         REW_VAL                       |
++ *         +------+------+------+------+------+------+------+------+
++ *  79: 72 |                          RSV                          |
++ *         +------+------+------+------+------+------+------+------+
++ *  71: 64 |            RSV            |           DEST            |
++ *         +------+------+------+------+------+------+------+------+
++ *  63: 56 |                         DEST                          |
++ *         +------+------+------+------+------+------+------+------+
++ *  55: 48 |                          RSV                          |
++ *         +------+------+------+------+------+------+------+------+
++ *  47: 40 |  RSV |         SRC_PORT          |     RSV     |TFRM_TIMER|
++ *         +------+------+------+------+------+------+------+------+
++ *  39: 32 |     TFRM_TIMER     |               RSV                |
++ *         +------+------+------+------+------+------+------+------+
++ *  31: 24 |  RSV |  DP  |   POP_CNT   |           CPUQ            |
++ *         +------+------+------+------+------+------+------+------+
++ *  23: 16 |           CPUQ            |      QOS_CLASS     |TAG_TYPE|
++ *         +------+------+------+------+------+------+------+------+
++ *  15:  8 |         PCP        |  DEI |            VID            |
++ *         +------+------+------+------+------+------+------+------+
++ *   7:  0 |                          VID                          |
++ *         +------+------+------+------+------+------+------+------+
++ *
++ * And the extraction header looks like this:
++ *
++ *         +------+------+------+------+------+------+------+------+
++ * 127:120 |  RSV |                  REW_OP                        |
++ *         +------+------+------+------+------+------+------+------+
++ * 119:112 |       REW_OP       |              REW_VAL             |
++ *         +------+------+------+------+------+------+------+------+
++ * 111:104 |                         REW_VAL                       |
++ *         +------+------+------+------+------+------+------+------+
++ * 103: 96 |                         REW_VAL                       |
++ *         +------+------+------+------+------+------+------+------+
++ *  95: 88 |                         REW_VAL                       |
++ *         +------+------+------+------+------+------+------+------+
++ *  87: 80 |       REW_VAL      |               LLEN               |
++ *         +------+------+------+------+------+------+------+------+
++ *  79: 72 | LLEN |                      WLEN                      |
++ *         +------+------+------+------+------+------+------+------+
++ *  71: 64 | WLEN |                      RSV                       |
++ *         +------+------+------+------+------+------+------+------+
++ *  63: 56 |                          RSV                          |
++ *         +------+------+------+------+------+------+------+------+
++ *  55: 48 |                          RSV                          |
++ *         +------+------+------+------+------+------+------+------+
++ *  47: 40 | RSV  |          SRC_PORT         |       ACL_ID       |
++ *         +------+------+------+------+------+------+------+------+
++ *  39: 32 |       ACL_ID       |  RSV |         SFLOW_ID          |
++ *         +------+------+------+------+------+------+------+------+
++ *  31: 24 |ACL_HIT| DP  |  LRN_FLAGS  |           CPUQ            |
++ *         +------+------+------+------+------+------+------+------+
++ *  23: 16 |           CPUQ            |      QOS_CLASS     |TAG_TYPE|
++ *         +------+------+------+------+------+------+------+------+
++ *  15:  8 |         PCP        |  DEI |            VID            |
++ *         +------+------+------+------+------+------+------+------+
++ *   7:  0 |                          VID                          |
++ *         +------+------+------+------+------+------+------+------+
++ */
++
++static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
++                                 struct net_device *netdev)
++{
++      struct dsa_port *dp = dsa_slave_to_port(netdev);
++      u64 bypass, dest, src, qos_class;
++      struct dsa_switch *ds = dp->ds;
++      int port = dp->index;
++      u8 *injection;
++
++      if (unlikely(skb_cow_head(skb, OCELOT_TAG_LEN) < 0)) {
++              netdev_err(netdev, "Cannot make room for tag.\n");
++              return NULL;
++      }
++
++      injection = skb_push(skb, OCELOT_TAG_LEN);
++
++      memset(injection, 0, OCELOT_TAG_LEN);
++
++      src = dsa_upstream_port(ds, port);
++      dest = BIT(port);
++      bypass = true;
++      qos_class = skb->priority;
++
++      packing(injection, &bypass,   127, 127, OCELOT_TAG_LEN, PACK, 0);
++      packing(injection, &dest,      68,  56, OCELOT_TAG_LEN, PACK, 0);
++      packing(injection, &src,       46,  43, OCELOT_TAG_LEN, PACK, 0);
++      packing(injection, &qos_class, 19,  17, OCELOT_TAG_LEN, PACK, 0);
++
++      return skb;
++}
++
++static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
++                                struct net_device *netdev,
++                                struct packet_type *pt)
++{
++      u64 src_port, qos_class;
++      u8 *start = skb->data;
++      u8 *extraction;
++
++      /* Revert skb->data by the amount consumed by the DSA master,
++       * so it points to the beginning of the frame.
++       */
++      skb_push(skb, ETH_HLEN);
++      /* We don't care about the long prefix, it is just for easy entrance
++       * into the DSA master's RX filter. Discard it now by moving it into
++       * the headroom.
++       */
++      skb_pull(skb, OCELOT_LONG_PREFIX_LEN);
++      /* And skb->data now points to the extraction frame header.
++       * Keep a pointer to it.
++       */
++      extraction = skb->data;
++      /* Now the EFH is part of the headroom as well */
++      skb_pull(skb, OCELOT_TAG_LEN);
++      /* Reset the pointer to the real MAC header */
++      skb_reset_mac_header(skb);
++      skb_reset_mac_len(skb);
++      /* And move skb->data to the correct location again */
++      skb_pull(skb, ETH_HLEN);
++
++      /* Remove from inet csum the extraction header */
++      skb_postpull_rcsum(skb, start, OCELOT_LONG_PREFIX_LEN + OCELOT_TAG_LEN);
++
++      packing(extraction, &src_port,  46, 43, OCELOT_TAG_LEN, UNPACK, 0);
++      packing(extraction, &qos_class, 19, 17, OCELOT_TAG_LEN, UNPACK, 0);
++
++      skb->dev = dsa_master_find_slave(netdev, 0, src_port);
++      if (!skb->dev)
++              /* The switch will reflect back some frames sent through
++               * sockets opened on the bare DSA master. These will come back
++               * with src_port equal to the index of the CPU port, for which
++               * there is no slave registered. So don't print any error
++               * message here (ignore and drop those frames).
++               */
++              return NULL;
++
++      skb->offload_fwd_mark = 1;
++      skb->priority = qos_class;
++
++      return skb;
++}
++
++static struct dsa_device_ops ocelot_netdev_ops = {
++      .name                   = "ocelot",
++      .proto                  = DSA_TAG_PROTO_OCELOT,
++      .xmit                   = ocelot_xmit,
++      .rcv                    = ocelot_rcv,
++      .overhead               = OCELOT_TAG_LEN + OCELOT_LONG_PREFIX_LEN,
++};
++
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_OCELOT);
++
++module_dsa_tag_driver(ocelot_netdev_ops);