All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] net: Add support for Lantiq / Intel vrx200 network
@ 2018-07-21 19:13 Hauke Mehrtens
  2018-07-21 19:13 ` [PATCH 1/4] MIPS: lantiq: Do not enable IRQs in dma open Hauke Mehrtens
                   ` (3 more replies)
  0 siblings, 4 replies; 29+ messages in thread
From: Hauke Mehrtens @ 2018-07-21 19:13 UTC (permalink / raw)
  To: davem
  Cc: netdev, andrew, vivien.didelot, f.fainelli, john, linux-mips,
	dev, hauke.mehrtens, Hauke Mehrtens

This adds basic support for the GSWIP (Gigabit Switch) found in the 
VRX200 SoC.
There are different versions of this IP core used in different SoCs, but 
this driver was currently only tested on the VRX200 SoC line, for other 
SoCs this driver probably need some adoptions to work.

I also plan to add Layer 2 offloading to the DSA driver and later also 
layer 3 offloading which is supported by the PPE HW block.

Hauke Mehrtens (4):
  MIPS: lantiq: Do not enable IRQs in dma open
  net: dsa: Add Lantiq / Intel GSWIP tag support
  net: lantiq: Add Lantiq / Intel vrx200 Ethernet driver
  net: dsa: Add Lantiq / Intel DSA driver for vrx200

 MAINTAINERS                          |   9 +
 arch/mips/lantiq/xway/dma.c          |   1 -
 arch/mips/lantiq/xway/sysctrl.c      |   2 +-
 drivers/net/dsa/Kconfig              |   8 +
 drivers/net/dsa/Makefile             |   1 +
 drivers/net/dsa/lantiq-gswip.c       | 750 +++++++++++++++++++++++++++++++++++
 drivers/net/dsa/lantiq_pce.h         | 153 +++++++
 drivers/net/ethernet/Kconfig         |   6 +
 drivers/net/ethernet/Makefile        |   1 +
 drivers/net/ethernet/lantiq_etop.c   |   1 +
 drivers/net/ethernet/lantiq_xrx200.c | 609 ++++++++++++++++++++++++++++
 include/net/dsa.h                    |   1 +
 net/dsa/Kconfig                      |   3 +
 net/dsa/Makefile                     |   1 +
 net/dsa/dsa.c                        |   3 +
 net/dsa/dsa_priv.h                   |   3 +
 net/dsa/tag_gswip.c                  | 110 +++++
 17 files changed, 1660 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/dsa/lantiq-gswip.c
 create mode 100644 drivers/net/dsa/lantiq_pce.h
 create mode 100644 drivers/net/ethernet/lantiq_xrx200.c
 create mode 100644 net/dsa/tag_gswip.c

-- 
2.11.0

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH 1/4] MIPS: lantiq: Do not enable IRQs in dma open
  2018-07-21 19:13 [PATCH 0/4] net: Add support for Lantiq / Intel vrx200 network Hauke Mehrtens
@ 2018-07-21 19:13 ` Hauke Mehrtens
  2018-07-24  0:19   ` Paul Burton
  2018-07-21 19:13 ` [PATCH 2/4] net: dsa: Add Lantiq / Intel GSWIP tag support Hauke Mehrtens
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 29+ messages in thread
From: Hauke Mehrtens @ 2018-07-21 19:13 UTC (permalink / raw)
  To: davem
  Cc: netdev, andrew, vivien.didelot, f.fainelli, john, linux-mips,
	dev, hauke.mehrtens, Hauke Mehrtens

When a DMA channel is opened the IRQ should not get activated
automatically, this allows it to pull data out manually without the help
of interrupts. This is needed for a workaround in the vrx200 Ethernet
driver.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 arch/mips/lantiq/xway/dma.c        | 1 -
 drivers/net/ethernet/lantiq_etop.c | 1 +
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c
index 4b9fbb6744ad..3a90bb4edacc 100644
--- a/arch/mips/lantiq/xway/dma.c
+++ b/arch/mips/lantiq/xway/dma.c
@@ -106,7 +106,6 @@ ltq_dma_open(struct ltq_dma_channel *ch)
 	spin_lock_irqsave(&ltq_dma_lock, flag);
 	ltq_dma_w32(ch->nr, LTQ_DMA_CS);
 	ltq_dma_w32_mask(0, DMA_CHAN_ON, LTQ_DMA_CCTRL);
-	ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN);
 	spin_unlock_irqrestore(&ltq_dma_lock, flag);
 }
 EXPORT_SYMBOL_GPL(ltq_dma_open);
diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c
index afc810069440..c978a857a25c 100644
--- a/drivers/net/ethernet/lantiq_etop.c
+++ b/drivers/net/ethernet/lantiq_etop.c
@@ -438,6 +438,7 @@ ltq_etop_open(struct net_device *dev)
 		if (!IS_TX(i) && (!IS_RX(i)))
 			continue;
 		ltq_dma_open(&ch->dma);
+		ltq_dma_enable_irq(&ch->dma);
 		napi_enable(&ch->napi);
 	}
 	phy_start(dev->phydev);
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 2/4] net: dsa: Add Lantiq / Intel GSWIP tag support
  2018-07-21 19:13 [PATCH 0/4] net: Add support for Lantiq / Intel vrx200 network Hauke Mehrtens
  2018-07-21 19:13 ` [PATCH 1/4] MIPS: lantiq: Do not enable IRQs in dma open Hauke Mehrtens
@ 2018-07-21 19:13 ` Hauke Mehrtens
  2018-07-25 14:20   ` Andrew Lunn
  2018-07-21 19:13 ` [PATCH 3/4] net: lantiq: Add Lantiq / Intel vrx200 Ethernet driver Hauke Mehrtens
  2018-07-21 19:13 ` [PATCH 4/4] net: dsa: Add Lantiq / Intel DSA driver for vrx200 Hauke Mehrtens
  3 siblings, 1 reply; 29+ messages in thread
From: Hauke Mehrtens @ 2018-07-21 19:13 UTC (permalink / raw)
  To: davem
  Cc: netdev, andrew, vivien.didelot, f.fainelli, john, linux-mips,
	dev, hauke.mehrtens, Hauke Mehrtens

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.0 found in the VRX200 SoCs, other GSWIP
versions use slightly different PMAC special tags

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 MAINTAINERS         |   6 +++
 include/net/dsa.h   |   1 +
 net/dsa/Kconfig     |   3 ++
 net/dsa/Makefile    |   1 +
 net/dsa/dsa.c       |   3 ++
 net/dsa/dsa_priv.h  |   3 ++
 net/dsa/tag_gswip.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 127 insertions(+)
 create mode 100644 net/dsa/tag_gswip.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 192d7f73fd01..741718ff9b79 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8009,6 +8009,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
diff --git a/include/net/dsa.h b/include/net/dsa.h
index fdbd6082945d..60bc8952e29b 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -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,
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
index 4183e4ba27a5..48c41918fb35 100644
--- a/net/dsa/Kconfig
+++ b/net/dsa/Kconfig
@@ -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
 
diff --git a/net/dsa/Makefile b/net/dsa/Makefile
index 9e4d3536f977..6e721f7a2947 100644
--- a/net/dsa/Makefile
+++ b/net/dsa/Makefile
@@ -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
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index e63c554e0623..81212109c507 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -54,6 +54,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
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index 3964c6f7a7c0..824ca07a30aa 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -205,6 +205,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
index 000000000000..cb559768c87f
--- /dev/null
+++ b/net/dsa/tag_gswip.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel / Lantiq GSWIP 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_DPID_EN		BIT(0)
+#define GSWIP_TX_PORT_MAP_SHIFT		1
+#define GSWIP_TX_PORT_MAP_MASK		GENMASK(6, 1)
+
+/* Byte 1 */
+#define GSWIP_TX_CLASS_SHIFT		0
+#define GSWIP_TX_CLASS_MASK		GENMASK(3, 0)
+#define GSWIP_TX_CLASS_EN		BIT(4)
+#define GSWIP_TX_LRN_DIS		BIT(5)
+#define GSWIP_TX_PORT_MAP_SEL		BIT(6)
+#define GSWIP_TX_PORT_MAP_EN		BIT(7)
+
+/* Byte 2 */
+#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 3 */
+#define GSWIP_TX_CRCGEN_DIS		BIT(23)
+#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
+
+
+#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 = ((u8 *)skb->data) - ETH_HLEN;
+	skb_pull_rcsum(skb, GSWIP_RX_HEADER_LEN);
+
+	/* 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;
+
+	return skb;
+}
+
+const struct dsa_device_ops gswip_netdev_ops = {
+	.xmit = gswip_tag_xmit,
+	.rcv = gswip_tag_rcv,
+};
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 3/4] net: lantiq: Add Lantiq / Intel vrx200 Ethernet driver
  2018-07-21 19:13 [PATCH 0/4] net: Add support for Lantiq / Intel vrx200 network Hauke Mehrtens
  2018-07-21 19:13 ` [PATCH 1/4] MIPS: lantiq: Do not enable IRQs in dma open Hauke Mehrtens
  2018-07-21 19:13 ` [PATCH 2/4] net: dsa: Add Lantiq / Intel GSWIP tag support Hauke Mehrtens
@ 2018-07-21 19:13 ` Hauke Mehrtens
  2018-07-21 20:25   ` John Crispin
                     ` (2 more replies)
  2018-07-21 19:13 ` [PATCH 4/4] net: dsa: Add Lantiq / Intel DSA driver for vrx200 Hauke Mehrtens
  3 siblings, 3 replies; 29+ messages in thread
From: Hauke Mehrtens @ 2018-07-21 19:13 UTC (permalink / raw)
  To: davem
  Cc: netdev, andrew, vivien.didelot, f.fainelli, john, linux-mips,
	dev, hauke.mehrtens, Hauke Mehrtens

This drives the PMAC between the GSWIP Switch and the CPU in the VRX200
SoC. This is currently only the very basic version of the Ethernet
driver.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 MAINTAINERS                          |   2 +
 arch/mips/lantiq/xway/sysctrl.c      |   2 +-
 drivers/net/ethernet/Kconfig         |   6 +
 drivers/net/ethernet/Makefile        |   1 +
 drivers/net/ethernet/lantiq_xrx200.c | 609 +++++++++++++++++++++++++++++++++++
 5 files changed, 619 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/lantiq_xrx200.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 741718ff9b79..cc0607a58c51 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8014,6 +8014,8 @@ M:	Hauke Mehrtens <hauke@hauke-m.de>
 L:	netdev@vger.kernel.org
 S:	Maintained
 F:	net/dsa/tag_gswip.c
+F:	drivers/net/ethernet/lantiq_xrx200.c
+F:	drivers/net/dsa/lantiq_pce.h
 
 LANTIQ MIPS ARCHITECTURE
 M:	John Crispin <john@phrozen.org>
diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c
index e0af39b33e28..c704312ef7d5 100644
--- a/arch/mips/lantiq/xway/sysctrl.c
+++ b/arch/mips/lantiq/xway/sysctrl.c
@@ -536,7 +536,7 @@ void __init ltq_soc_init(void)
 		clkdev_add_pmu(NULL, "ahb", 1, 0, PMU_AHBM | PMU_AHBS);
 
 		clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF);
-		clkdev_add_pmu("1e108000.eth", NULL, 0, 0,
+		clkdev_add_pmu("1e10b308.eth", NULL, 0, 0,
 				PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM |
 				PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 |
 				PMU_PPE_QSB | PMU_PPE_TOP);
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index af766fd61151..1767f2ee1795 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -109,6 +109,12 @@ config LANTIQ_ETOP
 	---help---
 	  Support for the MII0 inside the Lantiq SoC
 
+config LANTIQ_XRX200
+	tristate "Lantiq SoC XRX200 driver"
+	depends on SOC_TYPE_XWAY
+	---help---
+	  Support for the PMAC of the GSWIP inside the Lantiq VRX200 VDSL SoC
+
 source "drivers/net/ethernet/marvell/Kconfig"
 source "drivers/net/ethernet/mediatek/Kconfig"
 source "drivers/net/ethernet/mellanox/Kconfig"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index 8fbfe9ce2fa5..839322f353ca 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_NET_VENDOR_XSCALE) += xscale/
 obj-$(CONFIG_JME) += jme.o
 obj-$(CONFIG_KORINA) += korina.o
 obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o
+obj-$(CONFIG_LANTIQ_XRX200) += lantiq_xrx200.o
 obj-$(CONFIG_NET_VENDOR_MARVELL) += marvell/
 obj-$(CONFIG_NET_VENDOR_MEDIATEK) += mediatek/
 obj-$(CONFIG_NET_VENDOR_MELLANOX) += mellanox/
diff --git a/drivers/net/ethernet/lantiq_xrx200.c b/drivers/net/ethernet/lantiq_xrx200.c
new file mode 100644
index 000000000000..e31a6ce3c84c
--- /dev/null
+++ b/drivers/net/ethernet/lantiq_xrx200.c
@@ -0,0 +1,609 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Lantiq / Intel PMAC driver for XRX200 SoCs
+ *
+ * Copyright (C) 2010 Lantiq Deutschland
+ * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2017 - 2018 Hauke Mehrtens <hauke@hauke-m.de>
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+
+#include <linux/of_net.h>
+#include <linux/of_platform.h>
+
+#include <xway_dma.h>
+
+/* DMA */
+#define XRX200_DMA_DATA_LEN	0x600
+#define XRX200_DMA_RX		0
+#define XRX200_DMA_TX		1
+
+
+/* cpu port mac */
+#define PMAC_RX_IPG		0x0024
+#define PMAC_RX_IPG_MASK	0xf
+
+#define PMAC_HD_CTL		0x0000
+/* Add Ethernet header to packets from DMA to PMAC */
+#define PMAC_HD_CTL_ADD		BIT(0)
+/* Add VLAN tag to Packets from DMA to PMAC */
+#define PMAC_HD_CTL_TAG		BIT(1)
+/* Add CRC to packets from DMA to PMAC */
+#define PMAC_HD_CTL_AC		BIT(2)
+/* Add status header to packets from PMAC to DMA */
+#define PMAC_HD_CTL_AS		BIT(3)
+/* Remove CRC from packets from PMAC to DMA */
+#define PMAC_HD_CTL_RC		BIT(4)
+/* Remove Layer-2 header from packets from PMAC to DMA */
+#define PMAC_HD_CTL_RL2		BIT(5)
+/* Status header is present from DMA to PMAC */
+#define PMAC_HD_CTL_RXSH	BIT(6)
+/* Add special tag from PMAC to switch */
+#define PMAC_HD_CTL_AST		BIT(7)
+/* Remove specail Tag from PMAC to DMA */
+#define PMAC_HD_CTL_RST		BIT(8)
+/* Check CRC from DMA to PMAC */
+#define PMAC_HD_CTL_CCRC	BIT(9)
+/* Enable reaction to Pause frames in the PMAC */
+#define PMAC_HD_CTL_FC		BIT(10)
+
+
+struct xrx200_chan {
+	int tx_free;
+
+	struct tasklet_struct tasklet;
+	struct napi_struct napi;
+	struct ltq_dma_channel dma;
+	struct sk_buff *skb[LTQ_DESC_NUM];
+
+	struct xrx200_priv *priv;
+};
+
+struct xrx200_priv {
+	struct net_device_stats stats;
+
+	struct clk *clk;
+
+	struct xrx200_chan chan_tx;
+	struct xrx200_chan chan_rx;
+
+	struct net_device *net_dev;
+	struct device *dev;
+
+	__iomem void *pmac_reg;
+};
+
+static u32 xrx200_pmac_r32(struct xrx200_priv *priv, u32 offset)
+{
+	return __raw_readl(priv->pmac_reg + offset);
+}
+
+static void xrx200_pmac_w32(struct xrx200_priv *priv, u32 val, u32 offset)
+{
+	return __raw_writel(val, priv->pmac_reg + offset);
+}
+
+static void xrx200_pmac_mask(struct xrx200_priv *priv, u32 clear, u32 set,
+			     u32 offset)
+{
+	u32 val = xrx200_pmac_r32(priv, offset);
+
+	val &= ~(clear);
+	val |= set;
+	xrx200_pmac_w32(priv, val, offset);
+}
+
+/* drop all the packets from the DMA ring */
+static void xrx200_flush_dma(struct xrx200_chan *ch)
+{
+	int i;
+
+	for (i = 0; i < LTQ_DESC_NUM; i++) {
+		struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
+
+		if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) != LTQ_DMA_C)
+			break;
+
+		desc->ctl = LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) |
+			    XRX200_DMA_DATA_LEN;
+		ch->dma.desc++;
+		ch->dma.desc %= LTQ_DESC_NUM;
+	}
+}
+
+static int xrx200_open(struct net_device *dev)
+{
+	struct xrx200_priv *priv = netdev_priv(dev);
+
+	ltq_dma_open(&priv->chan_tx.dma);
+	ltq_dma_enable_irq(&priv->chan_tx.dma);
+
+	napi_enable(&priv->chan_rx.napi);
+	ltq_dma_open(&priv->chan_rx.dma);
+	/* The boot loader does not always deactivate the receiving of frames
+	 * on the ports and then some packets queue up in the PPE buffers.
+	 * They already passed the PMAC so they do not have the tags
+	 * configured here. Read the these packets here and drop them.
+	 * The HW should have written them into memory after 10us
+	 */
+	udelay(10);
+	xrx200_flush_dma(&priv->chan_rx);
+	ltq_dma_enable_irq(&priv->chan_rx.dma);
+
+	netif_wake_queue(dev);
+
+	return 0;
+}
+
+static int xrx200_close(struct net_device *dev)
+{
+	struct xrx200_priv *priv = netdev_priv(dev);
+
+	netif_stop_queue(dev);
+
+	napi_disable(&priv->chan_rx.napi);
+	ltq_dma_close(&priv->chan_rx.dma);
+
+	ltq_dma_close(&priv->chan_tx.dma);
+
+	return 0;
+}
+
+static int xrx200_alloc_skb(struct xrx200_chan *ch)
+{
+	int ret = 0;
+
+#define DMA_PAD	(NET_IP_ALIGN + NET_SKB_PAD)
+	ch->skb[ch->dma.desc] = dev_alloc_skb(XRX200_DMA_DATA_LEN + DMA_PAD);
+	if (!ch->skb[ch->dma.desc]) {
+		ret = -ENOMEM;
+		goto skip;
+	}
+
+	skb_reserve(ch->skb[ch->dma.desc], NET_SKB_PAD);
+	ch->dma.desc_base[ch->dma.desc].addr = dma_map_single(ch->priv->dev,
+		ch->skb[ch->dma.desc]->data, XRX200_DMA_DATA_LEN,
+			DMA_FROM_DEVICE);
+	if (unlikely(dma_mapping_error(ch->priv->dev,
+				       ch->dma.desc_base[ch->dma.desc].addr))) {
+		dev_kfree_skb_any(ch->skb[ch->dma.desc]);
+		ret = -ENOMEM;
+		goto skip;
+	}
+
+	ch->dma.desc_base[ch->dma.desc].addr =
+		CPHYSADDR(ch->skb[ch->dma.desc]->data);
+	skb_reserve(ch->skb[ch->dma.desc], NET_IP_ALIGN);
+
+skip:
+	ch->dma.desc_base[ch->dma.desc].ctl =
+		LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) |
+		XRX200_DMA_DATA_LEN;
+
+	return ret;
+}
+
+static int xrx200_hw_receive(struct xrx200_chan *ch)
+{
+	struct xrx200_priv *priv = ch->priv;
+	struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
+	struct sk_buff *skb = ch->skb[ch->dma.desc];
+	int len = (desc->ctl & LTQ_DMA_SIZE_MASK);
+	int ret;
+
+	ret = xrx200_alloc_skb(ch);
+
+	ch->dma.desc++;
+	ch->dma.desc %= LTQ_DESC_NUM;
+
+	if (ret) {
+		netdev_err(priv->net_dev,
+			   "failed to allocate new rx buffer\n");
+		return ret;
+	}
+
+	skb_put(skb, len);
+	skb->dev = priv->net_dev;
+	skb->protocol = eth_type_trans(skb, priv->net_dev);
+	netif_receive_skb(skb);
+	priv->stats.rx_packets++;
+	priv->stats.rx_bytes += len;
+
+	return 0;
+}
+
+static int xrx200_poll_rx(struct napi_struct *napi, int budget)
+{
+	struct xrx200_chan *ch = container_of(napi,
+				struct xrx200_chan, napi);
+	int rx = 0;
+	int ret;
+
+	while (rx < budget) {
+		struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
+
+		if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) {
+			ret = xrx200_hw_receive(ch);
+			if (ret)
+				return ret;
+			rx++;
+		} else {
+			break;
+		}
+	}
+
+	if (rx < budget) {
+		napi_complete(&ch->napi);
+		ltq_dma_enable_irq(&ch->dma);
+	}
+
+	return rx;
+}
+
+static void xrx200_tx_housekeeping(unsigned long ptr)
+{
+	struct xrx200_chan *ch = (struct xrx200_chan *)ptr;
+	int pkts = 0;
+	int bytes = 0;
+
+	ltq_dma_ack_irq(&ch->dma);
+	while ((ch->dma.desc_base[ch->tx_free].ctl &
+		(LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) {
+		struct sk_buff *skb = ch->skb[ch->tx_free];
+
+		pkts++;
+		bytes += skb->len;
+		ch->skb[ch->tx_free] = NULL;
+		dev_kfree_skb(skb);
+		memset(&ch->dma.desc_base[ch->tx_free], 0,
+		       sizeof(struct ltq_dma_desc));
+		ch->tx_free++;
+		ch->tx_free %= LTQ_DESC_NUM;
+	}
+	ltq_dma_enable_irq(&ch->dma);
+
+	netdev_completed_queue(ch->priv->net_dev, pkts, bytes);
+
+	if (!pkts)
+		return;
+
+	netif_wake_queue(ch->priv->net_dev);
+}
+
+static struct net_device_stats *xrx200_get_stats(struct net_device *dev)
+{
+	struct xrx200_priv *priv = netdev_priv(dev);
+
+	return &priv->stats;
+}
+
+static int xrx200_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct xrx200_priv *priv = netdev_priv(dev);
+	struct xrx200_chan *ch;
+	struct ltq_dma_desc *desc;
+	u32 byte_offset;
+	dma_addr_t mapping;
+	int len;
+
+	ch = &priv->chan_tx;
+
+	desc = &ch->dma.desc_base[ch->dma.desc];
+
+	skb->dev = dev;
+	len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
+
+	/* dma needs to start on a 16 byte aligned address */
+	byte_offset = CPHYSADDR(skb->data) % 16;
+
+	if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || ch->skb[ch->dma.desc]) {
+		netdev_err(dev, "tx ring full\n");
+		netif_stop_queue(dev);
+		return NETDEV_TX_BUSY;
+	}
+
+	ch->skb[ch->dma.desc] = skb;
+
+	netif_trans_update(dev);
+
+	mapping = dma_map_single(priv->dev, skb->data, len, DMA_TO_DEVICE);
+	if (unlikely(dma_mapping_error(priv->dev, mapping)))
+		goto err_drop;
+
+	desc->addr = mapping - byte_offset;
+	/* Make sure the address is written before we give it to HW */
+	wmb();
+	desc->ctl = LTQ_DMA_OWN | LTQ_DMA_SOP | LTQ_DMA_EOP |
+		LTQ_DMA_TX_OFFSET(byte_offset) | (len & LTQ_DMA_SIZE_MASK);
+	ch->dma.desc++;
+	ch->dma.desc %= LTQ_DESC_NUM;
+	if (ch->dma.desc == ch->tx_free)
+		netif_stop_queue(dev);
+
+	netdev_sent_queue(dev, skb->len);
+	priv->stats.tx_packets++;
+	priv->stats.tx_bytes += len;
+
+	return NETDEV_TX_OK;
+
+err_drop:
+	dev_kfree_skb(skb);
+	priv->stats.tx_dropped++;
+	priv->stats.tx_errors++;
+	return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops xrx200_netdev_ops = {
+	.ndo_open		= xrx200_open,
+	.ndo_stop		= xrx200_close,
+	.ndo_start_xmit		= xrx200_start_xmit,
+	.ndo_set_mac_address	= eth_mac_addr,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_change_mtu		= eth_change_mtu,
+	.ndo_get_stats		= xrx200_get_stats,
+};
+
+static irqreturn_t xrx200_dma_irq_tx(int irq, void *ptr)
+{
+	struct xrx200_priv *priv = ptr;
+	struct xrx200_chan *ch = &priv->chan_tx;
+
+	ltq_dma_disable_irq(&ch->dma);
+	ltq_dma_ack_irq(&ch->dma);
+
+	tasklet_schedule(&ch->tasklet);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t xrx200_dma_irq_rx(int irq, void *ptr)
+{
+	struct xrx200_priv *priv = ptr;
+	struct xrx200_chan *ch = &priv->chan_rx;
+
+	ltq_dma_disable_irq(&ch->dma);
+	ltq_dma_ack_irq(&ch->dma);
+
+	napi_schedule(&ch->napi);
+
+	return IRQ_HANDLED;
+}
+
+static int xrx200_dma_init(struct xrx200_priv *priv)
+{
+	struct xrx200_chan *ch_rx = &priv->chan_rx;
+	struct xrx200_chan *ch_tx = &priv->chan_tx;
+	int ret = 0;
+	int i;
+
+	ltq_dma_init_port(DMA_PORT_ETOP);
+
+	ch_rx->dma.nr = XRX200_DMA_RX;
+	ch_rx->priv = priv;
+
+	ltq_dma_alloc_rx(&ch_rx->dma);
+	for (ch_rx->dma.desc = 0; ch_rx->dma.desc < LTQ_DESC_NUM;
+	     ch_rx->dma.desc++) {
+		ret = xrx200_alloc_skb(ch_rx);
+		if (ret)
+			goto rx_free;
+	}
+	ch_rx->dma.desc = 0;
+	ret = devm_request_irq(priv->dev, ch_rx->dma.irq, xrx200_dma_irq_rx, 0,
+			       "xrx200_net_rx", priv);
+	if (ret) {
+		dev_err(priv->dev, "failed to request RX irq %d\n",
+			ch_rx->dma.irq);
+		goto rx_ring_free;
+	}
+
+	ch_tx->dma.nr = XRX200_DMA_TX;
+	ch_tx->priv = priv;
+
+	ltq_dma_alloc_tx(&ch_tx->dma);
+	ret = devm_request_irq(priv->dev, ch_tx->dma.irq, xrx200_dma_irq_tx, 0,
+			       "xrx200_net_tx", priv);
+	if (ret) {
+		dev_err(priv->dev, "failed to request TX irq %d\n",
+			ch_tx->dma.irq);
+		goto tx_free;
+	}
+
+	return ret;
+
+tx_free:
+	ltq_dma_free(&ch_tx->dma);
+
+rx_ring_free:
+	/* free the allocated RX ring */
+	for (i = 0; i < LTQ_DESC_NUM; i++) {
+		if (priv->chan_rx.skb[i])
+			dev_kfree_skb_any(priv->chan_rx.skb[i]);
+	}
+
+rx_free:
+	ltq_dma_free(&ch_rx->dma);
+	return ret;
+}
+
+static void xrx200_hw_cleanup(struct xrx200_priv *priv)
+{
+	int i;
+
+	ltq_dma_free(&priv->chan_tx.dma);
+	ltq_dma_free(&priv->chan_rx.dma);
+
+	/* free the allocated RX ring */
+	for (i = 0; i < LTQ_DESC_NUM; i++)
+		dev_kfree_skb_any(priv->chan_rx.skb[i]);
+}
+
+static int xrx200_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct resource *res;
+	struct device_node *phy_np;
+	struct of_phandle_iterator it;
+	struct xrx200_priv *priv;
+	struct net_device *net_dev;
+	const u8 *mac;
+	int err;
+
+	/* alloc the network device */
+	net_dev = devm_alloc_etherdev(dev, sizeof(struct xrx200_priv));
+	if (!net_dev)
+		return -ENOMEM;
+
+	priv = netdev_priv(net_dev);
+	priv->net_dev = net_dev;
+	priv->dev = dev;
+
+	net_dev->netdev_ops = &xrx200_netdev_ops;
+	SET_NETDEV_DEV(net_dev, dev);
+	net_dev->min_mtu = ETH_ZLEN;
+	net_dev->max_mtu = XRX200_DMA_DATA_LEN;
+
+	/* load the memory ranges */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "failed to get resources\n");
+		return -ENOENT;
+	}
+
+	priv->pmac_reg = devm_ioremap_resource(dev, res);
+	if (!priv->pmac_reg) {
+		dev_err(dev, "failed to request and remap io ranges\n");
+		return -ENOMEM;
+	}
+
+	priv->chan_rx.dma.irq = platform_get_irq_byname(pdev, "rx");
+	if (priv->chan_rx.dma.irq < 0) {
+		dev_err(dev, "failed to get RX IRQ, %i\n",
+			priv->chan_rx.dma.irq);
+		return -ENOENT;
+	}
+	priv->chan_tx.dma.irq = platform_get_irq_byname(pdev, "tx");
+	if (priv->chan_tx.dma.irq < 0) {
+		dev_err(dev, "failed to get TX IRQ, %i\n",
+			priv->chan_tx.dma.irq);
+		return -ENOENT;
+	}
+
+	/* Make sure the firmware of the embedded GPHY is loaded before,
+	 * otherwise they will not be detectable on the MDIO bus.
+	 */
+	of_for_each_phandle(&it, err, np, "lantiq,phys", NULL, 0) {
+		phy_np = it.node;
+		if (phy_np) {
+			struct platform_device *phy = of_find_device_by_node(phy_np);
+
+			of_node_put(phy_np);
+			if (!platform_get_drvdata(phy))
+				return -EPROBE_DEFER;
+		}
+	}
+
+	/* get the clock */
+	priv->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(priv->clk)) {
+		dev_err(dev, "failed to get clock\n");
+		return PTR_ERR(priv->clk);
+	}
+
+	mac = of_get_mac_address(np);
+	if (mac && is_valid_ether_addr(mac))
+		ether_addr_copy(net_dev->dev_addr, mac);
+	else
+		eth_hw_addr_random(net_dev);
+
+	/* bring up the dma engine and IP core */
+	err = xrx200_dma_init(priv);
+	if (err)
+		return err;
+
+	/* enable clock gate */
+	err = clk_prepare_enable(priv->clk);
+	if (err)
+		goto err_uninit_dma;
+
+	/* set IPG to 12 */
+	xrx200_pmac_mask(priv, PMAC_RX_IPG_MASK, 0xb, PMAC_RX_IPG);
+
+	/* enable status header, enable CRC */
+	xrx200_pmac_mask(priv, 0,
+			 PMAC_HD_CTL_RST | PMAC_HD_CTL_AST | PMAC_HD_CTL_RXSH |
+			 PMAC_HD_CTL_AS | PMAC_HD_CTL_AC | PMAC_HD_CTL_RC,
+			 PMAC_HD_CTL);
+
+	tasklet_init(&priv->chan_tx.tasklet, xrx200_tx_housekeeping,
+		     (u32) &priv->chan_tx);
+
+	/* setup NAPI */
+	netif_napi_add(net_dev, &priv->chan_rx.napi, xrx200_poll_rx, 32);
+
+	platform_set_drvdata(pdev, priv);
+
+	err = register_netdev(net_dev);
+	if (err)
+		goto err_unprepare_clk;
+	return err;
+
+err_unprepare_clk:
+	clk_disable_unprepare(priv->clk);
+
+err_uninit_dma:
+	xrx200_hw_cleanup(priv);
+
+	return 0;
+}
+
+
+
+static int xrx200_remove(struct platform_device *pdev)
+{
+	struct xrx200_priv *priv = platform_get_drvdata(pdev);
+	struct net_device *net_dev = priv->net_dev;
+
+	/* free stack related instances */
+	netif_stop_queue(net_dev);
+	netif_napi_del(&priv->chan_rx.napi);
+
+	/* remove the actual device */
+	unregister_netdev(net_dev);
+
+	/* release the clock */
+	clk_disable_unprepare(priv->clk);
+
+	/* shut down hardware */
+	xrx200_hw_cleanup(priv);
+
+	return 0;
+}
+
+static const struct of_device_id xrx200_match[] = {
+	{ .compatible = "lantiq,xrx200-net" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, xrx200_match);
+
+static struct platform_driver xrx200_driver = {
+	.probe = xrx200_probe,
+	.remove = xrx200_remove,
+	.driver = {
+		.name = "lantiq,xrx200-net",
+		.of_match_table = xrx200_match,
+	},
+};
+
+module_platform_driver(xrx200_driver);
+
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_DESCRIPTION("Lantiq SoC XRX200 ethernet");
+MODULE_LICENSE("GPL");
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH 4/4] net: dsa: Add Lantiq / Intel DSA driver for vrx200
  2018-07-21 19:13 [PATCH 0/4] net: Add support for Lantiq / Intel vrx200 network Hauke Mehrtens
                   ` (2 preceding siblings ...)
  2018-07-21 19:13 ` [PATCH 3/4] net: lantiq: Add Lantiq / Intel vrx200 Ethernet driver Hauke Mehrtens
@ 2018-07-21 19:13 ` Hauke Mehrtens
  2018-07-22  3:17   ` David Miller
                     ` (2 more replies)
  3 siblings, 3 replies; 29+ messages in thread
From: Hauke Mehrtens @ 2018-07-21 19:13 UTC (permalink / raw)
  To: davem
  Cc: netdev, andrew, vivien.didelot, f.fainelli, john, linux-mips,
	dev, hauke.mehrtens, Hauke Mehrtens

This adds the DSA driver for the GSWIP Switch found in the VRX200 SoC.
This switch is integrated in the DSL SoC, this SoC uses a GSWIP version
2.0, there are other SoCs using different versions of this IP block, but
this driver was only tested with the version found in the VRX200.
Currently only the basic features are implemented which will forward all
packages to the CPU and let the CPU do the forwarding. The hardware also
support Layer 2 offloading which is not yet implemented in this driver.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
 MAINTAINERS                    |   1 +
 drivers/net/dsa/Kconfig        |   8 +
 drivers/net/dsa/Makefile       |   1 +
 drivers/net/dsa/lantiq-gswip.c | 750 +++++++++++++++++++++++++++++++++++++++++
 drivers/net/dsa/lantiq_pce.h   | 153 +++++++++
 5 files changed, 913 insertions(+)
 create mode 100644 drivers/net/dsa/lantiq-gswip.c
 create mode 100644 drivers/net/dsa/lantiq_pce.h

diff --git a/MAINTAINERS b/MAINTAINERS
index cc0607a58c51..761446ff9dd7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8016,6 +8016,7 @@ S:	Maintained
 F:	net/dsa/tag_gswip.c
 F:	drivers/net/ethernet/lantiq_xrx200.c
 F:	drivers/net/dsa/lantiq_pce.h
+F:	drivers/net/dsa/intel-gswip.c
 
 LANTIQ MIPS ARCHITECTURE
 M:	John Crispin <john@phrozen.org>
diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
index 2b81b97e994f..f1280aa3f9bd 100644
--- a/drivers/net/dsa/Kconfig
+++ b/drivers/net/dsa/Kconfig
@@ -23,6 +23,14 @@ config NET_DSA_LOOP
 	  This enables support for a fake mock-up switch chip which
 	  exercises the DSA APIs.
 
+config NET_DSA_GSWIP
+	tristate "Intel / Lantiq GSWIP"
+	depends on NET_DSA
+	select NET_DSA_TAG_GSWIP
+	---help---
+	  This enables support for the Intel / Lantiq GSWIP 2.0 found in
+	  the xrx200 / VR9 SoC.
+
 config NET_DSA_MT7530
 	tristate "Mediatek MT7530 Ethernet switch support"
 	depends on NET_DSA
diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile
index 15c2a831edf1..11143d860a95 100644
--- a/drivers/net/dsa/Makefile
+++ b/drivers/net/dsa/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_NET_DSA_LOOP)	+= dsa_loop.o
 ifdef CONFIG_NET_DSA_LOOP
 obj-$(CONFIG_FIXED_PHY)		+= dsa_loop_bdinfo.o
 endif
+obj-$(CONFIG_NET_DSA_GSWIP)	+= lantiq-gswip.o
 obj-$(CONFIG_NET_DSA_MT7530)	+= mt7530.o
 obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
 obj-$(CONFIG_NET_DSA_QCA8K)	+= qca8k.o
diff --git a/drivers/net/dsa/lantiq-gswip.c b/drivers/net/dsa/lantiq-gswip.c
new file mode 100644
index 000000000000..b6e64ba7ff12
--- /dev/null
+++ b/drivers/net/dsa/lantiq-gswip.c
@@ -0,0 +1,750 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Lantiq / Intel GSWIP switch driver for VRX200 SoCs
+ *
+ * Copyright (C) 2010 Lantiq Deutschland
+ * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2017 - 2018 Hauke Mehrtens <hauke@hauke-m.de>
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/if_vlan.h>
+#include <linux/if_bridge.h>
+#include <net/dsa.h>
+
+#include <linux/of_net.h>
+#include <linux/of_mdio.h>
+#include <linux/of_platform.h>
+#include <linux/version.h>
+
+#include "lantiq_pce.h"
+
+
+/* GSWIP MDIO Registers */
+#define GSWIP_MDIO_GLOB			0x00
+#define  GSWIP_MDIO_GLOB_ENABLE		BIT(15)
+#define GSWIP_MDIO_CTRL			0x08
+#define  GSWIP_MDIO_CTRL_BUSY		BIT(12)
+#define  GSWIP_MDIO_CTRL_RD		BIT(11)
+#define  GSWIP_MDIO_CTRL_WR		BIT(10)
+#define  GSWIP_MDIO_CTRL_PHYAD_MASK	0x1f
+#define  GSWIP_MDIO_CTRL_PHYAD_SHIFT	5
+#define  GSWIP_MDIO_CTRL_REGAD_MASK	0x1f
+#define GSWIP_MDIO_READ			0x09
+#define GSWIP_MDIO_WRITE		0x0A
+#define GSWIP_MDIO_MDC_CFG0		0x0B
+#define GSWIP_MDIO_MDC_CFG1		0x0C
+#define GSWIP_MDIO_PHYp(p)		(0x15 - (p))
+#define  GSWIP_MDIO_PHY_LINK_DOWN	0x4000
+#define  GSWIP_MDIO_PHY_LINK_UP		0x2000
+#define  GSWIP_MDIO_PHY_SPEED_M10	0x0000
+#define  GSWIP_MDIO_PHY_SPEED_M100	0x0800
+#define  GSWIP_MDIO_PHY_SPEED_G1	0x1000
+#define  GSWIP_MDIO_PHY_FDUP_EN		0x0200
+#define  GSWIP_MDIO_PHY_FDUP_DIS	0x0600
+#define  GSWIP_MDIO_PHY_FCONTX_EN	0x0100
+#define  GSWIP_MDIO_PHY_FCONTX_DIS	0x0180
+#define  GSWIP_MDIO_PHY_FCONRX_EN	0x0020
+#define  GSWIP_MDIO_PHY_FCONRX_DIS	0x0060
+#define  GSWIP_MDIO_PHY_LINK_MASK	0x6000
+#define  GSWIP_MDIO_PHY_SPEED_MASK	0x1800
+#define  GSWIP_MDIO_PHY_FDUP_MASK	0x0600
+#define  GSWIP_MDIO_PHY_FCONTX_MASK	0x0180
+#define  GSWIP_MDIO_PHY_FCONRX_MASK	0x0060
+#define  GSWIP_MDIO_PHY_ADDR_MASK	0x001f
+#define  GSWIP_MDIO_PHY_MASK		(GSWIP_MDIO_PHY_ADDR_MASK | \
+					 GSWIP_MDIO_PHY_FCONRX_MASK | \
+					 GSWIP_MDIO_PHY_FCONTX_MASK | \
+					 GSWIP_MDIO_PHY_LINK_MASK | \
+					 GSWIP_MDIO_PHY_SPEED_MASK | \
+					 GSWIP_MDIO_PHY_FDUP_MASK)
+
+/* GSWIP MII Registers */
+#define GSWIP_MII_CFGp(p)		((p) * 2)
+#define  GSWIP_MII_CFG_EN		BIT(14)
+#define  GSWIP_MII_CFG_MODE_MIIP	0x0
+#define  GSWIP_MII_CFG_MODE_MIIM	0x1
+#define  GSWIP_MII_CFG_MODE_RMIIP	0x2
+#define  GSWIP_MII_CFG_MODE_RMIIM	0x3
+#define  GSWIP_MII_CFG_MODE_RGMII	0x4
+#define  GSWIP_MII_CFG_MODE_MASK	0xf
+#define  GSWIP_MII_CFG_RATE_M2P5	0x00
+#define  GSWIP_MII_CFG_RATE_M25	0x10
+#define  GSWIP_MII_CFG_RATE_M125	0x20
+#define  GSWIP_MII_CFG_RATE_M50	0x30
+#define  GSWIP_MII_CFG_RATE_AUTO	0x40
+#define  GSWIP_MII_CFG_RATE_MASK	0x70
+
+/* GSWIP Core Registers */
+#define GSWIP_ETHSW_SWRES		0x000
+#define  GSWIP_ETHSW_SWRES_R1		BIT(1)	/* GSWIP Software reset */
+#define  GSWIP_ETHSW_SWRES_R0		BIT(0)	/* GSWIP Hardware reset */
+
+#define GSWIP_BM_RAM_VAL(x)		(0x043 - (x))
+#define GSWIP_BM_RAM_ADDR		0x044
+#define GSWIP_BM_RAM_CTRL		0x045
+#define  GSWIP_BM_RAM_CTRL_BAS		BIT(15)
+#define  GSWIP_BM_RAM_CTRL_OPMOD	BIT(5)
+#define  GSWIP_BM_RAM_CTRL_ADDR_MASK	GENMASK(4, 0)
+#define GSWIP_BM_QUEUE_GCTRL		0x04A
+#define  GSWIP_BM_QUEUE_GCTRL_GL_MOD	BIT(10)
+/* buffer management Port Configuration Register */
+#define GSWIP_BM_PCFGp(p)		(0x080 + ((p) * 2))
+#define  GSWIP_BM_PCFG_CNTEN		BIT(0)	/* RMON Counter Enable */
+#define  GSWIP_BM_PCFG_IGCNT		BIT(1)	/* Ingres Special Tag RMON count */
+/* buffer management Port Control Register */
+#define GSWIP_BM_RMON_CTRLp(p)		(0x81 + ((p) * 2))
+#define  GSWIP_BM_CTRL_RMON_RAM1_RES	BIT(0)	/* Software Reset for RMON RAM 1 */
+#define  GSWIP_BM_CTRL_RMON_RAM2_RES	BIT(1)	/* Software Reset for RMON RAM 2 */
+
+/* PCE */
+#define GSWIP_PCE_TBL_KEY(x)		(0x447 - (x))
+#define GSWIP_PCE_TBL_MASK		0x448
+#define GSWIP_PCE_TBL_VAL(x)		(0x44D - (x))
+#define GSWIP_PCE_TBL_ADDR		0x44E
+#define GSWIP_PCE_TBL_CTRL		0x44F
+#define  GSWIP_PCE_TBL_CTRL_BAS		BIT(15)
+#define  GSWIP_PCE_TBL_CTRL_TYPE	BIT(13)
+#define  GSWIP_PCE_TBL_CTRL_VLD		BIT(12)
+#define  GSWIP_PCE_TBL_CTRL_KEYFORM	BIT(11)
+#define  GSWIP_PCE_TBL_CTRL_GMAP_MASK	GENMASK(10, 7)
+#define  GSWIP_PCE_TBL_CTRL_OPMOD_MASK	GENMASK(6, 5)
+#define  GSWIP_PCE_TBL_CTRL_OPMOD_ADRD	0x00
+#define  GSWIP_PCE_TBL_CTRL_OPMOD_ADWR	0x20
+#define  GSWIP_PCE_TBL_CTRL_OPMOD_KSRD	0x40
+#define  GSWIP_PCE_TBL_CTRL_OPMOD_KSWR	0x60
+#define  GSWIP_PCE_TBL_CTRL_ADDR_MASK	GENMASK(4, 0)
+#define GSWIP_PCE_PMAP1			0x453	/* Monitoring port map */
+#define GSWIP_PCE_PMAP2			0x454	/* Default Multicast port map */
+#define GSWIP_PCE_PMAP3			0x455	/* Default Unknown Unicast port map */
+#define GSWIP_PCE_GCTRL_0		0x456
+#define  GSWIP_PCE_GCTRL_0_MC_VALID	BIT(3)
+#define  GSWIP_PCE_GCTRL_0_VLAN		BIT(14) /* VLAN aware Switching */
+#define GSWIP_PCE_GCTRL_1		0x457
+#define  GSWIP_PCE_GCTRL_1_MAC_GLOCK	BIT(2)	/* MAC Address table lock */
+#define  GSWIP_PCE_GCTRL_1_MAC_GLOCK_MOD	BIT(3) /* Mac address table lock forwarding mode */
+#define GSWIP_PCE_PCTRL_0p(p)		(0x480 + ((p) * 0xA))
+#define  GSWIP_PCE_PCTRL_0_INGRESS	BIT(11)
+#define  GSWIP_PCE_PCTRL_0_PSTATE_LISTEN	0x0
+#define  GSWIP_PCE_PCTRL_0_PSTATE_RX		0x1
+#define  GSWIP_PCE_PCTRL_0_PSTATE_TX		0x2
+#define  GSWIP_PCE_PCTRL_0_PSTATE_LEARNING	0x3
+#define  GSWIP_PCE_PCTRL_0_PSTATE_FORWARDING	0x7
+#define  GSWIP_PCE_PCTRL_0_PSTATE_MASK	GENMASK(2, 0)
+
+#define GSWIP_MAC_FLEN			0x8C5
+#define GSWIP_MAC_CTRL_2p(p)		(0x905 + ((p) * 0xC))
+#define GSWIP_MAC_CTRL_2_MLEN		BIT(3) /* Maximum Untagged Frame Lnegth */
+
+/* Ethernet Switch Fetch DMA Port Control Register */
+#define GSWIP_FDMA_PCTRLp(p)		(0xA80 + ((p) * 0x6))
+#define  GSWIP_FDMA_PCTRL_EN		BIT(0)	/* FDMA Port Enable */
+#define  GSWIP_FDMA_PCTRL_STEN		BIT(1)	/* Special Tag Insertion Enable */
+#define  GSWIP_FDMA_PCTRL_VLANMOD_MASK	GENMASK(4, 3)	/* VLAN Modification Control */
+#define  GSWIP_FDMA_PCTRL_VLANMOD_SHIFT	3	/* VLAN Modification Control */
+#define  GSWIP_FDMA_PCTRL_VLANMOD_DIS	(0x0 << GSWIP_FDMA_PCTRL_VLANMOD_SHIFT)
+#define  GSWIP_FDMA_PCTRL_VLANMOD_PRIO	(0x1 << GSWIP_FDMA_PCTRL_VLANMOD_SHIFT)
+#define  GSWIP_FDMA_PCTRL_VLANMOD_ID	(0x2 << GSWIP_FDMA_PCTRL_VLANMOD_SHIFT)
+#define  GSWIP_FDMA_PCTRL_VLANMOD_BOTH	(0x3 << GSWIP_FDMA_PCTRL_VLANMOD_SHIFT)
+
+/* Ethernet Switch Store DMA Port Control Register */
+#define GSWIP_SDMA_PCTRLp(p)		(0xBC0 + ((p) * 0x6))
+#define  GSWIP_SDMA_PCTRL_EN		BIT(0)	/* SDMA Port Enable */
+#define  GSWIP_SDMA_PCTRL_FCEN		BIT(1)	/* Flow Control Enable */
+#define  GSWIP_SDMA_PCTRL_PAUFWD	BIT(1)	/* Pause Frame Forwarding */
+
+struct gswip_priv {
+	__iomem void *gswip;
+	__iomem void *mdio;
+	__iomem void *mii;
+	int cpu_port;
+	struct dsa_switch *ds;
+	struct device *dev;
+};
+
+struct gswip_rmon_cnt_desc {
+	unsigned int size;
+	unsigned int offset;
+	const char *name;
+};
+
+#define MIB_DESC(_size, _offset, _name) {.size = _size, .offset = _offset, .name = _name}
+
+static const struct gswip_rmon_cnt_desc gswip_rmon_cnt[] = {
+	/** Receive Packet Count (only packets that are accepted and not discarded). */
+	MIB_DESC(1, 0x1F, "RxGoodPkts"),
+	/** Receive Unicast Packet Count. */
+	MIB_DESC(1, 0x23, "RxUnicastPkts"),
+	/** Receive Multicast Packet Count. */
+	MIB_DESC(1, 0x22, "RxMulticastPkts"),
+	/** Receive FCS Error Packet Count. */
+	MIB_DESC(1, 0x21, "RxFCSErrorPkts"),
+	/** Receive Undersize Good Packet Count. */
+	MIB_DESC(1, 0x1D, "RxUnderSizeGoodPkts"),
+	/** Receive Undersize Error Packet Count. */
+	MIB_DESC(1, 0x1E, "RxUnderSizeErrorPkts"),
+	/** Receive Oversize Good Packet Count. */
+	MIB_DESC(1, 0x1B, "RxOversizeGoodPkts"),
+	/** Receive Oversize Error Packet Count. */
+	MIB_DESC(1, 0x1C, "RxOversizeErrorPkts"),
+	/** Receive Good Pause Packet Count. */
+	MIB_DESC(1, 0x20, "RxGoodPausePkts"),
+	/** Receive Align Error Packet Count. */
+	MIB_DESC(1, 0x1A, "RxAlignErrorPkts"),
+	/** Receive Size 64 Packet Count. */
+	MIB_DESC(1, 0x12, "Rx64BytePkts"),
+	/** Receive Size 65-127 Packet Count. */
+	MIB_DESC(1, 0x13, "Rx127BytePkts"),
+	/** Receive Size 128-255 Packet Count. */
+	MIB_DESC(1, 0x14, "Rx255BytePkts"),
+	/** Receive Size 256-511 Packet Count. */
+	MIB_DESC(1, 0x15, "Rx511BytePkts"),
+	/** Receive Size 512-1023 Packet Count. */
+	MIB_DESC(1, 0x16, "Rx1023BytePkts"),
+	/** Receive Size 1024-1522 (or more, if configured) Packet Count. */
+	MIB_DESC(1, 0x17, "RxMaxBytePkts"),
+	/** Receive Dropped Packet Count. */
+	MIB_DESC(1, 0x18, "RxDroppedPkts"),
+	/** Filtered Packet Count. */
+	MIB_DESC(1, 0x19, "RxFilteredPkts"),
+	/** Receive Good Byte Count (64 bit). */
+	MIB_DESC(2, 0x24, "RxGoodBytes"),
+	/** Receive Bad Byte Count (64 bit). */
+	MIB_DESC(2, 0x26, "RxBadBytes"),
+	/** Transmit Dropped Packet Count, based on Congestion Management. */
+	MIB_DESC(1, 0x11, "TxAcmDroppedPkts"),
+	/** Transmit Packet Count. */
+	MIB_DESC(1, 0x0C, "TxGoodPkts"),
+	/** Transmit Unicast Packet Count. */
+	MIB_DESC(1, 0x06, "TxUnicastPkts"),
+	/** Transmit Multicast Packet Count. */
+	MIB_DESC(1, 0x07, "TxMulticastPkts"),
+	/** Transmit Size 64 Packet Count. */
+	MIB_DESC(1, 0x00, "Tx64BytePkts"),
+	/** Transmit Size 65-127 Packet Count. */
+	MIB_DESC(1, 0x01, "Tx127BytePkts"),
+	/** Transmit Size 128-255 Packet Count. */
+	MIB_DESC(1, 0x02, "Tx255BytePkts"),
+	/** Transmit Size 256-511 Packet Count. */
+	MIB_DESC(1, 0x03, "Tx511BytePkts"),
+	/** Transmit Size 512-1023 Packet Count. */
+	MIB_DESC(1, 0x04, "Tx1023BytePkts"),
+	/** Transmit Size 1024-1522 (or more, if configured) Packet Count. */
+	MIB_DESC(1, 0x05, "TxMaxBytePkts"),
+	/** Transmit Single Collision Count. */
+	MIB_DESC(1, 0x08, "TxSingleCollCount"),
+	/** Transmit Multiple Collision Count. */
+	MIB_DESC(1, 0x09, "TxMultCollCount"),
+	/** Transmit Late Collision Count. */
+	MIB_DESC(1, 0x0A, "TxLateCollCount"),
+	/** Transmit Excessive Collision Count. */
+	MIB_DESC(1, 0x0B, "TxExcessCollCount"),
+	/** Transmit Pause Packet Count. */
+	MIB_DESC(1, 0x0D, "TxPauseCount"),
+	/** Transmit Drop Packet Count. */
+	MIB_DESC(1, 0x10, "TxDroppedPkts"),
+	/** Transmit Good Byte Count (64 bit). */
+	MIB_DESC(2, 0x0E, "TxGoodBytes"),
+};
+
+static u32 gswip_switch_r(struct gswip_priv *priv, u32 offset)
+{
+	return __raw_readl(priv->gswip + (offset * 4));
+}
+
+static void gswip_switch_w(struct gswip_priv *priv, u32 val, u32 offset)
+{
+	return __raw_writel(val, priv->gswip + (offset * 4));
+}
+
+static void gswip_switch_mask(struct gswip_priv *priv, u32 clear, u32 set,
+			      u32 offset)
+{
+	u32 val = gswip_switch_r(priv, offset);
+
+	val &= ~(clear);
+	val |= set;
+	gswip_switch_w(priv, val, offset);
+}
+
+static u32 gswip_mdio_r(struct gswip_priv *priv, u32 offset)
+{
+	return __raw_readl(priv->mdio + (offset * 4));
+}
+
+static void gswip_mdio_w(struct gswip_priv *priv, u32 val, u32 offset)
+{
+	return __raw_writel(val, priv->mdio + (offset * 4));
+}
+
+static void gswip_mdio_mask(struct gswip_priv *priv, u32 clear, u32 set,
+			    u32 offset)
+{
+	u32 val = gswip_mdio_r(priv, offset);
+
+	val &= ~(clear);
+	val |= set;
+	gswip_mdio_w(priv, val, offset);
+}
+
+static u32 gswip_mii_r(struct gswip_priv *priv, u32 offset)
+{
+	return __raw_readl(priv->mii + (offset * 4));
+}
+
+static void gswip_mii_w(struct gswip_priv *priv, u32 val, u32 offset)
+{
+	return __raw_writel(val, priv->mii + (offset * 4));
+}
+
+static void gswip_mii_mask(struct gswip_priv *priv, u32 clear, u32 set,
+			   u32 offset)
+{
+	u32 val = gswip_mii_r(priv, offset);
+
+	val &= ~(clear);
+	val |= set;
+	gswip_mii_w(priv, val, offset);
+}
+
+static int xrx200_mdio_poll(struct gswip_priv *priv)
+{
+	int cnt = 10000;
+
+	while (likely(cnt--)) {
+		u32 ctrl = gswip_mdio_r(priv, GSWIP_MDIO_CTRL);
+
+		if ((ctrl & GSWIP_MDIO_CTRL_BUSY) == 0)
+			return 0;
+		cpu_relax();
+	}
+
+	return 1;
+}
+
+static int xrx200_mdio_wr(struct mii_bus *bus, int addr, int reg, u16 val)
+{
+	struct gswip_priv *priv = bus->priv;
+
+	if (xrx200_mdio_poll(priv))
+		return -EIO;
+
+	gswip_mdio_w(priv, val, GSWIP_MDIO_WRITE);
+	gswip_mdio_w(priv, GSWIP_MDIO_CTRL_BUSY | GSWIP_MDIO_CTRL_WR |
+		((addr & GSWIP_MDIO_CTRL_PHYAD_MASK) << GSWIP_MDIO_CTRL_PHYAD_SHIFT) |
+		(reg & GSWIP_MDIO_CTRL_REGAD_MASK),
+		GSWIP_MDIO_CTRL);
+
+	return 0;
+}
+
+static int xrx200_mdio_rd(struct mii_bus *bus, int addr, int reg)
+{
+	struct gswip_priv *priv = bus->priv;
+
+	if (xrx200_mdio_poll(priv))
+		return -EIO;
+
+	gswip_mdio_w(priv, GSWIP_MDIO_CTRL_BUSY | GSWIP_MDIO_CTRL_RD |
+		((addr & GSWIP_MDIO_CTRL_PHYAD_MASK) << GSWIP_MDIO_CTRL_PHYAD_SHIFT) |
+		(reg & GSWIP_MDIO_CTRL_REGAD_MASK),
+		GSWIP_MDIO_CTRL);
+
+	if (xrx200_mdio_poll(priv))
+		return -EIO;
+
+	return gswip_mdio_r(priv, GSWIP_MDIO_READ);
+}
+
+static int gswip_mdio(struct gswip_priv *priv, struct device_node *mdio_np)
+{
+	struct dsa_switch *ds = priv->ds;
+
+	ds->slave_mii_bus = devm_mdiobus_alloc(priv->dev);
+	if (!ds->slave_mii_bus)
+		return -ENOMEM;
+
+	ds->slave_mii_bus->priv = priv;
+	ds->slave_mii_bus->read = xrx200_mdio_rd;
+	ds->slave_mii_bus->write = xrx200_mdio_wr;
+	ds->slave_mii_bus->name = "lantiq,xrx200-mdio";
+	snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "%x", 0);
+	ds->slave_mii_bus->parent = priv->dev;
+	ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask;
+
+	return of_mdiobus_register(ds->slave_mii_bus, mdio_np);
+}
+
+static void gswip_wait_pce_tbl_ready(struct gswip_priv *priv)
+{
+	while (gswip_switch_r(priv, GSWIP_PCE_TBL_CTRL) & GSWIP_PCE_TBL_CTRL_BAS)
+		cond_resched();
+}
+
+static int gswip_port_enable(struct dsa_switch *ds, int port,
+			     struct phy_device *phy)
+{
+	struct gswip_priv *priv = (struct gswip_priv *)ds->priv;
+
+	/* RMON Counter Enable for port */
+	gswip_switch_w(priv, GSWIP_BM_PCFG_CNTEN, GSWIP_BM_PCFGp(port));
+
+	/* enable port fetch/store dma & VLAN Modification */
+	gswip_switch_mask(priv, 0, GSWIP_FDMA_PCTRL_EN |
+				   GSWIP_FDMA_PCTRL_VLANMOD_BOTH,
+			 GSWIP_FDMA_PCTRLp(port));
+	gswip_switch_mask(priv, 0, GSWIP_SDMA_PCTRL_EN,
+			  GSWIP_SDMA_PCTRLp(port));
+	gswip_switch_mask(priv, 0, GSWIP_PCE_PCTRL_0_INGRESS,
+			  GSWIP_PCE_PCTRL_0p(port));
+
+	return 0;
+}
+
+static void gswip_port_disable(struct dsa_switch *ds, int port,
+			       struct phy_device *phy)
+{
+	struct gswip_priv *priv = (struct gswip_priv *)ds->priv;
+
+	gswip_switch_mask(priv, GSWIP_FDMA_PCTRL_EN, 0,
+			  GSWIP_FDMA_PCTRLp(port));
+	gswip_switch_mask(priv, GSWIP_SDMA_PCTRL_EN, 0,
+			  GSWIP_SDMA_PCTRLp(port));
+}
+
+static void xrx200_pci_microcode(struct gswip_priv *priv)
+{
+	int i;
+
+	gswip_switch_mask(priv, GSWIP_PCE_TBL_CTRL_ADDR_MASK |
+				GSWIP_PCE_TBL_CTRL_OPMOD_MASK,
+			  GSWIP_PCE_TBL_CTRL_OPMOD_ADWR, GSWIP_PCE_TBL_CTRL);
+	gswip_switch_w(priv, 0, GSWIP_PCE_TBL_MASK);
+
+	for (i = 0; i < ARRAY_SIZE(gswip_pce_microcode); i++) {
+		gswip_switch_w(priv, i, GSWIP_PCE_TBL_ADDR);
+		gswip_switch_w(priv, gswip_pce_microcode[i].val_0,
+			       GSWIP_PCE_TBL_VAL(0));
+		gswip_switch_w(priv, gswip_pce_microcode[i].val_1,
+			       GSWIP_PCE_TBL_VAL(1));
+		gswip_switch_w(priv, gswip_pce_microcode[i].val_2,
+			       GSWIP_PCE_TBL_VAL(2));
+		gswip_switch_w(priv, gswip_pce_microcode[i].val_3,
+			       GSWIP_PCE_TBL_VAL(3));
+
+		// start the table access:
+		gswip_switch_mask(priv, 0, GSWIP_PCE_TBL_CTRL_BAS,
+				  GSWIP_PCE_TBL_CTRL);
+		gswip_wait_pce_tbl_ready(priv);
+	}
+
+	/* tell the switch that the microcode is loaded */
+	gswip_switch_mask(priv, 0, GSWIP_PCE_GCTRL_0_MC_VALID,
+			  GSWIP_PCE_GCTRL_0);
+}
+
+static int gswip_setup(struct dsa_switch *ds)
+{
+	struct gswip_priv *priv = ds->priv;
+	int i;
+
+	gswip_switch_w(priv, GSWIP_ETHSW_SWRES_R0, GSWIP_ETHSW_SWRES);
+	usleep_range(5000, 10000);
+	gswip_switch_w(priv, 0, GSWIP_ETHSW_SWRES);
+
+	/* disable port fetch/store dma, assume CPU port is last port */
+	for (i = 0; i <= priv->cpu_port; i++)
+		gswip_port_disable(ds, i, NULL);
+
+	/* enable Switch */
+	gswip_mdio_mask(priv, 0, GSWIP_MDIO_GLOB_ENABLE, GSWIP_MDIO_GLOB);
+
+	xrx200_pci_microcode(priv);
+
+	/* Default unknown Broadcast/Multicast/Unicast port maps */
+	gswip_switch_w(priv, BIT(priv->cpu_port), GSWIP_PCE_PMAP1);
+	gswip_switch_w(priv, BIT(priv->cpu_port), GSWIP_PCE_PMAP2);
+	gswip_switch_w(priv, BIT(priv->cpu_port), GSWIP_PCE_PMAP3);
+
+	/* disable auto polling */
+	gswip_mdio_w(priv, 0x0, GSWIP_MDIO_MDC_CFG0);
+
+	/* enable special tag insertion on cpu port */
+	gswip_switch_mask(priv, 0, GSWIP_FDMA_PCTRL_STEN,
+			  GSWIP_FDMA_PCTRLp(priv->cpu_port));
+
+	gswip_switch_mask(priv, 0, GSWIP_MAC_CTRL_2_MLEN,
+			  GSWIP_MAC_CTRL_2p(priv->cpu_port));
+	gswip_switch_w(priv, VLAN_ETH_FRAME_LEN + 8, GSWIP_MAC_FLEN);
+	gswip_switch_mask(priv, 0, GSWIP_BM_QUEUE_GCTRL_GL_MOD,
+			  GSWIP_BM_QUEUE_GCTRL);
+
+	/* VLAN aware Switching */
+	gswip_switch_mask(priv, 0, GSWIP_PCE_GCTRL_0_VLAN, GSWIP_PCE_GCTRL_0);
+
+	/* Mac Address Table Lock */
+	gswip_switch_mask(priv, 0, GSWIP_PCE_GCTRL_1_MAC_GLOCK |
+				   GSWIP_PCE_GCTRL_1_MAC_GLOCK_MOD,
+			  GSWIP_PCE_GCTRL_1);
+
+	gswip_port_enable(ds, priv->cpu_port, NULL);
+	return 0;
+}
+
+static void gswip_adjust_link(struct dsa_switch *ds, int port,
+			      struct phy_device *phydev)
+{
+	struct gswip_priv *priv = (struct gswip_priv *)ds->priv;
+	u16 phyaddr = phydev->mdio.addr & GSWIP_MDIO_PHY_ADDR_MASK;
+	u16 miirate = 0;
+	u16 miimode;
+	u16 lcl_adv = 0, rmt_adv = 0;
+	u8 flowctrl;
+
+	/* do not run this for the CPU port 6 */
+	if (port >= priv->cpu_port)
+		return;
+
+	miimode = gswip_mdio_r(priv, GSWIP_MII_CFGp(port));
+	miimode &= GSWIP_MII_CFG_MODE_MASK;
+
+	switch (phydev->speed) {
+	case SPEED_1000:
+		phyaddr |= GSWIP_MDIO_PHY_SPEED_G1;
+		miirate = GSWIP_MII_CFG_RATE_M125;
+		break;
+
+	case SPEED_100:
+		phyaddr |= GSWIP_MDIO_PHY_SPEED_M100;
+		switch (miimode) {
+		case GSWIP_MII_CFG_MODE_RMIIM:
+		case GSWIP_MII_CFG_MODE_RMIIP:
+			miirate = GSWIP_MII_CFG_RATE_M50;
+			break;
+		default:
+			miirate = GSWIP_MII_CFG_RATE_M25;
+			break;
+		}
+		break;
+
+	default:
+		phyaddr |= GSWIP_MDIO_PHY_SPEED_M10;
+		miirate = GSWIP_MII_CFG_RATE_M2P5;
+		break;
+	}
+
+	if (phydev->link)
+		phyaddr |= GSWIP_MDIO_PHY_LINK_UP;
+	else
+		phyaddr |= GSWIP_MDIO_PHY_LINK_DOWN;
+
+	if (phydev->duplex == DUPLEX_FULL)
+		phyaddr |= GSWIP_MDIO_PHY_FDUP_EN;
+	else
+		phyaddr |= GSWIP_MDIO_PHY_FDUP_DIS;
+
+	if (phydev->pause)
+		rmt_adv = LPA_PAUSE_CAP;
+	if (phydev->asym_pause)
+		rmt_adv |= LPA_PAUSE_ASYM;
+
+	if (phydev->advertising & ADVERTISED_Pause)
+		lcl_adv |= ADVERTISE_PAUSE_CAP;
+	if (phydev->advertising & ADVERTISED_Asym_Pause)
+		lcl_adv |= ADVERTISE_PAUSE_ASYM;
+
+	flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
+
+	if (flowctrl & FLOW_CTRL_TX)
+		phyaddr |= GSWIP_MDIO_PHY_FCONTX_EN;
+	else
+		phyaddr |= GSWIP_MDIO_PHY_FCONTX_DIS;
+	if (flowctrl & FLOW_CTRL_RX)
+		phyaddr |= GSWIP_MDIO_PHY_FCONRX_EN;
+	else
+		phyaddr |= GSWIP_MDIO_PHY_FCONRX_DIS;
+
+	gswip_mdio_mask(priv, GSWIP_MDIO_PHY_MASK, phyaddr,
+			GSWIP_MDIO_PHYp(port));
+	gswip_mii_mask(priv, GSWIP_MII_CFG_RATE_MASK, miirate,
+		       GSWIP_MII_CFGp(port));
+}
+
+static enum dsa_tag_protocol gswip_get_tag_protocol(struct dsa_switch *ds,
+						    int port)
+{
+	return DSA_TAG_PROTO_GSWIP;
+}
+
+static void gswip_get_strings(struct dsa_switch *ds, int port, u32 stringset,
+			      uint8_t *data)
+{
+	int i;
+
+	if (stringset != ETH_SS_STATS)
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(gswip_rmon_cnt); i++)
+		strncpy(data + i * ETH_GSTRING_LEN, gswip_rmon_cnt[i].name,
+			ETH_GSTRING_LEN);
+}
+
+static u32 gswip_bcm_ram_entry_read(struct gswip_priv *priv, u32 table,
+				    u32 index)
+{
+	u32 result;
+
+	gswip_switch_w(priv, index, GSWIP_BM_RAM_ADDR);
+	gswip_switch_mask(priv, GSWIP_BM_RAM_CTRL_ADDR_MASK |
+				GSWIP_BM_RAM_CTRL_OPMOD,
+			      table | GSWIP_BM_RAM_CTRL_BAS,
+			      GSWIP_BM_RAM_CTRL);
+
+	while (gswip_switch_r(priv, GSWIP_BM_RAM_CTRL) & GSWIP_BM_RAM_CTRL_BAS)
+		cond_resched();
+
+	result = gswip_switch_r(priv, GSWIP_BM_RAM_VAL(0));
+	result |= gswip_switch_r(priv, GSWIP_BM_RAM_VAL(1)) << 16;
+
+	return result;
+}
+
+static void gswip_get_ethtool_stats(struct dsa_switch *ds, int port,
+				    uint64_t *data)
+{
+	struct gswip_priv *priv = ds->priv;
+	const struct gswip_rmon_cnt_desc *rmon_cnt;
+	int i;
+	u64 high;
+
+	for (i = 0; i < ARRAY_SIZE(gswip_rmon_cnt); i++) {
+		rmon_cnt = &gswip_rmon_cnt[i];
+
+		data[i] = gswip_bcm_ram_entry_read(priv, port,
+						   rmon_cnt->offset);
+		if (rmon_cnt->size == 2) {
+			high = gswip_bcm_ram_entry_read(priv, port,
+							rmon_cnt->offset + 1);
+			data[i] |= high << 32;
+		}
+	}
+}
+
+static int gswip_get_sset_count(struct dsa_switch *ds, int port, int sset)
+{
+	if (sset != ETH_SS_STATS)
+		return 0;
+
+	return ARRAY_SIZE(gswip_rmon_cnt);
+}
+
+static const struct dsa_switch_ops gswip_switch_ops = {
+	.get_tag_protocol	= gswip_get_tag_protocol,
+	.setup			= gswip_setup,
+	.adjust_link		= gswip_adjust_link,
+	.port_enable		= gswip_port_enable,
+	.port_disable		= gswip_port_disable,
+	.get_strings		= gswip_get_strings,
+	.get_ethtool_stats	= gswip_get_ethtool_stats,
+	.get_sset_count		= gswip_get_sset_count,
+};
+
+static int gswip_probe(struct platform_device *pdev)
+{
+	struct gswip_priv *priv;
+	struct resource *gswip_res, *mdio_res, *mii_res;
+	struct device_node *mdio_np;
+	struct device *dev = &pdev->dev;
+	int err;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	gswip_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->gswip = devm_ioremap_resource(dev, gswip_res);
+	if (!priv->gswip)
+		return -ENOMEM;
+
+	mdio_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	priv->mdio = devm_ioremap_resource(dev, mdio_res);
+	if (!priv->mdio)
+		return -ENOMEM;
+
+	mii_res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	priv->mii = devm_ioremap_resource(dev, mii_res);
+	if (!priv->mii)
+		return -ENOMEM;
+
+	priv->ds = dsa_switch_alloc(dev, DSA_MAX_PORTS);
+	if (!priv->ds)
+		return -ENOMEM;
+
+	priv->ds->priv = priv;
+	priv->ds->ops = &gswip_switch_ops;
+	priv->dev = dev;
+	priv->cpu_port = 6;
+
+	/* bring up the mdio bus */
+	mdio_np = of_find_compatible_node(pdev->dev.of_node, NULL,
+					  "lantiq,xrx200-mdio");
+	if (mdio_np) {
+		err = gswip_mdio(priv, mdio_np);
+		if (err) {
+			dev_err(dev, "mdio probe failed\n");
+			return err;
+		}
+	}
+
+	platform_set_drvdata(pdev, priv);
+
+	err = dsa_register_switch(priv->ds);
+	if (err) {
+		dev_err(dev, "dsa switch register failed: %i\n", err);
+		if (mdio_np)
+			mdiobus_unregister(priv->ds->slave_mii_bus);
+	}
+
+	return err;
+}
+
+static int gswip_remove(struct platform_device *pdev)
+{
+	struct gswip_priv *priv = platform_get_drvdata(pdev);
+
+	if (!priv)
+		return 0;
+
+	/* disable the switch */
+	gswip_mdio_mask(priv, GSWIP_MDIO_GLOB_ENABLE, 0, GSWIP_MDIO_GLOB);
+
+	dsa_unregister_switch(priv->ds);
+
+	if (priv->ds->slave_mii_bus)
+		mdiobus_unregister(priv->ds->slave_mii_bus);
+
+	return 0;
+}
+
+static const struct of_device_id gswip_of_match[] = {
+	{ .compatible = "lantiq,xrx200-gswip" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, xrx200_match);
+
+static struct platform_driver gswip_driver = {
+	.probe = gswip_probe,
+	.remove = gswip_remove,
+	.driver = {
+		.name = "gswip",
+		.of_match_table = gswip_of_match,
+	},
+};
+
+module_platform_driver(gswip_driver);
+
+MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
+MODULE_DESCRIPTION("Intel / Lantiq GSWIP driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/dsa/lantiq_pce.h b/drivers/net/dsa/lantiq_pce.h
new file mode 100644
index 000000000000..aa57d9fe7089
--- /dev/null
+++ b/drivers/net/dsa/lantiq_pce.h
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PCE microcode extracted from UGW 7.1.1 switch api
+ *
+ * Copyright (c) 2012, 2014, 2015 Lantiq Deutschland GmbH
+ * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2017 - 2018 Hauke Mehrtens <hauke@hauke-m.de>
+ */
+
+enum {
+	OUT_MAC0 = 0,
+	OUT_MAC1,
+	OUT_MAC2,
+	OUT_MAC3,
+	OUT_MAC4,
+	OUT_MAC5,
+	OUT_ETHTYP,
+	OUT_VTAG0,
+	OUT_VTAG1,
+	OUT_ITAG0,
+	OUT_ITAG1,	/*10 */
+	OUT_ITAG2,
+	OUT_ITAG3,
+	OUT_IP0,
+	OUT_IP1,
+	OUT_IP2,
+	OUT_IP3,
+	OUT_SIP0,
+	OUT_SIP1,
+	OUT_SIP2,
+	OUT_SIP3,	/*20*/
+	OUT_SIP4,
+	OUT_SIP5,
+	OUT_SIP6,
+	OUT_SIP7,
+	OUT_DIP0,
+	OUT_DIP1,
+	OUT_DIP2,
+	OUT_DIP3,
+	OUT_DIP4,
+	OUT_DIP5,	/*30*/
+	OUT_DIP6,
+	OUT_DIP7,
+	OUT_SESID,
+	OUT_PROT,
+	OUT_APP0,
+	OUT_APP1,
+	OUT_IGMP0,
+	OUT_IGMP1,
+	OUT_IPOFF,	/*39*/
+	OUT_NONE = 63,
+};
+
+/* parser's microcode length type */
+#define INSTR		0
+#define IPV6		1
+#define LENACCU		2
+
+/* parser's microcode flag type */
+enum {
+	FLAG_ITAG = 0,
+	FLAG_VLAN,
+	FLAG_SNAP,
+	FLAG_PPPOE,
+	FLAG_IPV6,
+	FLAG_IPV6FL,
+	FLAG_IPV4,
+	FLAG_IGMP,
+	FLAG_TU,
+	FLAG_HOP,
+	FLAG_NN1,	/*10 */
+	FLAG_NN2,
+	FLAG_END,
+	FLAG_NO,	/*13*/
+};
+
+struct gswip_pce_microcode {
+	u16 val_3;
+	u16 val_2;
+	u16 val_1;
+	u16 val_0;
+};
+
+#define MC_ENTRY(val, msk, ns, out, len, type, flags, ipv4_len) \
+	{ val, msk, (ns << 10 | out << 4 | len >> 1),\
+		(len & 1) << 15 | type << 13 | flags << 9 | ipv4_len << 8 }
+static const struct gswip_pce_microcode gswip_pce_microcode[] = {
+	/*      value    mask    ns  fields      L  type     flags       ipv4_len */
+	MC_ENTRY(0x88c3, 0xFFFF,  1, OUT_ITAG0,  4, INSTR,   FLAG_ITAG,  0),
+	MC_ENTRY(0x8100, 0xFFFF,  2, OUT_VTAG0,  2, INSTR,   FLAG_VLAN,  0),
+	MC_ENTRY(0x88A8, 0xFFFF,  1, OUT_VTAG0,  2, INSTR,   FLAG_VLAN,  0),
+	MC_ENTRY(0x8100, 0xFFFF,  1, OUT_VTAG0,  2, INSTR,   FLAG_VLAN,  0),
+	MC_ENTRY(0x8864, 0xFFFF, 17, OUT_ETHTYP, 1, INSTR,   FLAG_NO,    0),
+	MC_ENTRY(0x0800, 0xFFFF, 21, OUT_ETHTYP, 1, INSTR,   FLAG_NO,    0),
+	MC_ENTRY(0x86DD, 0xFFFF, 22, OUT_ETHTYP, 1, INSTR,   FLAG_NO,    0),
+	MC_ENTRY(0x8863, 0xFFFF, 16, OUT_ETHTYP, 1, INSTR,   FLAG_NO,    0),
+	MC_ENTRY(0x0000, 0xF800, 10, OUT_NONE,   0, INSTR,   FLAG_NO,    0),
+	MC_ENTRY(0x0000, 0x0000, 40, OUT_ETHTYP, 1, INSTR,   FLAG_NO,    0),
+	MC_ENTRY(0x0600, 0x0600, 40, OUT_ETHTYP, 1, INSTR,   FLAG_NO,    0),
+	MC_ENTRY(0x0000, 0x0000, 12, OUT_NONE,   1, INSTR,   FLAG_NO,    0),
+	MC_ENTRY(0xAAAA, 0xFFFF, 14, OUT_NONE,   1, INSTR,   FLAG_NO,    0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_NO,    0),
+	MC_ENTRY(0x0300, 0xFF00, 41, OUT_NONE,   0, INSTR,   FLAG_SNAP,  0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_NO,    0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_DIP7,   3, INSTR,   FLAG_NO,    0),
+	MC_ENTRY(0x0000, 0x0000, 18, OUT_DIP7,   3, INSTR,   FLAG_PPPOE, 0),
+	MC_ENTRY(0x0021, 0xFFFF, 21, OUT_NONE,   1, INSTR,   FLAG_NO,    0),
+	MC_ENTRY(0x0057, 0xFFFF, 22, OUT_NONE,   1, INSTR,   FLAG_NO,    0),
+	MC_ENTRY(0x0000, 0x0000, 40, OUT_NONE,   0, INSTR,   FLAG_NO,    0),
+	MC_ENTRY(0x4000, 0xF000, 24, OUT_IP0,    4, INSTR,   FLAG_IPV4,  1),
+	MC_ENTRY(0x6000, 0xF000, 27, OUT_IP0,    3, INSTR,   FLAG_IPV6,  0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_NO,    0),
+	MC_ENTRY(0x0000, 0x0000, 25, OUT_IP3,    2, INSTR,   FLAG_NO,    0),
+	MC_ENTRY(0x0000, 0x0000, 26, OUT_SIP0,   4, INSTR,   FLAG_NO,    0),
+	MC_ENTRY(0x0000, 0x0000, 40, OUT_NONE,   0, LENACCU, FLAG_NO,    0),
+	MC_ENTRY(0x1100, 0xFF00, 39, OUT_PROT,   1, INSTR,   FLAG_NO,    0),
+	MC_ENTRY(0x0600, 0xFF00, 39, OUT_PROT,   1, INSTR,   FLAG_NO,    0),
+	MC_ENTRY(0x0000, 0xFF00, 33, OUT_IP3,   17, INSTR,   FLAG_HOP,   0),
+	MC_ENTRY(0x2B00, 0xFF00, 33, OUT_IP3,   17, INSTR,   FLAG_NN1,   0),
+	MC_ENTRY(0x3C00, 0xFF00, 33, OUT_IP3,   17, INSTR,   FLAG_NN2,   0),
+	MC_ENTRY(0x0000, 0x0000, 39, OUT_PROT,   1, INSTR,   FLAG_NO,    0),
+	MC_ENTRY(0x0000, 0x00E0, 35, OUT_NONE,   0, INSTR,   FLAG_NO,    0),
+	MC_ENTRY(0x0000, 0x0000, 40, OUT_NONE,   0, INSTR,   FLAG_NO,    0),
+	MC_ENTRY(0x0000, 0xFF00, 33, OUT_NONE,   0, IPV6,    FLAG_HOP,   0),
+	MC_ENTRY(0x2B00, 0xFF00, 33, OUT_NONE,   0, IPV6,    FLAG_NN1,   0),
+	MC_ENTRY(0x3C00, 0xFF00, 33, OUT_NONE,   0, IPV6,    FLAG_NN2,   0),
+	MC_ENTRY(0x0000, 0x0000, 40, OUT_PROT,   1, IPV6,    FLAG_NO,    0),
+	MC_ENTRY(0x0000, 0x0000, 40, OUT_SIP0,  16, INSTR,   FLAG_NO,    0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_APP0,   4, INSTR,   FLAG_IGMP,  0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
+	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
+};
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [PATCH 3/4] net: lantiq: Add Lantiq / Intel vrx200 Ethernet driver
  2018-07-21 19:13 ` [PATCH 3/4] net: lantiq: Add Lantiq / Intel vrx200 Ethernet driver Hauke Mehrtens
@ 2018-07-21 20:25   ` John Crispin
  2018-07-21 23:18     ` Hauke Mehrtens
  2018-07-24  0:34   ` Paul Burton
  2018-07-25 15:28   ` Andrew Lunn
  2 siblings, 1 reply; 29+ messages in thread
From: John Crispin @ 2018-07-21 20:25 UTC (permalink / raw)
  To: Hauke Mehrtens, davem
  Cc: netdev, andrew, vivien.didelot, f.fainelli, linux-mips, dev,
	hauke.mehrtens



On 21/07/18 21:13, Hauke Mehrtens wrote:
> + * Copyright (C) 2012 John Crispin<blogic@openwrt.org>
that is not my mail addr :-)
     John

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 3/4] net: lantiq: Add Lantiq / Intel vrx200 Ethernet driver
  2018-07-21 20:25   ` John Crispin
@ 2018-07-21 23:18     ` Hauke Mehrtens
  0 siblings, 0 replies; 29+ messages in thread
From: Hauke Mehrtens @ 2018-07-21 23:18 UTC (permalink / raw)
  To: John Crispin
  Cc: davem, netdev, andrew, vivien.didelot, f.fainelli, linux-mips,
	dev, hauke.mehrtens

On 07/21/2018 10:25 PM, John Crispin wrote:
> 
> 
> On 21/07/18 21:13, Hauke Mehrtens wrote:
>> + * Copyright (C) 2012 John Crispin<blogic@openwrt.org>
> that is not my mail addr :-)
>     John

Thanks for the information, I fixed your mail address.

Hauke

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 4/4] net: dsa: Add Lantiq / Intel DSA driver for vrx200
  2018-07-21 19:13 ` [PATCH 4/4] net: dsa: Add Lantiq / Intel DSA driver for vrx200 Hauke Mehrtens
@ 2018-07-22  3:17   ` David Miller
  2018-07-22  9:29     ` Hauke Mehrtens
  2018-07-22  9:29     ` Hauke Mehrtens
  2018-07-25 16:12   ` Andrew Lunn
  2018-07-25 16:32   ` John Crispin
  2 siblings, 2 replies; 29+ messages in thread
From: David Miller @ 2018-07-22  3:17 UTC (permalink / raw)
  To: hauke
  Cc: netdev, andrew, vivien.didelot, f.fainelli, john, linux-mips,
	dev, hauke.mehrtens

From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sat, 21 Jul 2018 21:13:58 +0200

> +		// start the table access:

Please stick to C-style comments, except perhaps in the SPDX
identifiers.

Thank you.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 4/4] net: dsa: Add Lantiq / Intel DSA driver for vrx200
  2018-07-22  3:17   ` David Miller
@ 2018-07-22  9:29     ` Hauke Mehrtens
  2018-07-22  9:29     ` Hauke Mehrtens
  1 sibling, 0 replies; 29+ messages in thread
From: Hauke Mehrtens @ 2018-07-22  9:29 UTC (permalink / raw)
  To: linux-mips

On 07/22/2018 05:17 AM, David Miller wrote:
> From: Hauke Mehrtens <hauke@hauke-m.de>
> Date: Sat, 21 Jul 2018 21:13:58 +0200
> 
>> +		// start the table access:
> 
> Please stick to C-style comments, except perhaps in the SPDX
> identifiers.
> 
> Thank you.
> 

Sorry that I missed that, it is fixed now.

Hauke

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 4/4] net: dsa: Add Lantiq / Intel DSA driver for vrx200
  2018-07-22  3:17   ` David Miller
  2018-07-22  9:29     ` Hauke Mehrtens
@ 2018-07-22  9:29     ` Hauke Mehrtens
  1 sibling, 0 replies; 29+ messages in thread
From: Hauke Mehrtens @ 2018-07-22  9:29 UTC (permalink / raw)
  To: David Miller
  Cc: netdev, andrew, vivien.didelot, f.fainelli, john, linux-mips,
	dev, hauke.mehrtens

On 07/22/2018 05:17 AM, David Miller wrote:
> From: Hauke Mehrtens <hauke@hauke-m.de>
> Date: Sat, 21 Jul 2018 21:13:58 +0200
> 
>> +		// start the table access:
> 
> Please stick to C-style comments, except perhaps in the SPDX
> identifiers.
> 
> Thank you.
> 

Sorry that I missed that, it is fixed now.

Hauke

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 1/4] MIPS: lantiq: Do not enable IRQs in dma open
  2018-07-21 19:13 ` [PATCH 1/4] MIPS: lantiq: Do not enable IRQs in dma open Hauke Mehrtens
@ 2018-07-24  0:19   ` Paul Burton
  2018-07-24  5:32     ` Hauke Mehrtens
  0 siblings, 1 reply; 29+ messages in thread
From: Paul Burton @ 2018-07-24  0:19 UTC (permalink / raw)
  To: Hauke Mehrtens
  Cc: davem, netdev, andrew, vivien.didelot, f.fainelli, john,
	linux-mips, dev, hauke.mehrtens

Hi Hauke,

On Sat, Jul 21, 2018 at 09:13:55PM +0200, Hauke Mehrtens wrote:
> When a DMA channel is opened the IRQ should not get activated
> automatically, this allows it to pull data out manually without the help
> of interrupts. This is needed for a workaround in the vrx200 Ethernet
> driver.
> 
> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
> ---
>  arch/mips/lantiq/xway/dma.c        | 1 -
>  drivers/net/ethernet/lantiq_etop.c | 1 +
>  2 files changed, 1 insertion(+), 1 deletion(-)

If you'd like this to go via the netdev tree to keep it with the rest of
the series:

    Acked-by: Paul Burton <paul.burton@mips.com>

Though I'd be happier if we didn't have DMA code seemingly used only by
an ethernet driver in arch/mips/ :)

Thanks,
    Paul

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 3/4] net: lantiq: Add Lantiq / Intel vrx200 Ethernet driver
  2018-07-21 19:13 ` [PATCH 3/4] net: lantiq: Add Lantiq / Intel vrx200 Ethernet driver Hauke Mehrtens
  2018-07-21 20:25   ` John Crispin
@ 2018-07-24  0:34   ` Paul Burton
  2018-07-24  5:27     ` Hauke Mehrtens
  2018-07-25 15:28   ` Andrew Lunn
  2 siblings, 1 reply; 29+ messages in thread
From: Paul Burton @ 2018-07-24  0:34 UTC (permalink / raw)
  To: Hauke Mehrtens
  Cc: davem, netdev, andrew, vivien.didelot, f.fainelli, john,
	linux-mips, dev, hauke.mehrtens

Hi Hauke,

On Sat, Jul 21, 2018 at 09:13:57PM +0200, Hauke Mehrtens wrote:
> diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c
> index e0af39b33e28..c704312ef7d5 100644
> --- a/arch/mips/lantiq/xway/sysctrl.c
> +++ b/arch/mips/lantiq/xway/sysctrl.c
> @@ -536,7 +536,7 @@ void __init ltq_soc_init(void)
>  		clkdev_add_pmu(NULL, "ahb", 1, 0, PMU_AHBM | PMU_AHBS);
>  
>  		clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF);
> -		clkdev_add_pmu("1e108000.eth", NULL, 0, 0,
> +		clkdev_add_pmu("1e10b308.eth", NULL, 0, 0,
>  				PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM |
>  				PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 |
>  				PMU_PPE_QSB | PMU_PPE_TOP);

Is this intentional?

Why is it needed? Was the old address wrong? Does it change anything
functionally?

If it is needed it seems like a separate change - unless there's some
reason it's tied to adding this driver?

Should this really apply only to the lantiq,vr9 case or also to the
similar lantiq,grx390 & lantiq,ar10 paths?

Whatever the answers to these questions it would be good to include them
in the commit message.

Thanks,
    Paul

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 3/4] net: lantiq: Add Lantiq / Intel vrx200 Ethernet driver
  2018-07-24  0:34   ` Paul Burton
@ 2018-07-24  5:27     ` Hauke Mehrtens
  0 siblings, 0 replies; 29+ messages in thread
From: Hauke Mehrtens @ 2018-07-24  5:27 UTC (permalink / raw)
  To: Paul Burton
  Cc: davem, netdev, andrew, vivien.didelot, f.fainelli, john,
	linux-mips, dev, hauke.mehrtens

Hi Paul,

On 07/24/2018 02:34 AM, Paul Burton wrote:
> Hi Hauke,
> 
> On Sat, Jul 21, 2018 at 09:13:57PM +0200, Hauke Mehrtens wrote:
>> diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c
>> index e0af39b33e28..c704312ef7d5 100644
>> --- a/arch/mips/lantiq/xway/sysctrl.c
>> +++ b/arch/mips/lantiq/xway/sysctrl.c
>> @@ -536,7 +536,7 @@ void __init ltq_soc_init(void)
>>  		clkdev_add_pmu(NULL, "ahb", 1, 0, PMU_AHBM | PMU_AHBS);
>>  
>>  		clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF);
>> -		clkdev_add_pmu("1e108000.eth", NULL, 0, 0,
>> +		clkdev_add_pmu("1e10b308.eth", NULL, 0, 0,
>>  				PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM |
>>  				PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 |
>>  				PMU_PPE_QSB | PMU_PPE_TOP);
> 
> Is this intentional?

Yes

> Why is it needed? Was the old address wrong? Does it change anything
> functionally?

The Ethernet driver is newly added in these patches, this entry was not
used before.
This has to match the device name and the device name is now named
1e10b308.eth because this only uses the register range of the pmac and
not of the complete switch core, this is different to the old driver
used in OpenWrt.

The lantiq clock code should really be converted to the common clock
framework so we can define this in device tree and do not need this code
any more.
I am planning to do this, but want to wait till the xrx500 clk code from
these patches is in mainline:
https://www.linux-mips.org/archives/linux-mips/2018-06/msg00092.html
There are already some more recent versions available internally.

> If it is needed it seems like a separate change - unless there's some
> reason it's tied to adding this driver?
> 
> Should this really apply only to the lantiq,vr9 case or also to the
> similar lantiq,grx390 & lantiq,ar10 paths?

The AR10 has a similar switch core, but I haven't tested this device
with this Ethernet driver, but there is a good chance it works out of
the box when the sysctrl.c gets adapted and the correct device tree is
provided.
I do not know exactly what the grx390 SoC is, this is probably some
uncommon name for one of the Lantiq / Intel SoCs, I have to look this up.

> 
> Whatever the answers to these questions it would be good to include them
> in the commit message.

I will update the commit massage for the v2.

Hauke

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 1/4] MIPS: lantiq: Do not enable IRQs in dma open
  2018-07-24  0:19   ` Paul Burton
@ 2018-07-24  5:32     ` Hauke Mehrtens
  2018-07-24  5:39       ` David Miller
  0 siblings, 1 reply; 29+ messages in thread
From: Hauke Mehrtens @ 2018-07-24  5:32 UTC (permalink / raw)
  To: Paul Burton
  Cc: davem, netdev, andrew, vivien.didelot, f.fainelli, john,
	linux-mips, dev, hauke.mehrtens



On 07/24/2018 02:19 AM, Paul Burton wrote:
> Hi Hauke,
> 
> On Sat, Jul 21, 2018 at 09:13:55PM +0200, Hauke Mehrtens wrote:
>> When a DMA channel is opened the IRQ should not get activated
>> automatically, this allows it to pull data out manually without the help
>> of interrupts. This is needed for a workaround in the vrx200 Ethernet
>> driver.
>>
>> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
>> ---
>>  arch/mips/lantiq/xway/dma.c        | 1 -
>>  drivers/net/ethernet/lantiq_etop.c | 1 +
>>  2 files changed, 1 insertion(+), 1 deletion(-)
> 
> If you'd like this to go via the netdev tree to keep it with the rest of
> the series:
> 
>     Acked-by: Paul Burton <paul.burton@mips.com>

Thanks, I also prefer that this goes through netdev.

> Though I'd be happier if we didn't have DMA code seemingly used only by
> an ethernet driver in arch/mips/ :)

There are also some out of tree driver that use this DMA code. This
should probably be converted to a DMA channel driver but that is not
very high on my todo list.

Hauke

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 1/4] MIPS: lantiq: Do not enable IRQs in dma open
  2018-07-24  5:32     ` Hauke Mehrtens
@ 2018-07-24  5:39       ` David Miller
  0 siblings, 0 replies; 29+ messages in thread
From: David Miller @ 2018-07-24  5:39 UTC (permalink / raw)
  To: hauke
  Cc: paul.burton, netdev, andrew, vivien.didelot, f.fainelli, john,
	linux-mips, dev, hauke.mehrtens

From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Tue, 24 Jul 2018 07:32:27 +0200

> 
> 
> On 07/24/2018 02:19 AM, Paul Burton wrote:
>> Hi Hauke,
>> 
>> On Sat, Jul 21, 2018 at 09:13:55PM +0200, Hauke Mehrtens wrote:
>>> When a DMA channel is opened the IRQ should not get activated
>>> automatically, this allows it to pull data out manually without the help
>>> of interrupts. This is needed for a workaround in the vrx200 Ethernet
>>> driver.
>>>
>>> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
>>> ---
>>>  arch/mips/lantiq/xway/dma.c        | 1 -
>>>  drivers/net/ethernet/lantiq_etop.c | 1 +
>>>  2 files changed, 1 insertion(+), 1 deletion(-)
>> 
>> If you'd like this to go via the netdev tree to keep it with the rest of
>> the series:
>> 
>>     Acked-by: Paul Burton <paul.burton@mips.com>
> 
> Thanks, I also prefer that this goes through netdev.

Please be sure to repost your series with Paul's ACK added.

Also, in the patch postings and cover letter, put "net-next" in
the Subject line so that the target tree is clear, like:

	Subject: [PATCH net-next 1/4] MIPS: ...


Thank you.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 2/4] net: dsa: Add Lantiq / Intel GSWIP tag support
  2018-07-21 19:13 ` [PATCH 2/4] net: dsa: Add Lantiq / Intel GSWIP tag support Hauke Mehrtens
@ 2018-07-25 14:20   ` Andrew Lunn
  2018-07-29 14:01     ` Hauke Mehrtens
  0 siblings, 1 reply; 29+ messages in thread
From: Andrew Lunn @ 2018-07-25 14:20 UTC (permalink / raw)
  To: Hauke Mehrtens
  Cc: davem, netdev, vivien.didelot, f.fainelli, john, linux-mips, dev,
	hauke.mehrtens

On Sat, Jul 21, 2018 at 09:13:56PM +0200, Hauke Mehrtens wrote:
> 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.0 found in the VRX200 SoCs, other GSWIP
> versions use slightly different PMAC special tags
> 
> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>

Hi Hauke

This looks good. A new minor nitpicks below.

> +#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

Single newline is sufficient.

> +/* Byte 3 */
> +#define GSWIP_TX_CRCGEN_DIS		BIT(23)

BIT(23) in a byte is a bit odd.

> +#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
> +
> +
> +#define GSWIP_RX_HEADER_LEN	8

Single newline is sufficient. Please fix them all, if there are more
of them.

> +
> +/* 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_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 = ((u8 *)skb->data) - ETH_HLEN;

The cast should not be needed, data already is an unsigned char.

> +	skb_pull_rcsum(skb, GSWIP_RX_HEADER_LEN);
> +
> +	/* 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;
> +
> +	return skb;
> +}

  Andrew

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 3/4] net: lantiq: Add Lantiq / Intel vrx200 Ethernet driver
  2018-07-21 19:13 ` [PATCH 3/4] net: lantiq: Add Lantiq / Intel vrx200 Ethernet driver Hauke Mehrtens
  2018-07-21 20:25   ` John Crispin
  2018-07-24  0:34   ` Paul Burton
@ 2018-07-25 15:28   ` Andrew Lunn
  2018-07-29 14:03     ` Hauke Mehrtens
  2 siblings, 1 reply; 29+ messages in thread
From: Andrew Lunn @ 2018-07-25 15:28 UTC (permalink / raw)
  To: Hauke Mehrtens
  Cc: davem, netdev, vivien.didelot, f.fainelli, john, linux-mips, dev,
	hauke.mehrtens

> +	/* Make sure the firmware of the embedded GPHY is loaded before,
> +	 * otherwise they will not be detectable on the MDIO bus.
> +	 */
> +	of_for_each_phandle(&it, err, np, "lantiq,phys", NULL, 0) {
> +		phy_np = it.node;
> +		if (phy_np) {
> +			struct platform_device *phy = of_find_device_by_node(phy_np);
> +
> +			of_node_put(phy_np);
> +			if (!platform_get_drvdata(phy))
> +				return -EPROBE_DEFER;
> +		}
> +	}

Is there a device tree binding document for this somewhere?

   Andrew

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 4/4] net: dsa: Add Lantiq / Intel DSA driver for vrx200
  2018-07-21 19:13 ` [PATCH 4/4] net: dsa: Add Lantiq / Intel DSA driver for vrx200 Hauke Mehrtens
  2018-07-22  3:17   ` David Miller
@ 2018-07-25 16:12   ` Andrew Lunn
  2018-07-29 16:25     ` Hauke Mehrtens
  2018-07-25 16:32   ` John Crispin
  2 siblings, 1 reply; 29+ messages in thread
From: Andrew Lunn @ 2018-07-25 16:12 UTC (permalink / raw)
  To: Hauke Mehrtens
  Cc: davem, netdev, vivien.didelot, f.fainelli, john, linux-mips, dev,
	hauke.mehrtens

>  LANTIQ MIPS ARCHITECTURE
>  M:	John Crispin <john@phrozen.org>
> diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
> index 2b81b97e994f..f1280aa3f9bd 100644
> --- a/drivers/net/dsa/Kconfig
> +++ b/drivers/net/dsa/Kconfig
> @@ -23,6 +23,14 @@ config NET_DSA_LOOP
>  	  This enables support for a fake mock-up switch chip which
>  	  exercises the DSA APIs.
>  
> +config NET_DSA_GSWIP
> +	tristate "Intel / Lantiq GSWIP"

Minor nit pick. Could you make this NET_DSA_LANTIQ_GSWIP. We generally
have some manufacture ID in the name. And change the text to Lantiq /
Intel GSWIP.

> +static const struct gswip_rmon_cnt_desc gswip_rmon_cnt[] = {
> +	/** Receive Packet Count (only packets that are accepted and not discarded). */
> +	MIB_DESC(1, 0x1F, "RxGoodPkts"),
> +	/** Receive Unicast Packet Count. */
> +	MIB_DESC(1, 0x23, "RxUnicastPkts"),
> +	/** Receive Multicast Packet Count. */
> +	MIB_DESC(1, 0x22, "RxMulticastPkts"),
> +	/** Receive FCS Error Packet Count. */
> +	MIB_DESC(1, 0x21, "RxFCSErrorPkts"),
> +	/** Receive Undersize Good Packet Count. */
> +	MIB_DESC(1, 0x1D, "RxUnderSizeGoodPkts"),
> +	/** Receive Undersize Error Packet Count. */
> +	MIB_DESC(1, 0x1E, "RxUnderSizeErrorPkts"),
> +	/** Receive Oversize Good Packet Count. */
> +	MIB_DESC(1, 0x1B, "RxOversizeGoodPkts"),
> +	/** Receive Oversize Error Packet Count. */
> +	MIB_DESC(1, 0x1C, "RxOversizeErrorPkts"),
> +	/** Receive Good Pause Packet Count. */
> +	MIB_DESC(1, 0x20, "RxGoodPausePkts"),
> +	/** Receive Align Error Packet Count. */
> +	MIB_DESC(1, 0x1A, "RxAlignErrorPkts"),
> +	/** Receive Size 64 Packet Count. */
> +	MIB_DESC(1, 0x12, "Rx64BytePkts"),
> +	/** Receive Size 65-127 Packet Count. */
> +	MIB_DESC(1, 0x13, "Rx127BytePkts"),
> +	/** Receive Size 128-255 Packet Count. */
> +	MIB_DESC(1, 0x14, "Rx255BytePkts"),
> +	/** Receive Size 256-511 Packet Count. */
> +	MIB_DESC(1, 0x15, "Rx511BytePkts"),
> +	/** Receive Size 512-1023 Packet Count. */
> +	MIB_DESC(1, 0x16, "Rx1023BytePkts"),
> +	/** Receive Size 1024-1522 (or more, if configured) Packet Count. */
> +	MIB_DESC(1, 0x17, "RxMaxBytePkts"),
> +	/** Receive Dropped Packet Count. */
> +	MIB_DESC(1, 0x18, "RxDroppedPkts"),
> +	/** Filtered Packet Count. */
> +	MIB_DESC(1, 0x19, "RxFilteredPkts"),
> +	/** Receive Good Byte Count (64 bit). */
> +	MIB_DESC(2, 0x24, "RxGoodBytes"),
> +	/** Receive Bad Byte Count (64 bit). */
> +	MIB_DESC(2, 0x26, "RxBadBytes"),
> +	/** Transmit Dropped Packet Count, based on Congestion Management. */
> +	MIB_DESC(1, 0x11, "TxAcmDroppedPkts"),
> +	/** Transmit Packet Count. */
> +	MIB_DESC(1, 0x0C, "TxGoodPkts"),
> +	/** Transmit Unicast Packet Count. */
> +	MIB_DESC(1, 0x06, "TxUnicastPkts"),
> +	/** Transmit Multicast Packet Count. */
> +	MIB_DESC(1, 0x07, "TxMulticastPkts"),
> +	/** Transmit Size 64 Packet Count. */
> +	MIB_DESC(1, 0x00, "Tx64BytePkts"),
> +	/** Transmit Size 65-127 Packet Count. */
> +	MIB_DESC(1, 0x01, "Tx127BytePkts"),
> +	/** Transmit Size 128-255 Packet Count. */
> +	MIB_DESC(1, 0x02, "Tx255BytePkts"),
> +	/** Transmit Size 256-511 Packet Count. */
> +	MIB_DESC(1, 0x03, "Tx511BytePkts"),
> +	/** Transmit Size 512-1023 Packet Count. */
> +	MIB_DESC(1, 0x04, "Tx1023BytePkts"),
> +	/** Transmit Size 1024-1522 (or more, if configured) Packet Count. */
> +	MIB_DESC(1, 0x05, "TxMaxBytePkts"),
> +	/** Transmit Single Collision Count. */
> +	MIB_DESC(1, 0x08, "TxSingleCollCount"),
> +	/** Transmit Multiple Collision Count. */
> +	MIB_DESC(1, 0x09, "TxMultCollCount"),
> +	/** Transmit Late Collision Count. */
> +	MIB_DESC(1, 0x0A, "TxLateCollCount"),
> +	/** Transmit Excessive Collision Count. */
> +	MIB_DESC(1, 0x0B, "TxExcessCollCount"),
> +	/** Transmit Pause Packet Count. */
> +	MIB_DESC(1, 0x0D, "TxPauseCount"),
> +	/** Transmit Drop Packet Count. */
> +	MIB_DESC(1, 0x10, "TxDroppedPkts"),
> +	/** Transmit Good Byte Count (64 bit). */
> +	MIB_DESC(2, 0x0E, "TxGoodBytes"),

Most of the comments here don't add anything useful. Maybe remove
them?

> +};
> +
> +static u32 gswip_switch_r(struct gswip_priv *priv, u32 offset)
> +{
> +	return __raw_readl(priv->gswip + (offset * 4));
> +}
> +
> +static void gswip_switch_w(struct gswip_priv *priv, u32 val, u32 offset)
> +{
> +	return __raw_writel(val, priv->gswip + (offset * 4));
> +}

Since this is MIPS, i assume re-ordering cannot happen, there are
barriers, etc?

> +static int xrx200_mdio_poll(struct gswip_priv *priv)
> +{
> +	int cnt = 10000;
> +
> +	while (likely(cnt--)) {
> +		u32 ctrl = gswip_mdio_r(priv, GSWIP_MDIO_CTRL);
> +
> +		if ((ctrl & GSWIP_MDIO_CTRL_BUSY) == 0)
> +			return 0;
> +		cpu_relax();
> +	}
> +
> +	return 1;
> +}

Please return ETIMEOUT when needed. Maybe use one of the variants of
readx_poll_timeout().

> +
> +static int xrx200_mdio_wr(struct mii_bus *bus, int addr, int reg, u16 val)
> +{
> +	struct gswip_priv *priv = bus->priv;
> +
> +	if (xrx200_mdio_poll(priv))
> +		return -EIO;

EIO is wrong, it should be a timeout. Solved above...

> +
> +	gswip_mdio_w(priv, val, GSWIP_MDIO_WRITE);
> +	gswip_mdio_w(priv, GSWIP_MDIO_CTRL_BUSY | GSWIP_MDIO_CTRL_WR |
> +		((addr & GSWIP_MDIO_CTRL_PHYAD_MASK) << GSWIP_MDIO_CTRL_PHYAD_SHIFT) |
> +		(reg & GSWIP_MDIO_CTRL_REGAD_MASK),
> +		GSWIP_MDIO_CTRL);
> +
> +	return 0;
> +}
> +

> +static int gswip_mdio(struct gswip_priv *priv, struct device_node *mdio_np)
> +{
> +	struct dsa_switch *ds = priv->ds;
> +
> +	ds->slave_mii_bus = devm_mdiobus_alloc(priv->dev);
> +	if (!ds->slave_mii_bus)
> +		return -ENOMEM;
> +
> +	ds->slave_mii_bus->priv = priv;
> +	ds->slave_mii_bus->read = xrx200_mdio_rd;
> +	ds->slave_mii_bus->write = xrx200_mdio_wr;
> +	ds->slave_mii_bus->name = "lantiq,xrx200-mdio";
> +	snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "%x", 0);

You should be able to do better than that.

> +	ds->slave_mii_bus->parent = priv->dev;
> +	ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask;
> +
> +	return of_mdiobus_register(ds->slave_mii_bus, mdio_np);
> +}
> +
> +static void gswip_wait_pce_tbl_ready(struct gswip_priv *priv)
> +{
> +	while (gswip_switch_r(priv, GSWIP_PCE_TBL_CTRL) & GSWIP_PCE_TBL_CTRL_BAS)
> +		cond_resched();

Please add some form of timeout.

> +}
> +
> +static int gswip_port_enable(struct dsa_switch *ds, int port,
> +			     struct phy_device *phy)
> +{
> +	struct gswip_priv *priv = (struct gswip_priv *)ds->priv;

Casts like this are not needed.

> +	/* RMON Counter Enable for port */
> +	gswip_switch_w(priv, GSWIP_BM_PCFG_CNTEN, GSWIP_BM_PCFGp(port));
> +
> +	/* enable port fetch/store dma & VLAN Modification */
> +	gswip_switch_mask(priv, 0, GSWIP_FDMA_PCTRL_EN |
> +				   GSWIP_FDMA_PCTRL_VLANMOD_BOTH,
> +			 GSWIP_FDMA_PCTRLp(port));
> +	gswip_switch_mask(priv, 0, GSWIP_SDMA_PCTRL_EN,
> +			  GSWIP_SDMA_PCTRLp(port));
> +	gswip_switch_mask(priv, 0, GSWIP_PCE_PCTRL_0_INGRESS,
> +			  GSWIP_PCE_PCTRL_0p(port));
> +
> +	return 0;
> +}
> +

> +static int gswip_setup(struct dsa_switch *ds)
> +{
> +	struct gswip_priv *priv = ds->priv;
> +	int i;
> +
> +	gswip_switch_w(priv, GSWIP_ETHSW_SWRES_R0, GSWIP_ETHSW_SWRES);
> +	usleep_range(5000, 10000);
> +	gswip_switch_w(priv, 0, GSWIP_ETHSW_SWRES);
> +
> +	/* disable port fetch/store dma, assume CPU port is last port */

Since this comes from device tree, you should really verify that and
return EINVAL if not, in the probe() function.

> +	for (i = 0; i <= priv->cpu_port; i++)
> +		gswip_port_disable(ds, i, NULL);
> +
> +	/* enable Switch */
> +	gswip_mdio_mask(priv, 0, GSWIP_MDIO_GLOB_ENABLE, GSWIP_MDIO_GLOB);
> +
> +	xrx200_pci_microcode(priv);
> +
> +	/* Default unknown Broadcast/Multicast/Unicast port maps */
> +	gswip_switch_w(priv, BIT(priv->cpu_port), GSWIP_PCE_PMAP1);
> +	gswip_switch_w(priv, BIT(priv->cpu_port), GSWIP_PCE_PMAP2);
> +	gswip_switch_w(priv, BIT(priv->cpu_port), GSWIP_PCE_PMAP3);
> +
> +	/* disable auto polling */
> +	gswip_mdio_w(priv, 0x0, GSWIP_MDIO_MDC_CFG0);
> +
> +	/* enable special tag insertion on cpu port */
> +	gswip_switch_mask(priv, 0, GSWIP_FDMA_PCTRL_STEN,
> +			  GSWIP_FDMA_PCTRLp(priv->cpu_port));
> +
> +	gswip_switch_mask(priv, 0, GSWIP_MAC_CTRL_2_MLEN,
> +			  GSWIP_MAC_CTRL_2p(priv->cpu_port));
> +	gswip_switch_w(priv, VLAN_ETH_FRAME_LEN + 8, GSWIP_MAC_FLEN);
> +	gswip_switch_mask(priv, 0, GSWIP_BM_QUEUE_GCTRL_GL_MOD,
> +			  GSWIP_BM_QUEUE_GCTRL);
> +
> +	/* VLAN aware Switching */
> +	gswip_switch_mask(priv, 0, GSWIP_PCE_GCTRL_0_VLAN, GSWIP_PCE_GCTRL_0);
> +
> +	/* Mac Address Table Lock */
> +	gswip_switch_mask(priv, 0, GSWIP_PCE_GCTRL_1_MAC_GLOCK |
> +				   GSWIP_PCE_GCTRL_1_MAC_GLOCK_MOD,
> +			  GSWIP_PCE_GCTRL_1);
> +
> +	gswip_port_enable(ds, priv->cpu_port, NULL);
> +	return 0;
> +}
> +
> +static void gswip_adjust_link(struct dsa_switch *ds, int port,
> +			      struct phy_device *phydev)
> +{
> +	struct gswip_priv *priv = (struct gswip_priv *)ds->priv;
> +	u16 phyaddr = phydev->mdio.addr & GSWIP_MDIO_PHY_ADDR_MASK;
> +	u16 miirate = 0;
> +	u16 miimode;
> +	u16 lcl_adv = 0, rmt_adv = 0;
> +	u8 flowctrl;
> +
> +	/* do not run this for the CPU port 6 */
> +	if (port >= priv->cpu_port)

Please use  dsa_is_cpu_port(ds, port)

> +		return;
> +
> +	miimode = gswip_mdio_r(priv, GSWIP_MII_CFGp(port));
> +	miimode &= GSWIP_MII_CFG_MODE_MASK;
> +
> +	switch (phydev->speed) {
> +	case SPEED_1000:
> +		phyaddr |= GSWIP_MDIO_PHY_SPEED_G1;
> +		miirate = GSWIP_MII_CFG_RATE_M125;
> +		break;
> +
> +	case SPEED_100:
> +		phyaddr |= GSWIP_MDIO_PHY_SPEED_M100;
> +		switch (miimode) {
> +		case GSWIP_MII_CFG_MODE_RMIIM:
> +		case GSWIP_MII_CFG_MODE_RMIIP:
> +			miirate = GSWIP_MII_CFG_RATE_M50;
> +			break;
> +		default:
> +			miirate = GSWIP_MII_CFG_RATE_M25;
> +			break;
> +		}
> +		break;
> +
> +	default:
> +		phyaddr |= GSWIP_MDIO_PHY_SPEED_M10;
> +		miirate = GSWIP_MII_CFG_RATE_M2P5;
> +		break;
> +	}
> +
> +	if (phydev->link)
> +		phyaddr |= GSWIP_MDIO_PHY_LINK_UP;
> +	else
> +		phyaddr |= GSWIP_MDIO_PHY_LINK_DOWN;
> +
> +	if (phydev->duplex == DUPLEX_FULL)
> +		phyaddr |= GSWIP_MDIO_PHY_FDUP_EN;
> +	else
> +		phyaddr |= GSWIP_MDIO_PHY_FDUP_DIS;
> +
> +	if (phydev->pause)
> +		rmt_adv = LPA_PAUSE_CAP;
> +	if (phydev->asym_pause)
> +		rmt_adv |= LPA_PAUSE_ASYM;
> +
> +	if (phydev->advertising & ADVERTISED_Pause)
> +		lcl_adv |= ADVERTISE_PAUSE_CAP;
> +	if (phydev->advertising & ADVERTISED_Asym_Pause)
> +		lcl_adv |= ADVERTISE_PAUSE_ASYM;
> +
> +	flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
> +
> +	if (flowctrl & FLOW_CTRL_TX)
> +		phyaddr |= GSWIP_MDIO_PHY_FCONTX_EN;
> +	else
> +		phyaddr |= GSWIP_MDIO_PHY_FCONTX_DIS;
> +	if (flowctrl & FLOW_CTRL_RX)
> +		phyaddr |= GSWIP_MDIO_PHY_FCONRX_EN;
> +	else
> +		phyaddr |= GSWIP_MDIO_PHY_FCONRX_DIS;
> +
> +	gswip_mdio_mask(priv, GSWIP_MDIO_PHY_MASK, phyaddr,
> +			GSWIP_MDIO_PHYp(port));

The names make this unclear. The callback is used to configure the MAC
layer when something happens at the PHY layer. phyaddr does not appear
to be an address, not should it be doing anything to a PHY.

> +	gswip_mii_mask(priv, GSWIP_MII_CFG_RATE_MASK, miirate,
> +		       GSWIP_MII_CFGp(port));
> +}
> +
> +static u32 gswip_bcm_ram_entry_read(struct gswip_priv *priv, u32 table,
> +				    u32 index)
> +{
> +	u32 result;
> +
> +	gswip_switch_w(priv, index, GSWIP_BM_RAM_ADDR);
> +	gswip_switch_mask(priv, GSWIP_BM_RAM_CTRL_ADDR_MASK |
> +				GSWIP_BM_RAM_CTRL_OPMOD,
> +			      table | GSWIP_BM_RAM_CTRL_BAS,
> +			      GSWIP_BM_RAM_CTRL);
> +
> +	while (gswip_switch_r(priv, GSWIP_BM_RAM_CTRL) & GSWIP_BM_RAM_CTRL_BAS)
> +		cond_resched();

Please add a timeout.

> +
> +	result = gswip_switch_r(priv, GSWIP_BM_RAM_VAL(0));
> +	result |= gswip_switch_r(priv, GSWIP_BM_RAM_VAL(1)) << 16;
> +
> +	return result;
> +}
> +

> +static int gswip_probe(struct platform_device *pdev)
> +{
> +	struct gswip_priv *priv;
> +	struct resource *gswip_res, *mdio_res, *mii_res;
> +	struct device_node *mdio_np;
> +	struct device *dev = &pdev->dev;
> +	int err;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	gswip_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	priv->gswip = devm_ioremap_resource(dev, gswip_res);
> +	if (!priv->gswip)
> +		return -ENOMEM;
> +
> +	mdio_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> +	priv->mdio = devm_ioremap_resource(dev, mdio_res);
> +	if (!priv->mdio)
> +		return -ENOMEM;
> +
> +	mii_res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
> +	priv->mii = devm_ioremap_resource(dev, mii_res);
> +	if (!priv->mii)
> +		return -ENOMEM;
> +
> +	priv->ds = dsa_switch_alloc(dev, DSA_MAX_PORTS);

If you know how many ports there are, it is better to pass it.

> +	if (!priv->ds)
> +		return -ENOMEM;
> +
> +	priv->ds->priv = priv;
> +	priv->ds->ops = &gswip_switch_ops;
> +	priv->dev = dev;
> +	priv->cpu_port = 6;
> +
> +	/* bring up the mdio bus */
> +	mdio_np = of_find_compatible_node(pdev->dev.of_node, NULL,
> +					  "lantiq,xrx200-mdio");
> +	if (mdio_np) {
> +		err = gswip_mdio(priv, mdio_np);
> +		if (err) {
> +			dev_err(dev, "mdio probe failed\n");
> +			return err;
> +		}
> +	}
> +
> +	platform_set_drvdata(pdev, priv);
> +
> +	err = dsa_register_switch(priv->ds);
> +	if (err) {
> +		dev_err(dev, "dsa switch register failed: %i\n", err);
> +		if (mdio_np)
> +			mdiobus_unregister(priv->ds->slave_mii_bus);
> +	}
> +
> +	return err;
> +}

> +static const struct of_device_id gswip_of_match[] = {
> +	{ .compatible = "lantiq,xrx200-gswip" },
> +	{},
> +};

Please add device tree documentation.

> +MODULE_DEVICE_TABLE(of, xrx200_match);
> +
> +static struct platform_driver gswip_driver = {
> +	.probe = gswip_probe,
> +	.remove = gswip_remove,
> +	.driver = {
> +		.name = "gswip",
> +		.of_match_table = gswip_of_match,
> +	},
> +};
> +#define MC_ENTRY(val, msk, ns, out, len, type, flags, ipv4_len) \
> +	{ val, msk, (ns << 10 | out << 4 | len >> 1),\
> +		(len & 1) << 15 | type << 13 | flags << 9 | ipv4_len << 8 }
> +static const struct gswip_pce_microcode gswip_pce_microcode[] = {

How big is this table? I'm wondering if it should be loaded from
/lib/firmware. Or can it be marked __initdata?

Thanks
       Andrew

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 4/4] net: dsa: Add Lantiq / Intel DSA driver for vrx200
  2018-07-21 19:13 ` [PATCH 4/4] net: dsa: Add Lantiq / Intel DSA driver for vrx200 Hauke Mehrtens
  2018-07-22  3:17   ` David Miller
  2018-07-25 16:12   ` Andrew Lunn
@ 2018-07-25 16:32   ` John Crispin
  2018-07-25 16:46     ` Andrew Lunn
  2 siblings, 1 reply; 29+ messages in thread
From: John Crispin @ 2018-07-25 16:32 UTC (permalink / raw)
  To: Hauke Mehrtens, davem
  Cc: netdev, andrew, vivien.didelot, f.fainelli, linux-mips, dev,
	hauke.mehrtens



On 21/07/18 21:13, Hauke Mehrtens wrote:
> +#define MC_ENTRY(val, msk, ns, out, len, type, flags, ipv4_len) \
> +	{ val, msk, (ns << 10 | out << 4 | len >> 1),\
> +		(len & 1) << 15 | type << 13 | flags << 9 | ipv4_len << 8 }
> +static const struct gswip_pce_microcode gswip_pce_microcode[] = {
> +	/*      value    mask    ns  fields      L  type     flags       ipv4_len */
> +	MC_ENTRY(0x88c3, 0xFFFF,  1, OUT_ITAG0,  4, INSTR,   FLAG_ITAG,  0),
> +	MC_ENTRY(0x8100, 0xFFFF,  2, OUT_VTAG0,  2, INSTR,   FLAG_VLAN,  0),
> +	MC_ENTRY(0x88A8, 0xFFFF,  1, OUT_VTAG0,  2, INSTR,   FLAG_VLAN,  0),
> +	MC_ENTRY(0x8100, 0xFFFF,  1, OUT_VTAG0,  2, INSTR,   FLAG_VLAN,  0),
> +	MC_ENTRY(0x8864, 0xFFFF, 17, OUT_ETHTYP, 1, INSTR,   FLAG_NO,    0),
> +	MC_ENTRY(0x0800, 0xFFFF, 21, OUT_ETHTYP, 1, INSTR,   FLAG_NO,    0),
> +	MC_ENTRY(0x86DD, 0xFFFF, 22, OUT_ETHTYP, 1, INSTR,   FLAG_NO,    0),
> +	MC_ENTRY(0x8863, 0xFFFF, 16, OUT_ETHTYP, 1, INSTR,   FLAG_NO,    0),
> +	MC_ENTRY(0x0000, 0xF800, 10, OUT_NONE,   0, INSTR,   FLAG_NO,    0),
> +	MC_ENTRY(0x0000, 0x0000, 40, OUT_ETHTYP, 1, INSTR,   FLAG_NO,    0),
> +	MC_ENTRY(0x0600, 0x0600, 40, OUT_ETHTYP, 1, INSTR,   FLAG_NO,    0),
> +	MC_ENTRY(0x0000, 0x0000, 12, OUT_NONE,   1, INSTR,   FLAG_NO,    0),
> +	MC_ENTRY(0xAAAA, 0xFFFF, 14, OUT_NONE,   1, INSTR,   FLAG_NO,    0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_NO,    0),
> +	MC_ENTRY(0x0300, 0xFF00, 41, OUT_NONE,   0, INSTR,   FLAG_SNAP,  0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_NO,    0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_DIP7,   3, INSTR,   FLAG_NO,    0),
> +	MC_ENTRY(0x0000, 0x0000, 18, OUT_DIP7,   3, INSTR,   FLAG_PPPOE, 0),
> +	MC_ENTRY(0x0021, 0xFFFF, 21, OUT_NONE,   1, INSTR,   FLAG_NO,    0),
> +	MC_ENTRY(0x0057, 0xFFFF, 22, OUT_NONE,   1, INSTR,   FLAG_NO,    0),
> +	MC_ENTRY(0x0000, 0x0000, 40, OUT_NONE,   0, INSTR,   FLAG_NO,    0),
> +	MC_ENTRY(0x4000, 0xF000, 24, OUT_IP0,    4, INSTR,   FLAG_IPV4,  1),
> +	MC_ENTRY(0x6000, 0xF000, 27, OUT_IP0,    3, INSTR,   FLAG_IPV6,  0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_NO,    0),
> +	MC_ENTRY(0x0000, 0x0000, 25, OUT_IP3,    2, INSTR,   FLAG_NO,    0),
> +	MC_ENTRY(0x0000, 0x0000, 26, OUT_SIP0,   4, INSTR,   FLAG_NO,    0),
> +	MC_ENTRY(0x0000, 0x0000, 40, OUT_NONE,   0, LENACCU, FLAG_NO,    0),
> +	MC_ENTRY(0x1100, 0xFF00, 39, OUT_PROT,   1, INSTR,   FLAG_NO,    0),
> +	MC_ENTRY(0x0600, 0xFF00, 39, OUT_PROT,   1, INSTR,   FLAG_NO,    0),
> +	MC_ENTRY(0x0000, 0xFF00, 33, OUT_IP3,   17, INSTR,   FLAG_HOP,   0),
> +	MC_ENTRY(0x2B00, 0xFF00, 33, OUT_IP3,   17, INSTR,   FLAG_NN1,   0),
> +	MC_ENTRY(0x3C00, 0xFF00, 33, OUT_IP3,   17, INSTR,   FLAG_NN2,   0),
> +	MC_ENTRY(0x0000, 0x0000, 39, OUT_PROT,   1, INSTR,   FLAG_NO,    0),
> +	MC_ENTRY(0x0000, 0x00E0, 35, OUT_NONE,   0, INSTR,   FLAG_NO,    0),
> +	MC_ENTRY(0x0000, 0x0000, 40, OUT_NONE,   0, INSTR,   FLAG_NO,    0),
> +	MC_ENTRY(0x0000, 0xFF00, 33, OUT_NONE,   0, IPV6,    FLAG_HOP,   0),
> +	MC_ENTRY(0x2B00, 0xFF00, 33, OUT_NONE,   0, IPV6,    FLAG_NN1,   0),
> +	MC_ENTRY(0x3C00, 0xFF00, 33, OUT_NONE,   0, IPV6,    FLAG_NN2,   0),
> +	MC_ENTRY(0x0000, 0x0000, 40, OUT_PROT,   1, IPV6,    FLAG_NO,    0),
> +	MC_ENTRY(0x0000, 0x0000, 40, OUT_SIP0,  16, INSTR,   FLAG_NO,    0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_APP0,   4, INSTR,   FLAG_IGMP,  0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
> +	MC_ENTRY(0x0000, 0x0000, 41, OUT_NONE,   0, INSTR,   FLAG_END,   0),
> +};

i extracted this struct/blob/voodoo from UGW3/4 7 years ago and was 
puzzled by it. for those of us that have worked with this table in the 
past, its semi understandable, yet its almost like a blackbox FW blob. 
can we try to make it a little more readable by adding a comment on each 
line explaining why its there and what it does ?
     John

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 4/4] net: dsa: Add Lantiq / Intel DSA driver for vrx200
  2018-07-25 16:32   ` John Crispin
@ 2018-07-25 16:46     ` Andrew Lunn
  0 siblings, 0 replies; 29+ messages in thread
From: Andrew Lunn @ 2018-07-25 16:46 UTC (permalink / raw)
  To: John Crispin
  Cc: Hauke Mehrtens, davem, netdev, vivien.didelot, f.fainelli,
	linux-mips, dev, hauke.mehrtens

> 
> i extracted this struct/blob/voodoo from UGW3/4 7 years ago and was puzzled
> by it. for those of us that have worked with this table in the past, its
> semi understandable, yet its almost like a blackbox FW blob. can we try to
> make it a little more readable by adding a comment on each line explaining
> why its there and what it does ?

Hi John

I was wondering if there was any reverse engineered documentation. Do
you have any links?

Thanks
	Andrew

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 2/4] net: dsa: Add Lantiq / Intel GSWIP tag support
  2018-07-25 14:20   ` Andrew Lunn
@ 2018-07-29 14:01     ` Hauke Mehrtens
  0 siblings, 0 replies; 29+ messages in thread
From: Hauke Mehrtens @ 2018-07-29 14:01 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: davem, netdev, vivien.didelot, f.fainelli, john, linux-mips, dev,
	hauke.mehrtens

On 07/25/2018 04:20 PM, Andrew Lunn wrote:
> On Sat, Jul 21, 2018 at 09:13:56PM +0200, Hauke Mehrtens wrote:
>> 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.0 found in the VRX200 SoCs, other GSWIP
>> versions use slightly different PMAC special tags
>>
>> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
> 
> Hi Hauke
> 
> This looks good. A new minor nitpicks below.
> 
>> +#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
> 
> Single newline is sufficient.

removed
> 
>> +/* Byte 3 */
>> +#define GSWIP_TX_CRCGEN_DIS		BIT(23)
> 
> BIT(23) in a byte is a bit odd.

OK, this should be BIT(7)
The ordering of these defines was also strange I fixed that.

> 
>> +#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
>> +
>> +
>> +#define GSWIP_RX_HEADER_LEN	8
> 
> Single newline is sufficient. Please fix them all, if there are more
> of them.

ok

>> +
>> +/* 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_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 = ((u8 *)skb->data) - ETH_HLEN;
> 
> The cast should not be needed, data already is an unsigned char.

OK, I removed that.

>> +	skb_pull_rcsum(skb, GSWIP_RX_HEADER_LEN);
>> +
>> +	/* 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;
>> +
>> +	return skb;
>> +}
> 
>   Andrew
> 

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 3/4] net: lantiq: Add Lantiq / Intel vrx200 Ethernet driver
  2018-07-25 15:28   ` Andrew Lunn
@ 2018-07-29 14:03     ` Hauke Mehrtens
  2018-07-29 15:51       ` Andrew Lunn
  0 siblings, 1 reply; 29+ messages in thread
From: Hauke Mehrtens @ 2018-07-29 14:03 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: davem, netdev, vivien.didelot, f.fainelli, john, linux-mips, dev,
	hauke.mehrtens

On 07/25/2018 05:28 PM, Andrew Lunn wrote:
>> +	/* Make sure the firmware of the embedded GPHY is loaded before,
>> +	 * otherwise they will not be detectable on the MDIO bus.
>> +	 */
>> +	of_for_each_phandle(&it, err, np, "lantiq,phys", NULL, 0) {
>> +		phy_np = it.node;
>> +		if (phy_np) {
>> +			struct platform_device *phy = of_find_device_by_node(phy_np);
>> +
>> +			of_node_put(phy_np);
>> +			if (!platform_get_drvdata(phy))
>> +				return -EPROBE_DEFER;
>> +		}
>> +	}
> 
> Is there a device tree binding document for this somewhere?
> 
>    Andrew
> 

No, but I will create one.

I am also not sure iof this is the correct way of doing this.

We first have to load the FW into the Ethernet PHY though some generic
SoC registers and then we can find it normally on the MDIO bus and
interact with it like an external PHY on the MDIO bus.

Hauke

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 3/4] net: lantiq: Add Lantiq / Intel vrx200 Ethernet driver
  2018-07-29 14:03     ` Hauke Mehrtens
@ 2018-07-29 15:51       ` Andrew Lunn
  2018-07-29 15:53         ` Hauke Mehrtens
  0 siblings, 1 reply; 29+ messages in thread
From: Andrew Lunn @ 2018-07-29 15:51 UTC (permalink / raw)
  To: Hauke Mehrtens
  Cc: davem, netdev, vivien.didelot, f.fainelli, john, linux-mips, dev,
	hauke.mehrtens

On Sun, Jul 29, 2018 at 04:03:10PM +0200, Hauke Mehrtens wrote:
> On 07/25/2018 05:28 PM, Andrew Lunn wrote:
> >> +	/* Make sure the firmware of the embedded GPHY is loaded before,
> >> +	 * otherwise they will not be detectable on the MDIO bus.
> >> +	 */
> >> +	of_for_each_phandle(&it, err, np, "lantiq,phys", NULL, 0) {
> >> +		phy_np = it.node;
> >> +		if (phy_np) {
> >> +			struct platform_device *phy = of_find_device_by_node(phy_np);
> >> +
> >> +			of_node_put(phy_np);
> >> +			if (!platform_get_drvdata(phy))
> >> +				return -EPROBE_DEFER;
> >> +		}
> >> +	}
> > 
> > Is there a device tree binding document for this somewhere?
> > 
> >    Andrew
> > 
> 
> No, but I will create one.
> 
> I am also not sure iof this is the correct way of doing this.
> 
> We first have to load the FW into the Ethernet PHY though some generic
> SoC registers and then we can find it normally on the MDIO bus and
> interact with it like an external PHY on the MDIO bus.

Hi Hauke

It look sensible so far, but it would be good to post the PHY firmware
download code as well. Lets see the big picture, then we can decide if
there is a better way.

    Andrew

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 3/4] net: lantiq: Add Lantiq / Intel vrx200 Ethernet driver
  2018-07-29 15:51       ` Andrew Lunn
@ 2018-07-29 15:53         ` Hauke Mehrtens
  2018-07-29 16:40           ` Andrew Lunn
  0 siblings, 1 reply; 29+ messages in thread
From: Hauke Mehrtens @ 2018-07-29 15:53 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: davem, netdev, vivien.didelot, f.fainelli, john, linux-mips, dev,
	hauke.mehrtens

On 07/29/2018 05:51 PM, Andrew Lunn wrote:
> On Sun, Jul 29, 2018 at 04:03:10PM +0200, Hauke Mehrtens wrote:
>> On 07/25/2018 05:28 PM, Andrew Lunn wrote:
>>>> +	/* Make sure the firmware of the embedded GPHY is loaded before,
>>>> +	 * otherwise they will not be detectable on the MDIO bus.
>>>> +	 */
>>>> +	of_for_each_phandle(&it, err, np, "lantiq,phys", NULL, 0) {
>>>> +		phy_np = it.node;
>>>> +		if (phy_np) {
>>>> +			struct platform_device *phy = of_find_device_by_node(phy_np);
>>>> +
>>>> +			of_node_put(phy_np);
>>>> +			if (!platform_get_drvdata(phy))
>>>> +				return -EPROBE_DEFER;
>>>> +		}
>>>> +	}
>>>
>>> Is there a device tree binding document for this somewhere?
>>>
>>>    Andrew
>>>
>>
>> No, but I will create one.
>>
>> I am also not sure iof this is the correct way of doing this.
>>
>> We first have to load the FW into the Ethernet PHY though some generic
>> SoC registers and then we can find it normally on the MDIO bus and
>> interact with it like an external PHY on the MDIO bus.
> 
> Hi Hauke
> 
> It look sensible so far, but it would be good to post the PHY firmware
> download code as well. Lets see the big picture, then we can decide if
> there is a better way.

Hi Andrew,

It is already in the kernel tree and can be found here:
https://elixir.bootlin.com/linux/v4.18-rc6/source/drivers/soc/lantiq/gphy.c

I am thinking about merging this into the switch driver, then we do not
have to configure the dependency any more.

Hauke

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 4/4] net: dsa: Add Lantiq / Intel DSA driver for vrx200
  2018-07-25 16:12   ` Andrew Lunn
@ 2018-07-29 16:25     ` Hauke Mehrtens
  2018-07-29 16:49       ` Andrew Lunn
  0 siblings, 1 reply; 29+ messages in thread
From: Hauke Mehrtens @ 2018-07-29 16:25 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: davem, netdev, vivien.didelot, f.fainelli, john, linux-mips, dev,
	hauke.mehrtens

On 07/25/2018 06:12 PM, Andrew Lunn wrote:
>>  LANTIQ MIPS ARCHITECTURE
>>  M:	John Crispin <john@phrozen.org>
>> diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
>> index 2b81b97e994f..f1280aa3f9bd 100644
>> --- a/drivers/net/dsa/Kconfig
>> +++ b/drivers/net/dsa/Kconfig
>> @@ -23,6 +23,14 @@ config NET_DSA_LOOP
>>  	  This enables support for a fake mock-up switch chip which
>>  	  exercises the DSA APIs.
>>  
>> +config NET_DSA_GSWIP
>> +	tristate "Intel / Lantiq GSWIP"
> 
> Minor nit pick. Could you make this NET_DSA_LANTIQ_GSWIP. We generally
> have some manufacture ID in the name. And change the text to Lantiq /
> Intel GSWIP.

done

>> +static const struct gswip_rmon_cnt_desc gswip_rmon_cnt[] = {
>> +	/** Receive Packet Count (only packets that are accepted and not discarded). */
>> +	MIB_DESC(1, 0x1F, "RxGoodPkts"),
>> +	/** Receive Unicast Packet Count. */
>> +	MIB_DESC(1, 0x23, "RxUnicastPkts"),
>> +	/** Receive Multicast Packet Count. */
>> +	MIB_DESC(1, 0x22, "RxMulticastPkts"),
>> +	/** Receive FCS Error Packet Count. */
>> +	MIB_DESC(1, 0x21, "RxFCSErrorPkts"),
>> +	/** Receive Undersize Good Packet Count. */
>> +	MIB_DESC(1, 0x1D, "RxUnderSizeGoodPkts"),
>> +	/** Receive Undersize Error Packet Count. */
>> +	MIB_DESC(1, 0x1E, "RxUnderSizeErrorPkts"),
>> +	/** Receive Oversize Good Packet Count. */
>> +	MIB_DESC(1, 0x1B, "RxOversizeGoodPkts"),
>> +	/** Receive Oversize Error Packet Count. */
>> +	MIB_DESC(1, 0x1C, "RxOversizeErrorPkts"),
>> +	/** Receive Good Pause Packet Count. */
>> +	MIB_DESC(1, 0x20, "RxGoodPausePkts"),
>> +	/** Receive Align Error Packet Count. */
>> +	MIB_DESC(1, 0x1A, "RxAlignErrorPkts"),
>> +	/** Receive Size 64 Packet Count. */
>> +	MIB_DESC(1, 0x12, "Rx64BytePkts"),
>> +	/** Receive Size 65-127 Packet Count. */
>> +	MIB_DESC(1, 0x13, "Rx127BytePkts"),
>> +	/** Receive Size 128-255 Packet Count. */
>> +	MIB_DESC(1, 0x14, "Rx255BytePkts"),
>> +	/** Receive Size 256-511 Packet Count. */
>> +	MIB_DESC(1, 0x15, "Rx511BytePkts"),
>> +	/** Receive Size 512-1023 Packet Count. */
>> +	MIB_DESC(1, 0x16, "Rx1023BytePkts"),
>> +	/** Receive Size 1024-1522 (or more, if configured) Packet Count. */
>> +	MIB_DESC(1, 0x17, "RxMaxBytePkts"),
>> +	/** Receive Dropped Packet Count. */
>> +	MIB_DESC(1, 0x18, "RxDroppedPkts"),
>> +	/** Filtered Packet Count. */
>> +	MIB_DESC(1, 0x19, "RxFilteredPkts"),
>> +	/** Receive Good Byte Count (64 bit). */
>> +	MIB_DESC(2, 0x24, "RxGoodBytes"),
>> +	/** Receive Bad Byte Count (64 bit). */
>> +	MIB_DESC(2, 0x26, "RxBadBytes"),
>> +	/** Transmit Dropped Packet Count, based on Congestion Management. */
>> +	MIB_DESC(1, 0x11, "TxAcmDroppedPkts"),
>> +	/** Transmit Packet Count. */
>> +	MIB_DESC(1, 0x0C, "TxGoodPkts"),
>> +	/** Transmit Unicast Packet Count. */
>> +	MIB_DESC(1, 0x06, "TxUnicastPkts"),
>> +	/** Transmit Multicast Packet Count. */
>> +	MIB_DESC(1, 0x07, "TxMulticastPkts"),
>> +	/** Transmit Size 64 Packet Count. */
>> +	MIB_DESC(1, 0x00, "Tx64BytePkts"),
>> +	/** Transmit Size 65-127 Packet Count. */
>> +	MIB_DESC(1, 0x01, "Tx127BytePkts"),
>> +	/** Transmit Size 128-255 Packet Count. */
>> +	MIB_DESC(1, 0x02, "Tx255BytePkts"),
>> +	/** Transmit Size 256-511 Packet Count. */
>> +	MIB_DESC(1, 0x03, "Tx511BytePkts"),
>> +	/** Transmit Size 512-1023 Packet Count. */
>> +	MIB_DESC(1, 0x04, "Tx1023BytePkts"),
>> +	/** Transmit Size 1024-1522 (or more, if configured) Packet Count. */
>> +	MIB_DESC(1, 0x05, "TxMaxBytePkts"),
>> +	/** Transmit Single Collision Count. */
>> +	MIB_DESC(1, 0x08, "TxSingleCollCount"),
>> +	/** Transmit Multiple Collision Count. */
>> +	MIB_DESC(1, 0x09, "TxMultCollCount"),
>> +	/** Transmit Late Collision Count. */
>> +	MIB_DESC(1, 0x0A, "TxLateCollCount"),
>> +	/** Transmit Excessive Collision Count. */
>> +	MIB_DESC(1, 0x0B, "TxExcessCollCount"),
>> +	/** Transmit Pause Packet Count. */
>> +	MIB_DESC(1, 0x0D, "TxPauseCount"),
>> +	/** Transmit Drop Packet Count. */
>> +	MIB_DESC(1, 0x10, "TxDroppedPkts"),
>> +	/** Transmit Good Byte Count (64 bit). */
>> +	MIB_DESC(2, 0x0E, "TxGoodBytes"),
> 
> Most of the comments here don't add anything useful. Maybe remove
> them?

Ok I removed them. Are the names ok, or should they follow any Linux
definition?

>> +};
>> +
>> +static u32 gswip_switch_r(struct gswip_priv *priv, u32 offset)
>> +{
>> +	return __raw_readl(priv->gswip + (offset * 4));
>> +}
>> +
>> +static void gswip_switch_w(struct gswip_priv *priv, u32 val, u32 offset)
>> +{
>> +	return __raw_writel(val, priv->gswip + (offset * 4));
>> +}
> 
> Since this is MIPS, i assume re-ordering cannot happen, there are
> barriers, etc?

As far as I know this is not a problem on this bus and no barriers are
needed here.

>> +static int xrx200_mdio_poll(struct gswip_priv *priv)
>> +{
>> +	int cnt = 10000;
>> +
>> +	while (likely(cnt--)) {
>> +		u32 ctrl = gswip_mdio_r(priv, GSWIP_MDIO_CTRL);
>> +
>> +		if ((ctrl & GSWIP_MDIO_CTRL_BUSY) == 0)
>> +			return 0;
>> +		cpu_relax();
>> +	}
>> +
>> +	return 1;
>> +}
> 
> Please return ETIMEOUT when needed. Maybe use one of the variants of
> readx_poll_timeout().

I am returning ETIMEOUT now.

When I would use readx_poll_timeout() I can not use the gswip_mdio_r()
function, because it takes two arguments and would have to use readl
directly. I do not think that this would make the code much better
readable.


>> +
>> +static int xrx200_mdio_wr(struct mii_bus *bus, int addr, int reg, u16 val)
>> +{
>> +	struct gswip_priv *priv = bus->priv;
>> +
>> +	if (xrx200_mdio_poll(priv))
>> +		return -EIO;
> 
> EIO is wrong, it should be a timeout. Solved above...

OK I replaced this now with this code:

err = gswip_mdio_poll(priv);
if (err)
	return err;

>> +
>> +	gswip_mdio_w(priv, val, GSWIP_MDIO_WRITE);
>> +	gswip_mdio_w(priv, GSWIP_MDIO_CTRL_BUSY | GSWIP_MDIO_CTRL_WR |
>> +		((addr & GSWIP_MDIO_CTRL_PHYAD_MASK) << GSWIP_MDIO_CTRL_PHYAD_SHIFT) |
>> +		(reg & GSWIP_MDIO_CTRL_REGAD_MASK),
>> +		GSWIP_MDIO_CTRL);
>> +
>> +	return 0;
>> +}
>> +
> 
>> +static int gswip_mdio(struct gswip_priv *priv, struct device_node *mdio_np)
>> +{
>> +	struct dsa_switch *ds = priv->ds;
>> +
>> +	ds->slave_mii_bus = devm_mdiobus_alloc(priv->dev);
>> +	if (!ds->slave_mii_bus)
>> +		return -ENOMEM;
>> +
>> +	ds->slave_mii_bus->priv = priv;
>> +	ds->slave_mii_bus->read = xrx200_mdio_rd;
>> +	ds->slave_mii_bus->write = xrx200_mdio_wr;
>> +	ds->slave_mii_bus->name = "lantiq,xrx200-mdio";
>> +	snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "%x", 0);
> 
> You should be able to do better than that.

I replaced this now with this code:
snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "%s-mii",
dev_name(priv->dev));

>> +	ds->slave_mii_bus->parent = priv->dev;
>> +	ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask;
>> +
>> +	return of_mdiobus_register(ds->slave_mii_bus, mdio_np);
>> +}
>> +
>> +static void gswip_wait_pce_tbl_ready(struct gswip_priv *priv)
>> +{
>> +	while (gswip_switch_r(priv, GSWIP_PCE_TBL_CTRL) & GSWIP_PCE_TBL_CTRL_BAS)
>> +		cond_resched();
> 
> Please add some form of timeout.

I introduced a new function gswip_switch_r_timeout() which uses
readx_poll_timeout().

>> +}
>> +
>> +static int gswip_port_enable(struct dsa_switch *ds, int port,
>> +			     struct phy_device *phy)
>> +{
>> +	struct gswip_priv *priv = (struct gswip_priv *)ds->priv;
> 
> Casts like this are not needed.

removed

>> +	/* RMON Counter Enable for port */
>> +	gswip_switch_w(priv, GSWIP_BM_PCFG_CNTEN, GSWIP_BM_PCFGp(port));
>> +
>> +	/* enable port fetch/store dma & VLAN Modification */
>> +	gswip_switch_mask(priv, 0, GSWIP_FDMA_PCTRL_EN |
>> +				   GSWIP_FDMA_PCTRL_VLANMOD_BOTH,
>> +			 GSWIP_FDMA_PCTRLp(port));
>> +	gswip_switch_mask(priv, 0, GSWIP_SDMA_PCTRL_EN,
>> +			  GSWIP_SDMA_PCTRLp(port));
>> +	gswip_switch_mask(priv, 0, GSWIP_PCE_PCTRL_0_INGRESS,
>> +			  GSWIP_PCE_PCTRL_0p(port));
>> +
>> +	return 0;
>> +}
>> +
> 
>> +static int gswip_setup(struct dsa_switch *ds)
>> +{
>> +	struct gswip_priv *priv = ds->priv;
>> +	int i;
>> +
>> +	gswip_switch_w(priv, GSWIP_ETHSW_SWRES_R0, GSWIP_ETHSW_SWRES);
>> +	usleep_range(5000, 10000);
>> +	gswip_switch_w(priv, 0, GSWIP_ETHSW_SWRES);
>> +
>> +	/* disable port fetch/store dma, assume CPU port is last port */
> 
> Since this comes from device tree, you should really verify that and
> return EINVAL if not, in the probe() function.

I defined a struct hw_info which describes the details of this switch,
max port numbers and CPU port, as this is hard coded and this is then
compared to the device tree settings.

>> +	for (i = 0; i <= priv->cpu_port; i++)
>> +		gswip_port_disable(ds, i, NULL);
>> +
>> +	/* enable Switch */
>> +	gswip_mdio_mask(priv, 0, GSWIP_MDIO_GLOB_ENABLE, GSWIP_MDIO_GLOB);
>> +
>> +	xrx200_pci_microcode(priv);
>> +
>> +	/* Default unknown Broadcast/Multicast/Unicast port maps */
>> +	gswip_switch_w(priv, BIT(priv->cpu_port), GSWIP_PCE_PMAP1);
>> +	gswip_switch_w(priv, BIT(priv->cpu_port), GSWIP_PCE_PMAP2);
>> +	gswip_switch_w(priv, BIT(priv->cpu_port), GSWIP_PCE_PMAP3);
>> +
>> +	/* disable auto polling */
>> +	gswip_mdio_w(priv, 0x0, GSWIP_MDIO_MDC_CFG0);
>> +
>> +	/* enable special tag insertion on cpu port */
>> +	gswip_switch_mask(priv, 0, GSWIP_FDMA_PCTRL_STEN,
>> +			  GSWIP_FDMA_PCTRLp(priv->cpu_port));
>> +
>> +	gswip_switch_mask(priv, 0, GSWIP_MAC_CTRL_2_MLEN,
>> +			  GSWIP_MAC_CTRL_2p(priv->cpu_port));
>> +	gswip_switch_w(priv, VLAN_ETH_FRAME_LEN + 8, GSWIP_MAC_FLEN);
>> +	gswip_switch_mask(priv, 0, GSWIP_BM_QUEUE_GCTRL_GL_MOD,
>> +			  GSWIP_BM_QUEUE_GCTRL);
>> +
>> +	/* VLAN aware Switching */
>> +	gswip_switch_mask(priv, 0, GSWIP_PCE_GCTRL_0_VLAN, GSWIP_PCE_GCTRL_0);
>> +
>> +	/* Mac Address Table Lock */
>> +	gswip_switch_mask(priv, 0, GSWIP_PCE_GCTRL_1_MAC_GLOCK |
>> +				   GSWIP_PCE_GCTRL_1_MAC_GLOCK_MOD,
>> +			  GSWIP_PCE_GCTRL_1);
>> +
>> +	gswip_port_enable(ds, priv->cpu_port, NULL);
>> +	return 0;
>> +}
>> +
>> +static void gswip_adjust_link(struct dsa_switch *ds, int port,
>> +			      struct phy_device *phydev)
>> +{
>> +	struct gswip_priv *priv = (struct gswip_priv *)ds->priv;
>> +	u16 phyaddr = phydev->mdio.addr & GSWIP_MDIO_PHY_ADDR_MASK;
>> +	u16 miirate = 0;
>> +	u16 miimode;
>> +	u16 lcl_adv = 0, rmt_adv = 0;
>> +	u8 flowctrl;
>> +
>> +	/* do not run this for the CPU port 6 */
>> +	if (port >= priv->cpu_port)
> 
> Please use  dsa_is_cpu_port(ds, port)

done

>> +		return;
>> +
>> +	miimode = gswip_mdio_r(priv, GSWIP_MII_CFGp(port));
>> +	miimode &= GSWIP_MII_CFG_MODE_MASK;
>> +
>> +	switch (phydev->speed) {
>> +	case SPEED_1000:
>> +		phyaddr |= GSWIP_MDIO_PHY_SPEED_G1;
>> +		miirate = GSWIP_MII_CFG_RATE_M125;
>> +		break;
>> +
>> +	case SPEED_100:
>> +		phyaddr |= GSWIP_MDIO_PHY_SPEED_M100;
>> +		switch (miimode) {
>> +		case GSWIP_MII_CFG_MODE_RMIIM:
>> +		case GSWIP_MII_CFG_MODE_RMIIP:
>> +			miirate = GSWIP_MII_CFG_RATE_M50;
>> +			break;
>> +		default:
>> +			miirate = GSWIP_MII_CFG_RATE_M25;
>> +			break;
>> +		}
>> +		break;
>> +
>> +	default:
>> +		phyaddr |= GSWIP_MDIO_PHY_SPEED_M10;
>> +		miirate = GSWIP_MII_CFG_RATE_M2P5;
>> +		break;
>> +	}
>> +
>> +	if (phydev->link)
>> +		phyaddr |= GSWIP_MDIO_PHY_LINK_UP;
>> +	else
>> +		phyaddr |= GSWIP_MDIO_PHY_LINK_DOWN;
>> +
>> +	if (phydev->duplex == DUPLEX_FULL)
>> +		phyaddr |= GSWIP_MDIO_PHY_FDUP_EN;
>> +	else
>> +		phyaddr |= GSWIP_MDIO_PHY_FDUP_DIS;
>> +
>> +	if (phydev->pause)
>> +		rmt_adv = LPA_PAUSE_CAP;
>> +	if (phydev->asym_pause)
>> +		rmt_adv |= LPA_PAUSE_ASYM;
>> +
>> +	if (phydev->advertising & ADVERTISED_Pause)
>> +		lcl_adv |= ADVERTISE_PAUSE_CAP;
>> +	if (phydev->advertising & ADVERTISED_Asym_Pause)
>> +		lcl_adv |= ADVERTISE_PAUSE_ASYM;
>> +
>> +	flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
>> +
>> +	if (flowctrl & FLOW_CTRL_TX)
>> +		phyaddr |= GSWIP_MDIO_PHY_FCONTX_EN;
>> +	else
>> +		phyaddr |= GSWIP_MDIO_PHY_FCONTX_DIS;
>> +	if (flowctrl & FLOW_CTRL_RX)
>> +		phyaddr |= GSWIP_MDIO_PHY_FCONRX_EN;
>> +	else
>> +		phyaddr |= GSWIP_MDIO_PHY_FCONRX_DIS;
>> +
>> +	gswip_mdio_mask(priv, GSWIP_MDIO_PHY_MASK, phyaddr,
>> +			GSWIP_MDIO_PHYp(port));
> 
> The names make this unclear. The callback is used to configure the MAC
> layer when something happens at the PHY layer. phyaddr does not appear
> to be an address, not should it be doing anything to a PHY.

I renamed this to phyconf, as this contains multiple configuration
values. This tells the mac what settings the phy wants to use.

> 
>> +	gswip_mii_mask(priv, GSWIP_MII_CFG_RATE_MASK, miirate,
>> +		       GSWIP_MII_CFGp(port));
>> +}
>> +
>> +static u32 gswip_bcm_ram_entry_read(struct gswip_priv *priv, u32 table,
>> +				    u32 index)
>> +{
>> +	u32 result;
>> +
>> +	gswip_switch_w(priv, index, GSWIP_BM_RAM_ADDR);
>> +	gswip_switch_mask(priv, GSWIP_BM_RAM_CTRL_ADDR_MASK |
>> +				GSWIP_BM_RAM_CTRL_OPMOD,
>> +			      table | GSWIP_BM_RAM_CTRL_BAS,
>> +			      GSWIP_BM_RAM_CTRL);
>> +
>> +	while (gswip_switch_r(priv, GSWIP_BM_RAM_CTRL) & GSWIP_BM_RAM_CTRL_BAS)
>> +		cond_resched();
> 
> Please add a timeout.

I introduced a new funtion gswip_switch_r_timeout() which uses
readx_poll_timeout().

>> +
>> +	result = gswip_switch_r(priv, GSWIP_BM_RAM_VAL(0));
>> +	result |= gswip_switch_r(priv, GSWIP_BM_RAM_VAL(1)) << 16;
>> +
>> +	return result;
>> +}
>> +
> 
>> +static int gswip_probe(struct platform_device *pdev)
>> +{
>> +	struct gswip_priv *priv;
>> +	struct resource *gswip_res, *mdio_res, *mii_res;
>> +	struct device_node *mdio_np;
>> +	struct device *dev = &pdev->dev;
>> +	int err;
>> +
>> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
>> +	if (!priv)
>> +		return -ENOMEM;
>> +
>> +	gswip_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	priv->gswip = devm_ioremap_resource(dev, gswip_res);
>> +	if (!priv->gswip)
>> +		return -ENOMEM;
>> +
>> +	mdio_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
>> +	priv->mdio = devm_ioremap_resource(dev, mdio_res);
>> +	if (!priv->mdio)
>> +		return -ENOMEM;
>> +
>> +	mii_res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
>> +	priv->mii = devm_ioremap_resource(dev, mii_res);
>> +	if (!priv->mii)
>> +		return -ENOMEM;
>> +
>> +	priv->ds = dsa_switch_alloc(dev, DSA_MAX_PORTS);
> 
> If you know how many ports there are, it is better to pass it.

done

>> +	if (!priv->ds)
>> +		return -ENOMEM;
>> +
>> +	priv->ds->priv = priv;
>> +	priv->ds->ops = &gswip_switch_ops;
>> +	priv->dev = dev;
>> +	priv->cpu_port = 6;
>> +
>> +	/* bring up the mdio bus */
>> +	mdio_np = of_find_compatible_node(pdev->dev.of_node, NULL,
>> +					  "lantiq,xrx200-mdio");
>> +	if (mdio_np) {
>> +		err = gswip_mdio(priv, mdio_np);
>> +		if (err) {
>> +			dev_err(dev, "mdio probe failed\n");
>> +			return err;
>> +		}
>> +	}
>> +
>> +	platform_set_drvdata(pdev, priv);
>> +
>> +	err = dsa_register_switch(priv->ds);
>> +	if (err) {
>> +		dev_err(dev, "dsa switch register failed: %i\n", err);
>> +		if (mdio_np)
>> +			mdiobus_unregister(priv->ds->slave_mii_bus);
>> +	}
>> +
>> +	return err;
>> +}
> 
>> +static const struct of_device_id gswip_of_match[] = {
>> +	{ .compatible = "lantiq,xrx200-gswip" },
>> +	{},
>> +};
> 
> Please add device tree documentation.

Will do that.

> 
>> +MODULE_DEVICE_TABLE(of, xrx200_match);
>> +
>> +static struct platform_driver gswip_driver = {
>> +	.probe = gswip_probe,
>> +	.remove = gswip_remove,
>> +	.driver = {
>> +		.name = "gswip",
>> +		.of_match_table = gswip_of_match,
>> +	},
>> +};
>> +#define MC_ENTRY(val, msk, ns, out, len, type, flags, ipv4_len) \
>> +	{ val, msk, (ns << 10 | out << 4 | len >> 1),\
>> +		(len & 1) << 15 | type << 13 | flags << 9 | ipv4_len << 8 }
>> +static const struct gswip_pce_microcode gswip_pce_microcode[] = {
> 
> How big is this table? I'm wondering if it should be loaded from
> /lib/firmware. Or can it be marked __initdata?

This is sort of a firmware, but it is also in the GPL driver.
Currently the probe function is not marked __init so we can not make
this easily __initdata.
It has 64 entries of 8 bytes each so, 512 bytes, I think we can put this
into the code.

Hauke

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 3/4] net: lantiq: Add Lantiq / Intel vrx200 Ethernet driver
  2018-07-29 15:53         ` Hauke Mehrtens
@ 2018-07-29 16:40           ` Andrew Lunn
  2018-07-29 17:44             ` Hauke Mehrtens
  0 siblings, 1 reply; 29+ messages in thread
From: Andrew Lunn @ 2018-07-29 16:40 UTC (permalink / raw)
  To: Hauke Mehrtens
  Cc: davem, netdev, vivien.didelot, f.fainelli, john, linux-mips, dev,
	hauke.mehrtens

> I am thinking about merging this into the switch driver, then we do not
> have to configure the dependency any more.

Hi Hauke

Are there any PHYs which are not part of the switch?

Making it part of the switch driver would make sense. Are there any
backwards compatibility issues? I don't actually see any boards in
mailine using the compatible strings.

Another option would be to write an independent mdio driver, and make
firmware download part of that. That gives the advantage of supporting
PHYs which are not part of the switch.

     Andrew

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 4/4] net: dsa: Add Lantiq / Intel DSA driver for vrx200
  2018-07-29 16:25     ` Hauke Mehrtens
@ 2018-07-29 16:49       ` Andrew Lunn
  0 siblings, 0 replies; 29+ messages in thread
From: Andrew Lunn @ 2018-07-29 16:49 UTC (permalink / raw)
  To: Hauke Mehrtens
  Cc: davem, netdev, vivien.didelot, f.fainelli, john, linux-mips, dev,
	hauke.mehrtens

> >> +static const struct gswip_rmon_cnt_desc gswip_rmon_cnt[] = {
> >> +	/** Receive Packet Count (only packets that are accepted and not discarded). */
> >> +	MIB_DESC(1, 0x1F, "RxGoodPkts"),
> >> +	/** Receive Size 1024-1522 (or more, if configured) Packet Count. */
> >> +	MIB_DESC(1, 0x17, "RxMaxBytePkts"),
> >> +	/** Transmit Size 1024-1522 (or more, if configured) Packet Count. */
> >> +	MIB_DESC(1, 0x05, "TxMaxBytePkts"),
> > 
> > Most of the comments here don't add anything useful. Maybe remove
> > them?
> 
> Ok I removed them.

The comments i left above are useful, since they give additional
information which is not obvious from the name.

> Are the names ok, or should they follow any Linux definition?

There are no standard names. So each driver tends to be different.

> > Please return ETIMEOUT when needed. Maybe use one of the variants of
> > readx_poll_timeout().
> 
> I am returning ETIMEOUT now.
> 
> When I would use readx_poll_timeout() I can not use the gswip_mdio_r()
> function, because it takes two arguments and would have to use readl
> directly.

Yes, they don't always fit, which is why is said "maybe".

> > The names make this unclear. The callback is used to configure the MAC
> > layer when something happens at the PHY layer. phyaddr does not appear
> > to be an address, not should it be doing anything to a PHY.
> 
> I renamed this to phyconf, as this contains multiple configuration
> values. This tells the mac what settings the phy wants to use.

macconf might be better, since this is configuring the MAC, not the
PHY.

> This is sort of a firmware, but it is also in the GPL driver.
> Currently the probe function is not marked __init so we can not make
> this easily __initdata.
> It has 64 entries of 8 bytes each so, 512 bytes, I think we can put this
> into the code.

512 bytes is fine.

    Andrew

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 3/4] net: lantiq: Add Lantiq / Intel vrx200 Ethernet driver
  2018-07-29 16:40           ` Andrew Lunn
@ 2018-07-29 17:44             ` Hauke Mehrtens
  2018-07-29 18:10               ` Andrew Lunn
  0 siblings, 1 reply; 29+ messages in thread
From: Hauke Mehrtens @ 2018-07-29 17:44 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: davem, netdev, vivien.didelot, f.fainelli, john, linux-mips, dev,
	hauke.mehrtens

On 07/29/2018 06:40 PM, Andrew Lunn wrote:
>> I am thinking about merging this into the switch driver, then we do not
>> have to configure the dependency any more.
> 
> Hi Hauke
> 
> Are there any PHYs which are not part of the switch?

The embedded PHYs are only connected to the switch in this SoC and on
all other SoCs from this line I am aware of.

> Making it part of the switch driver would make sense. Are there any
> backwards compatibility issues? I don't actually see any boards in
> mailine using the compatible strings.

There is currently no device tree file added for any board in mainline.
I would then prefer to add this to the switch driver.

I have to make sure the firmware gets loaded before we scan the MDIO
bus. When no FW is loaded they do not get detected.

More recent SoC have more embedded Ethernet PHYs so I would like to
support a variable number of these PHYs.

The firmware is 64KBytes big and we have to load that into continuous
memory which is then used by the PHY itself. When we are late in the
boot process we could run into memory problems, most devices have 64MB
or 128MB of RAM.

How should the device tree binding should look like?

Should I create an extra sub node:

gswip: gswip@E108000 {
	#address-cells = <1>;
	#size-cells = <0>;
	compatible = "lantiq,xrx200-gswip";
	reg = <	0xE108000 0x3000 /* switch */
		0xE10B100 0x70 /* mdio */
		0xE10B1D8 0x30 /* mii */
		>;
	dsa,member = <0 0>;

	ports {
		#address-cells = <1>;
		#size-cells = <0>;

		port@0 {
			reg = <0>;
			label = "lan3";
			phy-mode = "rgmii";
			phy-handle = <&phy0>;
		};
		....
	};

	mdio@0 {
		#address-cells = <1>;
		#size-cells = <0>;
		compatible = "lantiq,xrx200-mdio";
		reg = <0>;

		phy0: ethernet-phy@0 {
			reg = <0x0>;
		};
		....
	};

	# this would be the new part
	phys {
		gphy0: gphy@20 {
			compatible = "lantiq,xrx200a2x-gphy";
			reg = <0x20 0x4>;
			rcu = <&rcu0>;

			resets = <&reset0 31 30>, <&reset1 7 7>;
			reset-names = "gphy", "gphy2";
			clocks = <&pmu0 XRX200_PMU_GATE_GPHY>;
			lantiq,gphy-mode = <GPHY_MODE_GE>;
		};
		....
	};
};

> Another option would be to write an independent mdio driver, and make
> firmware download part of that. That gives the advantage of supporting
> PHYs which are not part of the switch.
> 
>      Andrew
> 

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH 3/4] net: lantiq: Add Lantiq / Intel vrx200 Ethernet driver
  2018-07-29 17:44             ` Hauke Mehrtens
@ 2018-07-29 18:10               ` Andrew Lunn
  0 siblings, 0 replies; 29+ messages in thread
From: Andrew Lunn @ 2018-07-29 18:10 UTC (permalink / raw)
  To: Hauke Mehrtens
  Cc: davem, netdev, vivien.didelot, f.fainelli, john, linux-mips, dev,
	hauke.mehrtens

> The embedded PHYs are only connected to the switch in this SoC and on
> all other SoCs from this line I am aware of.

Hi Hauke

O.K, then it makes sense to have it part of the switch driver.

> The firmware is 64KBytes big and we have to load that into continuous
> memory which is then used by the PHY itself. When we are late in the
> boot process we could run into memory problems, most devices have 64MB
> or 128MB of RAM.

You might want to look at using CMA. I've never used it myself, so
cannot help much.

> How should the device tree binding should look like?
> 
> Should I create an extra sub node:
> 
> gswip: gswip@E108000 {
> 	#address-cells = <1>;
> 	#size-cells = <0>;
> 	compatible = "lantiq,xrx200-gswip";
> 	reg = <	0xE108000 0x3000 /* switch */
> 		0xE10B100 0x70 /* mdio */
> 		0xE10B1D8 0x30 /* mii */
> 		>;
> 	dsa,member = <0 0>;
> 
> 	ports {
> 		#address-cells = <1>;
> 		#size-cells = <0>;
> 
> 		port@0 {
> 			reg = <0>;
> 			label = "lan3";
> 			phy-mode = "rgmii";
> 			phy-handle = <&phy0>;
> 		};
> 		....
> 	};
> 
> 	mdio@0 {
> 		#address-cells = <1>;
> 		#size-cells = <0>;
> 		compatible = "lantiq,xrx200-mdio";
> 		reg = <0>;
> 
> 		phy0: ethernet-phy@0 {
> 			reg = <0x0>;
> 		};
> 		....
> 	};
> 
> 	# this would be the new part
> 	phys {
> 		gphy0: gphy@20 {
> 			compatible = "lantiq,xrx200a2x-gphy";

It would be good to make it clear this is for firmware download. So
scatter "firmware" or "fw" in some of these names. What we don't want
is a mix up with phy's within the mdio subtree. Otherwise this looks
good. But you should cross post the device tree binding to the device
tree mailing list.

	Andrew

^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2018-07-29 19:41 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-07-21 19:13 [PATCH 0/4] net: Add support for Lantiq / Intel vrx200 network Hauke Mehrtens
2018-07-21 19:13 ` [PATCH 1/4] MIPS: lantiq: Do not enable IRQs in dma open Hauke Mehrtens
2018-07-24  0:19   ` Paul Burton
2018-07-24  5:32     ` Hauke Mehrtens
2018-07-24  5:39       ` David Miller
2018-07-21 19:13 ` [PATCH 2/4] net: dsa: Add Lantiq / Intel GSWIP tag support Hauke Mehrtens
2018-07-25 14:20   ` Andrew Lunn
2018-07-29 14:01     ` Hauke Mehrtens
2018-07-21 19:13 ` [PATCH 3/4] net: lantiq: Add Lantiq / Intel vrx200 Ethernet driver Hauke Mehrtens
2018-07-21 20:25   ` John Crispin
2018-07-21 23:18     ` Hauke Mehrtens
2018-07-24  0:34   ` Paul Burton
2018-07-24  5:27     ` Hauke Mehrtens
2018-07-25 15:28   ` Andrew Lunn
2018-07-29 14:03     ` Hauke Mehrtens
2018-07-29 15:51       ` Andrew Lunn
2018-07-29 15:53         ` Hauke Mehrtens
2018-07-29 16:40           ` Andrew Lunn
2018-07-29 17:44             ` Hauke Mehrtens
2018-07-29 18:10               ` Andrew Lunn
2018-07-21 19:13 ` [PATCH 4/4] net: dsa: Add Lantiq / Intel DSA driver for vrx200 Hauke Mehrtens
2018-07-22  3:17   ` David Miller
2018-07-22  9:29     ` Hauke Mehrtens
2018-07-22  9:29     ` Hauke Mehrtens
2018-07-25 16:12   ` Andrew Lunn
2018-07-29 16:25     ` Hauke Mehrtens
2018-07-29 16:49       ` Andrew Lunn
2018-07-25 16:32   ` John Crispin
2018-07-25 16:46     ` Andrew Lunn

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.