linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/11] mediatek: add support for MediaTek Ethernet MAC
@ 2020-05-05 14:02 Bartosz Golaszewski
  2020-05-05 14:02 ` [PATCH 01/11] dt-bindings: add a binding document for MediaTek PERICFG controller Bartosz Golaszewski
                   ` (10 more replies)
  0 siblings, 11 replies; 40+ messages in thread
From: Bartosz Golaszewski @ 2020-05-05 14:02 UTC (permalink / raw)
  To: Rob Herring, David S . Miller, Matthias Brugger, Felix Fietkau,
	John Crispin, Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann,
	Fabien Parent
  Cc: devicetree, linux-kernel, netdev, linux-arm-kernel,
	linux-mediatek, Bartosz Golaszewski

From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

This adds support for the Ethernet Controller present on MediaTeK SoCs
from the MT8* family.

The first two patches add binding documents for the PERICFG syscon and
for the MAC itself.

Patches 3/11 & 4/11 do some cleanup of the mediatek ethernet drivers
directory.

Patch 5/11 provides a devres variant of register_netdev().

Patch 6/11 adds the new ethernet driver.

The rest of the patches add DT fixups for the boards already supported
upstream.

Bartosz Golaszewski (11):
  dt-bindings: add a binding document for MediaTek PERICFG controller
  dt-bindings: new: add yaml bindings for MediaTek Ethernet MAC
  net: ethernet: mediatek: rename Kconfig prompt
  net: ethernet: mediatek: remove unnecessary spaces from Makefile
  net: core: provide devm_register_netdev()
  net: ethernet: mtk-eth-mac: new driver
  ARM64: dts: mediatek: add pericfg syscon to mt8516.dtsi
  ARM64: dts: mediatek: add the ethernet node to mt8516.dtsi
  ARM64: dts: mediatek: add an alias for ethernet0 for pumpkin boards
  ARM64: dts: mediatek: add ethernet pins for pumpkin boards
  ARM64: dts: mediatek: enable ethernet on pumpkin boards

 .../arm/mediatek/mediatek,pericfg.yaml        |   34 +
 .../bindings/net/mediatek,eth-mac.yaml        |   80 +
 arch/arm64/boot/dts/mediatek/mt8516.dtsi      |   17 +
 .../boot/dts/mediatek/pumpkin-common.dtsi     |   34 +
 drivers/net/ethernet/mediatek/Kconfig         |    8 +-
 drivers/net/ethernet/mediatek/Makefile        |    3 +-
 drivers/net/ethernet/mediatek/mtk_eth_mac.c   | 1476 +++++++++++++++++
 include/linux/netdevice.h                     |    4 +
 net/core/dev.c                                |   48 +
 net/ethernet/eth.c                            |    1 +
 10 files changed, 1703 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.yaml
 create mode 100644 Documentation/devicetree/bindings/net/mediatek,eth-mac.yaml
 create mode 100644 drivers/net/ethernet/mediatek/mtk_eth_mac.c

-- 
2.25.0


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

* [PATCH 01/11] dt-bindings: add a binding document for MediaTek PERICFG controller
  2020-05-05 14:02 [PATCH 00/11] mediatek: add support for MediaTek Ethernet MAC Bartosz Golaszewski
@ 2020-05-05 14:02 ` Bartosz Golaszewski
  2020-05-13  2:38   ` Rob Herring
  2020-05-05 14:02 ` [PATCH 02/11] dt-bindings: new: add yaml bindings for MediaTek Ethernet MAC Bartosz Golaszewski
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 40+ messages in thread
From: Bartosz Golaszewski @ 2020-05-05 14:02 UTC (permalink / raw)
  To: Rob Herring, David S . Miller, Matthias Brugger, Felix Fietkau,
	John Crispin, Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann,
	Fabien Parent
  Cc: devicetree, linux-kernel, netdev, linux-arm-kernel,
	linux-mediatek, Bartosz Golaszewski

From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

This adds a binding document for the PERICFG controller present on
MediaTek SoCs. For now the only variant supported is 'mt8516-pericfg'.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 .../arm/mediatek/mediatek,pericfg.yaml        | 34 +++++++++++++++++++
 1 file changed, 34 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.yaml

diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.yaml b/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.yaml
new file mode 100644
index 000000000000..74b2a6173ffb
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.yaml
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/arm/mediatek/mediatek,pericfg.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: MediaTek Peripheral Configuration Controller
+
+maintainers:
+  - Bartosz Golaszewski <bgolaszewski@baylibre.com>
+
+properties:
+  compatible:
+    oneOf:
+      - items:
+        - enum:
+          - mediatek,pericfg
+        - const: syscon
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    pericfg: pericfg@10003050 {
+        compatible = "mediatek,mt8516-pericfg", "syscon";
+        reg = <0 0x10003050 0 0x1000>;
+    };
-- 
2.25.0


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

* [PATCH 02/11] dt-bindings: new: add yaml bindings for MediaTek Ethernet MAC
  2020-05-05 14:02 [PATCH 00/11] mediatek: add support for MediaTek Ethernet MAC Bartosz Golaszewski
  2020-05-05 14:02 ` [PATCH 01/11] dt-bindings: add a binding document for MediaTek PERICFG controller Bartosz Golaszewski
@ 2020-05-05 14:02 ` Bartosz Golaszewski
  2020-05-13  2:41   ` Rob Herring
  2020-05-05 14:02 ` [PATCH 03/11] net: ethernet: mediatek: rename Kconfig prompt Bartosz Golaszewski
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 40+ messages in thread
From: Bartosz Golaszewski @ 2020-05-05 14:02 UTC (permalink / raw)
  To: Rob Herring, David S . Miller, Matthias Brugger, Felix Fietkau,
	John Crispin, Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann,
	Fabien Parent
  Cc: devicetree, linux-kernel, netdev, linux-arm-kernel,
	linux-mediatek, Bartosz Golaszewski

From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

This adds yaml DT bindings for the MediaTek Ethernet MAC present on the
mt8* family of SoCs.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 .../bindings/net/mediatek,eth-mac.yaml        | 80 +++++++++++++++++++
 1 file changed, 80 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/mediatek,eth-mac.yaml

diff --git a/Documentation/devicetree/bindings/net/mediatek,eth-mac.yaml b/Documentation/devicetree/bindings/net/mediatek,eth-mac.yaml
new file mode 100644
index 000000000000..7682fe9d8109
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/mediatek,eth-mac.yaml
@@ -0,0 +1,80 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/mediatek,eth-mac.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek Ethernet MAC Controller
+
+maintainers:
+  - Bartosz Golaszewski <bgolaszewski@baylibre.com>
+
+description:
+  This Ethernet MAC is used on the MT8* family of SoCs from MediaTek.
+  It's compliant with 802.3 standards and supports half- and full-duplex
+  modes with flow-control as well as CRC offloading and VLAN tags.
+
+properties:
+  compatible:
+    enum:
+      - mediatek,mt8516-eth
+      - mediatek,mt8518-eth
+      - mediatek,mt8175-eth
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    minItems: 3
+    maxItems: 3
+
+  clock-names:
+    additionalItems: false
+    items:
+      - const: core
+      - const: reg
+      - const: trans
+
+  mediatek,pericfg:
+    $ref: /schemas/types.yaml#definitions/phandle
+    description:
+      Phandle to the device containing the PERICFG register range.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - mediatek,pericfg
+  - phy-handle
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/mt8516-clk.h>
+
+    ethernet: ethernet@11180000 {
+        compatible = "mediatek,mt8516-eth";
+        reg = <0 0x11180000 0 0x1000>;
+        mediatek,pericfg = <&pericfg>;
+        interrupts = <GIC_SPI 111 IRQ_TYPE_LEVEL_LOW>;
+        clocks = <&topckgen CLK_TOP_RG_ETH>,
+                 <&topckgen CLK_TOP_66M_ETH>,
+                 <&topckgen CLK_TOP_133M_ETH>;
+        clock-names = "core", "reg", "trans";
+        phy-handle = <&eth_phy>;
+        phy-mode = "rmii";
+
+        mdio {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            eth_phy: ethernet-phy@0 {
+                reg = <0>;
+            };
+        };
+    };
-- 
2.25.0


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

* [PATCH 03/11] net: ethernet: mediatek: rename Kconfig prompt
  2020-05-05 14:02 [PATCH 00/11] mediatek: add support for MediaTek Ethernet MAC Bartosz Golaszewski
  2020-05-05 14:02 ` [PATCH 01/11] dt-bindings: add a binding document for MediaTek PERICFG controller Bartosz Golaszewski
  2020-05-05 14:02 ` [PATCH 02/11] dt-bindings: new: add yaml bindings for MediaTek Ethernet MAC Bartosz Golaszewski
@ 2020-05-05 14:02 ` Bartosz Golaszewski
  2020-05-05 14:02 ` [PATCH 04/11] net: ethernet: mediatek: remove unnecessary spaces from Makefile Bartosz Golaszewski
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 40+ messages in thread
From: Bartosz Golaszewski @ 2020-05-05 14:02 UTC (permalink / raw)
  To: Rob Herring, David S . Miller, Matthias Brugger, Felix Fietkau,
	John Crispin, Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann,
	Fabien Parent
  Cc: devicetree, linux-kernel, netdev, linux-arm-kernel,
	linux-mediatek, Bartosz Golaszewski

From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

We'll soon by adding a second MediaTek Ethernet driver so modify the
Kconfig prompt.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 drivers/net/ethernet/mediatek/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/mediatek/Kconfig b/drivers/net/ethernet/mediatek/Kconfig
index 4968352ba188..5079b8090f16 100644
--- a/drivers/net/ethernet/mediatek/Kconfig
+++ b/drivers/net/ethernet/mediatek/Kconfig
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 config NET_VENDOR_MEDIATEK
-	bool "MediaTek ethernet driver"
+	bool "MediaTek devices"
 	depends on ARCH_MEDIATEK || SOC_MT7621 || SOC_MT7620
 	---help---
 	  If you have a Mediatek SoC with ethernet, say Y.
-- 
2.25.0


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

* [PATCH 04/11] net: ethernet: mediatek: remove unnecessary spaces from Makefile
  2020-05-05 14:02 [PATCH 00/11] mediatek: add support for MediaTek Ethernet MAC Bartosz Golaszewski
                   ` (2 preceding siblings ...)
  2020-05-05 14:02 ` [PATCH 03/11] net: ethernet: mediatek: rename Kconfig prompt Bartosz Golaszewski
@ 2020-05-05 14:02 ` Bartosz Golaszewski
  2020-05-05 14:02 ` [PATCH 05/11] net: core: provide devm_register_netdev() Bartosz Golaszewski
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 40+ messages in thread
From: Bartosz Golaszewski @ 2020-05-05 14:02 UTC (permalink / raw)
  To: Rob Herring, David S . Miller, Matthias Brugger, Felix Fietkau,
	John Crispin, Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann,
	Fabien Parent
  Cc: devicetree, linux-kernel, netdev, linux-arm-kernel,
	linux-mediatek, Bartosz Golaszewski

From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

The Makefile formatting in the kernel tree usually doesn't use tabs,
so remove them before we add a second driver.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 drivers/net/ethernet/mediatek/Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/mediatek/Makefile b/drivers/net/ethernet/mediatek/Makefile
index 2d8362f9341b..3362fb7ef859 100644
--- a/drivers/net/ethernet/mediatek/Makefile
+++ b/drivers/net/ethernet/mediatek/Makefile
@@ -3,5 +3,5 @@
 # Makefile for the Mediatek SoCs built-in ethernet macs
 #
 
-obj-$(CONFIG_NET_MEDIATEK_SOC)                 += mtk_eth.o
+obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o
 mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o
-- 
2.25.0


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

* [PATCH 05/11] net: core: provide devm_register_netdev()
  2020-05-05 14:02 [PATCH 00/11] mediatek: add support for MediaTek Ethernet MAC Bartosz Golaszewski
                   ` (3 preceding siblings ...)
  2020-05-05 14:02 ` [PATCH 04/11] net: ethernet: mediatek: remove unnecessary spaces from Makefile Bartosz Golaszewski
@ 2020-05-05 14:02 ` Bartosz Golaszewski
  2020-05-05 17:31   ` Jakub Kicinski
  2020-05-05 19:25   ` Edwin Peer
  2020-05-05 14:02 ` [PATCH 06/11] net: ethernet: mtk-eth-mac: new driver Bartosz Golaszewski
                   ` (5 subsequent siblings)
  10 siblings, 2 replies; 40+ messages in thread
From: Bartosz Golaszewski @ 2020-05-05 14:02 UTC (permalink / raw)
  To: Rob Herring, David S . Miller, Matthias Brugger, Felix Fietkau,
	John Crispin, Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann,
	Fabien Parent
  Cc: devicetree, linux-kernel, netdev, linux-arm-kernel,
	linux-mediatek, Bartosz Golaszewski

From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

Provide devm_register_netdev() - a device resource managed variant
of register_netdev(). This new helper will only work for net_device
structs that have a parent device assigned and are devres managed too.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 include/linux/netdevice.h |  4 ++++
 net/core/dev.c            | 48 +++++++++++++++++++++++++++++++++++++++
 net/ethernet/eth.c        |  1 +
 3 files changed, 53 insertions(+)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 130a668049ab..433bd5ca2efc 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1515,6 +1515,8 @@ struct net_device_ops {
  * @IFF_FAILOVER_SLAVE: device is lower dev of a failover master device
  * @IFF_L3MDEV_RX_HANDLER: only invoke the rx handler of L3 master device
  * @IFF_LIVE_RENAME_OK: rename is allowed while device is up and running
+ * @IFF_IS_DEVRES: this structure was allocated dynamically and is managed by
+ *	devres
  */
 enum netdev_priv_flags {
 	IFF_802_1Q_VLAN			= 1<<0,
@@ -1548,6 +1550,7 @@ enum netdev_priv_flags {
 	IFF_FAILOVER_SLAVE		= 1<<28,
 	IFF_L3MDEV_RX_HANDLER		= 1<<29,
 	IFF_LIVE_RENAME_OK		= 1<<30,
+	IFF_IS_DEVRES			= 1<<31,
 };
 
 #define IFF_802_1Q_VLAN			IFF_802_1Q_VLAN
@@ -4206,6 +4209,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
 			 count)
 
 int register_netdev(struct net_device *dev);
+int devm_register_netdev(struct net_device *ndev);
 void unregister_netdev(struct net_device *dev);
 
 /* General hardware address lists handling functions */
diff --git a/net/core/dev.c b/net/core/dev.c
index 522288177bbd..99db537c9468 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -9519,6 +9519,54 @@ int register_netdev(struct net_device *dev)
 }
 EXPORT_SYMBOL(register_netdev);
 
+struct netdevice_devres {
+	struct net_device *ndev;
+};
+
+static void devm_netdev_release(struct device *dev, void *this)
+{
+	struct netdevice_devres *res = this;
+
+	unregister_netdev(res->ndev);
+}
+
+/**
+ *	devm_register_netdev - resource managed variant of register_netdev()
+ *	@ndev: device to register
+ *
+ *	This is a devres variant of register_netdev() for which the unregister
+ *	function will be call automatically when the parent device of ndev
+ *	is detached.
+ */
+int devm_register_netdev(struct net_device *ndev)
+{
+	struct netdevice_devres *dr;
+	int ret;
+
+	/* struct net_device itself must be devres managed. */
+	BUG_ON(!(ndev->priv_flags & IFF_IS_DEVRES));
+	/* struct net_device must have a parent device - it will be the device
+	 * managing this resource.
+	 */
+	BUG_ON(!ndev->dev.parent);
+
+	dr = devres_alloc(devm_netdev_release, sizeof(*dr), GFP_KERNEL);
+	if (!dr)
+		return -ENOMEM;
+
+	ret = register_netdev(ndev);
+	if (ret) {
+		devres_free(dr);
+		return ret;
+	}
+
+	dr->ndev = ndev;
+	devres_add(ndev->dev.parent, dr);
+
+	return 0;
+}
+EXPORT_SYMBOL(devm_register_netdev);
+
 int netdev_refcnt_read(const struct net_device *dev)
 {
 	int i, refcnt = 0;
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index c8b903302ff2..ce9b5e576f20 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -423,6 +423,7 @@ struct net_device *devm_alloc_etherdev_mqs(struct device *dev, int sizeof_priv,
 
 	*dr = netdev;
 	devres_add(dev, dr);
+	netdev->priv_flags |= IFF_IS_DEVRES;
 
 	return netdev;
 }
-- 
2.25.0


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

* [PATCH 06/11] net: ethernet: mtk-eth-mac: new driver
  2020-05-05 14:02 [PATCH 00/11] mediatek: add support for MediaTek Ethernet MAC Bartosz Golaszewski
                   ` (4 preceding siblings ...)
  2020-05-05 14:02 ` [PATCH 05/11] net: core: provide devm_register_netdev() Bartosz Golaszewski
@ 2020-05-05 14:02 ` Bartosz Golaszewski
  2020-05-05 17:47   ` Andrew Lunn
                     ` (3 more replies)
  2020-05-05 14:02 ` [PATCH 07/11] ARM64: dts: mediatek: add pericfg syscon to mt8516.dtsi Bartosz Golaszewski
                   ` (4 subsequent siblings)
  10 siblings, 4 replies; 40+ messages in thread
From: Bartosz Golaszewski @ 2020-05-05 14:02 UTC (permalink / raw)
  To: Rob Herring, David S . Miller, Matthias Brugger, Felix Fietkau,
	John Crispin, Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann,
	Fabien Parent
  Cc: devicetree, linux-kernel, netdev, linux-arm-kernel,
	linux-mediatek, Bartosz Golaszewski

From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

This adds the driver for the MediaTek Ethernet MAC used on the MT8* SoC
family. For now we only support full-duplex.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 drivers/net/ethernet/mediatek/Kconfig       |    6 +
 drivers/net/ethernet/mediatek/Makefile      |    1 +
 drivers/net/ethernet/mediatek/mtk_eth_mac.c | 1476 +++++++++++++++++++
 3 files changed, 1483 insertions(+)
 create mode 100644 drivers/net/ethernet/mediatek/mtk_eth_mac.c

diff --git a/drivers/net/ethernet/mediatek/Kconfig b/drivers/net/ethernet/mediatek/Kconfig
index 5079b8090f16..5c3793076765 100644
--- a/drivers/net/ethernet/mediatek/Kconfig
+++ b/drivers/net/ethernet/mediatek/Kconfig
@@ -14,4 +14,10 @@ config NET_MEDIATEK_SOC
 	  This driver supports the gigabit ethernet MACs in the
 	  MediaTek SoC family.
 
+config NET_MEDIATEK_MAC
+	tristate "MediaTek Ethernet MAC support"
+	select PHYLIB
+	help
+	  This driver supports the ethernet IP on MediaTek MT85** SoCs.
+
 endif #NET_VENDOR_MEDIATEK
diff --git a/drivers/net/ethernet/mediatek/Makefile b/drivers/net/ethernet/mediatek/Makefile
index 3362fb7ef859..f7f5638943a0 100644
--- a/drivers/net/ethernet/mediatek/Makefile
+++ b/drivers/net/ethernet/mediatek/Makefile
@@ -5,3 +5,4 @@
 
 obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o
 mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o
+obj-$(CONFIG_NET_MEDIATEK_MAC) += mtk_eth_mac.o
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_mac.c b/drivers/net/ethernet/mediatek/mtk_eth_mac.c
new file mode 100644
index 000000000000..e6e796e65228
--- /dev/null
+++ b/drivers/net/ethernet/mediatek/mtk_eth_mac.c
@@ -0,0 +1,1476 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020 MediaTek Corporation
+ * Copyright (c) 2020 BayLibre SAS
+ *
+ * Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/etherdevice.h>
+#include <linux/jiffies.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+
+#define MTK_MAC_DRVNAME				"mtk_eth_mac"
+#define MTK_MAC_VERSION				"1.0"
+
+#define MTK_MAC_WAIT_TIMEOUT			300
+#define MTK_MAC_MAX_FRAME_SIZE			1514
+#define MTK_MAC_SKB_ALIGNMENT			16
+#define MTK_MAC_NAPI_WEIGHT			64
+#define MTK_MAC_HASHTABLE_MC_LIMIT		256
+#define MTK_MAC_HASHTABLE_SIZE_MAX		512
+
+static const char *const mtk_mac_clk_names[] = { "core", "reg", "trans" };
+#define MTK_MAC_NCLKS ARRAY_SIZE(mtk_mac_clk_names)
+
+/* PHY Control Register 0 */
+#define MTK_MAC_REG_PHY_CTRL0			0x0000
+#define MTK_MAC_BIT_PHY_CTRL0_WTCMD		BIT(13)
+#define MTK_MAC_BIT_PHY_CTRL0_RDCMD		BIT(14)
+#define MTK_MAC_BIT_PHY_CTRL0_RWOK		BIT(15)
+#define MTK_MAC_MSK_PHY_CTRL0_PREG		GENMASK(12, 8)
+#define MTK_MAC_OFF_PHY_CTRL0_PREG		8
+#define MTK_MAC_MSK_PHY_CTRL0_RWDATA		GENMASK(31, 16)
+#define MTK_MAC_OFF_PHY_CTRL0_RWDATA		16
+
+/* PHY Control Register 1 */
+#define MTK_MAC_REG_PHY_CTRL1			0x0004
+#define MTK_MAC_BIT_PHY_CTRL1_LINK_ST		BIT(0)
+#define MTK_MAC_BIT_PHY_CTRL1_AN_EN		BIT(8)
+#define MTK_MAC_OFF_PHY_CTRL1_FORCE_SPD		9
+#define MTK_MAC_VAL_PHY_CTRL1_FORCE_SPD_10M	0x00
+#define MTK_MAC_VAL_PHY_CTRL1_FORCE_SPD_100M	0x01
+#define MTK_MAC_VAL_PHY_CTRL1_FORCE_SPD_1000M	0x02
+#define MTK_MAC_BIT_PHY_CTRL1_FORCE_DPX		BIT(11)
+#define MTK_MAC_BIT_PHY_CTRL1_FORCE_FC_RX	BIT(12)
+#define MTK_MAC_BIT_PHY_CTRL1_FORCE_FC_TX	BIT(13)
+
+/* MAC Configuration Register */
+#define MTK_MAC_REG_MAC_CFG			0x0008
+#define MTK_MAC_OFF_MAC_CFG_IPG			10
+#define MTK_MAC_VAL_MAC_CFG_IPG_96BIT		GENMASK(4, 0)
+#define MTK_MAC_BIT_MAC_CFG_MAXLEN_1522		BIT(16)
+#define MTK_MAC_BIT_MAC_CFG_AUTO_PAD		BIT(19)
+#define MTK_MAC_BIT_MAC_CFG_CRC_STRIP		BIT(20)
+#define MTK_MAC_BIT_MAC_CFG_VLAN_STRIP		BIT(22)
+#define MTK_MAC_BIT_MAC_CFG_NIC_PD		BIT(31)
+
+/* Flow-Control Configuration Register */
+#define MTK_MAC_REG_FC_CFG			0x000c
+#define MTK_MAC_BIT_FC_CFG_BP_EN		BIT(7)
+#define MTK_MAC_BIT_FC_CFG_UC_PAUSE_DIR	BIT(8)
+#define MTK_MAC_OFF_FC_CFG_SEND_PAUSE_TH	16
+#define MTK_MAC_VAL_FC_CFG_SEND_PAUSE_TH_2K	0x800
+
+/* ARL Configuration Register */
+#define MTK_MAC_REG_ARL_CFG			0x0010
+#define MTK_MAC_BIT_ARL_CFG_HASH_ALG		BIT(0)
+#define MTK_MAC_BIT_ARL_CFG_MISC_MODE		BIT(4)
+
+/* MAC High and Low Bytes Registers */
+#define MTK_MAC_REG_MY_MAC_H			0x0014
+#define MTK_MAC_REG_MY_MAC_L			0x0018
+
+/* Hash Table Control Register */
+#define MTK_MAC_REG_HASH_CTRL			0x001c
+#define MTK_MAC_MSK_HASH_CTRL_HASH_BIT_ADDR	GENMASK(8, 0)
+#define MTK_MAC_BIT_HASH_CTRL_HASH_BIT_DATA	BIT(12)
+#define MTK_MAC_BIT_HASH_CTRL_ACC_CMD		BIT(13)
+#define MTK_MAC_BIT_HASH_CTRL_CMD_START		BIT(14)
+#define MTK_MAC_BIT_HASH_CTRL_BIST_EN		BIT(31)
+
+/* TX DMA Control Register */
+#define MTK_MAC_REG_TX_DMA_CTRL			0x0034
+#define MTK_MAC_BIT_TX_DMA_CTRL_START		BIT(0)
+#define MTK_MAC_BIT_TX_DMA_CTRL_STOP		BIT(1)
+#define MTK_MAC_BIT_TX_DMA_CTRL_RESUME		BIT(2)
+
+/* RX DMA Control Register */
+#define MTK_MAC_REG_RX_DMA_CTRL			0x0038
+#define MTK_MAC_BIT_RX_DMA_CTRL_START		BIT(0)
+#define MTK_MAC_BIT_RX_DMA_CTRL_STOP		BIT(1)
+#define MTK_MAC_BIT_RX_DMA_CTRL_RESUME		BIT(2)
+
+/* DMA Address Registers */
+#define MTK_MAC_REG_TX_DPTR			0x003c
+#define MTK_MAC_REG_RX_DPTR			0x0040
+#define MTK_MAC_REG_TX_BASE_ADDR		0x0044
+#define MTK_MAC_REG_RX_BASE_ADDR		0x0048
+
+/* Interrupt Status Register */
+#define MTK_MAC_REG_INT_STS			0x0050
+#define MTK_MAC_REG_INT_STS_PORT_STS_CHG	BIT(2)
+#define MTK_MAC_REG_INT_STS_MIB_CNT_TH		BIT(3)
+#define MTK_MAC_BIT_INT_STS_FNRC		BIT(6)
+#define MTK_MAC_BIT_INT_STS_TNTC		BIT(8)
+
+/* Interrupt Mask Register */
+#define MTK_MAC_REG_INT_MASK			0x0054
+#define MTK_MAC_BIT_INT_MASK_FNRC		BIT(6)
+
+/* Misc. Config Register */
+#define MTK_MAC_REG_TEST1			0x005c
+#define MTK_MAC_BIT_TEST1_RST_HASH_MBIST	BIT(31)
+
+/* Extended Configuration Register */
+#define MTK_MAC_REG_EXT_CFG			0x0060
+#define MTK_MAC_OFF_EXT_CFG_SND_PAUSE_RLS	16
+#define MTK_MAC_VAL_EXT_CFG_SND_PAUSE_RLS_1K	0x400
+
+/* EthSys Configuration Register */
+#define MTK_MAC_REG_SYS_CONF			0x0094
+#define MTK_MAC_BIT_MII_PAD_OUT_ENABLE		BIT(0)
+#define MTK_MAC_BIT_EXT_MDC_MODE		BIT(1)
+#define MTK_MAC_BIT_SWC_MII_MODE		BIT(2)
+
+/* MAC Clock Configuration Register */
+#define MTK_MAC_REG_MAC_CLK_CONF		0x00ac
+#define MTK_MAC_MSK_MAC_CLK_CONF		GENMASK(7, 0)
+#define MTK_MAC_BIT_CLK_DIV_10			0x0a
+
+/* Counter registers. */
+#define MTK_MAC_REG_C_RXOKPKT			0x0100
+#define MTK_MAC_REG_C_RXOKBYTE			0x0104
+#define MTK_MAC_REG_C_RXRUNT			0x0108
+#define MTK_MAC_REG_C_RXLONG			0x010c
+#define MTK_MAC_REG_C_RXDROP			0x0110
+#define MTK_MAC_REG_C_RXCRC			0x0114
+#define MTK_MAC_REG_C_RXARLDROP			0x0118
+#define MTK_MAC_REG_C_RXVLANDROP		0x011c
+#define MTK_MAC_REG_C_RXCSERR			0x0120
+#define MTK_MAC_REG_C_RXPAUSE			0x0124
+#define MTK_MAC_REG_C_TXOKPKT			0x0128
+#define MTK_MAC_REG_C_TXOKBYTE			0x012c
+#define MTK_MAC_REG_C_TXPAUSECOL		0x0130
+#define MTK_MAC_REG_C_TXRTY			0x0134
+#define MTK_MAC_REG_C_TXSKIP			0x0138
+#define MTK_MAC_REG_C_TX_ARP			0x013c
+#define MTK_MAC_REG_C_RX_RERR			0x01d8
+#define MTK_MAC_REG_C_RX_UNI			0x01dc
+#define MTK_MAC_REG_C_RX_MULTI			0x01e0
+#define MTK_MAC_REG_C_RX_BROAD			0x01e4
+#define MTK_MAC_REG_C_RX_ALIGNERR		0x01e8
+#define MTK_MAC_REG_C_TX_UNI			0x01ec
+#define MTK_MAC_REG_C_TX_MULTI			0x01f0
+#define MTK_MAC_REG_C_TX_BROAD			0x01f4
+#define MTK_MAC_REG_C_TX_TIMEOUT		0x01f8
+#define MTK_MAC_REG_C_TX_LATECOL		0x01fc
+#define MTK_MAC_REG_C_RX_LENGTHERR		0x0214
+#define MTK_MAC_REG_C_RX_TWIST			0x0218
+
+/* Ethernet CFG Control */
+#define MTK_PERICFG_REG_NIC_CFG_CON		0x03c4
+#define MTK_PERICFG_MSK_NIC_CFG_CON_CFG_MII	GENMASK(3, 0)
+#define MTK_PERICFG_BIT_NIC_CFG_CON_RMII	BIT(0)
+
+/* Represents the actual structure of descriptors used by the MAC. We can
+ * reuse the same structure for both TX and RX - the layout is the same, only
+ * the flags differ slightly.
+ */
+struct mtk_mac_ring_desc {
+	/* Contains both the status flags as well as packet length. */
+	u32 status;
+	u32 data_ptr;
+	u32 vtag;
+	u32 reserved;
+} __aligned(4) __packed;
+
+#define MTK_MAC_DESC_MSK_LEN			GENMASK(15, 0)
+#define MTK_MAC_DESC_BIT_RX_CRCE		BIT(24)
+#define MTK_MAC_DESC_BIT_RX_OSIZE		BIT(25)
+#define MTK_MAC_DESC_BIT_INT			BIT(27)
+#define MTK_MAC_DESC_BIT_LS			BIT(28)
+#define MTK_MAC_DESC_BIT_FS			BIT(29)
+#define MTK_MAC_DESC_BIT_EOR			BIT(30)
+#define MTK_MAC_DESC_BIT_COWN			BIT(31)
+
+/* Helper structure for storing data read from/written to descriptors in order
+ * to limit reads from/writes to DMA memory.
+ */
+struct mtk_mac_ring_desc_data {
+	unsigned int len;
+	unsigned int flags;
+	dma_addr_t dma_addr;
+	struct sk_buff *skb;
+};
+
+#define MTK_MAC_RING_NUM_DESCS			128
+#define MTK_MAC_NUM_TX_DESCS			MTK_MAC_RING_NUM_DESCS
+#define MTK_MAC_NUM_RX_DESCS			MTK_MAC_RING_NUM_DESCS
+#define MTK_MAC_NUM_DESCS_TOTAL			(MTK_MAC_RING_NUM_DESCS * 2)
+#define MTK_MAC_DMA_SIZE \
+		(MTK_MAC_NUM_DESCS_TOTAL * sizeof(struct mtk_mac_ring_desc))
+
+struct mtk_mac_ring {
+	struct mtk_mac_ring_desc *descs;
+	struct sk_buff *skbs[MTK_MAC_RING_NUM_DESCS];
+	unsigned int head;
+	unsigned int tail;
+	unsigned int count;
+};
+
+struct mtk_mac_priv {
+	struct regmap *regs;
+	struct regmap *pericfg;
+
+	struct clk_bulk_data clks[MTK_MAC_NCLKS];
+
+	void *ring_base;
+	struct mtk_mac_ring_desc *descs_base;
+	dma_addr_t dma_addr;
+	struct mtk_mac_ring tx_ring;
+	struct mtk_mac_ring rx_ring;
+	struct work_struct tx_work;
+
+	struct mii_bus *mii;
+	struct napi_struct napi;
+
+	struct device_node *phy_node;
+	phy_interface_t phy_intf;
+	struct phy_device *phydev;
+	unsigned int link;
+	int speed;
+	int duplex;
+
+	/* Protects against concurrent descriptor access. */
+	spinlock_t lock;
+	unsigned long lock_flags;
+
+	struct rtnl_link_stats64 stats;
+};
+
+static struct net_device *mtk_mac_get_netdev(struct mtk_mac_priv *priv)
+{
+	char *ptr = (char *)priv;
+
+	return (struct net_device *)(ptr - ALIGN(sizeof(struct net_device),
+						 NETDEV_ALIGN));
+}
+
+static struct device *mtk_mac_get_dev(struct mtk_mac_priv *priv)
+{
+	struct net_device *ndev = mtk_mac_get_netdev(priv);
+
+	return ndev->dev.parent;
+}
+
+static const struct regmap_config mtk_mac_regmap_config = {
+	.reg_bits		= 32,
+	.val_bits		= 32,
+	.reg_stride		= 4,
+	.fast_io		= true,
+};
+
+static void mtk_mac_ring_init(struct mtk_mac_ring *ring,
+			      struct mtk_mac_ring_desc *descs,
+			      unsigned int start_count)
+{
+	memset(ring, 0, sizeof(*ring));
+	ring->descs = descs;
+	ring->head = 0;
+	ring->tail = 0;
+	ring->count = start_count;
+}
+
+static int mtk_mac_ring_pop_tail(struct mtk_mac_ring *ring,
+				 struct mtk_mac_ring_desc_data *desc_data)
+{
+	struct mtk_mac_ring_desc *desc = &ring->descs[ring->tail];
+	unsigned int status;
+
+	dma_rmb();
+	status = desc->status;
+
+	if (!(status & MTK_MAC_DESC_BIT_COWN))
+		return -1;
+
+	desc_data->len = status & MTK_MAC_DESC_MSK_LEN;
+	desc_data->flags = status & ~MTK_MAC_DESC_MSK_LEN;
+	desc_data->dma_addr = desc->data_ptr;
+	desc_data->skb = ring->skbs[ring->tail];
+
+	desc->data_ptr = 0;
+	desc->status = MTK_MAC_DESC_BIT_COWN;
+	if (status & MTK_MAC_DESC_BIT_EOR)
+		desc->status |= MTK_MAC_DESC_BIT_EOR;
+
+	dma_wmb();
+
+	ring->tail = (ring->tail + 1) % MTK_MAC_RING_NUM_DESCS;
+	ring->count--;
+
+	return 0;
+}
+
+static void mtk_mac_ring_push_head(struct mtk_mac_ring *ring,
+				   struct mtk_mac_ring_desc_data *desc_data,
+				   unsigned int flags)
+{
+	struct mtk_mac_ring_desc *desc = &ring->descs[ring->head];
+	unsigned int status;
+
+	dma_rmb();
+	status = desc->status;
+
+	ring->skbs[ring->head] = desc_data->skb;
+	desc->data_ptr = desc_data->dma_addr;
+
+	status |= desc_data->len;
+	if (flags)
+		status |= flags;
+	desc->status = status;
+
+	dma_wmb();
+	desc->status &= ~MTK_MAC_DESC_BIT_COWN;
+
+	ring->head = (ring->head + 1) % MTK_MAC_RING_NUM_DESCS;
+	ring->count++;
+}
+
+static void mtk_mac_ring_push_head_rx(struct mtk_mac_ring *ring,
+				      struct mtk_mac_ring_desc_data *desc_data)
+{
+	mtk_mac_ring_push_head(ring, desc_data, 0);
+}
+
+static void mtk_mac_ring_push_head_tx(struct mtk_mac_ring *ring,
+				      struct mtk_mac_ring_desc_data *desc_data)
+{
+	static const unsigned int flags = MTK_MAC_DESC_BIT_FS |
+					  MTK_MAC_DESC_BIT_LS |
+					  MTK_MAC_DESC_BIT_INT;
+
+	mtk_mac_ring_push_head(ring, desc_data, flags);
+}
+
+static bool mtk_mac_ring_full(struct mtk_mac_ring *ring)
+{
+	return ring->count == MTK_MAC_RING_NUM_DESCS;
+}
+
+static bool mtk_mac_ring_descs_available(struct mtk_mac_ring *ring)
+{
+	return ring->count > 0;
+}
+
+static void mtk_mac_lock(struct mtk_mac_priv *priv)
+{
+	spin_lock_irqsave(&priv->lock, priv->lock_flags);
+}
+
+static void mtk_mac_unlock(struct mtk_mac_priv *priv)
+{
+	spin_unlock_irqrestore(&priv->lock, priv->lock_flags);
+}
+
+static dma_addr_t mtk_mac_dma_map_rx(struct mtk_mac_priv *priv,
+				     struct sk_buff *skb)
+{
+	struct device *dev = mtk_mac_get_dev(priv);
+
+	/* Data pointer for the RX DMA descriptor must be aligned to 4N + 2. */
+	return dma_map_single(dev, skb_tail_pointer(skb) - 2,
+			      skb_tailroom(skb), DMA_FROM_DEVICE);
+}
+
+static void mtk_mac_dma_unmap_rx(struct mtk_mac_priv *priv,
+				 struct mtk_mac_ring_desc_data *desc_data)
+{
+	struct device *dev = mtk_mac_get_dev(priv);
+
+	dma_unmap_single(dev, desc_data->dma_addr,
+			 skb_tailroom(desc_data->skb), DMA_FROM_DEVICE);
+}
+
+static dma_addr_t mtk_mac_dma_map_tx(struct mtk_mac_priv *priv,
+				     struct sk_buff *skb)
+{
+	struct device *dev = mtk_mac_get_dev(priv);
+
+	return dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
+}
+
+static void mtk_mac_dma_unmap_tx(struct mtk_mac_priv *priv,
+				 struct mtk_mac_ring_desc_data *desc_data)
+{
+	struct device *dev = mtk_mac_get_dev(priv);
+
+	return dma_unmap_single(dev, desc_data->dma_addr,
+				desc_data->len, DMA_TO_DEVICE);
+}
+
+static void mtk_mac_nic_disable_pd(struct mtk_mac_priv *priv)
+{
+	regmap_update_bits(priv->regs, MTK_MAC_REG_MAC_CFG,
+			   MTK_MAC_BIT_MAC_CFG_NIC_PD, 0);
+}
+
+static void mtk_mac_intr_unmask_all(struct mtk_mac_priv *priv)
+{
+	regmap_write(priv->regs, MTK_MAC_REG_INT_MASK, 0);
+}
+
+static void mtk_mac_intr_mask_all(struct mtk_mac_priv *priv)
+{
+	regmap_write(priv->regs, MTK_MAC_REG_INT_MASK, ~0);
+}
+
+static unsigned int mtk_mac_intr_read_and_clear(struct mtk_mac_priv *priv)
+{
+	unsigned int val;
+
+	regmap_read(priv->regs, MTK_MAC_REG_INT_STS, &val);
+	regmap_write(priv->regs, MTK_MAC_REG_INT_STS, val);
+
+	return val;
+}
+
+static void mtk_mac_dma_init(struct mtk_mac_priv *priv)
+{
+	struct mtk_mac_ring_desc *desc;
+	unsigned int val;
+	int i;
+
+	priv->descs_base = (struct mtk_mac_ring_desc *)priv->ring_base;
+
+	for (i = 0; i < MTK_MAC_NUM_DESCS_TOTAL; i++) {
+		desc = &priv->descs_base[i];
+
+		memset(desc, 0, sizeof(*desc));
+		desc->status = MTK_MAC_DESC_BIT_COWN;
+		if ((i == MTK_MAC_NUM_TX_DESCS - 1) ||
+		    (i == MTK_MAC_NUM_DESCS_TOTAL - 1))
+			desc->status |= MTK_MAC_DESC_BIT_EOR;
+	}
+
+	mtk_mac_ring_init(&priv->tx_ring, priv->descs_base, 0);
+	mtk_mac_ring_init(&priv->rx_ring,
+			  priv->descs_base + MTK_MAC_NUM_TX_DESCS,
+			  MTK_MAC_NUM_RX_DESCS);
+
+	/* Set DMA pointers. */
+	val = (unsigned int)priv->dma_addr;
+	regmap_write(priv->regs, MTK_MAC_REG_TX_BASE_ADDR, val);
+	regmap_write(priv->regs, MTK_MAC_REG_TX_DPTR, val);
+
+	val += sizeof(struct mtk_mac_ring_desc) * MTK_MAC_NUM_TX_DESCS;
+	regmap_write(priv->regs, MTK_MAC_REG_RX_BASE_ADDR, val);
+	regmap_write(priv->regs, MTK_MAC_REG_RX_DPTR, val);
+}
+
+static void mtk_mac_dma_start(struct mtk_mac_priv *priv)
+{
+	regmap_update_bits(priv->regs, MTK_MAC_REG_TX_DMA_CTRL,
+			   MTK_MAC_BIT_TX_DMA_CTRL_START,
+			   MTK_MAC_BIT_TX_DMA_CTRL_START);
+	regmap_update_bits(priv->regs, MTK_MAC_REG_RX_DMA_CTRL,
+			   MTK_MAC_BIT_RX_DMA_CTRL_START,
+			   MTK_MAC_BIT_RX_DMA_CTRL_START);
+}
+
+static void mtk_mac_dma_stop(struct mtk_mac_priv *priv)
+{
+	regmap_write(priv->regs, MTK_MAC_REG_TX_DMA_CTRL,
+		     MTK_MAC_BIT_TX_DMA_CTRL_STOP);
+	regmap_write(priv->regs, MTK_MAC_REG_RX_DMA_CTRL,
+		     MTK_MAC_BIT_RX_DMA_CTRL_STOP);
+}
+
+static void mtk_mac_dma_disable(struct mtk_mac_priv *priv)
+{
+	int i;
+
+	mtk_mac_dma_stop(priv);
+
+	/* Take back all descriptors. */
+	for (i = 0; i < MTK_MAC_NUM_DESCS_TOTAL; i++)
+		priv->descs_base[i].status |= MTK_MAC_DESC_BIT_COWN;
+}
+
+static void mtk_mac_dma_resume_rx(struct mtk_mac_priv *priv)
+{
+	regmap_update_bits(priv->regs, MTK_MAC_REG_RX_DMA_CTRL,
+			   MTK_MAC_BIT_RX_DMA_CTRL_RESUME,
+			   MTK_MAC_BIT_RX_DMA_CTRL_RESUME);
+}
+
+static void mtk_mac_dma_resume_tx(struct mtk_mac_priv *priv)
+{
+	regmap_update_bits(priv->regs, MTK_MAC_REG_TX_DMA_CTRL,
+			   MTK_MAC_BIT_TX_DMA_CTRL_RESUME,
+			   MTK_MAC_BIT_TX_DMA_CTRL_RESUME);
+}
+
+static void mtk_mac_set_mac_addr(struct net_device *ndev)
+{
+	struct mtk_mac_priv *priv = netdev_priv(ndev);
+	u8 *mac_addr = ndev->dev_addr;
+	unsigned int high, low;
+
+	high = mac_addr[0] << 8 | mac_addr[1] << 0;
+	low = mac_addr[2] << 24 | mac_addr[3] << 16 |
+	      mac_addr[4] << 8 | mac_addr[5];
+
+	regmap_write(priv->regs, MTK_MAC_REG_MY_MAC_H, high);
+	regmap_write(priv->regs, MTK_MAC_REG_MY_MAC_L, low);
+}
+
+static void mtk_mac_reset_counters(struct mtk_mac_priv *priv)
+{
+	static const unsigned int counter_regs[] = {
+		MTK_MAC_REG_C_RXOKPKT,
+		MTK_MAC_REG_C_RXOKBYTE,
+		MTK_MAC_REG_C_RXRUNT,
+		MTK_MAC_REG_C_RXLONG,
+		MTK_MAC_REG_C_RXDROP,
+		MTK_MAC_REG_C_RXCRC,
+		MTK_MAC_REG_C_RXARLDROP,
+		MTK_MAC_REG_C_RXVLANDROP,
+		MTK_MAC_REG_C_RXCSERR,
+		MTK_MAC_REG_C_RXPAUSE,
+		MTK_MAC_REG_C_TXOKPKT,
+		MTK_MAC_REG_C_TXOKBYTE,
+		MTK_MAC_REG_C_TXPAUSECOL,
+		MTK_MAC_REG_C_TXRTY,
+		MTK_MAC_REG_C_TXSKIP,
+		MTK_MAC_REG_C_TX_ARP,
+		MTK_MAC_REG_C_RX_RERR,
+		MTK_MAC_REG_C_RX_UNI,
+		MTK_MAC_REG_C_RX_MULTI,
+		MTK_MAC_REG_C_RX_BROAD,
+		MTK_MAC_REG_C_RX_ALIGNERR,
+		MTK_MAC_REG_C_TX_UNI,
+		MTK_MAC_REG_C_TX_MULTI,
+		MTK_MAC_REG_C_TX_BROAD,
+		MTK_MAC_REG_C_TX_TIMEOUT,
+		MTK_MAC_REG_C_TX_LATECOL,
+		MTK_MAC_REG_C_RX_LENGTHERR,
+		MTK_MAC_REG_C_RX_TWIST,
+	};
+
+	unsigned int i, val;
+
+	for (i = 0; i < ARRAY_SIZE(counter_regs); i++)
+		regmap_read(priv->regs, counter_regs[i], &val);
+}
+
+static void mtk_mac_update_stat(struct mtk_mac_priv *priv,
+				unsigned int reg, u64 *stat)
+{
+	unsigned int val;
+
+	regmap_read(priv->regs, reg, &val);
+	*stat += val;
+}
+
+/* Try to get as many stats as possible from the internal registers instead
+ * of tracking them ourselves.
+ */
+static void mtk_mac_update_stats(struct mtk_mac_priv *priv)
+{
+	struct rtnl_link_stats64 *stats = &priv->stats;
+
+	/* OK packets and bytes. */
+	mtk_mac_update_stat(priv, MTK_MAC_REG_C_RXOKPKT, &stats->rx_packets);
+	mtk_mac_update_stat(priv, MTK_MAC_REG_C_TXOKPKT, &stats->tx_packets);
+	mtk_mac_update_stat(priv, MTK_MAC_REG_C_RXOKBYTE, &stats->rx_bytes);
+	mtk_mac_update_stat(priv, MTK_MAC_REG_C_TXOKBYTE, &stats->tx_bytes);
+
+	/* RX & TX multicast. */
+	mtk_mac_update_stat(priv, MTK_MAC_REG_C_RX_MULTI, &stats->multicast);
+	mtk_mac_update_stat(priv, MTK_MAC_REG_C_TX_MULTI, &stats->multicast);
+
+	/* Collisions. */
+	mtk_mac_update_stat(priv, MTK_MAC_REG_C_TXPAUSECOL, &stats->collisions);
+	mtk_mac_update_stat(priv, MTK_MAC_REG_C_TX_LATECOL, &stats->collisions);
+	mtk_mac_update_stat(priv, MTK_MAC_REG_C_RXRUNT, &stats->collisions);
+
+	/* RX Errors. */
+	mtk_mac_update_stat(priv, MTK_MAC_REG_C_RX_LENGTHERR,
+			    &stats->rx_length_errors);
+	mtk_mac_update_stat(priv, MTK_MAC_REG_C_RXLONG, &stats->rx_over_errors);
+	mtk_mac_update_stat(priv, MTK_MAC_REG_C_RXCRC, &stats->rx_crc_errors);
+	mtk_mac_update_stat(priv, MTK_MAC_REG_C_RX_ALIGNERR,
+			    &stats->rx_frame_errors);
+	mtk_mac_update_stat(priv, MTK_MAC_REG_C_RXDROP, &stats->rx_fifo_errors);
+	/* Sum of the general RX error counter + all of the above. */
+	mtk_mac_update_stat(priv, MTK_MAC_REG_C_RX_RERR, &stats->rx_errors);
+	stats->rx_errors += stats->rx_length_errors;
+	stats->rx_errors += stats->rx_over_errors;
+	stats->rx_errors += stats->rx_crc_errors;
+	stats->rx_errors += stats->rx_frame_errors;
+	stats->rx_errors += stats->rx_fifo_errors;
+}
+
+static struct sk_buff *mtk_mac_alloc_skb(struct net_device *ndev)
+{
+	uintptr_t tail, offset;
+	struct sk_buff *skb;
+
+	skb = dev_alloc_skb(MTK_MAC_MAX_FRAME_SIZE);
+	if (!skb)
+		return NULL;
+
+	/* Align to 16 bytes. */
+	tail = (uintptr_t)skb_tail_pointer(skb);
+	if (tail & (MTK_MAC_SKB_ALIGNMENT - 1)) {
+		offset = tail & (MTK_MAC_SKB_ALIGNMENT - 1);
+		skb_reserve(skb, MTK_MAC_SKB_ALIGNMENT - offset);
+	}
+
+	/* Ensure 16-byte alignment of the skb pointer: eth_type_trans() will
+	 * extract the Ethernet header (14 bytes) so we need two more bytes.
+	 */
+	skb_reserve(skb, 2);
+
+	return skb;
+}
+
+static int mtk_mac_prepare_rx_skbs(struct net_device *ndev)
+{
+	struct mtk_mac_priv *priv = netdev_priv(ndev);
+	struct mtk_mac_ring *ring = &priv->rx_ring;
+	struct device *dev = mtk_mac_get_dev(priv);
+	struct mtk_mac_ring_desc *desc;
+	struct sk_buff *skb;
+	dma_addr_t dma_addr;
+	int i;
+
+	for (i = 0; i < MTK_MAC_NUM_RX_DESCS; i++) {
+		skb = mtk_mac_alloc_skb(ndev);
+		if (!skb)
+			return -ENOMEM;
+
+		dma_addr = mtk_mac_dma_map_rx(priv, skb);
+		if (dma_mapping_error(dev, dma_addr)) {
+			dev_kfree_skb(skb);
+			return -ENOMEM;
+		}
+
+		desc = &ring->descs[i];
+		desc->data_ptr = dma_addr;
+		desc->status |= skb_tailroom(skb) & MTK_MAC_DESC_MSK_LEN;
+		desc->status &= ~MTK_MAC_DESC_BIT_COWN;
+		ring->skbs[i] = skb;
+	}
+
+	ring->count = MTK_MAC_NUM_RX_DESCS;
+
+	return 0;
+}
+
+/* All processing for TX and RX happens in the napi poll callback. */
+static irqreturn_t mtk_mac_handle_irq(int irq, void *data)
+{
+	struct mtk_mac_priv *priv;
+	struct net_device *ndev;
+	unsigned int status;
+
+	ndev = data;
+	priv = netdev_priv(ndev);
+
+	if (netif_running(ndev)) {
+		mtk_mac_intr_mask_all(priv);
+		status = mtk_mac_intr_read_and_clear(priv);
+
+		/* RX Complete */
+		if (status & MTK_MAC_BIT_INT_STS_FNRC)
+			napi_schedule(&priv->napi);
+
+		/* TX Complete */
+		if (status & MTK_MAC_BIT_INT_STS_TNTC)
+			schedule_work(&priv->tx_work);
+
+		/* One of the counter reached 0x8000000 */
+		if (status & MTK_MAC_REG_INT_STS_MIB_CNT_TH) {
+			mtk_mac_update_stats(priv);
+			mtk_mac_reset_counters(priv);
+		}
+
+		mtk_mac_intr_unmask_all(priv);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void mtk_mac_free_rx_skbs(struct net_device *ndev)
+{
+	struct mtk_mac_priv *priv = netdev_priv(ndev);
+	struct mtk_mac_ring *ring = &priv->rx_ring;
+	struct mtk_mac_ring_desc_data desc_data;
+	struct mtk_mac_ring_desc *desc;
+	int i;
+
+	for (i = 0; i < MTK_MAC_NUM_RX_DESCS; i++) {
+		desc = &ring->descs[i];
+
+		if (!desc->data_ptr)
+			continue;
+
+		desc_data.dma_addr = desc->data_ptr;
+		desc_data.skb = ring->skbs[i];
+
+		mtk_mac_dma_unmap_rx(priv, &desc_data);
+		dev_kfree_skb(desc_data.skb);
+	}
+}
+
+static void mtk_mac_free_tx_skbs(struct net_device *ndev)
+{
+	struct mtk_mac_priv *priv = netdev_priv(ndev);
+	struct mtk_mac_ring *ring = &priv->tx_ring;
+	struct mtk_mac_ring_desc_data desc_data;
+	struct mtk_mac_ring_desc *desc;
+	int i;
+
+	for (i = 0; i < MTK_MAC_NUM_TX_DESCS; i++) {
+		desc = &ring->descs[i];
+
+		if (!desc->data_ptr)
+			continue;
+
+		desc_data.dma_addr = desc->data_ptr;
+		desc_data.len = desc->status & MTK_MAC_DESC_MSK_LEN;
+		desc_data.skb = ring->skbs[i];
+
+		mtk_mac_dma_unmap_tx(priv, &desc_data);
+		dev_kfree_skb(desc_data.skb);
+	}
+}
+
+static void mtk_mac_phy_config(struct mtk_mac_priv *priv)
+{
+	unsigned int val;
+
+	if (priv->speed == SPEED_1000)
+		val = MTK_MAC_VAL_PHY_CTRL1_FORCE_SPD_1000M;
+	else if (priv->speed == SPEED_100)
+		val = MTK_MAC_VAL_PHY_CTRL1_FORCE_SPD_100M;
+	else
+		val = MTK_MAC_VAL_PHY_CTRL1_FORCE_SPD_10M;
+	val <<= MTK_MAC_OFF_PHY_CTRL1_FORCE_SPD;
+
+	val |= MTK_MAC_BIT_PHY_CTRL1_AN_EN;
+	val |= MTK_MAC_BIT_PHY_CTRL1_FORCE_FC_RX;
+	val |= MTK_MAC_BIT_PHY_CTRL1_FORCE_FC_TX;
+	/* Only full-duplex supported for now. */
+	val |= MTK_MAC_BIT_PHY_CTRL1_FORCE_DPX;
+
+	regmap_write(priv->regs, MTK_MAC_REG_PHY_CTRL1, val);
+}
+
+static void mtk_mac_adjust_link(struct net_device *ndev)
+{
+	struct mtk_mac_priv *priv = netdev_priv(ndev);
+	struct phy_device *phydev = priv->phydev;
+	bool new_state = false;
+
+	if (phydev->link) {
+		if (!priv->link) {
+			priv->link = phydev->link;
+			new_state = true;
+		}
+
+		if (priv->speed != phydev->speed) {
+			priv->speed = phydev->speed;
+			new_state = true;
+		}
+	} else {
+		if (priv->link) {
+			priv->link = phydev->link;
+			new_state = true;
+		}
+	}
+
+	if (new_state) {
+		if (phydev->link)
+			mtk_mac_phy_config(priv);
+		phy_print_status(ndev->phydev);
+	}
+}
+
+static void mtk_mac_init_config(struct mtk_mac_priv *priv)
+{
+	unsigned int val;
+
+	val = (MTK_MAC_BIT_MII_PAD_OUT_ENABLE |
+	       MTK_MAC_BIT_EXT_MDC_MODE |
+	       MTK_MAC_BIT_SWC_MII_MODE);
+
+	regmap_write(priv->regs, MTK_MAC_REG_SYS_CONF, val);
+	regmap_update_bits(priv->regs, MTK_MAC_REG_MAC_CLK_CONF,
+			   MTK_MAC_MSK_MAC_CLK_CONF,
+			   MTK_MAC_BIT_CLK_DIV_10);
+}
+
+static void mtk_mac_set_mode_rmii(struct mtk_mac_priv *priv)
+{
+	regmap_update_bits(priv->pericfg, MTK_PERICFG_REG_NIC_CFG_CON,
+			   MTK_PERICFG_MSK_NIC_CFG_CON_CFG_MII,
+			   MTK_PERICFG_BIT_NIC_CFG_CON_RMII);
+}
+
+static int mtk_mac_enable(struct net_device *ndev)
+{
+	struct mtk_mac_priv *priv = netdev_priv(ndev);
+	unsigned int val;
+	int ret;
+
+	mtk_mac_nic_disable_pd(priv);
+	mtk_mac_intr_mask_all(priv);
+	mtk_mac_dma_stop(priv);
+	netif_carrier_off(ndev);
+
+	mtk_mac_set_mac_addr(ndev);
+
+	/* Configure the MAC */
+	val = MTK_MAC_VAL_MAC_CFG_IPG_96BIT;
+	val <<= MTK_MAC_OFF_MAC_CFG_IPG;
+	val |= MTK_MAC_BIT_MAC_CFG_MAXLEN_1522;
+	val |= MTK_MAC_BIT_MAC_CFG_AUTO_PAD;
+	val |= MTK_MAC_BIT_MAC_CFG_CRC_STRIP;
+	regmap_write(priv->regs, MTK_MAC_REG_MAC_CFG, val);
+
+	/* Configure flow control */
+	val = MTK_MAC_VAL_FC_CFG_SEND_PAUSE_TH_2K;
+	val <<= MTK_MAC_OFF_FC_CFG_SEND_PAUSE_TH;
+	val |= MTK_MAC_BIT_FC_CFG_BP_EN;
+	val |= MTK_MAC_BIT_FC_CFG_UC_PAUSE_DIR;
+	regmap_write(priv->regs, MTK_MAC_REG_FC_CFG, val);
+
+	/* Set SEND_PAUSE_RLS to 1K */
+	val = MTK_MAC_VAL_EXT_CFG_SND_PAUSE_RLS_1K;
+	val <<= MTK_MAC_OFF_EXT_CFG_SND_PAUSE_RLS;
+	regmap_write(priv->regs, MTK_MAC_REG_EXT_CFG, val);
+
+	/* Reset all counters */
+	mtk_mac_reset_counters(priv);
+
+	/* Enable Hash Table BIST and reset it */
+	regmap_update_bits(priv->regs, MTK_MAC_REG_HASH_CTRL,
+			   MTK_MAC_BIT_HASH_CTRL_BIST_EN,
+			   MTK_MAC_BIT_HASH_CTRL_BIST_EN);
+	regmap_update_bits(priv->regs, MTK_MAC_REG_TEST1,
+			   MTK_MAC_BIT_TEST1_RST_HASH_MBIST,
+			   MTK_MAC_BIT_TEST1_RST_HASH_MBIST);
+
+	/* Setup the hashing algorithm */
+	regmap_update_bits(priv->regs, MTK_MAC_REG_ARL_CFG,
+			   MTK_MAC_BIT_ARL_CFG_HASH_ALG |
+			   MTK_MAC_BIT_ARL_CFG_MISC_MODE, 0);
+
+	/* Don't strip VLAN tags */
+	regmap_update_bits(priv->regs, MTK_MAC_REG_MAC_CFG,
+			   MTK_MAC_BIT_MAC_CFG_VLAN_STRIP, 0);
+
+	/* Setup DMA */
+	mtk_mac_dma_init(priv);
+
+	ret = mtk_mac_prepare_rx_skbs(ndev);
+	if (ret)
+		goto err_out;
+
+	/* Request the interrupt */
+	ret = request_irq(ndev->irq, mtk_mac_handle_irq,
+			  IRQF_TRIGGER_FALLING, ndev->name, ndev);
+	if (ret)
+		goto err_free_skbs;
+
+	napi_enable(&priv->napi);
+
+	mtk_mac_intr_read_and_clear(priv);
+	mtk_mac_intr_unmask_all(priv);
+
+	/* Connect to and start PHY */
+	priv->phydev = of_phy_connect(ndev, priv->phy_node,
+				      mtk_mac_adjust_link, 0, priv->phy_intf);
+	if (!priv->phydev) {
+		netdev_err(ndev, "failed to connect to PHY\n");
+		goto err_free_irq;
+	}
+
+	mtk_mac_dma_start(priv);
+	phy_start(priv->phydev);
+	netif_start_queue(ndev);
+
+	return 0;
+
+err_free_irq:
+	free_irq(ndev->irq, ndev);
+err_free_skbs:
+	mtk_mac_free_rx_skbs(ndev);
+err_out:
+	return ret;
+}
+
+static void mtk_mac_disable(struct net_device *ndev)
+{
+	struct mtk_mac_priv *priv = netdev_priv(ndev);
+
+	netif_stop_queue(ndev);
+	napi_disable(&priv->napi);
+	mtk_mac_intr_mask_all(priv);
+	mtk_mac_dma_disable(priv);
+	mtk_mac_intr_read_and_clear(priv);
+	phy_stop(priv->phydev);
+	phy_disconnect(priv->phydev);
+	free_irq(ndev->irq, ndev);
+	mtk_mac_free_rx_skbs(ndev);
+	mtk_mac_free_tx_skbs(ndev);
+}
+
+static int mtk_mac_netdev_open(struct net_device *ndev)
+{
+	return mtk_mac_enable(ndev);
+}
+
+static int mtk_mac_netdev_stop(struct net_device *ndev)
+{
+	mtk_mac_disable(ndev);
+
+	return 0;
+}
+
+static int mtk_mac_netdev_ioctl(struct net_device *ndev,
+				struct ifreq *req, int cmd)
+{
+	if (!netif_running(ndev))
+		return -EINVAL;
+
+	return phy_mii_ioctl(ndev->phydev, req, cmd);
+}
+
+static int mtk_mac_netdev_start_xmit(struct sk_buff *skb,
+				     struct net_device *ndev)
+{
+	struct mtk_mac_priv *priv = netdev_priv(ndev);
+	struct mtk_mac_ring *ring = &priv->tx_ring;
+	struct device *dev = mtk_mac_get_dev(priv);
+	struct mtk_mac_ring_desc_data desc_data;
+
+	if (skb->len > MTK_MAC_MAX_FRAME_SIZE)
+		goto err_drop_packet;
+
+	desc_data.dma_addr = mtk_mac_dma_map_tx(priv, skb);
+	if (dma_mapping_error(dev, desc_data.dma_addr))
+		goto err_drop_packet;
+
+	desc_data.skb = skb;
+	desc_data.len = skb->len;
+
+	mtk_mac_lock(priv);
+	mtk_mac_ring_push_head_tx(ring, &desc_data);
+
+	if (mtk_mac_ring_full(ring))
+		netif_stop_queue(ndev);
+	mtk_mac_unlock(priv);
+
+	mtk_mac_dma_resume_tx(priv);
+
+	return NETDEV_TX_OK;
+
+err_drop_packet:
+	dev_kfree_skb(skb);
+	ndev->stats.tx_dropped++;
+	return NETDEV_TX_BUSY;
+}
+
+static int mtk_mac_tx_complete(struct mtk_mac_priv *priv)
+{
+	struct mtk_mac_ring *ring = &priv->tx_ring;
+	struct mtk_mac_ring_desc_data desc_data;
+	int ret;
+
+	ret = mtk_mac_ring_pop_tail(ring, &desc_data);
+	if (ret)
+		return ret;
+
+	mtk_mac_dma_unmap_tx(priv, &desc_data);
+	dev_kfree_skb_irq(desc_data.skb);
+
+	return 0;
+}
+
+static void mtk_mac_tx_work(struct work_struct *work)
+{
+	struct mtk_mac_priv *priv;
+	struct mtk_mac_ring *ring;
+	struct net_device *ndev;
+	bool wake = false;
+	int ret;
+
+	priv = container_of(work, struct mtk_mac_priv, tx_work);
+	ndev = mtk_mac_get_netdev(priv);
+	ring = &priv->tx_ring;
+
+	for (;;) {
+		mtk_mac_lock(priv);
+
+		if (!mtk_mac_ring_descs_available(ring)) {
+			mtk_mac_unlock(priv);
+			break;
+		}
+
+		ret = mtk_mac_tx_complete(priv);
+		mtk_mac_unlock(priv);
+		if (ret)
+			break;
+
+		wake = true;
+	}
+
+	if (wake)
+		netif_wake_queue(ndev);
+}
+
+static void mtk_mac_netdev_get_stats64(struct net_device *ndev,
+				       struct rtnl_link_stats64 *stats)
+{
+	struct mtk_mac_priv *priv = netdev_priv(ndev);
+
+	mtk_mac_update_stats(priv);
+
+	memcpy(stats, &priv->stats, sizeof(*stats));
+}
+
+static void mtk_mac_set_hashbit(struct mtk_mac_priv *priv,
+				unsigned int hash_addr)
+{
+	unsigned int val;
+
+	val = hash_addr & MTK_MAC_MSK_HASH_CTRL_HASH_BIT_ADDR;
+	val |= MTK_MAC_BIT_HASH_CTRL_ACC_CMD;
+	val |= MTK_MAC_BIT_HASH_CTRL_CMD_START;
+	val |= MTK_MAC_BIT_HASH_CTRL_BIST_EN;
+	val |= MTK_MAC_BIT_HASH_CTRL_HASH_BIT_DATA;
+
+	regmap_write(priv->regs, MTK_MAC_REG_HASH_CTRL, val);
+}
+
+static void mtk_mac_set_rx_mode(struct net_device *ndev)
+{
+	struct mtk_mac_priv *priv = netdev_priv(ndev);
+	struct netdev_hw_addr *hw_addr;
+	unsigned int hash_addr, i;
+
+	if (ndev->flags & IFF_PROMISC) {
+		regmap_update_bits(priv->regs, MTK_MAC_REG_ARL_CFG,
+				   MTK_MAC_BIT_ARL_CFG_MISC_MODE,
+				   MTK_MAC_BIT_ARL_CFG_MISC_MODE);
+	} else if (netdev_mc_count(ndev) > MTK_MAC_HASHTABLE_MC_LIMIT ||
+		   ndev->flags & IFF_ALLMULTI) {
+		for (i = 0; i < MTK_MAC_HASHTABLE_SIZE_MAX; i++)
+			mtk_mac_set_hashbit(priv, i);
+	} else {
+		netdev_for_each_mc_addr(hw_addr, ndev) {
+			hash_addr = (hw_addr->addr[0] & 0x01) << 8;
+			hash_addr += hw_addr->addr[5];
+			mtk_mac_set_hashbit(priv, hash_addr);
+		}
+	}
+}
+
+static const struct net_device_ops mtk_mac_netdev_ops = {
+	.ndo_open		= mtk_mac_netdev_open,
+	.ndo_stop		= mtk_mac_netdev_stop,
+	.ndo_start_xmit		= mtk_mac_netdev_start_xmit,
+	.ndo_get_stats64	= mtk_mac_netdev_get_stats64,
+	.ndo_set_rx_mode	= mtk_mac_set_rx_mode,
+	.ndo_do_ioctl		= mtk_mac_netdev_ioctl,
+	.ndo_set_mac_address	= eth_mac_addr,
+	.ndo_validate_addr	= eth_validate_addr,
+};
+
+static void mtk_mac_get_drvinfo(struct net_device *dev,
+				struct ethtool_drvinfo *info)
+{
+	strlcpy(info->driver, MTK_MAC_DRVNAME, sizeof(info->driver));
+	strlcpy(info->version, MTK_MAC_VERSION, sizeof(info->version));
+}
+
+/* TODO Add ethtool stats. */
+static const struct ethtool_ops mtk_mac_ethtool_ops = {
+	.get_drvinfo		= mtk_mac_get_drvinfo,
+	.get_link		= ethtool_op_get_link,
+	.get_link_ksettings	= phy_ethtool_get_link_ksettings,
+	.set_link_ksettings	= phy_ethtool_set_link_ksettings,
+};
+
+static int mtk_mac_receive_packet(struct mtk_mac_priv *priv)
+{
+	struct net_device *ndev = mtk_mac_get_netdev(priv);
+	struct mtk_mac_ring *ring = &priv->rx_ring;
+	struct device *dev = mtk_mac_get_dev(priv);
+	struct mtk_mac_ring_desc_data desc_data;
+	struct sk_buff *new_skb;
+	int ret;
+
+	mtk_mac_lock(priv);
+	ret = mtk_mac_ring_pop_tail(ring, &desc_data);
+	mtk_mac_unlock(priv);
+	if (ret)
+		return -1;
+
+	mtk_mac_dma_unmap_rx(priv, &desc_data);
+
+	if ((desc_data.flags & MTK_MAC_DESC_BIT_RX_CRCE) ||
+	    (desc_data.flags & MTK_MAC_DESC_BIT_RX_OSIZE)) {
+		/* Error packet -> drop and reuse skb. */
+		new_skb = desc_data.skb;
+		goto map_skb;
+	}
+
+	new_skb = mtk_mac_alloc_skb(ndev);
+	if (!new_skb) {
+		netdev_err(ndev, "out of memory for skb\n");
+		ndev->stats.rx_dropped++;
+		new_skb = desc_data.skb;
+		goto map_skb;
+	}
+
+	skb_put(desc_data.skb, desc_data.len);
+	desc_data.skb->ip_summed = CHECKSUM_NONE;
+	desc_data.skb->protocol = eth_type_trans(desc_data.skb, ndev);
+	desc_data.skb->dev = ndev;
+	netif_receive_skb(desc_data.skb);
+
+map_skb:
+	desc_data.dma_addr = mtk_mac_dma_map_rx(priv, new_skb);
+	if (dma_mapping_error(dev, desc_data.dma_addr)) {
+		dev_kfree_skb(new_skb);
+		netdev_err(ndev, "DMA mapping error of RX descriptor\n");
+		return -ENOMEM;
+	}
+
+	desc_data.len = skb_tailroom(new_skb);
+	desc_data.skb = new_skb;
+
+	mtk_mac_lock(priv);
+	mtk_mac_ring_push_head_rx(ring, &desc_data);
+	mtk_mac_unlock(priv);
+
+	return 0;
+}
+
+static int mtk_mac_process_rx(struct mtk_mac_priv *priv, int budget)
+{
+	int received, ret;
+
+	for (received = 0, ret = 0; received < budget && ret == 0; received++)
+		ret = mtk_mac_receive_packet(priv);
+
+	mtk_mac_dma_resume_rx(priv);
+
+	return received;
+}
+
+static int mtk_mac_poll(struct napi_struct *napi, int budget)
+{
+	struct mtk_mac_priv *priv;
+	int received = 0;
+
+	priv = container_of(napi, struct mtk_mac_priv, napi);
+
+	received = mtk_mac_process_rx(priv, budget);
+	if (received < budget)
+		napi_complete_done(napi, received);
+
+	return received;
+}
+
+static void mtk_mac_mdio_rwok_clear(struct mtk_mac_priv *priv)
+{
+	regmap_write(priv->regs, MTK_MAC_REG_PHY_CTRL0,
+		     MTK_MAC_BIT_PHY_CTRL0_RWOK);
+}
+
+static int mtk_mac_mdio_rwok_wait(struct mtk_mac_priv *priv)
+{
+	unsigned long start = jiffies;
+	unsigned int val;
+
+	for (;;) {
+		regmap_read(priv->regs, MTK_MAC_REG_PHY_CTRL0, &val);
+		if (val & MTK_MAC_BIT_PHY_CTRL0_RWOK)
+			break;
+
+		udelay(10);
+		if (time_after(jiffies, start + MTK_MAC_WAIT_TIMEOUT))
+			return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int mtk_mac_mdio_read(struct mii_bus *mii, int phy_id, int regnum)
+{
+	struct mtk_mac_priv *priv = mii->priv;
+	unsigned int val, data;
+	int ret;
+
+	mtk_mac_mdio_rwok_clear(priv);
+
+	val = (regnum << MTK_MAC_OFF_PHY_CTRL0_PREG);
+	val &= MTK_MAC_MSK_PHY_CTRL0_PREG;
+	val |= MTK_MAC_BIT_PHY_CTRL0_RDCMD;
+
+	regmap_write(priv->regs, MTK_MAC_REG_PHY_CTRL0, val);
+
+	ret = mtk_mac_mdio_rwok_wait(priv);
+	if (ret)
+		return ret;
+
+	regmap_read(priv->regs, MTK_MAC_REG_PHY_CTRL0, &data);
+
+	data &= MTK_MAC_MSK_PHY_CTRL0_RWDATA;
+	data >>= MTK_MAC_OFF_PHY_CTRL0_RWDATA;
+
+	return data;
+}
+
+static int mtk_mac_mdio_write(struct mii_bus *mii, int phy_id,
+			      int regnum, u16 data)
+{
+	struct mtk_mac_priv *priv = mii->priv;
+	unsigned int val;
+
+	mtk_mac_mdio_rwok_clear(priv);
+
+	val = data;
+	val <<= MTK_MAC_OFF_PHY_CTRL0_RWDATA;
+	val &= MTK_MAC_MSK_PHY_CTRL0_RWDATA;
+	regnum <<= MTK_MAC_OFF_PHY_CTRL0_PREG;
+	regnum &= MTK_MAC_MSK_PHY_CTRL0_PREG;
+	val |= regnum;
+	val |= MTK_MAC_BIT_PHY_CTRL0_WTCMD;
+
+	regmap_write(priv->regs, MTK_MAC_REG_PHY_CTRL0, val);
+
+	return mtk_mac_mdio_rwok_wait(priv);
+}
+
+static int mtk_mac_mdio_init(struct net_device *ndev)
+{
+	struct mtk_mac_priv *priv = netdev_priv(ndev);
+	struct device *dev = mtk_mac_get_dev(priv);
+	struct device_node *of_node, *mdio_node;
+	int ret;
+
+	of_node = dev->of_node;
+
+	mdio_node = of_get_child_by_name(of_node, "mdio");
+	if (!mdio_node)
+		return -ENODEV;
+
+	if (!of_device_is_available(mdio_node)) {
+		ret = -ENODEV;
+		goto out_put_node;
+	}
+
+	priv->mii = devm_mdiobus_alloc(dev);
+	if (!priv->mii) {
+		ret = -ENOMEM;
+		goto out_put_node;
+	}
+
+	snprintf(priv->mii->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
+	priv->mii->name = "mdio";
+	priv->mii->parent = dev;
+	priv->mii->read = mtk_mac_mdio_read;
+	priv->mii->write = mtk_mac_mdio_write;
+	priv->mii->priv = priv;
+
+	ret = of_mdiobus_register(priv->mii, mdio_node);
+
+out_put_node:
+	of_node_put(mdio_node);
+	return ret;
+}
+
+static int mtk_mac_suspend(struct device *dev)
+{
+	struct mtk_mac_priv *priv;
+	struct net_device *ndev;
+
+	ndev = dev_get_drvdata(dev);
+	priv = netdev_priv(ndev);
+
+	mtk_mac_disable(ndev);
+	clk_bulk_disable_unprepare(MTK_MAC_NCLKS, priv->clks);
+
+	return 0;
+}
+
+static int mtk_mac_resume(struct device *dev)
+{
+	struct mtk_mac_priv *priv;
+	struct net_device *ndev;
+	int ret;
+
+	ndev = dev_get_drvdata(dev);
+	priv = netdev_priv(ndev);
+
+	ret = clk_bulk_prepare_enable(MTK_MAC_NCLKS, priv->clks);
+	if (ret)
+		return ret;
+
+	ret = mtk_mac_enable(ndev);
+	if (ret)
+		clk_bulk_disable_unprepare(MTK_MAC_NCLKS, priv->clks);
+
+	return ret;
+}
+
+static void mtk_mac_clk_disable_unprepare(void *data)
+{
+	struct mtk_mac_priv *priv = data;
+
+	clk_bulk_disable_unprepare(MTK_MAC_NCLKS, priv->clks);
+}
+
+static int mtk_mac_probe(struct platform_device *pdev)
+{
+	struct device_node *of_node;
+	struct mtk_mac_priv *priv;
+	struct net_device *ndev;
+	struct device *dev;
+	void __iomem *base;
+	int ret, i;
+
+	dev = &pdev->dev;
+	of_node = dev->of_node;
+
+	ndev = devm_alloc_etherdev(dev, sizeof(*priv));
+	if (!ndev)
+		return -ENOMEM;
+
+	priv = netdev_priv(ndev);
+	SET_NETDEV_DEV(ndev, dev);
+	platform_set_drvdata(pdev, ndev);
+
+	spin_lock_init(&priv->lock);
+	INIT_WORK(&priv->tx_work, mtk_mac_tx_work);
+
+	base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	/* We won't be checking the return values of regmap read & write
+	 * functions. They can only fail for mmio if there's a clock attached
+	 * to regmap which is not the case here.
+	 */
+	priv->regs = devm_regmap_init_mmio(dev, base,
+					   &mtk_mac_regmap_config);
+	if (IS_ERR(priv->regs))
+		return PTR_ERR(priv->regs);
+
+	priv->pericfg = syscon_regmap_lookup_by_phandle(of_node,
+							"mediatek,pericfg");
+	if (IS_ERR(priv->pericfg)) {
+		dev_err(dev, "Failed to lookup the PERICFG syscon\n");
+		return PTR_ERR(priv->pericfg);
+	}
+
+	ndev->irq = platform_get_irq(pdev, 0);
+	if (ndev->irq < 0)
+		return ndev->irq;
+
+	for (i = 0; i < MTK_MAC_NCLKS; i++)
+		priv->clks[i].id = mtk_mac_clk_names[i];
+	ret = devm_clk_bulk_get(dev, MTK_MAC_NCLKS, priv->clks);
+	if (ret)
+		return ret;
+
+	ret = clk_bulk_prepare_enable(MTK_MAC_NCLKS, priv->clks);
+	if (ret)
+		return ret;
+
+	ret = devm_add_action_or_reset(dev,
+				       mtk_mac_clk_disable_unprepare, priv);
+	if (ret)
+		return ret;
+
+	ret = of_get_phy_mode(of_node, &priv->phy_intf);
+	if (ret) {
+		return ret;
+	} else if (priv->phy_intf != PHY_INTERFACE_MODE_RMII) {
+		dev_err(dev, "unsupported phy mode: %s\n",
+			phy_modes(priv->phy_intf));
+		return -EINVAL;
+	}
+
+	priv->phy_node = of_parse_phandle(of_node, "phy-handle", 0);
+	if (!priv->phy_node) {
+		dev_err(dev, "failed to retrieve the phy handle from device tree\n");
+		return -ENODEV;
+	}
+
+	mtk_mac_set_mode_rmii(priv);
+
+	dev->coherent_dma_mask = DMA_BIT_MASK(32);
+	dev->dma_mask = &dev->coherent_dma_mask;
+	priv->ring_base = dmam_alloc_coherent(dev, MTK_MAC_DMA_SIZE,
+					      &priv->dma_addr,
+					      GFP_KERNEL | GFP_DMA);
+	if (!priv->ring_base)
+		return -ENOMEM;
+
+	mtk_mac_nic_disable_pd(priv);
+	mtk_mac_init_config(priv);
+
+	ret = mtk_mac_mdio_init(ndev);
+	if (ret)
+		return ret;
+
+	ret = eth_platform_get_mac_address(dev, ndev->dev_addr);
+	if (ret || !is_valid_ether_addr(ndev->dev_addr)) {
+		random_ether_addr(ndev->dev_addr);
+		ndev->addr_assign_type = NET_ADDR_RANDOM;
+	}
+
+	ndev->netdev_ops = &mtk_mac_netdev_ops;
+	ndev->ethtool_ops = &mtk_mac_ethtool_ops;
+
+	netif_napi_add(ndev, &priv->napi, mtk_mac_poll, MTK_MAC_NAPI_WEIGHT);
+
+	return devm_register_netdev(ndev);
+}
+
+static const struct of_device_id mtk_mac_of_match[] = {
+	{ .compatible = "mediatek,mt8516-eth", },
+	{ .compatible = "mediatek,mt8518-eth", },
+	{ .compatible = "mediatek,mt8175-eth", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, mtk_mac_of_match);
+
+static SIMPLE_DEV_PM_OPS(mtk_mac_pm_ops,
+			 mtk_mac_suspend, mtk_mac_resume);
+
+static struct platform_driver mtk_mac_driver = {
+	.driver = {
+		.name = MTK_MAC_DRVNAME,
+		.pm = &mtk_mac_pm_ops,
+		.of_match_table = of_match_ptr(mtk_mac_of_match),
+	},
+	.probe = mtk_mac_probe,
+};
+module_platform_driver(mtk_mac_driver);
+
+MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
+MODULE_DESCRIPTION("Mediatek Ethernet MAC Driver");
+MODULE_LICENSE("GPL");
-- 
2.25.0


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

* [PATCH 07/11] ARM64: dts: mediatek: add pericfg syscon to mt8516.dtsi
  2020-05-05 14:02 [PATCH 00/11] mediatek: add support for MediaTek Ethernet MAC Bartosz Golaszewski
                   ` (5 preceding siblings ...)
  2020-05-05 14:02 ` [PATCH 06/11] net: ethernet: mtk-eth-mac: new driver Bartosz Golaszewski
@ 2020-05-05 14:02 ` Bartosz Golaszewski
  2020-05-05 14:02 ` [PATCH 08/11] ARM64: dts: mediatek: add the ethernet node " Bartosz Golaszewski
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 40+ messages in thread
From: Bartosz Golaszewski @ 2020-05-05 14:02 UTC (permalink / raw)
  To: Rob Herring, David S . Miller, Matthias Brugger, Felix Fietkau,
	John Crispin, Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann,
	Fabien Parent
  Cc: devicetree, linux-kernel, netdev, linux-arm-kernel,
	linux-mediatek, Bartosz Golaszewski

From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

This adds support for the PERICFG register range as a syscon. This will
soon be used by the MediaTek Ethernet MAC driver for NIC configuration.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 arch/arm64/boot/dts/mediatek/mt8516.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8516.dtsi b/arch/arm64/boot/dts/mediatek/mt8516.dtsi
index 2f8adf042195..8cedaf74ae86 100644
--- a/arch/arm64/boot/dts/mediatek/mt8516.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8516.dtsi
@@ -191,6 +191,11 @@ infracfg: infracfg@10001000 {
 			#clock-cells = <1>;
 		};
 
+		pericfg: pericfg@10003050 {
+			compatible = "mediatek,mt8516-pericfg", "syscon";
+			reg = <0 0x10003050 0 0x1000>;
+		};
+
 		apmixedsys: apmixedsys@10018000 {
 			compatible = "mediatek,mt8516-apmixedsys", "syscon";
 			reg = <0 0x10018000 0 0x710>;
-- 
2.25.0


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

* [PATCH 08/11] ARM64: dts: mediatek: add the ethernet node to mt8516.dtsi
  2020-05-05 14:02 [PATCH 00/11] mediatek: add support for MediaTek Ethernet MAC Bartosz Golaszewski
                   ` (6 preceding siblings ...)
  2020-05-05 14:02 ` [PATCH 07/11] ARM64: dts: mediatek: add pericfg syscon to mt8516.dtsi Bartosz Golaszewski
@ 2020-05-05 14:02 ` Bartosz Golaszewski
  2020-05-05 14:02 ` [PATCH 09/11] ARM64: dts: mediatek: add an alias for ethernet0 for pumpkin boards Bartosz Golaszewski
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 40+ messages in thread
From: Bartosz Golaszewski @ 2020-05-05 14:02 UTC (permalink / raw)
  To: Rob Herring, David S . Miller, Matthias Brugger, Felix Fietkau,
	John Crispin, Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann,
	Fabien Parent
  Cc: devicetree, linux-kernel, netdev, linux-arm-kernel,
	linux-mediatek, Bartosz Golaszewski

From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

Add the Ethernet MAC node to mt8516.dtsi. This defines parameters common
to all the boards based on this SoC.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 arch/arm64/boot/dts/mediatek/mt8516.dtsi | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8516.dtsi b/arch/arm64/boot/dts/mediatek/mt8516.dtsi
index 8cedaf74ae86..89af661e7f63 100644
--- a/arch/arm64/boot/dts/mediatek/mt8516.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8516.dtsi
@@ -406,6 +406,18 @@ mmc2: mmc@11170000 {
 			status = "disabled";
 		};
 
+		ethernet: ethernet@11180000 {
+			compatible = "mediatek,mt8516-eth";
+			reg = <0 0x11180000 0 0x1000>;
+			mediatek,pericfg = <&pericfg>;
+			interrupts = <GIC_SPI 111 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&topckgen CLK_TOP_RG_ETH>,
+				 <&topckgen CLK_TOP_66M_ETH>,
+				 <&topckgen CLK_TOP_133M_ETH>;
+			clock-names = "core", "reg", "trans";
+			status = "disabled";
+		};
+
 		rng: rng@1020c000 {
 			compatible = "mediatek,mt8516-rng",
 				     "mediatek,mt7623-rng";
-- 
2.25.0


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

* [PATCH 09/11] ARM64: dts: mediatek: add an alias for ethernet0 for pumpkin boards
  2020-05-05 14:02 [PATCH 00/11] mediatek: add support for MediaTek Ethernet MAC Bartosz Golaszewski
                   ` (7 preceding siblings ...)
  2020-05-05 14:02 ` [PATCH 08/11] ARM64: dts: mediatek: add the ethernet node " Bartosz Golaszewski
@ 2020-05-05 14:02 ` Bartosz Golaszewski
  2020-05-05 14:02 ` [PATCH 10/11] ARM64: dts: mediatek: add ethernet pins " Bartosz Golaszewski
  2020-05-05 14:02 ` [PATCH 11/11] ARM64: dts: mediatek: enable ethernet on " Bartosz Golaszewski
  10 siblings, 0 replies; 40+ messages in thread
From: Bartosz Golaszewski @ 2020-05-05 14:02 UTC (permalink / raw)
  To: Rob Herring, David S . Miller, Matthias Brugger, Felix Fietkau,
	John Crispin, Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann,
	Fabien Parent
  Cc: devicetree, linux-kernel, netdev, linux-arm-kernel,
	linux-mediatek, Bartosz Golaszewski

From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

Add the ethernet0 alias for ethernet so that u-boot can find this node
and fill in the MAC address.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi b/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi
index a31093d7142b..97d9b000c37e 100644
--- a/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi
+++ b/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi
@@ -9,6 +9,7 @@
 / {
 	aliases {
 		serial0 = &uart0;
+		ethernet0 = &ethernet;
 	};
 
 	chosen {
-- 
2.25.0


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

* [PATCH 10/11] ARM64: dts: mediatek: add ethernet pins for pumpkin boards
  2020-05-05 14:02 [PATCH 00/11] mediatek: add support for MediaTek Ethernet MAC Bartosz Golaszewski
                   ` (8 preceding siblings ...)
  2020-05-05 14:02 ` [PATCH 09/11] ARM64: dts: mediatek: add an alias for ethernet0 for pumpkin boards Bartosz Golaszewski
@ 2020-05-05 14:02 ` Bartosz Golaszewski
  2020-05-05 14:02 ` [PATCH 11/11] ARM64: dts: mediatek: enable ethernet on " Bartosz Golaszewski
  10 siblings, 0 replies; 40+ messages in thread
From: Bartosz Golaszewski @ 2020-05-05 14:02 UTC (permalink / raw)
  To: Rob Herring, David S . Miller, Matthias Brugger, Felix Fietkau,
	John Crispin, Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann,
	Fabien Parent
  Cc: devicetree, linux-kernel, netdev, linux-arm-kernel,
	linux-mediatek, Bartosz Golaszewski

From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

Setup the pin control for the Ethernet MAC.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi b/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi
index 97d9b000c37e..4b1d5f69aba6 100644
--- a/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi
+++ b/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi
@@ -219,4 +219,19 @@ gpio_mux_int_n_pin {
 			bias-pull-up;
 		};
 	};
+
+	ethernet_pins_default: ethernet {
+		pins_ethernet {
+			pinmux = <MT8516_PIN_0_EINT0__FUNC_EXT_TXD0>,
+				 <MT8516_PIN_1_EINT1__FUNC_EXT_TXD1>,
+				 <MT8516_PIN_5_EINT5__FUNC_EXT_RXER>,
+				 <MT8516_PIN_6_EINT6__FUNC_EXT_RXC>,
+				 <MT8516_PIN_7_EINT7__FUNC_EXT_RXDV>,
+				 <MT8516_PIN_8_EINT8__FUNC_EXT_RXD0>,
+				 <MT8516_PIN_9_EINT9__FUNC_EXT_RXD1>,
+				 <MT8516_PIN_12_EINT12__FUNC_EXT_TXEN>,
+				 <MT8516_PIN_38_MRG_DI__FUNC_EXT_MDIO>,
+				 <MT8516_PIN_39_MRG_DO__FUNC_EXT_MDC>;
+		};
+	};
 };
-- 
2.25.0


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

* [PATCH 11/11] ARM64: dts: mediatek: enable ethernet on pumpkin boards
  2020-05-05 14:02 [PATCH 00/11] mediatek: add support for MediaTek Ethernet MAC Bartosz Golaszewski
                   ` (9 preceding siblings ...)
  2020-05-05 14:02 ` [PATCH 10/11] ARM64: dts: mediatek: add ethernet pins " Bartosz Golaszewski
@ 2020-05-05 14:02 ` Bartosz Golaszewski
  10 siblings, 0 replies; 40+ messages in thread
From: Bartosz Golaszewski @ 2020-05-05 14:02 UTC (permalink / raw)
  To: Rob Herring, David S . Miller, Matthias Brugger, Felix Fietkau,
	John Crispin, Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann,
	Fabien Parent
  Cc: devicetree, linux-kernel, netdev, linux-arm-kernel,
	linux-mediatek, Bartosz Golaszewski

From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

Add remaining properties to the ethernet node and enable it.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 .../boot/dts/mediatek/pumpkin-common.dtsi      | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi b/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi
index 4b1d5f69aba6..dfceffe6950a 100644
--- a/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi
+++ b/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi
@@ -167,6 +167,24 @@ &uart0 {
 	status = "okay";
 };
 
+&ethernet {
+	pinctrl-names = "default";
+	pinctrl-0 = <&ethernet_pins_default>;
+	phy-handle = <&eth_phy>;
+	phy-mode = "rmii";
+	mac-address = [00 00 00 00 00 00];
+	status = "okay";
+
+	mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		eth_phy: ethernet-phy@0 {
+			reg = <0>;
+		};
+	};
+};
+
 &usb0 {
 	status = "okay";
 	dr_mode = "peripheral";
-- 
2.25.0


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

* Re: [PATCH 05/11] net: core: provide devm_register_netdev()
  2020-05-05 14:02 ` [PATCH 05/11] net: core: provide devm_register_netdev() Bartosz Golaszewski
@ 2020-05-05 17:31   ` Jakub Kicinski
  2020-05-06  6:39     ` Bartosz Golaszewski
  2020-05-05 19:25   ` Edwin Peer
  1 sibling, 1 reply; 40+ messages in thread
From: Jakub Kicinski @ 2020-05-05 17:31 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Rob Herring, David S . Miller, Matthias Brugger, Felix Fietkau,
	John Crispin, Sean Wang, Mark Lee, Arnd Bergmann, Fabien Parent,
	devicetree, linux-kernel, netdev, linux-arm-kernel,
	linux-mediatek, Bartosz Golaszewski

On Tue,  5 May 2020 16:02:25 +0200 Bartosz Golaszewski wrote:
> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> 
> Provide devm_register_netdev() - a device resource managed variant
> of register_netdev(). This new helper will only work for net_device
> structs that have a parent device assigned and are devres managed too.
> 
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>

> diff --git a/net/core/dev.c b/net/core/dev.c
> index 522288177bbd..99db537c9468 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -9519,6 +9519,54 @@ int register_netdev(struct net_device *dev)
>  }
>  EXPORT_SYMBOL(register_netdev);
>  
> +struct netdevice_devres {
> +	struct net_device *ndev;
> +};

Is there really a need to define a structure if we only need a pointer?

> +static void devm_netdev_release(struct device *dev, void *this)
> +{
> +	struct netdevice_devres *res = this;
> +
> +	unregister_netdev(res->ndev);
> +}
> +
> +/**
> + *	devm_register_netdev - resource managed variant of register_netdev()
> + *	@ndev: device to register
> + *
> + *	This is a devres variant of register_netdev() for which the unregister
> + *	function will be call automatically when the parent device of ndev
> + *	is detached.
> + */
> +int devm_register_netdev(struct net_device *ndev)
> +{
> +	struct netdevice_devres *dr;
> +	int ret;
> +
> +	/* struct net_device itself must be devres managed. */
> +	BUG_ON(!(ndev->priv_flags & IFF_IS_DEVRES));
> +	/* struct net_device must have a parent device - it will be the device
> +	 * managing this resource.
> +	 */
> +	BUG_ON(!ndev->dev.parent);

Please convert those to WARN_ON, and return an error. No need to crash
the kernel.

> +	dr = devres_alloc(devm_netdev_release, sizeof(*dr), GFP_KERNEL);
> +	if (!dr)
> +		return -ENOMEM;
> +
> +	ret = register_netdev(ndev);
> +	if (ret) {
> +		devres_free(dr);
> +		return ret;
> +	}
> +
> +	dr->ndev = ndev;
> +	devres_add(ndev->dev.parent, dr);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(devm_register_netdev);

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

* Re: [PATCH 06/11] net: ethernet: mtk-eth-mac: new driver
  2020-05-05 14:02 ` [PATCH 06/11] net: ethernet: mtk-eth-mac: new driver Bartosz Golaszewski
@ 2020-05-05 17:47   ` Andrew Lunn
  2020-05-06  7:02     ` Bartosz Golaszewski
  2020-05-05 18:04   ` Jakub Kicinski
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 40+ messages in thread
From: Andrew Lunn @ 2020-05-05 17:47 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Rob Herring, David S . Miller, Matthias Brugger, Felix Fietkau,
	John Crispin, Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann,
	Fabien Parent, devicetree, netdev, linux-kernel,
	Bartosz Golaszewski, linux-mediatek, linux-arm-kernel

> +static struct net_device *mtk_mac_get_netdev(struct mtk_mac_priv *priv)
> +{
> +	char *ptr = (char *)priv;
> +
> +	return (struct net_device *)(ptr - ALIGN(sizeof(struct net_device),
> +						 NETDEV_ALIGN));
> +}

Bit of an odd way to do it. It is much more normal to just have

    return priv->netdev;

> +static struct sk_buff *mtk_mac_alloc_skb(struct net_device *ndev)
> +{
> +	uintptr_t tail, offset;
> +	struct sk_buff *skb;
> +
> +	skb = dev_alloc_skb(MTK_MAC_MAX_FRAME_SIZE);
> +	if (!skb)
> +		return NULL;
> +
> +	/* Align to 16 bytes. */
> +	tail = (uintptr_t)skb_tail_pointer(skb);
> +	if (tail & (MTK_MAC_SKB_ALIGNMENT - 1)) {
> +		offset = tail & (MTK_MAC_SKB_ALIGNMENT - 1);
> +		skb_reserve(skb, MTK_MAC_SKB_ALIGNMENT - offset);
> +	}
> +
> +	/* Ensure 16-byte alignment of the skb pointer: eth_type_trans() will
> +	 * extract the Ethernet header (14 bytes) so we need two more bytes.
> +	 */
> +	skb_reserve(skb, 2);

NET_IP_ALIGN

There might also be something in skbuf.h which will do your 16 byte
alignment for you.

> +static int mtk_mac_enable(struct net_device *ndev)
> +{
> +	struct mtk_mac_priv *priv = netdev_priv(ndev);
> +	unsigned int val;
> +	int ret;
> +
> +	mtk_mac_nic_disable_pd(priv);
> +	mtk_mac_intr_mask_all(priv);
> +	mtk_mac_dma_stop(priv);
> +	netif_carrier_off(ndev);

Attaching the PHY will turn the carrier off.  If you are using phylib
correctly, you should not have to touch the carrier status, phylib
will do it for you.

> +	/* Configure flow control */
> +	val = MTK_MAC_VAL_FC_CFG_SEND_PAUSE_TH_2K;
> +	val <<= MTK_MAC_OFF_FC_CFG_SEND_PAUSE_TH;
> +	val |= MTK_MAC_BIT_FC_CFG_BP_EN;
> +	val |= MTK_MAC_BIT_FC_CFG_UC_PAUSE_DIR;
> +	regmap_write(priv->regs, MTK_MAC_REG_FC_CFG, val);
> +
> +	/* Set SEND_PAUSE_RLS to 1K */
> +	val = MTK_MAC_VAL_EXT_CFG_SND_PAUSE_RLS_1K;
> +	val <<= MTK_MAC_OFF_EXT_CFG_SND_PAUSE_RLS;
> +	regmap_write(priv->regs, MTK_MAC_REG_EXT_CFG, val);

Pause is something this is auto-negotiated. You should be setting this
in your link change notifier which phylib will call when the link goes
up.

> +static int mtk_mac_mdio_rwok_wait(struct mtk_mac_priv *priv)
> +{
> +	unsigned long start = jiffies;
> +	unsigned int val;
> +
> +	for (;;) {
> +		regmap_read(priv->regs, MTK_MAC_REG_PHY_CTRL0, &val);
> +		if (val & MTK_MAC_BIT_PHY_CTRL0_RWOK)
> +			break;
> +
> +		udelay(10);
> +		if (time_after(jiffies, start + MTK_MAC_WAIT_TIMEOUT))
> +			return -ETIMEDOUT;
> +	}

regmap_read_poll_timeout() ?

> +static int mtk_mac_mdio_read(struct mii_bus *mii, int phy_id, int regnum)
> +{
> +	struct mtk_mac_priv *priv = mii->priv;
> +	unsigned int val, data;
> +	int ret;

It would be good if here and in _write() you check for C45 addresses
and return -EOPNOTSUP.

> +
> +	mtk_mac_mdio_rwok_clear(priv);
> +
> +	val = (regnum << MTK_MAC_OFF_PHY_CTRL0_PREG);
> +	val &= MTK_MAC_MSK_PHY_CTRL0_PREG;
> +	val |= MTK_MAC_BIT_PHY_CTRL0_RDCMD;
> +
> +	regmap_write(priv->regs, MTK_MAC_REG_PHY_CTRL0, val);
> +
> +	ret = mtk_mac_mdio_rwok_wait(priv);
> +	if (ret)
> +		return ret;
> +
> +	regmap_read(priv->regs, MTK_MAC_REG_PHY_CTRL0, &data);
> +
> +	data &= MTK_MAC_MSK_PHY_CTRL0_RWDATA;
> +	data >>= MTK_MAC_OFF_PHY_CTRL0_RWDATA;
> +
> +	return data;
> +}

> +static int mtk_mac_mdio_init(struct net_device *ndev)
> +{
> +	struct mtk_mac_priv *priv = netdev_priv(ndev);
> +	struct device *dev = mtk_mac_get_dev(priv);
> +	struct device_node *of_node, *mdio_node;
> +	int ret;
> +
> +	of_node = dev->of_node;
> +
> +	mdio_node = of_get_child_by_name(of_node, "mdio");
> +	if (!mdio_node)
> +		return -ENODEV;
> +
> +	if (!of_device_is_available(mdio_node)) {
> +		ret = -ENODEV;
> +		goto out_put_node;
> +	}
> +
> +	priv->mii = devm_mdiobus_alloc(dev);
> +	if (!priv->mii) {
> +		ret = -ENOMEM;
> +		goto out_put_node;
> +	}
> +
> +	snprintf(priv->mii->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
> +	priv->mii->name = "mdio";

It is normal to include something like 'MTK' in the name.

> +	priv->mii->parent = dev;
> +	priv->mii->read = mtk_mac_mdio_read;
> +	priv->mii->write = mtk_mac_mdio_write;
> +	priv->mii->priv = priv;
> +
> +	ret = of_mdiobus_register(priv->mii, mdio_node);
> +
> +out_put_node:
> +	of_node_put(mdio_node);
> +	return ret;
> +}

  Andrew

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

* Re: [PATCH 06/11] net: ethernet: mtk-eth-mac: new driver
  2020-05-05 14:02 ` [PATCH 06/11] net: ethernet: mtk-eth-mac: new driver Bartosz Golaszewski
  2020-05-05 17:47   ` Andrew Lunn
@ 2020-05-05 18:04   ` Jakub Kicinski
  2020-05-06  7:09     ` Bartosz Golaszewski
  2020-05-06 19:16   ` Leon Romanovsky
       [not found]   ` <1588844771.5921.27.camel@mtksdccf07>
  3 siblings, 1 reply; 40+ messages in thread
From: Jakub Kicinski @ 2020-05-05 18:04 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Rob Herring, David S . Miller, Matthias Brugger, Felix Fietkau,
	John Crispin, Sean Wang, Mark Lee, Arnd Bergmann, Fabien Parent,
	devicetree, linux-kernel, netdev, linux-arm-kernel,
	linux-mediatek, Bartosz Golaszewski

On Tue,  5 May 2020 16:02:26 +0200 Bartosz Golaszewski wrote:
> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> 
> This adds the driver for the MediaTek Ethernet MAC used on the MT8* SoC
> family. For now we only support full-duplex.
> 
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>

> +#define MTK_MAC_VERSION				"1.0"

Please don't add driver versions, we're removing those from networking
drivers.

> +/* Represents the actual structure of descriptors used by the MAC. We can
> + * reuse the same structure for both TX and RX - the layout is the same, only
> + * the flags differ slightly.
> + */
> +struct mtk_mac_ring_desc {
> +	/* Contains both the status flags as well as packet length. */
> +	u32 status;
> +	u32 data_ptr;
> +	u32 vtag;
> +	u32 reserved;
> +} __aligned(4) __packed;

It will be aligned to 4, because the members are all 4B. And there is
no possibility of holes. You can safely remove those attrs.

> +static int mtk_mac_ring_pop_tail(struct mtk_mac_ring *ring,
> +				 struct mtk_mac_ring_desc_data *desc_data)
> +{
> +	struct mtk_mac_ring_desc *desc = &ring->descs[ring->tail];
> +	unsigned int status;
> +
> +	dma_rmb();

This should be after desc->status read, probably.

> +	status = desc->status;
> +
> +	if (!(status & MTK_MAC_DESC_BIT_COWN))
> +		return -1;
> +
> +	desc_data->len = status & MTK_MAC_DESC_MSK_LEN;
> +	desc_data->flags = status & ~MTK_MAC_DESC_MSK_LEN;
> +	desc_data->dma_addr = desc->data_ptr;
> +	desc_data->skb = ring->skbs[ring->tail];
> +
> +	desc->data_ptr = 0;
> +	desc->status = MTK_MAC_DESC_BIT_COWN;
> +	if (status & MTK_MAC_DESC_BIT_EOR)
> +		desc->status |= MTK_MAC_DESC_BIT_EOR;
> +
> +	dma_wmb();

What is this separating?

> +	ring->tail = (ring->tail + 1) % MTK_MAC_RING_NUM_DESCS;
> +	ring->count--;
> +
> +	return 0;
> +}
> +
> +static void mtk_mac_ring_push_head(struct mtk_mac_ring *ring,
> +				   struct mtk_mac_ring_desc_data *desc_data,
> +				   unsigned int flags)
> +{
> +	struct mtk_mac_ring_desc *desc = &ring->descs[ring->head];
> +	unsigned int status;
> +
> +	dma_rmb();

What's this barrier separating?

> +	status = desc->status;
> +
> +	ring->skbs[ring->head] = desc_data->skb;
> +	desc->data_ptr = desc_data->dma_addr;
> +
> +	status |= desc_data->len;
> +	if (flags)
> +		status |= flags;
> +	desc->status = status;
> +
> +	dma_wmb();
> +	desc->status &= ~MTK_MAC_DESC_BIT_COWN;
> +
> +	ring->head = (ring->head + 1) % MTK_MAC_RING_NUM_DESCS;
> +	ring->count++;
> +}

> +/* All processing for TX and RX happens in the napi poll callback. */
> +static irqreturn_t mtk_mac_handle_irq(int irq, void *data)
> +{
> +	struct mtk_mac_priv *priv;
> +	struct net_device *ndev;
> +	unsigned int status;
> +
> +	ndev = data;
> +	priv = netdev_priv(ndev);
> +
> +	if (netif_running(ndev)) {
> +		mtk_mac_intr_mask_all(priv);
> +		status = mtk_mac_intr_read_and_clear(priv);
> +
> +		/* RX Complete */
> +		if (status & MTK_MAC_BIT_INT_STS_FNRC)
> +			napi_schedule(&priv->napi);
> +
> +		/* TX Complete */
> +		if (status & MTK_MAC_BIT_INT_STS_TNTC)
> +			schedule_work(&priv->tx_work);
> +
> +		/* One of the counter reached 0x8000000 */
> +		if (status & MTK_MAC_REG_INT_STS_MIB_CNT_TH) {
> +			mtk_mac_update_stats(priv);
> +			mtk_mac_reset_counters(priv);
> +		}
> +
> +		mtk_mac_intr_unmask_all(priv);

Why do you unmask all IRQs here? The usual way to operate is to leave
TX and RX IRQs masked until NAPI finishes.

> +	}
> +
> +	return IRQ_HANDLED;
> +}

> +static int mtk_mac_enable(struct net_device *ndev)
> +{
> +	/* Reset all counters */
> +	mtk_mac_reset_counters(priv);

This doesn't reset the counters to zero, right?

> +	/* Enable Hash Table BIST and reset it */
> +	regmap_update_bits(priv->regs, MTK_MAC_REG_HASH_CTRL,
> +			   MTK_MAC_BIT_HASH_CTRL_BIST_EN,
> +			   MTK_MAC_BIT_HASH_CTRL_BIST_EN);

> +}
> +
> +static void mtk_mac_disable(struct net_device *ndev)
> +{
> +	struct mtk_mac_priv *priv = netdev_priv(ndev);
> +
> +	netif_stop_queue(ndev);
> +	napi_disable(&priv->napi);
> +	mtk_mac_intr_mask_all(priv);
> +	mtk_mac_dma_disable(priv);
> +	mtk_mac_intr_read_and_clear(priv);
> +	phy_stop(priv->phydev);
> +	phy_disconnect(priv->phydev);
> +	free_irq(ndev->irq, ndev);
> +	mtk_mac_free_rx_skbs(ndev);
> +	mtk_mac_free_tx_skbs(ndev);
> +}

> +static int mtk_mac_netdev_start_xmit(struct sk_buff *skb,
> +				     struct net_device *ndev)
> +{
> +	struct mtk_mac_priv *priv = netdev_priv(ndev);
> +	struct mtk_mac_ring *ring = &priv->tx_ring;
> +	struct device *dev = mtk_mac_get_dev(priv);
> +	struct mtk_mac_ring_desc_data desc_data;
> +
> +	if (skb->len > MTK_MAC_MAX_FRAME_SIZE)
> +		goto err_drop_packet;

This should never happen if you set mtu right, you can drop it.

> +	desc_data.dma_addr = mtk_mac_dma_map_tx(priv, skb);
> +	if (dma_mapping_error(dev, desc_data.dma_addr))
> +		goto err_drop_packet;
> +
> +	desc_data.skb = skb;
> +	desc_data.len = skb->len;
> +
> +	mtk_mac_lock(priv);
> +	mtk_mac_ring_push_head_tx(ring, &desc_data);
> +
> +	if (mtk_mac_ring_full(ring))
> +		netif_stop_queue(ndev);
> +	mtk_mac_unlock(priv);
> +
> +	mtk_mac_dma_resume_tx(priv);
> +
> +	return NETDEV_TX_OK;
> +
> +err_drop_packet:
> +	dev_kfree_skb(skb);
> +	ndev->stats.tx_dropped++;
> +	return NETDEV_TX_BUSY;
> +}

> +static void mtk_mac_tx_work(struct work_struct *work)
> +{
> +	struct mtk_mac_priv *priv;
> +	struct mtk_mac_ring *ring;
> +	struct net_device *ndev;
> +	bool wake = false;
> +	int ret;
> +
> +	priv = container_of(work, struct mtk_mac_priv, tx_work);
> +	ndev = mtk_mac_get_netdev(priv);
> +	ring = &priv->tx_ring;
> +
> +	for (;;) {
> +		mtk_mac_lock(priv);
> +
> +		if (!mtk_mac_ring_descs_available(ring)) {
> +			mtk_mac_unlock(priv);
> +			break;
> +		}
> +
> +		ret = mtk_mac_tx_complete(priv);
> +		mtk_mac_unlock(priv);
> +		if (ret)
> +			break;
> +
> +		wake = true;
> +	}
> +
> +	if (wake)
> +		netif_wake_queue(ndev);

This looks racy, if the TX path runs in parallel the queue may have
already been filled up at the point you wake it up.

> +}

Why do you clean the TX ring from a work rather than from the NAPI
context?

> +static void mtk_mac_set_rx_mode(struct net_device *ndev)
> +{
> +	struct mtk_mac_priv *priv = netdev_priv(ndev);
> +	struct netdev_hw_addr *hw_addr;
> +	unsigned int hash_addr, i;
> +
> +	if (ndev->flags & IFF_PROMISC) {
> +		regmap_update_bits(priv->regs, MTK_MAC_REG_ARL_CFG,
> +				   MTK_MAC_BIT_ARL_CFG_MISC_MODE,
> +				   MTK_MAC_BIT_ARL_CFG_MISC_MODE);
> +	} else if (netdev_mc_count(ndev) > MTK_MAC_HASHTABLE_MC_LIMIT ||
> +		   ndev->flags & IFF_ALLMULTI) {
> +		for (i = 0; i < MTK_MAC_HASHTABLE_SIZE_MAX; i++)
> +			mtk_mac_set_hashbit(priv, i);
> +	} else {
> +		netdev_for_each_mc_addr(hw_addr, ndev) {
> +			hash_addr = (hw_addr->addr[0] & 0x01) << 8;
> +			hash_addr += hw_addr->addr[5];
> +			mtk_mac_set_hashbit(priv, hash_addr);

Hm, are the hash bits cleared when address is removed?

> +		}
> +	}
> +}

> +static int mtk_mac_receive_packet(struct mtk_mac_priv *priv)
> +{
> +	struct net_device *ndev = mtk_mac_get_netdev(priv);
> +	struct mtk_mac_ring *ring = &priv->rx_ring;
> +	struct device *dev = mtk_mac_get_dev(priv);
> +	struct mtk_mac_ring_desc_data desc_data;
> +	struct sk_buff *new_skb;
> +	int ret;
> +
> +	mtk_mac_lock(priv);
> +	ret = mtk_mac_ring_pop_tail(ring, &desc_data);
> +	mtk_mac_unlock(priv);
> +	if (ret)
> +		return -1;
> +
> +	mtk_mac_dma_unmap_rx(priv, &desc_data);
> +
> +	if ((desc_data.flags & MTK_MAC_DESC_BIT_RX_CRCE) ||
> +	    (desc_data.flags & MTK_MAC_DESC_BIT_RX_OSIZE)) {
> +		/* Error packet -> drop and reuse skb. */
> +		new_skb = desc_data.skb;
> +		goto map_skb;
> +	}
> +
> +	new_skb = mtk_mac_alloc_skb(ndev);
> +	if (!new_skb) {
> +		netdev_err(ndev, "out of memory for skb\n");

No need for printing, kernel will complain loudly about oom.

> +		ndev->stats.rx_dropped++;
> +		new_skb = desc_data.skb;
> +		goto map_skb;
> +	}
> +
> +	skb_put(desc_data.skb, desc_data.len);
> +	desc_data.skb->ip_summed = CHECKSUM_NONE;
> +	desc_data.skb->protocol = eth_type_trans(desc_data.skb, ndev);
> +	desc_data.skb->dev = ndev;
> +	netif_receive_skb(desc_data.skb);
> +
> +map_skb:
> +	desc_data.dma_addr = mtk_mac_dma_map_rx(priv, new_skb);
> +	if (dma_mapping_error(dev, desc_data.dma_addr)) {
> +		dev_kfree_skb(new_skb);
> +		netdev_err(ndev, "DMA mapping error of RX descriptor\n");
> +		return -ENOMEM;

In this case nothing will ever replenish the RX ring right? If we hit
this condition 128 times the ring will be empty?

> +	}
> +
> +	desc_data.len = skb_tailroom(new_skb);
> +	desc_data.skb = new_skb;
> +
> +	mtk_mac_lock(priv);
> +	mtk_mac_ring_push_head_rx(ring, &desc_data);
> +	mtk_mac_unlock(priv);
> +
> +	return 0;
> +}
> +
> +static int mtk_mac_process_rx(struct mtk_mac_priv *priv, int budget)
> +{
> +	int received, ret;
> +
> +	for (received = 0, ret = 0; received < budget && ret == 0; received++)
> +		ret = mtk_mac_receive_packet(priv);
> +
> +	mtk_mac_dma_resume_rx(priv);
> +
> +	return received;
> +}

> +static int mtk_mac_probe(struct platform_device *pdev)
> +{

> +	mtk_mac_set_mode_rmii(priv);
> +
> +	dev->coherent_dma_mask = DMA_BIT_MASK(32);
> +	dev->dma_mask = &dev->coherent_dma_mask;

Why set this manually and no thru dma_set_mask_and_coherent()?

> +	priv->ring_base = dmam_alloc_coherent(dev, MTK_MAC_DMA_SIZE,
> +					      &priv->dma_addr,
> +					      GFP_KERNEL | GFP_DMA);
> +	if (!priv->ring_base)
> +		return -ENOMEM;
> +
> +	mtk_mac_nic_disable_pd(priv);
> +	mtk_mac_init_config(priv);
> +
> +	ret = mtk_mac_mdio_init(ndev);
> +	if (ret)
> +		return ret;
> +
> +	ret = eth_platform_get_mac_address(dev, ndev->dev_addr);
> +	if (ret || !is_valid_ether_addr(ndev->dev_addr)) {
> +		random_ether_addr(ndev->dev_addr);
> +		ndev->addr_assign_type = NET_ADDR_RANDOM;

eth_hw_addr_random()

> +	}
> +
> +	ndev->netdev_ops = &mtk_mac_netdev_ops;
> +	ndev->ethtool_ops = &mtk_mac_ethtool_ops;
> +
> +	netif_napi_add(ndev, &priv->napi, mtk_mac_poll, MTK_MAC_NAPI_WEIGHT);
> +
> +	return devm_register_netdev(ndev);
> +}


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

* Re: [PATCH 05/11] net: core: provide devm_register_netdev()
  2020-05-05 14:02 ` [PATCH 05/11] net: core: provide devm_register_netdev() Bartosz Golaszewski
  2020-05-05 17:31   ` Jakub Kicinski
@ 2020-05-05 19:25   ` Edwin Peer
  2020-05-06  6:46     ` Bartosz Golaszewski
  1 sibling, 1 reply; 40+ messages in thread
From: Edwin Peer @ 2020-05-05 19:25 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Rob Herring, David S . Miller, Matthias Brugger, Felix Fietkau,
	John Crispin, Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann,
	Fabien Parent, devicetree, linux-kernel, netdev,
	linux-arm-kernel, linux-mediatek, Bartosz Golaszewski

On Tue, May 5, 2020 at 7:05 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>
> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>
> Provide devm_register_netdev() - a device resource managed variant
> of register_netdev(). This new helper will only work for net_device
> structs that have a parent device assigned and are devres managed too.
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> ---
>  include/linux/netdevice.h |  4 ++++
>  net/core/dev.c            | 48 +++++++++++++++++++++++++++++++++++++++
>  net/ethernet/eth.c        |  1 +
>  3 files changed, 53 insertions(+)
>
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index 130a668049ab..433bd5ca2efc 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -1515,6 +1515,8 @@ struct net_device_ops {
>   * @IFF_FAILOVER_SLAVE: device is lower dev of a failover master device
>   * @IFF_L3MDEV_RX_HANDLER: only invoke the rx handler of L3 master device
>   * @IFF_LIVE_RENAME_OK: rename is allowed while device is up and running
> + * @IFF_IS_DEVRES: this structure was allocated dynamically and is managed by
> + *     devres
>   */
>  enum netdev_priv_flags {
>         IFF_802_1Q_VLAN                 = 1<<0,
> @@ -1548,6 +1550,7 @@ enum netdev_priv_flags {
>         IFF_FAILOVER_SLAVE              = 1<<28,
>         IFF_L3MDEV_RX_HANDLER           = 1<<29,
>         IFF_LIVE_RENAME_OK              = 1<<30,
> +       IFF_IS_DEVRES                   = 1<<31,
>  };
>
>  #define IFF_802_1Q_VLAN                        IFF_802_1Q_VLAN
> @@ -4206,6 +4209,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
>                          count)
>
>  int register_netdev(struct net_device *dev);
> +int devm_register_netdev(struct net_device *ndev);
>  void unregister_netdev(struct net_device *dev);
>
>  /* General hardware address lists handling functions */
> diff --git a/net/core/dev.c b/net/core/dev.c
> index 522288177bbd..99db537c9468 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -9519,6 +9519,54 @@ int register_netdev(struct net_device *dev)
>  }
>  EXPORT_SYMBOL(register_netdev);
>
> +struct netdevice_devres {
> +       struct net_device *ndev;
> +};
> +
> +static void devm_netdev_release(struct device *dev, void *this)
> +{
> +       struct netdevice_devres *res = this;
> +
> +       unregister_netdev(res->ndev);
> +}
> +
> +/**
> + *     devm_register_netdev - resource managed variant of register_netdev()
> + *     @ndev: device to register
> + *
> + *     This is a devres variant of register_netdev() for which the unregister
> + *     function will be call automatically when the parent device of ndev
> + *     is detached.
> + */
> +int devm_register_netdev(struct net_device *ndev)
> +{
> +       struct netdevice_devres *dr;
> +       int ret;
> +
> +       /* struct net_device itself must be devres managed. */
> +       BUG_ON(!(ndev->priv_flags & IFF_IS_DEVRES));
> +       /* struct net_device must have a parent device - it will be the device
> +        * managing this resource.
> +        */

Catching static programming errors seems like an expensive use of the
last runtime flag in the enum. It would be weird to devres manage the
unregister and not also choose to manage the underlying memory in the
same fashion, so it wouldn't be an obvious mistake to make. If it must
be enforced, one could also iterate over the registered release
functions and check for the presence of devm_free_netdev without
burning the flag.

> +       BUG_ON(!ndev->dev.parent);
> +
> +       dr = devres_alloc(devm_netdev_release, sizeof(*dr), GFP_KERNEL);
> +       if (!dr)
> +               return -ENOMEM;
> +
> +       ret = register_netdev(ndev);
> +       if (ret) {
> +               devres_free(dr);
> +               return ret;
> +       }
> +
> +       dr->ndev = ndev;
> +       devres_add(ndev->dev.parent, dr);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(devm_register_netdev);
> +
>  int netdev_refcnt_read(const struct net_device *dev)
>  {
>         int i, refcnt = 0;
> diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
> index c8b903302ff2..ce9b5e576f20 100644
> --- a/net/ethernet/eth.c
> +++ b/net/ethernet/eth.c
> @@ -423,6 +423,7 @@ struct net_device *devm_alloc_etherdev_mqs(struct device *dev, int sizeof_priv,
>
>         *dr = netdev;
>         devres_add(dev, dr);
> +       netdev->priv_flags |= IFF_IS_DEVRES;
>
>         return netdev;
>  }
> --
> 2.25.0
>

Regards,
Edwin Peer

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

* Re: [PATCH 05/11] net: core: provide devm_register_netdev()
  2020-05-05 17:31   ` Jakub Kicinski
@ 2020-05-06  6:39     ` Bartosz Golaszewski
  2020-05-06 17:12       ` Jakub Kicinski
  0 siblings, 1 reply; 40+ messages in thread
From: Bartosz Golaszewski @ 2020-05-06  6:39 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Rob Herring, David S . Miller, Matthias Brugger, Felix Fietkau,
	John Crispin, Sean Wang, Mark Lee, Arnd Bergmann, Fabien Parent,
	devicetree, Linux Kernel Mailing List, netdev, Linux ARM,
	linux-mediatek, Bartosz Golaszewski

wt., 5 maj 2020 o 19:31 Jakub Kicinski <kuba@kernel.org> napisał(a):
>
> On Tue,  5 May 2020 16:02:25 +0200 Bartosz Golaszewski wrote:
> > From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> >
> > Provide devm_register_netdev() - a device resource managed variant
> > of register_netdev(). This new helper will only work for net_device
> > structs that have a parent device assigned and are devres managed too.
> >
> > Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>
> > diff --git a/net/core/dev.c b/net/core/dev.c
> > index 522288177bbd..99db537c9468 100644
> > --- a/net/core/dev.c
> > +++ b/net/core/dev.c
> > @@ -9519,6 +9519,54 @@ int register_netdev(struct net_device *dev)
> >  }
> >  EXPORT_SYMBOL(register_netdev);
> >
> > +struct netdevice_devres {
> > +     struct net_device *ndev;
> > +};
>
> Is there really a need to define a structure if we only need a pointer?
>

There is no need for that, but it really is more readable this way.
Also: using a pointer directly doesn't save us any memory nor code
here.

Bart

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

* Re: [PATCH 05/11] net: core: provide devm_register_netdev()
  2020-05-05 19:25   ` Edwin Peer
@ 2020-05-06  6:46     ` Bartosz Golaszewski
  2020-05-06 18:20       ` Edwin Peer
  0 siblings, 1 reply; 40+ messages in thread
From: Bartosz Golaszewski @ 2020-05-06  6:46 UTC (permalink / raw)
  To: Edwin Peer
  Cc: Rob Herring, David S . Miller, Matthias Brugger, John Crispin,
	Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann,
	Fabien Parent, devicetree, Linux Kernel Mailing List, netdev,
	Linux ARM, linux-mediatek, Bartosz Golaszewski

wt., 5 maj 2020 o 21:25 Edwin Peer <edwin.peer@broadcom.com> napisał(a):
> > +
> > +static void devm_netdev_release(struct device *dev, void *this)
> > +{
> > +       struct netdevice_devres *res = this;
> > +
> > +       unregister_netdev(res->ndev);
> > +}
> > +
> > +/**
> > + *     devm_register_netdev - resource managed variant of register_netdev()
> > + *     @ndev: device to register
> > + *
> > + *     This is a devres variant of register_netdev() for which the unregister
> > + *     function will be call automatically when the parent device of ndev
> > + *     is detached.
> > + */
> > +int devm_register_netdev(struct net_device *ndev)
> > +{
> > +       struct netdevice_devres *dr;
> > +       int ret;
> > +
> > +       /* struct net_device itself must be devres managed. */
> > +       BUG_ON(!(ndev->priv_flags & IFF_IS_DEVRES));
> > +       /* struct net_device must have a parent device - it will be the device
> > +        * managing this resource.
> > +        */
>
> Catching static programming errors seems like an expensive use of the
> last runtime flag in the enum. It would be weird to devres manage the
> unregister and not also choose to manage the underlying memory in the
> same fashion, so it wouldn't be an obvious mistake to make. If it must
> be enforced, one could also iterate over the registered release
> functions and check for the presence of devm_free_netdev without
> burning the flag.
>

Hi Edwin,

I've submitted this patch some time ago already and was told to check
if the underlying memory is managed too. I guess I could try to use
devres_find() here though.

Re the last bit in priv_flags: is this really a problem though? It's
not like struct net_device must remain stable - e.g. we can make
priv_flags a bitmap.

Bart

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

* Re: [PATCH 06/11] net: ethernet: mtk-eth-mac: new driver
  2020-05-05 17:47   ` Andrew Lunn
@ 2020-05-06  7:02     ` Bartosz Golaszewski
  0 siblings, 0 replies; 40+ messages in thread
From: Bartosz Golaszewski @ 2020-05-06  7:02 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Rob Herring, David S . Miller, Matthias Brugger, Felix Fietkau,
	John Crispin, Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann,
	Fabien Parent, devicetree, netdev, Linux Kernel Mailing List,
	Bartosz Golaszewski, linux-mediatek, Linux ARM

Hi Andrew,

thanks for the review.

wt., 5 maj 2020 o 19:47 Andrew Lunn <andrew@lunn.ch> napisał(a):
>
> > +static struct net_device *mtk_mac_get_netdev(struct mtk_mac_priv *priv)
> > +{
> > +     char *ptr = (char *)priv;
> > +
> > +     return (struct net_device *)(ptr - ALIGN(sizeof(struct net_device),
> > +                                              NETDEV_ALIGN));
> > +}
>
> Bit of an odd way to do it. It is much more normal to just have
>
>     return priv->netdev;
>

But then you store a pointer to the starting address of the structure
in that very structure. This is actually weirder to me. :) I'd say:
let's generalize it and provide a counterpart to netdev_priv():
priv_to_netdev(), how about that?

For the other issues: I'll address them in v2.

Bart

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

* Re: [PATCH 06/11] net: ethernet: mtk-eth-mac: new driver
  2020-05-05 18:04   ` Jakub Kicinski
@ 2020-05-06  7:09     ` Bartosz Golaszewski
  2020-05-06 17:19       ` Jakub Kicinski
  0 siblings, 1 reply; 40+ messages in thread
From: Bartosz Golaszewski @ 2020-05-06  7:09 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Rob Herring, David S . Miller, Matthias Brugger, John Crispin,
	Sean Wang, Mark Lee, Arnd Bergmann, Fabien Parent, devicetree,
	Linux Kernel Mailing List, netdev, Linux ARM, linux-mediatek,
	Bartosz Golaszewski

Hi Jakub,

thanks for the review.

wt., 5 maj 2020 o 20:04 Jakub Kicinski <kuba@kernel.org> napisał(a):
>
> > +/* Represents the actual structure of descriptors used by the MAC. We can
> > + * reuse the same structure for both TX and RX - the layout is the same, only
> > + * the flags differ slightly.
> > + */
> > +struct mtk_mac_ring_desc {
> > +     /* Contains both the status flags as well as packet length. */
> > +     u32 status;
> > +     u32 data_ptr;
> > +     u32 vtag;
> > +     u32 reserved;
> > +} __aligned(4) __packed;
>
> It will be aligned to 4, because the members are all 4B. And there is
> no possibility of holes. You can safely remove those attrs.
>

I noticed some other drivers whose descriptors are well aligned define
these attributes anyway so I assumed it's a convention. I'll drop them
in v2.

>
> > +     status = desc->status;
> > +
> > +     if (!(status & MTK_MAC_DESC_BIT_COWN))
> > +             return -1;
> > +
> > +     desc_data->len = status & MTK_MAC_DESC_MSK_LEN;
> > +     desc_data->flags = status & ~MTK_MAC_DESC_MSK_LEN;
> > +     desc_data->dma_addr = desc->data_ptr;
> > +     desc_data->skb = ring->skbs[ring->tail];
> > +
> > +     desc->data_ptr = 0;
> > +     desc->status = MTK_MAC_DESC_BIT_COWN;
> > +     if (status & MTK_MAC_DESC_BIT_EOR)
> > +             desc->status |= MTK_MAC_DESC_BIT_EOR;
> > +
> > +     dma_wmb();
>
> What is this separating?

I'll add comments to barriers in v2.

>
> > +/* All processing for TX and RX happens in the napi poll callback. */
> > +static irqreturn_t mtk_mac_handle_irq(int irq, void *data)
> > +{
> > +     struct mtk_mac_priv *priv;
> > +     struct net_device *ndev;
> > +     unsigned int status;
> > +
> > +     ndev = data;
> > +     priv = netdev_priv(ndev);
> > +
> > +     if (netif_running(ndev)) {
> > +             mtk_mac_intr_mask_all(priv);
> > +             status = mtk_mac_intr_read_and_clear(priv);
> > +
> > +             /* RX Complete */
> > +             if (status & MTK_MAC_BIT_INT_STS_FNRC)
> > +                     napi_schedule(&priv->napi);
> > +
> > +             /* TX Complete */
> > +             if (status & MTK_MAC_BIT_INT_STS_TNTC)
> > +                     schedule_work(&priv->tx_work);
> > +
> > +             /* One of the counter reached 0x8000000 */
> > +             if (status & MTK_MAC_REG_INT_STS_MIB_CNT_TH) {
> > +                     mtk_mac_update_stats(priv);
> > +                     mtk_mac_reset_counters(priv);
> > +             }
> > +
> > +             mtk_mac_intr_unmask_all(priv);
>
> Why do you unmask all IRQs here? The usual way to operate is to leave
> TX and RX IRQs masked until NAPI finishes.
>

I actually did it before as the leftover comment says above the
function. Then I thought this way we mask interrupt for a shorter
period of time. I can go back to the previous approach.

> > +     }
> > +
> > +     return IRQ_HANDLED;
> > +}
>
> > +static int mtk_mac_enable(struct net_device *ndev)
> > +{
> > +     /* Reset all counters */
> > +     mtk_mac_reset_counters(priv);
>
> This doesn't reset the counters to zero, right?
>

Yes, it does actually. I'll drop it in v2 - it's not necessary.

>
> > +static void mtk_mac_tx_work(struct work_struct *work)
> > +{
> > +     struct mtk_mac_priv *priv;
> > +     struct mtk_mac_ring *ring;
> > +     struct net_device *ndev;
> > +     bool wake = false;
> > +     int ret;
> > +
> > +     priv = container_of(work, struct mtk_mac_priv, tx_work);
> > +     ndev = mtk_mac_get_netdev(priv);
> > +     ring = &priv->tx_ring;
> > +
> > +     for (;;) {
> > +             mtk_mac_lock(priv);
> > +
> > +             if (!mtk_mac_ring_descs_available(ring)) {
> > +                     mtk_mac_unlock(priv);
> > +                     break;
> > +             }
> > +
> > +             ret = mtk_mac_tx_complete(priv);
> > +             mtk_mac_unlock(priv);
> > +             if (ret)
> > +                     break;
> > +
> > +             wake = true;
> > +     }
> > +
> > +     if (wake)
> > +             netif_wake_queue(ndev);
>
> This looks racy, if the TX path runs in parallel the queue may have
> already been filled up at the point you wake it up.
>
> > +}
>
> Why do you clean the TX ring from a work rather than from the NAPI
> context?
>

So this was unclear to me, that's why I went with a workqueue. The
budget argument in napi poll is for RX. Should I put some cap on the
number of TX descriptors processed in napi context?

>
> > +static int mtk_mac_receive_packet(struct mtk_mac_priv *priv)
> > +{
> > +     struct net_device *ndev = mtk_mac_get_netdev(priv);
> > +     struct mtk_mac_ring *ring = &priv->rx_ring;
> > +     struct device *dev = mtk_mac_get_dev(priv);
> > +     struct mtk_mac_ring_desc_data desc_data;
> > +     struct sk_buff *new_skb;
> > +     int ret;
> > +
> > +     mtk_mac_lock(priv);
> > +     ret = mtk_mac_ring_pop_tail(ring, &desc_data);
> > +     mtk_mac_unlock(priv);
> > +     if (ret)
> > +             return -1;
> > +
> > +     mtk_mac_dma_unmap_rx(priv, &desc_data);
> > +
> > +     if ((desc_data.flags & MTK_MAC_DESC_BIT_RX_CRCE) ||
> > +         (desc_data.flags & MTK_MAC_DESC_BIT_RX_OSIZE)) {
> > +             /* Error packet -> drop and reuse skb. */
> > +             new_skb = desc_data.skb;
> > +             goto map_skb;
> > +     }
> > +
> > +     new_skb = mtk_mac_alloc_skb(ndev);
> > +     if (!new_skb) {
> > +             netdev_err(ndev, "out of memory for skb\n");
>
> No need for printing, kernel will complain loudly about oom.
>
> > +             ndev->stats.rx_dropped++;
> > +             new_skb = desc_data.skb;
> > +             goto map_skb;
> > +     }
> > +
> > +     skb_put(desc_data.skb, desc_data.len);
> > +     desc_data.skb->ip_summed = CHECKSUM_NONE;
> > +     desc_data.skb->protocol = eth_type_trans(desc_data.skb, ndev);
> > +     desc_data.skb->dev = ndev;
> > +     netif_receive_skb(desc_data.skb);
> > +
> > +map_skb:
> > +     desc_data.dma_addr = mtk_mac_dma_map_rx(priv, new_skb);
> > +     if (dma_mapping_error(dev, desc_data.dma_addr)) {
> > +             dev_kfree_skb(new_skb);
> > +             netdev_err(ndev, "DMA mapping error of RX descriptor\n");
> > +             return -ENOMEM;
>
> In this case nothing will ever replenish the RX ring right? If we hit
> this condition 128 times the ring will be empty?
>

Indeed. What should I do if this fails though?

I'll address all other issues in v2.

Bart

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

* Re: [PATCH 05/11] net: core: provide devm_register_netdev()
  2020-05-06  6:39     ` Bartosz Golaszewski
@ 2020-05-06 17:12       ` Jakub Kicinski
  2020-05-07  9:25         ` Bartosz Golaszewski
  0 siblings, 1 reply; 40+ messages in thread
From: Jakub Kicinski @ 2020-05-06 17:12 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Rob Herring, David S . Miller, Matthias Brugger, Felix Fietkau,
	John Crispin, Sean Wang, Mark Lee, Arnd Bergmann, Fabien Parent,
	devicetree, Linux Kernel Mailing List, netdev, Linux ARM,
	linux-mediatek, Bartosz Golaszewski

On Wed, 6 May 2020 08:39:47 +0200 Bartosz Golaszewski wrote:
> wt., 5 maj 2020 o 19:31 Jakub Kicinski <kuba@kernel.org> napisał(a):
> >
> > On Tue,  5 May 2020 16:02:25 +0200 Bartosz Golaszewski wrote:  
> > > From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> > >
> > > Provide devm_register_netdev() - a device resource managed variant
> > > of register_netdev(). This new helper will only work for net_device
> > > structs that have a parent device assigned and are devres managed too.
> > >
> > > Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>  
> >  
> > > diff --git a/net/core/dev.c b/net/core/dev.c
> > > index 522288177bbd..99db537c9468 100644
> > > --- a/net/core/dev.c
> > > +++ b/net/core/dev.c
> > > @@ -9519,6 +9519,54 @@ int register_netdev(struct net_device *dev)
> > >  }
> > >  EXPORT_SYMBOL(register_netdev);
> > >
> > > +struct netdevice_devres {
> > > +     struct net_device *ndev;
> > > +};  
> >
> > Is there really a need to define a structure if we only need a pointer?
> >  
> 
> There is no need for that, but it really is more readable this way.
> Also: using a pointer directly doesn't save us any memory nor code
> here.

I don't care either way but devm_alloc_etherdev_mqs() and co. are using
the double pointer directly. Please make things consistent. Either do
the same, or define the structure in some header and convert other
helpers to also make use of it.

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

* Re: [PATCH 06/11] net: ethernet: mtk-eth-mac: new driver
  2020-05-06  7:09     ` Bartosz Golaszewski
@ 2020-05-06 17:19       ` Jakub Kicinski
  0 siblings, 0 replies; 40+ messages in thread
From: Jakub Kicinski @ 2020-05-06 17:19 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Rob Herring, David S . Miller, Matthias Brugger, John Crispin,
	Sean Wang, Mark Lee, Arnd Bergmann, Fabien Parent, devicetree,
	Linux Kernel Mailing List, netdev, Linux ARM, linux-mediatek,
	Bartosz Golaszewski

On Wed, 6 May 2020 09:09:52 +0200 Bartosz Golaszewski wrote:
> > > +}  
> >
> > Why do you clean the TX ring from a work rather than from the NAPI
> > context?
> 
> So this was unclear to me, that's why I went with a workqueue. The
> budget argument in napi poll is for RX. Should I put some cap on the
> number of TX descriptors processed in napi context?

The prevailing wisdom is to not count the TX cleanup as work at all.
I think the best practice is to first clean up all the TX you can, 
and then do at must @budget of RX.

Perhaps one day we will come up with a good way of capping TX, but
today not counting it towards budget is the safe choice.

> > > +static int mtk_mac_receive_packet(struct mtk_mac_priv *priv)
> > > +{
> > > +     struct net_device *ndev = mtk_mac_get_netdev(priv);
> > > +     struct mtk_mac_ring *ring = &priv->rx_ring;
> > > +     struct device *dev = mtk_mac_get_dev(priv);
> > > +     struct mtk_mac_ring_desc_data desc_data;
> > > +     struct sk_buff *new_skb;
> > > +     int ret;
> > > +
> > > +     mtk_mac_lock(priv);
> > > +     ret = mtk_mac_ring_pop_tail(ring, &desc_data);
> > > +     mtk_mac_unlock(priv);
> > > +     if (ret)
> > > +             return -1;
> > > +
> > > +     mtk_mac_dma_unmap_rx(priv, &desc_data);
> > > +
> > > +     if ((desc_data.flags & MTK_MAC_DESC_BIT_RX_CRCE) ||
> > > +         (desc_data.flags & MTK_MAC_DESC_BIT_RX_OSIZE)) {
> > > +             /* Error packet -> drop and reuse skb. */
> > > +             new_skb = desc_data.skb;
> > > +             goto map_skb;
> > > +     }
> > > +
> > > +     new_skb = mtk_mac_alloc_skb(ndev);
> > > +     if (!new_skb) {
> > > +             netdev_err(ndev, "out of memory for skb\n");  
> >
> > No need for printing, kernel will complain loudly about oom.
> >  
> > > +             ndev->stats.rx_dropped++;
> > > +             new_skb = desc_data.skb;
> > > +             goto map_skb;
> > > +     }
> > > +
> > > +     skb_put(desc_data.skb, desc_data.len);
> > > +     desc_data.skb->ip_summed = CHECKSUM_NONE;
> > > +     desc_data.skb->protocol = eth_type_trans(desc_data.skb, ndev);
> > > +     desc_data.skb->dev = ndev;
> > > +     netif_receive_skb(desc_data.skb);
> > > +
> > > +map_skb:
> > > +     desc_data.dma_addr = mtk_mac_dma_map_rx(priv, new_skb);
> > > +     if (dma_mapping_error(dev, desc_data.dma_addr)) {
> > > +             dev_kfree_skb(new_skb);
> > > +             netdev_err(ndev, "DMA mapping error of RX descriptor\n");
> > > +             return -ENOMEM;  
> >
> > In this case nothing will ever replenish the RX ring right? If we hit
> > this condition 128 times the ring will be empty?
> 
> Indeed. What should I do if this fails though?

I think if you move things around it should work:

	skb = pop_tail();
	if (!skb)
		return;

	new_skb = alloc();
	if (!new_skb)
		goto reuse;

	dma_map(new_skb);
	if (error)
		goto reuse;
	
	dma_unmap(skb);

	if (do_packet_processing()) 
		free(skb);
	else
		receive(skb);

	put_on_ring(new_skb);


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

* Re: [PATCH 05/11] net: core: provide devm_register_netdev()
  2020-05-06  6:46     ` Bartosz Golaszewski
@ 2020-05-06 18:20       ` Edwin Peer
  0 siblings, 0 replies; 40+ messages in thread
From: Edwin Peer @ 2020-05-06 18:20 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Rob Herring, David S . Miller, Matthias Brugger, John Crispin,
	Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann,
	Fabien Parent, devicetree, Linux Kernel Mailing List, netdev,
	Linux ARM, linux-mediatek, Bartosz Golaszewski

On Tue, May 5, 2020 at 11:46 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> Re the last bit in priv_flags: is this really a problem though? It's
> not like struct net_device must remain stable - e.g. we can make
> priv_flags a bitmap.

Fair enough.

Regards,
Edwin Peer

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

* Re: [PATCH 06/11] net: ethernet: mtk-eth-mac: new driver
  2020-05-05 14:02 ` [PATCH 06/11] net: ethernet: mtk-eth-mac: new driver Bartosz Golaszewski
  2020-05-05 17:47   ` Andrew Lunn
  2020-05-05 18:04   ` Jakub Kicinski
@ 2020-05-06 19:16   ` Leon Romanovsky
  2020-05-06 19:23     ` Jakub Kicinski
  2020-05-06 19:24     ` Joe Perches
       [not found]   ` <1588844771.5921.27.camel@mtksdccf07>
  3 siblings, 2 replies; 40+ messages in thread
From: Leon Romanovsky @ 2020-05-06 19:16 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Rob Herring, David S . Miller, Matthias Brugger, Felix Fietkau,
	John Crispin, Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann,
	Fabien Parent, devicetree, linux-kernel, linux-netdev,
	linux-arm-kernel, linux-mediatek, Bartosz Golaszewski

On Tue, May 5, 2020 at 5:03 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>
> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>
> This adds the driver for the MediaTek Ethernet MAC used on the MT8* SoC
> family. For now we only support full-duplex.
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> ---
>  drivers/net/ethernet/mediatek/Kconfig       |    6 +
>  drivers/net/ethernet/mediatek/Makefile      |    1 +
>  drivers/net/ethernet/mediatek/mtk_eth_mac.c | 1476 +++++++++++++++++++
>  3 files changed, 1483 insertions(+)
>  create mode 100644 drivers/net/ethernet/mediatek/mtk_eth_mac.c
>
> diff --git a/drivers/net/ethernet/mediatek/Kconfig b/drivers/net/ethernet/mediatek/Kconfig
> index 5079b8090f16..5c3793076765 100644
> --- a/drivers/net/ethernet/mediatek/Kconfig
> +++ b/drivers/net/ethernet/mediatek/Kconfig
> @@ -14,4 +14,10 @@ config NET_MEDIATEK_SOC
>           This driver supports the gigabit ethernet MACs in the
>           MediaTek SoC family.
>
> +config NET_MEDIATEK_MAC
> +       tristate "MediaTek Ethernet MAC support"
> +       select PHYLIB
> +       help
> +         This driver supports the ethernet IP on MediaTek MT85** SoCs.
> +
>  endif #NET_VENDOR_MEDIATEK
> diff --git a/drivers/net/ethernet/mediatek/Makefile b/drivers/net/ethernet/mediatek/Makefile
> index 3362fb7ef859..f7f5638943a0 100644
> --- a/drivers/net/ethernet/mediatek/Makefile
> +++ b/drivers/net/ethernet/mediatek/Makefile
> @@ -5,3 +5,4 @@
>
>  obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o
>  mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o
> +obj-$(CONFIG_NET_MEDIATEK_MAC) += mtk_eth_mac.o
> diff --git a/drivers/net/ethernet/mediatek/mtk_eth_mac.c b/drivers/net/ethernet/mediatek/mtk_eth_mac.c
> new file mode 100644
> index 000000000000..e6e796e65228
> --- /dev/null
> +++ b/drivers/net/ethernet/mediatek/mtk_eth_mac.c
> @@ -0,0 +1,1476 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2020 MediaTek Corporation
> + * Copyright (c) 2020 BayLibre SAS
> + *
> + * Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> + */
> +
> +#include <linux/bits.h>
> +#include <linux/clk.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/etherdevice.h>
> +#include <linux/jiffies.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/mii.h>
> +#include <linux/module.h>
> +#include <linux/netdevice.h>
> +#include <linux/of.h>
> +#include <linux/of_mdio.h>
> +#include <linux/of_net.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm.h>
> +#include <linux/regmap.h>
> +#include <linux/spinlock.h>
> +#include <linux/workqueue.h>
> +
> +#define MTK_MAC_DRVNAME                                "mtk_eth_mac"
> +#define MTK_MAC_VERSION                                "1.0"

Please don't add driver version to new driver.

Thanks

> +
> +#define MTK_MAC_WAIT_TIMEOUT                   300
> +#define MTK_MAC_MAX_FRAME_SIZE                 1514
> +#define MTK_MAC_SKB_ALIGNMENT                  16
> +#define MTK_MAC_NAPI_WEIGHT                    64
> +#define MTK_MAC_HASHTABLE_MC_LIMIT             256
> +#define MTK_MAC_HASHTABLE_SIZE_MAX             512
> +
> +static const char *const mtk_mac_clk_names[] = { "core", "reg", "trans" };
> +#define MTK_MAC_NCLKS ARRAY_SIZE(mtk_mac_clk_names)
> +
> +/* PHY Control Register 0 */
> +#define MTK_MAC_REG_PHY_CTRL0                  0x0000
> +#define MTK_MAC_BIT_PHY_CTRL0_WTCMD            BIT(13)
> +#define MTK_MAC_BIT_PHY_CTRL0_RDCMD            BIT(14)
> +#define MTK_MAC_BIT_PHY_CTRL0_RWOK             BIT(15)
> +#define MTK_MAC_MSK_PHY_CTRL0_PREG             GENMASK(12, 8)
> +#define MTK_MAC_OFF_PHY_CTRL0_PREG             8
> +#define MTK_MAC_MSK_PHY_CTRL0_RWDATA           GENMASK(31, 16)
> +#define MTK_MAC_OFF_PHY_CTRL0_RWDATA           16
> +
> +/* PHY Control Register 1 */
> +#define MTK_MAC_REG_PHY_CTRL1                  0x0004
> +#define MTK_MAC_BIT_PHY_CTRL1_LINK_ST          BIT(0)
> +#define MTK_MAC_BIT_PHY_CTRL1_AN_EN            BIT(8)
> +#define MTK_MAC_OFF_PHY_CTRL1_FORCE_SPD                9
> +#define MTK_MAC_VAL_PHY_CTRL1_FORCE_SPD_10M    0x00
> +#define MTK_MAC_VAL_PHY_CTRL1_FORCE_SPD_100M   0x01
> +#define MTK_MAC_VAL_PHY_CTRL1_FORCE_SPD_1000M  0x02
> +#define MTK_MAC_BIT_PHY_CTRL1_FORCE_DPX                BIT(11)
> +#define MTK_MAC_BIT_PHY_CTRL1_FORCE_FC_RX      BIT(12)
> +#define MTK_MAC_BIT_PHY_CTRL1_FORCE_FC_TX      BIT(13)
> +
> +/* MAC Configuration Register */
> +#define MTK_MAC_REG_MAC_CFG                    0x0008
> +#define MTK_MAC_OFF_MAC_CFG_IPG                        10
> +#define MTK_MAC_VAL_MAC_CFG_IPG_96BIT          GENMASK(4, 0)
> +#define MTK_MAC_BIT_MAC_CFG_MAXLEN_1522                BIT(16)
> +#define MTK_MAC_BIT_MAC_CFG_AUTO_PAD           BIT(19)
> +#define MTK_MAC_BIT_MAC_CFG_CRC_STRIP          BIT(20)
> +#define MTK_MAC_BIT_MAC_CFG_VLAN_STRIP         BIT(22)
> +#define MTK_MAC_BIT_MAC_CFG_NIC_PD             BIT(31)
> +
> +/* Flow-Control Configuration Register */
> +#define MTK_MAC_REG_FC_CFG                     0x000c
> +#define MTK_MAC_BIT_FC_CFG_BP_EN               BIT(7)
> +#define MTK_MAC_BIT_FC_CFG_UC_PAUSE_DIR        BIT(8)
> +#define MTK_MAC_OFF_FC_CFG_SEND_PAUSE_TH       16
> +#define MTK_MAC_VAL_FC_CFG_SEND_PAUSE_TH_2K    0x800
> +
> +/* ARL Configuration Register */
> +#define MTK_MAC_REG_ARL_CFG                    0x0010
> +#define MTK_MAC_BIT_ARL_CFG_HASH_ALG           BIT(0)
> +#define MTK_MAC_BIT_ARL_CFG_MISC_MODE          BIT(4)
> +
> +/* MAC High and Low Bytes Registers */
> +#define MTK_MAC_REG_MY_MAC_H                   0x0014
> +#define MTK_MAC_REG_MY_MAC_L                   0x0018
> +
> +/* Hash Table Control Register */
> +#define MTK_MAC_REG_HASH_CTRL                  0x001c
> +#define MTK_MAC_MSK_HASH_CTRL_HASH_BIT_ADDR    GENMASK(8, 0)
> +#define MTK_MAC_BIT_HASH_CTRL_HASH_BIT_DATA    BIT(12)
> +#define MTK_MAC_BIT_HASH_CTRL_ACC_CMD          BIT(13)
> +#define MTK_MAC_BIT_HASH_CTRL_CMD_START                BIT(14)
> +#define MTK_MAC_BIT_HASH_CTRL_BIST_EN          BIT(31)
> +
> +/* TX DMA Control Register */
> +#define MTK_MAC_REG_TX_DMA_CTRL                        0x0034
> +#define MTK_MAC_BIT_TX_DMA_CTRL_START          BIT(0)
> +#define MTK_MAC_BIT_TX_DMA_CTRL_STOP           BIT(1)
> +#define MTK_MAC_BIT_TX_DMA_CTRL_RESUME         BIT(2)
> +
> +/* RX DMA Control Register */
> +#define MTK_MAC_REG_RX_DMA_CTRL                        0x0038
> +#define MTK_MAC_BIT_RX_DMA_CTRL_START          BIT(0)
> +#define MTK_MAC_BIT_RX_DMA_CTRL_STOP           BIT(1)
> +#define MTK_MAC_BIT_RX_DMA_CTRL_RESUME         BIT(2)
> +
> +/* DMA Address Registers */
> +#define MTK_MAC_REG_TX_DPTR                    0x003c
> +#define MTK_MAC_REG_RX_DPTR                    0x0040
> +#define MTK_MAC_REG_TX_BASE_ADDR               0x0044
> +#define MTK_MAC_REG_RX_BASE_ADDR               0x0048
> +
> +/* Interrupt Status Register */
> +#define MTK_MAC_REG_INT_STS                    0x0050
> +#define MTK_MAC_REG_INT_STS_PORT_STS_CHG       BIT(2)
> +#define MTK_MAC_REG_INT_STS_MIB_CNT_TH         BIT(3)
> +#define MTK_MAC_BIT_INT_STS_FNRC               BIT(6)
> +#define MTK_MAC_BIT_INT_STS_TNTC               BIT(8)
> +
> +/* Interrupt Mask Register */
> +#define MTK_MAC_REG_INT_MASK                   0x0054
> +#define MTK_MAC_BIT_INT_MASK_FNRC              BIT(6)
> +
> +/* Misc. Config Register */
> +#define MTK_MAC_REG_TEST1                      0x005c
> +#define MTK_MAC_BIT_TEST1_RST_HASH_MBIST       BIT(31)
> +
> +/* Extended Configuration Register */
> +#define MTK_MAC_REG_EXT_CFG                    0x0060
> +#define MTK_MAC_OFF_EXT_CFG_SND_PAUSE_RLS      16
> +#define MTK_MAC_VAL_EXT_CFG_SND_PAUSE_RLS_1K   0x400
> +
> +/* EthSys Configuration Register */
> +#define MTK_MAC_REG_SYS_CONF                   0x0094
> +#define MTK_MAC_BIT_MII_PAD_OUT_ENABLE         BIT(0)
> +#define MTK_MAC_BIT_EXT_MDC_MODE               BIT(1)
> +#define MTK_MAC_BIT_SWC_MII_MODE               BIT(2)
> +
> +/* MAC Clock Configuration Register */
> +#define MTK_MAC_REG_MAC_CLK_CONF               0x00ac
> +#define MTK_MAC_MSK_MAC_CLK_CONF               GENMASK(7, 0)
> +#define MTK_MAC_BIT_CLK_DIV_10                 0x0a
> +
> +/* Counter registers. */
> +#define MTK_MAC_REG_C_RXOKPKT                  0x0100
> +#define MTK_MAC_REG_C_RXOKBYTE                 0x0104
> +#define MTK_MAC_REG_C_RXRUNT                   0x0108
> +#define MTK_MAC_REG_C_RXLONG                   0x010c
> +#define MTK_MAC_REG_C_RXDROP                   0x0110
> +#define MTK_MAC_REG_C_RXCRC                    0x0114
> +#define MTK_MAC_REG_C_RXARLDROP                        0x0118
> +#define MTK_MAC_REG_C_RXVLANDROP               0x011c
> +#define MTK_MAC_REG_C_RXCSERR                  0x0120
> +#define MTK_MAC_REG_C_RXPAUSE                  0x0124
> +#define MTK_MAC_REG_C_TXOKPKT                  0x0128
> +#define MTK_MAC_REG_C_TXOKBYTE                 0x012c
> +#define MTK_MAC_REG_C_TXPAUSECOL               0x0130
> +#define MTK_MAC_REG_C_TXRTY                    0x0134
> +#define MTK_MAC_REG_C_TXSKIP                   0x0138
> +#define MTK_MAC_REG_C_TX_ARP                   0x013c
> +#define MTK_MAC_REG_C_RX_RERR                  0x01d8
> +#define MTK_MAC_REG_C_RX_UNI                   0x01dc
> +#define MTK_MAC_REG_C_RX_MULTI                 0x01e0
> +#define MTK_MAC_REG_C_RX_BROAD                 0x01e4
> +#define MTK_MAC_REG_C_RX_ALIGNERR              0x01e8
> +#define MTK_MAC_REG_C_TX_UNI                   0x01ec
> +#define MTK_MAC_REG_C_TX_MULTI                 0x01f0
> +#define MTK_MAC_REG_C_TX_BROAD                 0x01f4
> +#define MTK_MAC_REG_C_TX_TIMEOUT               0x01f8
> +#define MTK_MAC_REG_C_TX_LATECOL               0x01fc
> +#define MTK_MAC_REG_C_RX_LENGTHERR             0x0214
> +#define MTK_MAC_REG_C_RX_TWIST                 0x0218
> +
> +/* Ethernet CFG Control */
> +#define MTK_PERICFG_REG_NIC_CFG_CON            0x03c4
> +#define MTK_PERICFG_MSK_NIC_CFG_CON_CFG_MII    GENMASK(3, 0)
> +#define MTK_PERICFG_BIT_NIC_CFG_CON_RMII       BIT(0)
> +
> +/* Represents the actual structure of descriptors used by the MAC. We can
> + * reuse the same structure for both TX and RX - the layout is the same, only
> + * the flags differ slightly.
> + */
> +struct mtk_mac_ring_desc {
> +       /* Contains both the status flags as well as packet length. */
> +       u32 status;
> +       u32 data_ptr;
> +       u32 vtag;
> +       u32 reserved;
> +} __aligned(4) __packed;
> +
> +#define MTK_MAC_DESC_MSK_LEN                   GENMASK(15, 0)
> +#define MTK_MAC_DESC_BIT_RX_CRCE               BIT(24)
> +#define MTK_MAC_DESC_BIT_RX_OSIZE              BIT(25)
> +#define MTK_MAC_DESC_BIT_INT                   BIT(27)
> +#define MTK_MAC_DESC_BIT_LS                    BIT(28)
> +#define MTK_MAC_DESC_BIT_FS                    BIT(29)
> +#define MTK_MAC_DESC_BIT_EOR                   BIT(30)
> +#define MTK_MAC_DESC_BIT_COWN                  BIT(31)
> +
> +/* Helper structure for storing data read from/written to descriptors in order
> + * to limit reads from/writes to DMA memory.
> + */
> +struct mtk_mac_ring_desc_data {
> +       unsigned int len;
> +       unsigned int flags;
> +       dma_addr_t dma_addr;
> +       struct sk_buff *skb;
> +};
> +
> +#define MTK_MAC_RING_NUM_DESCS                 128
> +#define MTK_MAC_NUM_TX_DESCS                   MTK_MAC_RING_NUM_DESCS
> +#define MTK_MAC_NUM_RX_DESCS                   MTK_MAC_RING_NUM_DESCS
> +#define MTK_MAC_NUM_DESCS_TOTAL                        (MTK_MAC_RING_NUM_DESCS * 2)
> +#define MTK_MAC_DMA_SIZE \
> +               (MTK_MAC_NUM_DESCS_TOTAL * sizeof(struct mtk_mac_ring_desc))
> +
> +struct mtk_mac_ring {
> +       struct mtk_mac_ring_desc *descs;
> +       struct sk_buff *skbs[MTK_MAC_RING_NUM_DESCS];
> +       unsigned int head;
> +       unsigned int tail;
> +       unsigned int count;
> +};
> +
> +struct mtk_mac_priv {
> +       struct regmap *regs;
> +       struct regmap *pericfg;
> +
> +       struct clk_bulk_data clks[MTK_MAC_NCLKS];
> +
> +       void *ring_base;
> +       struct mtk_mac_ring_desc *descs_base;
> +       dma_addr_t dma_addr;
> +       struct mtk_mac_ring tx_ring;
> +       struct mtk_mac_ring rx_ring;
> +       struct work_struct tx_work;
> +
> +       struct mii_bus *mii;
> +       struct napi_struct napi;
> +
> +       struct device_node *phy_node;
> +       phy_interface_t phy_intf;
> +       struct phy_device *phydev;
> +       unsigned int link;
> +       int speed;
> +       int duplex;
> +
> +       /* Protects against concurrent descriptor access. */
> +       spinlock_t lock;
> +       unsigned long lock_flags;
> +
> +       struct rtnl_link_stats64 stats;
> +};
> +
> +static struct net_device *mtk_mac_get_netdev(struct mtk_mac_priv *priv)
> +{
> +       char *ptr = (char *)priv;
> +
> +       return (struct net_device *)(ptr - ALIGN(sizeof(struct net_device),
> +                                                NETDEV_ALIGN));
> +}
> +
> +static struct device *mtk_mac_get_dev(struct mtk_mac_priv *priv)
> +{
> +       struct net_device *ndev = mtk_mac_get_netdev(priv);
> +
> +       return ndev->dev.parent;
> +}
> +
> +static const struct regmap_config mtk_mac_regmap_config = {
> +       .reg_bits               = 32,
> +       .val_bits               = 32,
> +       .reg_stride             = 4,
> +       .fast_io                = true,
> +};
> +
> +static void mtk_mac_ring_init(struct mtk_mac_ring *ring,
> +                             struct mtk_mac_ring_desc *descs,
> +                             unsigned int start_count)
> +{
> +       memset(ring, 0, sizeof(*ring));
> +       ring->descs = descs;
> +       ring->head = 0;
> +       ring->tail = 0;
> +       ring->count = start_count;
> +}
> +
> +static int mtk_mac_ring_pop_tail(struct mtk_mac_ring *ring,
> +                                struct mtk_mac_ring_desc_data *desc_data)
> +{
> +       struct mtk_mac_ring_desc *desc = &ring->descs[ring->tail];
> +       unsigned int status;
> +
> +       dma_rmb();
> +       status = desc->status;
> +
> +       if (!(status & MTK_MAC_DESC_BIT_COWN))
> +               return -1;
> +
> +       desc_data->len = status & MTK_MAC_DESC_MSK_LEN;
> +       desc_data->flags = status & ~MTK_MAC_DESC_MSK_LEN;
> +       desc_data->dma_addr = desc->data_ptr;
> +       desc_data->skb = ring->skbs[ring->tail];
> +
> +       desc->data_ptr = 0;
> +       desc->status = MTK_MAC_DESC_BIT_COWN;
> +       if (status & MTK_MAC_DESC_BIT_EOR)
> +               desc->status |= MTK_MAC_DESC_BIT_EOR;
> +
> +       dma_wmb();
> +
> +       ring->tail = (ring->tail + 1) % MTK_MAC_RING_NUM_DESCS;
> +       ring->count--;
> +
> +       return 0;
> +}
> +
> +static void mtk_mac_ring_push_head(struct mtk_mac_ring *ring,
> +                                  struct mtk_mac_ring_desc_data *desc_data,
> +                                  unsigned int flags)
> +{
> +       struct mtk_mac_ring_desc *desc = &ring->descs[ring->head];
> +       unsigned int status;
> +
> +       dma_rmb();
> +       status = desc->status;
> +
> +       ring->skbs[ring->head] = desc_data->skb;
> +       desc->data_ptr = desc_data->dma_addr;
> +
> +       status |= desc_data->len;
> +       if (flags)
> +               status |= flags;
> +       desc->status = status;
> +
> +       dma_wmb();
> +       desc->status &= ~MTK_MAC_DESC_BIT_COWN;
> +
> +       ring->head = (ring->head + 1) % MTK_MAC_RING_NUM_DESCS;
> +       ring->count++;
> +}
> +
> +static void mtk_mac_ring_push_head_rx(struct mtk_mac_ring *ring,
> +                                     struct mtk_mac_ring_desc_data *desc_data)
> +{
> +       mtk_mac_ring_push_head(ring, desc_data, 0);
> +}
> +
> +static void mtk_mac_ring_push_head_tx(struct mtk_mac_ring *ring,
> +                                     struct mtk_mac_ring_desc_data *desc_data)
> +{
> +       static const unsigned int flags = MTK_MAC_DESC_BIT_FS |
> +                                         MTK_MAC_DESC_BIT_LS |
> +                                         MTK_MAC_DESC_BIT_INT;
> +
> +       mtk_mac_ring_push_head(ring, desc_data, flags);
> +}
> +
> +static bool mtk_mac_ring_full(struct mtk_mac_ring *ring)
> +{
> +       return ring->count == MTK_MAC_RING_NUM_DESCS;
> +}
> +
> +static bool mtk_mac_ring_descs_available(struct mtk_mac_ring *ring)
> +{
> +       return ring->count > 0;
> +}
> +
> +static void mtk_mac_lock(struct mtk_mac_priv *priv)
> +{
> +       spin_lock_irqsave(&priv->lock, priv->lock_flags);
> +}
> +
> +static void mtk_mac_unlock(struct mtk_mac_priv *priv)
> +{
> +       spin_unlock_irqrestore(&priv->lock, priv->lock_flags);
> +}
> +
> +static dma_addr_t mtk_mac_dma_map_rx(struct mtk_mac_priv *priv,
> +                                    struct sk_buff *skb)
> +{
> +       struct device *dev = mtk_mac_get_dev(priv);
> +
> +       /* Data pointer for the RX DMA descriptor must be aligned to 4N + 2. */
> +       return dma_map_single(dev, skb_tail_pointer(skb) - 2,
> +                             skb_tailroom(skb), DMA_FROM_DEVICE);
> +}
> +
> +static void mtk_mac_dma_unmap_rx(struct mtk_mac_priv *priv,
> +                                struct mtk_mac_ring_desc_data *desc_data)
> +{
> +       struct device *dev = mtk_mac_get_dev(priv);
> +
> +       dma_unmap_single(dev, desc_data->dma_addr,
> +                        skb_tailroom(desc_data->skb), DMA_FROM_DEVICE);
> +}
> +
> +static dma_addr_t mtk_mac_dma_map_tx(struct mtk_mac_priv *priv,
> +                                    struct sk_buff *skb)
> +{
> +       struct device *dev = mtk_mac_get_dev(priv);
> +
> +       return dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
> +}
> +
> +static void mtk_mac_dma_unmap_tx(struct mtk_mac_priv *priv,
> +                                struct mtk_mac_ring_desc_data *desc_data)
> +{
> +       struct device *dev = mtk_mac_get_dev(priv);
> +
> +       return dma_unmap_single(dev, desc_data->dma_addr,
> +                               desc_data->len, DMA_TO_DEVICE);
> +}
> +
> +static void mtk_mac_nic_disable_pd(struct mtk_mac_priv *priv)
> +{
> +       regmap_update_bits(priv->regs, MTK_MAC_REG_MAC_CFG,
> +                          MTK_MAC_BIT_MAC_CFG_NIC_PD, 0);
> +}
> +
> +static void mtk_mac_intr_unmask_all(struct mtk_mac_priv *priv)
> +{
> +       regmap_write(priv->regs, MTK_MAC_REG_INT_MASK, 0);
> +}
> +
> +static void mtk_mac_intr_mask_all(struct mtk_mac_priv *priv)
> +{
> +       regmap_write(priv->regs, MTK_MAC_REG_INT_MASK, ~0);
> +}
> +
> +static unsigned int mtk_mac_intr_read_and_clear(struct mtk_mac_priv *priv)
> +{
> +       unsigned int val;
> +
> +       regmap_read(priv->regs, MTK_MAC_REG_INT_STS, &val);
> +       regmap_write(priv->regs, MTK_MAC_REG_INT_STS, val);
> +
> +       return val;
> +}
> +
> +static void mtk_mac_dma_init(struct mtk_mac_priv *priv)
> +{
> +       struct mtk_mac_ring_desc *desc;
> +       unsigned int val;
> +       int i;
> +
> +       priv->descs_base = (struct mtk_mac_ring_desc *)priv->ring_base;
> +
> +       for (i = 0; i < MTK_MAC_NUM_DESCS_TOTAL; i++) {
> +               desc = &priv->descs_base[i];
> +
> +               memset(desc, 0, sizeof(*desc));
> +               desc->status = MTK_MAC_DESC_BIT_COWN;
> +               if ((i == MTK_MAC_NUM_TX_DESCS - 1) ||
> +                   (i == MTK_MAC_NUM_DESCS_TOTAL - 1))
> +                       desc->status |= MTK_MAC_DESC_BIT_EOR;
> +       }
> +
> +       mtk_mac_ring_init(&priv->tx_ring, priv->descs_base, 0);
> +       mtk_mac_ring_init(&priv->rx_ring,
> +                         priv->descs_base + MTK_MAC_NUM_TX_DESCS,
> +                         MTK_MAC_NUM_RX_DESCS);
> +
> +       /* Set DMA pointers. */
> +       val = (unsigned int)priv->dma_addr;
> +       regmap_write(priv->regs, MTK_MAC_REG_TX_BASE_ADDR, val);
> +       regmap_write(priv->regs, MTK_MAC_REG_TX_DPTR, val);
> +
> +       val += sizeof(struct mtk_mac_ring_desc) * MTK_MAC_NUM_TX_DESCS;
> +       regmap_write(priv->regs, MTK_MAC_REG_RX_BASE_ADDR, val);
> +       regmap_write(priv->regs, MTK_MAC_REG_RX_DPTR, val);
> +}
> +
> +static void mtk_mac_dma_start(struct mtk_mac_priv *priv)
> +{
> +       regmap_update_bits(priv->regs, MTK_MAC_REG_TX_DMA_CTRL,
> +                          MTK_MAC_BIT_TX_DMA_CTRL_START,
> +                          MTK_MAC_BIT_TX_DMA_CTRL_START);
> +       regmap_update_bits(priv->regs, MTK_MAC_REG_RX_DMA_CTRL,
> +                          MTK_MAC_BIT_RX_DMA_CTRL_START,
> +                          MTK_MAC_BIT_RX_DMA_CTRL_START);
> +}
> +
> +static void mtk_mac_dma_stop(struct mtk_mac_priv *priv)
> +{
> +       regmap_write(priv->regs, MTK_MAC_REG_TX_DMA_CTRL,
> +                    MTK_MAC_BIT_TX_DMA_CTRL_STOP);
> +       regmap_write(priv->regs, MTK_MAC_REG_RX_DMA_CTRL,
> +                    MTK_MAC_BIT_RX_DMA_CTRL_STOP);
> +}
> +
> +static void mtk_mac_dma_disable(struct mtk_mac_priv *priv)
> +{
> +       int i;
> +
> +       mtk_mac_dma_stop(priv);
> +
> +       /* Take back all descriptors. */
> +       for (i = 0; i < MTK_MAC_NUM_DESCS_TOTAL; i++)
> +               priv->descs_base[i].status |= MTK_MAC_DESC_BIT_COWN;
> +}
> +
> +static void mtk_mac_dma_resume_rx(struct mtk_mac_priv *priv)
> +{
> +       regmap_update_bits(priv->regs, MTK_MAC_REG_RX_DMA_CTRL,
> +                          MTK_MAC_BIT_RX_DMA_CTRL_RESUME,
> +                          MTK_MAC_BIT_RX_DMA_CTRL_RESUME);
> +}
> +
> +static void mtk_mac_dma_resume_tx(struct mtk_mac_priv *priv)
> +{
> +       regmap_update_bits(priv->regs, MTK_MAC_REG_TX_DMA_CTRL,
> +                          MTK_MAC_BIT_TX_DMA_CTRL_RESUME,
> +                          MTK_MAC_BIT_TX_DMA_CTRL_RESUME);
> +}
> +
> +static void mtk_mac_set_mac_addr(struct net_device *ndev)
> +{
> +       struct mtk_mac_priv *priv = netdev_priv(ndev);
> +       u8 *mac_addr = ndev->dev_addr;
> +       unsigned int high, low;
> +
> +       high = mac_addr[0] << 8 | mac_addr[1] << 0;
> +       low = mac_addr[2] << 24 | mac_addr[3] << 16 |
> +             mac_addr[4] << 8 | mac_addr[5];
> +
> +       regmap_write(priv->regs, MTK_MAC_REG_MY_MAC_H, high);
> +       regmap_write(priv->regs, MTK_MAC_REG_MY_MAC_L, low);
> +}
> +
> +static void mtk_mac_reset_counters(struct mtk_mac_priv *priv)
> +{
> +       static const unsigned int counter_regs[] = {
> +               MTK_MAC_REG_C_RXOKPKT,
> +               MTK_MAC_REG_C_RXOKBYTE,
> +               MTK_MAC_REG_C_RXRUNT,
> +               MTK_MAC_REG_C_RXLONG,
> +               MTK_MAC_REG_C_RXDROP,
> +               MTK_MAC_REG_C_RXCRC,
> +               MTK_MAC_REG_C_RXARLDROP,
> +               MTK_MAC_REG_C_RXVLANDROP,
> +               MTK_MAC_REG_C_RXCSERR,
> +               MTK_MAC_REG_C_RXPAUSE,
> +               MTK_MAC_REG_C_TXOKPKT,
> +               MTK_MAC_REG_C_TXOKBYTE,
> +               MTK_MAC_REG_C_TXPAUSECOL,
> +               MTK_MAC_REG_C_TXRTY,
> +               MTK_MAC_REG_C_TXSKIP,
> +               MTK_MAC_REG_C_TX_ARP,
> +               MTK_MAC_REG_C_RX_RERR,
> +               MTK_MAC_REG_C_RX_UNI,
> +               MTK_MAC_REG_C_RX_MULTI,
> +               MTK_MAC_REG_C_RX_BROAD,
> +               MTK_MAC_REG_C_RX_ALIGNERR,
> +               MTK_MAC_REG_C_TX_UNI,
> +               MTK_MAC_REG_C_TX_MULTI,
> +               MTK_MAC_REG_C_TX_BROAD,
> +               MTK_MAC_REG_C_TX_TIMEOUT,
> +               MTK_MAC_REG_C_TX_LATECOL,
> +               MTK_MAC_REG_C_RX_LENGTHERR,
> +               MTK_MAC_REG_C_RX_TWIST,
> +       };
> +
> +       unsigned int i, val;
> +
> +       for (i = 0; i < ARRAY_SIZE(counter_regs); i++)
> +               regmap_read(priv->regs, counter_regs[i], &val);
> +}
> +
> +static void mtk_mac_update_stat(struct mtk_mac_priv *priv,
> +                               unsigned int reg, u64 *stat)
> +{
> +       unsigned int val;
> +
> +       regmap_read(priv->regs, reg, &val);
> +       *stat += val;
> +}
> +
> +/* Try to get as many stats as possible from the internal registers instead
> + * of tracking them ourselves.
> + */
> +static void mtk_mac_update_stats(struct mtk_mac_priv *priv)
> +{
> +       struct rtnl_link_stats64 *stats = &priv->stats;
> +
> +       /* OK packets and bytes. */
> +       mtk_mac_update_stat(priv, MTK_MAC_REG_C_RXOKPKT, &stats->rx_packets);
> +       mtk_mac_update_stat(priv, MTK_MAC_REG_C_TXOKPKT, &stats->tx_packets);
> +       mtk_mac_update_stat(priv, MTK_MAC_REG_C_RXOKBYTE, &stats->rx_bytes);
> +       mtk_mac_update_stat(priv, MTK_MAC_REG_C_TXOKBYTE, &stats->tx_bytes);
> +
> +       /* RX & TX multicast. */
> +       mtk_mac_update_stat(priv, MTK_MAC_REG_C_RX_MULTI, &stats->multicast);
> +       mtk_mac_update_stat(priv, MTK_MAC_REG_C_TX_MULTI, &stats->multicast);
> +
> +       /* Collisions. */
> +       mtk_mac_update_stat(priv, MTK_MAC_REG_C_TXPAUSECOL, &stats->collisions);
> +       mtk_mac_update_stat(priv, MTK_MAC_REG_C_TX_LATECOL, &stats->collisions);
> +       mtk_mac_update_stat(priv, MTK_MAC_REG_C_RXRUNT, &stats->collisions);
> +
> +       /* RX Errors. */
> +       mtk_mac_update_stat(priv, MTK_MAC_REG_C_RX_LENGTHERR,
> +                           &stats->rx_length_errors);
> +       mtk_mac_update_stat(priv, MTK_MAC_REG_C_RXLONG, &stats->rx_over_errors);
> +       mtk_mac_update_stat(priv, MTK_MAC_REG_C_RXCRC, &stats->rx_crc_errors);
> +       mtk_mac_update_stat(priv, MTK_MAC_REG_C_RX_ALIGNERR,
> +                           &stats->rx_frame_errors);
> +       mtk_mac_update_stat(priv, MTK_MAC_REG_C_RXDROP, &stats->rx_fifo_errors);
> +       /* Sum of the general RX error counter + all of the above. */
> +       mtk_mac_update_stat(priv, MTK_MAC_REG_C_RX_RERR, &stats->rx_errors);
> +       stats->rx_errors += stats->rx_length_errors;
> +       stats->rx_errors += stats->rx_over_errors;
> +       stats->rx_errors += stats->rx_crc_errors;
> +       stats->rx_errors += stats->rx_frame_errors;
> +       stats->rx_errors += stats->rx_fifo_errors;
> +}
> +
> +static struct sk_buff *mtk_mac_alloc_skb(struct net_device *ndev)
> +{
> +       uintptr_t tail, offset;
> +       struct sk_buff *skb;
> +
> +       skb = dev_alloc_skb(MTK_MAC_MAX_FRAME_SIZE);
> +       if (!skb)
> +               return NULL;
> +
> +       /* Align to 16 bytes. */
> +       tail = (uintptr_t)skb_tail_pointer(skb);
> +       if (tail & (MTK_MAC_SKB_ALIGNMENT - 1)) {
> +               offset = tail & (MTK_MAC_SKB_ALIGNMENT - 1);
> +               skb_reserve(skb, MTK_MAC_SKB_ALIGNMENT - offset);
> +       }
> +
> +       /* Ensure 16-byte alignment of the skb pointer: eth_type_trans() will
> +        * extract the Ethernet header (14 bytes) so we need two more bytes.
> +        */
> +       skb_reserve(skb, 2);
> +
> +       return skb;
> +}
> +
> +static int mtk_mac_prepare_rx_skbs(struct net_device *ndev)
> +{
> +       struct mtk_mac_priv *priv = netdev_priv(ndev);
> +       struct mtk_mac_ring *ring = &priv->rx_ring;
> +       struct device *dev = mtk_mac_get_dev(priv);
> +       struct mtk_mac_ring_desc *desc;
> +       struct sk_buff *skb;
> +       dma_addr_t dma_addr;
> +       int i;
> +
> +       for (i = 0; i < MTK_MAC_NUM_RX_DESCS; i++) {
> +               skb = mtk_mac_alloc_skb(ndev);
> +               if (!skb)
> +                       return -ENOMEM;
> +
> +               dma_addr = mtk_mac_dma_map_rx(priv, skb);
> +               if (dma_mapping_error(dev, dma_addr)) {
> +                       dev_kfree_skb(skb);
> +                       return -ENOMEM;
> +               }
> +
> +               desc = &ring->descs[i];
> +               desc->data_ptr = dma_addr;
> +               desc->status |= skb_tailroom(skb) & MTK_MAC_DESC_MSK_LEN;
> +               desc->status &= ~MTK_MAC_DESC_BIT_COWN;
> +               ring->skbs[i] = skb;
> +       }
> +
> +       ring->count = MTK_MAC_NUM_RX_DESCS;
> +
> +       return 0;
> +}
> +
> +/* All processing for TX and RX happens in the napi poll callback. */
> +static irqreturn_t mtk_mac_handle_irq(int irq, void *data)
> +{
> +       struct mtk_mac_priv *priv;
> +       struct net_device *ndev;
> +       unsigned int status;
> +
> +       ndev = data;
> +       priv = netdev_priv(ndev);
> +
> +       if (netif_running(ndev)) {
> +               mtk_mac_intr_mask_all(priv);
> +               status = mtk_mac_intr_read_and_clear(priv);
> +
> +               /* RX Complete */
> +               if (status & MTK_MAC_BIT_INT_STS_FNRC)
> +                       napi_schedule(&priv->napi);
> +
> +               /* TX Complete */
> +               if (status & MTK_MAC_BIT_INT_STS_TNTC)
> +                       schedule_work(&priv->tx_work);
> +
> +               /* One of the counter reached 0x8000000 */
> +               if (status & MTK_MAC_REG_INT_STS_MIB_CNT_TH) {
> +                       mtk_mac_update_stats(priv);
> +                       mtk_mac_reset_counters(priv);
> +               }
> +
> +               mtk_mac_intr_unmask_all(priv);
> +       }
> +
> +       return IRQ_HANDLED;
> +}
> +
> +static void mtk_mac_free_rx_skbs(struct net_device *ndev)
> +{
> +       struct mtk_mac_priv *priv = netdev_priv(ndev);
> +       struct mtk_mac_ring *ring = &priv->rx_ring;
> +       struct mtk_mac_ring_desc_data desc_data;
> +       struct mtk_mac_ring_desc *desc;
> +       int i;
> +
> +       for (i = 0; i < MTK_MAC_NUM_RX_DESCS; i++) {
> +               desc = &ring->descs[i];
> +
> +               if (!desc->data_ptr)
> +                       continue;
> +
> +               desc_data.dma_addr = desc->data_ptr;
> +               desc_data.skb = ring->skbs[i];
> +
> +               mtk_mac_dma_unmap_rx(priv, &desc_data);
> +               dev_kfree_skb(desc_data.skb);
> +       }
> +}
> +
> +static void mtk_mac_free_tx_skbs(struct net_device *ndev)
> +{
> +       struct mtk_mac_priv *priv = netdev_priv(ndev);
> +       struct mtk_mac_ring *ring = &priv->tx_ring;
> +       struct mtk_mac_ring_desc_data desc_data;
> +       struct mtk_mac_ring_desc *desc;
> +       int i;
> +
> +       for (i = 0; i < MTK_MAC_NUM_TX_DESCS; i++) {
> +               desc = &ring->descs[i];
> +
> +               if (!desc->data_ptr)
> +                       continue;
> +
> +               desc_data.dma_addr = desc->data_ptr;
> +               desc_data.len = desc->status & MTK_MAC_DESC_MSK_LEN;
> +               desc_data.skb = ring->skbs[i];
> +
> +               mtk_mac_dma_unmap_tx(priv, &desc_data);
> +               dev_kfree_skb(desc_data.skb);
> +       }
> +}
> +
> +static void mtk_mac_phy_config(struct mtk_mac_priv *priv)
> +{
> +       unsigned int val;
> +
> +       if (priv->speed == SPEED_1000)
> +               val = MTK_MAC_VAL_PHY_CTRL1_FORCE_SPD_1000M;
> +       else if (priv->speed == SPEED_100)
> +               val = MTK_MAC_VAL_PHY_CTRL1_FORCE_SPD_100M;
> +       else
> +               val = MTK_MAC_VAL_PHY_CTRL1_FORCE_SPD_10M;
> +       val <<= MTK_MAC_OFF_PHY_CTRL1_FORCE_SPD;
> +
> +       val |= MTK_MAC_BIT_PHY_CTRL1_AN_EN;
> +       val |= MTK_MAC_BIT_PHY_CTRL1_FORCE_FC_RX;
> +       val |= MTK_MAC_BIT_PHY_CTRL1_FORCE_FC_TX;
> +       /* Only full-duplex supported for now. */
> +       val |= MTK_MAC_BIT_PHY_CTRL1_FORCE_DPX;
> +
> +       regmap_write(priv->regs, MTK_MAC_REG_PHY_CTRL1, val);
> +}
> +
> +static void mtk_mac_adjust_link(struct net_device *ndev)
> +{
> +       struct mtk_mac_priv *priv = netdev_priv(ndev);
> +       struct phy_device *phydev = priv->phydev;
> +       bool new_state = false;
> +
> +       if (phydev->link) {
> +               if (!priv->link) {
> +                       priv->link = phydev->link;
> +                       new_state = true;
> +               }
> +
> +               if (priv->speed != phydev->speed) {
> +                       priv->speed = phydev->speed;
> +                       new_state = true;
> +               }
> +       } else {
> +               if (priv->link) {
> +                       priv->link = phydev->link;
> +                       new_state = true;
> +               }
> +       }
> +
> +       if (new_state) {
> +               if (phydev->link)
> +                       mtk_mac_phy_config(priv);
> +               phy_print_status(ndev->phydev);
> +       }
> +}
> +
> +static void mtk_mac_init_config(struct mtk_mac_priv *priv)
> +{
> +       unsigned int val;
> +
> +       val = (MTK_MAC_BIT_MII_PAD_OUT_ENABLE |
> +              MTK_MAC_BIT_EXT_MDC_MODE |
> +              MTK_MAC_BIT_SWC_MII_MODE);
> +
> +       regmap_write(priv->regs, MTK_MAC_REG_SYS_CONF, val);
> +       regmap_update_bits(priv->regs, MTK_MAC_REG_MAC_CLK_CONF,
> +                          MTK_MAC_MSK_MAC_CLK_CONF,
> +                          MTK_MAC_BIT_CLK_DIV_10);
> +}
> +
> +static void mtk_mac_set_mode_rmii(struct mtk_mac_priv *priv)
> +{
> +       regmap_update_bits(priv->pericfg, MTK_PERICFG_REG_NIC_CFG_CON,
> +                          MTK_PERICFG_MSK_NIC_CFG_CON_CFG_MII,
> +                          MTK_PERICFG_BIT_NIC_CFG_CON_RMII);
> +}
> +
> +static int mtk_mac_enable(struct net_device *ndev)
> +{
> +       struct mtk_mac_priv *priv = netdev_priv(ndev);
> +       unsigned int val;
> +       int ret;
> +
> +       mtk_mac_nic_disable_pd(priv);
> +       mtk_mac_intr_mask_all(priv);
> +       mtk_mac_dma_stop(priv);
> +       netif_carrier_off(ndev);
> +
> +       mtk_mac_set_mac_addr(ndev);
> +
> +       /* Configure the MAC */
> +       val = MTK_MAC_VAL_MAC_CFG_IPG_96BIT;
> +       val <<= MTK_MAC_OFF_MAC_CFG_IPG;
> +       val |= MTK_MAC_BIT_MAC_CFG_MAXLEN_1522;
> +       val |= MTK_MAC_BIT_MAC_CFG_AUTO_PAD;
> +       val |= MTK_MAC_BIT_MAC_CFG_CRC_STRIP;
> +       regmap_write(priv->regs, MTK_MAC_REG_MAC_CFG, val);
> +
> +       /* Configure flow control */
> +       val = MTK_MAC_VAL_FC_CFG_SEND_PAUSE_TH_2K;
> +       val <<= MTK_MAC_OFF_FC_CFG_SEND_PAUSE_TH;
> +       val |= MTK_MAC_BIT_FC_CFG_BP_EN;
> +       val |= MTK_MAC_BIT_FC_CFG_UC_PAUSE_DIR;
> +       regmap_write(priv->regs, MTK_MAC_REG_FC_CFG, val);
> +
> +       /* Set SEND_PAUSE_RLS to 1K */
> +       val = MTK_MAC_VAL_EXT_CFG_SND_PAUSE_RLS_1K;
> +       val <<= MTK_MAC_OFF_EXT_CFG_SND_PAUSE_RLS;
> +       regmap_write(priv->regs, MTK_MAC_REG_EXT_CFG, val);
> +
> +       /* Reset all counters */
> +       mtk_mac_reset_counters(priv);
> +
> +       /* Enable Hash Table BIST and reset it */
> +       regmap_update_bits(priv->regs, MTK_MAC_REG_HASH_CTRL,
> +                          MTK_MAC_BIT_HASH_CTRL_BIST_EN,
> +                          MTK_MAC_BIT_HASH_CTRL_BIST_EN);
> +       regmap_update_bits(priv->regs, MTK_MAC_REG_TEST1,
> +                          MTK_MAC_BIT_TEST1_RST_HASH_MBIST,
> +                          MTK_MAC_BIT_TEST1_RST_HASH_MBIST);
> +
> +       /* Setup the hashing algorithm */
> +       regmap_update_bits(priv->regs, MTK_MAC_REG_ARL_CFG,
> +                          MTK_MAC_BIT_ARL_CFG_HASH_ALG |
> +                          MTK_MAC_BIT_ARL_CFG_MISC_MODE, 0);
> +
> +       /* Don't strip VLAN tags */
> +       regmap_update_bits(priv->regs, MTK_MAC_REG_MAC_CFG,
> +                          MTK_MAC_BIT_MAC_CFG_VLAN_STRIP, 0);
> +
> +       /* Setup DMA */
> +       mtk_mac_dma_init(priv);
> +
> +       ret = mtk_mac_prepare_rx_skbs(ndev);
> +       if (ret)
> +               goto err_out;
> +
> +       /* Request the interrupt */
> +       ret = request_irq(ndev->irq, mtk_mac_handle_irq,
> +                         IRQF_TRIGGER_FALLING, ndev->name, ndev);
> +       if (ret)
> +               goto err_free_skbs;
> +
> +       napi_enable(&priv->napi);
> +
> +       mtk_mac_intr_read_and_clear(priv);
> +       mtk_mac_intr_unmask_all(priv);
> +
> +       /* Connect to and start PHY */
> +       priv->phydev = of_phy_connect(ndev, priv->phy_node,
> +                                     mtk_mac_adjust_link, 0, priv->phy_intf);
> +       if (!priv->phydev) {
> +               netdev_err(ndev, "failed to connect to PHY\n");
> +               goto err_free_irq;
> +       }
> +
> +       mtk_mac_dma_start(priv);
> +       phy_start(priv->phydev);
> +       netif_start_queue(ndev);
> +
> +       return 0;
> +
> +err_free_irq:
> +       free_irq(ndev->irq, ndev);
> +err_free_skbs:
> +       mtk_mac_free_rx_skbs(ndev);
> +err_out:
> +       return ret;
> +}
> +
> +static void mtk_mac_disable(struct net_device *ndev)
> +{
> +       struct mtk_mac_priv *priv = netdev_priv(ndev);
> +
> +       netif_stop_queue(ndev);
> +       napi_disable(&priv->napi);
> +       mtk_mac_intr_mask_all(priv);
> +       mtk_mac_dma_disable(priv);
> +       mtk_mac_intr_read_and_clear(priv);
> +       phy_stop(priv->phydev);
> +       phy_disconnect(priv->phydev);
> +       free_irq(ndev->irq, ndev);
> +       mtk_mac_free_rx_skbs(ndev);
> +       mtk_mac_free_tx_skbs(ndev);
> +}
> +
> +static int mtk_mac_netdev_open(struct net_device *ndev)
> +{
> +       return mtk_mac_enable(ndev);
> +}
> +
> +static int mtk_mac_netdev_stop(struct net_device *ndev)
> +{
> +       mtk_mac_disable(ndev);
> +
> +       return 0;
> +}
> +
> +static int mtk_mac_netdev_ioctl(struct net_device *ndev,
> +                               struct ifreq *req, int cmd)
> +{
> +       if (!netif_running(ndev))
> +               return -EINVAL;
> +
> +       return phy_mii_ioctl(ndev->phydev, req, cmd);
> +}
> +
> +static int mtk_mac_netdev_start_xmit(struct sk_buff *skb,
> +                                    struct net_device *ndev)
> +{
> +       struct mtk_mac_priv *priv = netdev_priv(ndev);
> +       struct mtk_mac_ring *ring = &priv->tx_ring;
> +       struct device *dev = mtk_mac_get_dev(priv);
> +       struct mtk_mac_ring_desc_data desc_data;
> +
> +       if (skb->len > MTK_MAC_MAX_FRAME_SIZE)
> +               goto err_drop_packet;
> +
> +       desc_data.dma_addr = mtk_mac_dma_map_tx(priv, skb);
> +       if (dma_mapping_error(dev, desc_data.dma_addr))
> +               goto err_drop_packet;
> +
> +       desc_data.skb = skb;
> +       desc_data.len = skb->len;
> +
> +       mtk_mac_lock(priv);
> +       mtk_mac_ring_push_head_tx(ring, &desc_data);
> +
> +       if (mtk_mac_ring_full(ring))
> +               netif_stop_queue(ndev);
> +       mtk_mac_unlock(priv);
> +
> +       mtk_mac_dma_resume_tx(priv);
> +
> +       return NETDEV_TX_OK;
> +
> +err_drop_packet:
> +       dev_kfree_skb(skb);
> +       ndev->stats.tx_dropped++;
> +       return NETDEV_TX_BUSY;
> +}
> +
> +static int mtk_mac_tx_complete(struct mtk_mac_priv *priv)
> +{
> +       struct mtk_mac_ring *ring = &priv->tx_ring;
> +       struct mtk_mac_ring_desc_data desc_data;
> +       int ret;
> +
> +       ret = mtk_mac_ring_pop_tail(ring, &desc_data);
> +       if (ret)
> +               return ret;
> +
> +       mtk_mac_dma_unmap_tx(priv, &desc_data);
> +       dev_kfree_skb_irq(desc_data.skb);
> +
> +       return 0;
> +}
> +
> +static void mtk_mac_tx_work(struct work_struct *work)
> +{
> +       struct mtk_mac_priv *priv;
> +       struct mtk_mac_ring *ring;
> +       struct net_device *ndev;
> +       bool wake = false;
> +       int ret;
> +
> +       priv = container_of(work, struct mtk_mac_priv, tx_work);
> +       ndev = mtk_mac_get_netdev(priv);
> +       ring = &priv->tx_ring;
> +
> +       for (;;) {
> +               mtk_mac_lock(priv);
> +
> +               if (!mtk_mac_ring_descs_available(ring)) {
> +                       mtk_mac_unlock(priv);
> +                       break;
> +               }
> +
> +               ret = mtk_mac_tx_complete(priv);
> +               mtk_mac_unlock(priv);
> +               if (ret)
> +                       break;
> +
> +               wake = true;
> +       }
> +
> +       if (wake)
> +               netif_wake_queue(ndev);
> +}
> +
> +static void mtk_mac_netdev_get_stats64(struct net_device *ndev,
> +                                      struct rtnl_link_stats64 *stats)
> +{
> +       struct mtk_mac_priv *priv = netdev_priv(ndev);
> +
> +       mtk_mac_update_stats(priv);
> +
> +       memcpy(stats, &priv->stats, sizeof(*stats));
> +}
> +
> +static void mtk_mac_set_hashbit(struct mtk_mac_priv *priv,
> +                               unsigned int hash_addr)
> +{
> +       unsigned int val;
> +
> +       val = hash_addr & MTK_MAC_MSK_HASH_CTRL_HASH_BIT_ADDR;
> +       val |= MTK_MAC_BIT_HASH_CTRL_ACC_CMD;
> +       val |= MTK_MAC_BIT_HASH_CTRL_CMD_START;
> +       val |= MTK_MAC_BIT_HASH_CTRL_BIST_EN;
> +       val |= MTK_MAC_BIT_HASH_CTRL_HASH_BIT_DATA;
> +
> +       regmap_write(priv->regs, MTK_MAC_REG_HASH_CTRL, val);
> +}
> +
> +static void mtk_mac_set_rx_mode(struct net_device *ndev)
> +{
> +       struct mtk_mac_priv *priv = netdev_priv(ndev);
> +       struct netdev_hw_addr *hw_addr;
> +       unsigned int hash_addr, i;
> +
> +       if (ndev->flags & IFF_PROMISC) {
> +               regmap_update_bits(priv->regs, MTK_MAC_REG_ARL_CFG,
> +                                  MTK_MAC_BIT_ARL_CFG_MISC_MODE,
> +                                  MTK_MAC_BIT_ARL_CFG_MISC_MODE);
> +       } else if (netdev_mc_count(ndev) > MTK_MAC_HASHTABLE_MC_LIMIT ||
> +                  ndev->flags & IFF_ALLMULTI) {
> +               for (i = 0; i < MTK_MAC_HASHTABLE_SIZE_MAX; i++)
> +                       mtk_mac_set_hashbit(priv, i);
> +       } else {
> +               netdev_for_each_mc_addr(hw_addr, ndev) {
> +                       hash_addr = (hw_addr->addr[0] & 0x01) << 8;
> +                       hash_addr += hw_addr->addr[5];
> +                       mtk_mac_set_hashbit(priv, hash_addr);
> +               }
> +       }
> +}
> +
> +static const struct net_device_ops mtk_mac_netdev_ops = {
> +       .ndo_open               = mtk_mac_netdev_open,
> +       .ndo_stop               = mtk_mac_netdev_stop,
> +       .ndo_start_xmit         = mtk_mac_netdev_start_xmit,
> +       .ndo_get_stats64        = mtk_mac_netdev_get_stats64,
> +       .ndo_set_rx_mode        = mtk_mac_set_rx_mode,
> +       .ndo_do_ioctl           = mtk_mac_netdev_ioctl,
> +       .ndo_set_mac_address    = eth_mac_addr,
> +       .ndo_validate_addr      = eth_validate_addr,
> +};
> +
> +static void mtk_mac_get_drvinfo(struct net_device *dev,
> +                               struct ethtool_drvinfo *info)
> +{
> +       strlcpy(info->driver, MTK_MAC_DRVNAME, sizeof(info->driver));
> +       strlcpy(info->version, MTK_MAC_VERSION, sizeof(info->version));

And this line should be removed too.

Thanks

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

* Re: [PATCH 06/11] net: ethernet: mtk-eth-mac: new driver
  2020-05-06 19:16   ` Leon Romanovsky
@ 2020-05-06 19:23     ` Jakub Kicinski
  2020-05-07  5:55       ` Leon Romanovsky
  2020-05-06 19:24     ` Joe Perches
  1 sibling, 1 reply; 40+ messages in thread
From: Jakub Kicinski @ 2020-05-06 19:23 UTC (permalink / raw)
  To: Leon Romanovsky
  Cc: Bartosz Golaszewski, Rob Herring, David S . Miller,
	Matthias Brugger, Felix Fietkau, John Crispin, Sean Wang,
	Mark Lee, Arnd Bergmann, Fabien Parent, devicetree, linux-kernel,
	linux-netdev, linux-arm-kernel, linux-mediatek,
	Bartosz Golaszewski

On Wed, 6 May 2020 22:16:11 +0300 Leon Romanovsky wrote:
> > +#define MTK_MAC_DRVNAME                                "mtk_eth_mac"
> > +#define MTK_MAC_VERSION                                "1.0"  
> 
> Please don't add driver version to new driver.

It has already been pointed out. Please trim your replies.

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

* Re: [PATCH 06/11] net: ethernet: mtk-eth-mac: new driver
  2020-05-06 19:16   ` Leon Romanovsky
  2020-05-06 19:23     ` Jakub Kicinski
@ 2020-05-06 19:24     ` Joe Perches
  1 sibling, 0 replies; 40+ messages in thread
From: Joe Perches @ 2020-05-06 19:24 UTC (permalink / raw)
  To: Leon Romanovsky, Bartosz Golaszewski
  Cc: Rob Herring, David S . Miller, Matthias Brugger, Felix Fietkau,
	John Crispin, Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann,
	Fabien Parent, devicetree, linux-kernel, linux-netdev,
	linux-arm-kernel, linux-mediatek, Bartosz Golaszewski

On Wed, 2020-05-06 at 22:16 +0300, Leon Romanovsky wrote:
> On Tue, May 5, 2020 at 5:03 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> > From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> > 
> > This adds the driver for the MediaTek Ethernet MAC used on the MT8* SoC
> > family. For now we only support full-duplex.
[]
> > diff --git a/drivers/net/ethernet/mediatek/mtk_eth_mac.c b/drivers/net/ethernet/mediatek/mtk_eth_mac.c
[]
> > +struct mtk_mac_priv {
> > +       struct regmap *regs;
> > +       struct regmap *pericfg;
> > +
> > +       struct clk_bulk_data clks[MTK_MAC_NCLKS];
> > +
> > +       void *ring_base;
> > +       struct mtk_mac_ring_desc *descs_base;
> > +       dma_addr_t dma_addr;
> > +       struct mtk_mac_ring tx_ring;
> > +       struct mtk_mac_ring rx_ring;
> > +       struct work_struct tx_work;
> > +
> > +       struct mii_bus *mii;
> > +       struct napi_struct napi;
> > +
> > +       struct device_node *phy_node;
> > +       phy_interface_t phy_intf;
> > +       struct phy_device *phydev;
> > +       unsigned int link;
> > +       int speed;
> > +       int duplex;
> > +
> > +       /* Protects against concurrent descriptor access. */
> > +       spinlock_t lock;
> > +       unsigned long lock_flags;
> > +
> > +       struct rtnl_link_stats64 stats;
> > +};
> > +
> > +static struct net_device *mtk_mac_get_netdev(struct mtk_mac_priv *priv)
> > +{
> > +       char *ptr = (char *)priv;
> > +
> > +       return (struct net_device *)(ptr - ALIGN(sizeof(struct net_device),
> > +                                                NETDEV_ALIGN));
> > +}

This code looks ugly/fragile.
Why not store the struct net_device * in struct mtk_mac_priv ?



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

* Re: [PATCH 06/11] net: ethernet: mtk-eth-mac: new driver
  2020-05-06 19:23     ` Jakub Kicinski
@ 2020-05-07  5:55       ` Leon Romanovsky
  2020-05-07 22:50         ` Jakub Kicinski
  0 siblings, 1 reply; 40+ messages in thread
From: Leon Romanovsky @ 2020-05-07  5:55 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Bartosz Golaszewski, Rob Herring, David S . Miller,
	Matthias Brugger, Felix Fietkau, John Crispin, Sean Wang,
	Mark Lee, Arnd Bergmann, Fabien Parent, devicetree, linux-kernel,
	linux-netdev, linux-arm-kernel, linux-mediatek,
	Bartosz Golaszewski

On Wed, May 06, 2020 at 12:23:29PM -0700, Jakub Kicinski wrote:
> On Wed, 6 May 2020 22:16:11 +0300 Leon Romanovsky wrote:
> > > +#define MTK_MAC_DRVNAME                                "mtk_eth_mac"
> > > +#define MTK_MAC_VERSION                                "1.0"
> >
> > Please don't add driver version to new driver.
>
> It has already been pointed out. Please trim your replies.

Off-topic.

Is there any simple way to trim replies semi-automatically in VIM?

Right now, I'm doing it manually, but maybe there is some better
way to do it.

Thanks

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

* Re: [PATCH 05/11] net: core: provide devm_register_netdev()
  2020-05-06 17:12       ` Jakub Kicinski
@ 2020-05-07  9:25         ` Bartosz Golaszewski
  2020-05-07 16:53           ` Jakub Kicinski
  0 siblings, 1 reply; 40+ messages in thread
From: Bartosz Golaszewski @ 2020-05-07  9:25 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Bartosz Golaszewski, Rob Herring, David S . Miller,
	Matthias Brugger, Felix Fietkau, John Crispin, Sean Wang,
	Mark Lee, Arnd Bergmann, Fabien Parent, devicetree,
	Linux Kernel Mailing List, netdev, Linux ARM, linux-mediatek

śr., 6 maj 2020 o 19:12 Jakub Kicinski <kuba@kernel.org> napisał(a):
>
> On Wed, 6 May 2020 08:39:47 +0200 Bartosz Golaszewski wrote:
> > wt., 5 maj 2020 o 19:31 Jakub Kicinski <kuba@kernel.org> napisał(a):
> > >
> > > On Tue,  5 May 2020 16:02:25 +0200 Bartosz Golaszewski wrote:
> > > > From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> > > >
> > > > Provide devm_register_netdev() - a device resource managed variant
> > > > of register_netdev(). This new helper will only work for net_device
> > > > structs that have a parent device assigned and are devres managed too.
> > > >
> > > > Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> > >
> > > > diff --git a/net/core/dev.c b/net/core/dev.c
> > > > index 522288177bbd..99db537c9468 100644
> > > > --- a/net/core/dev.c
> > > > +++ b/net/core/dev.c
> > > > @@ -9519,6 +9519,54 @@ int register_netdev(struct net_device *dev)
> > > >  }
> > > >  EXPORT_SYMBOL(register_netdev);
> > > >
> > > > +struct netdevice_devres {
> > > > +     struct net_device *ndev;
> > > > +};
> > >
> > > Is there really a need to define a structure if we only need a pointer?
> > >
> >
> > There is no need for that, but it really is more readable this way.
> > Also: using a pointer directly doesn't save us any memory nor code
> > here.
>
> I don't care either way but devm_alloc_etherdev_mqs() and co. are using
> the double pointer directly. Please make things consistent. Either do
> the same, or define the structure in some header and convert other
> helpers to also make use of it.

In order to use devres_find() to check if struct net_device is managed
in devm_register_netdev() I need to know the address of the release
function used by devm_alloc_etherdev_mqs(). Do you mind if I move all
networking devres routines (currently only devm_alloc_etherdev_mqs())
into a separate .c file (e.g. under net/devres.c)?

Bart

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

* Re: [PATCH 06/11] net: ethernet: mtk-eth-mac: new driver
       [not found]   ` <1588844771.5921.27.camel@mtksdccf07>
@ 2020-05-07 10:50     ` Bartosz Golaszewski
  2020-05-07 13:16       ` Andrew Lunn
  0 siblings, 1 reply; 40+ messages in thread
From: Bartosz Golaszewski @ 2020-05-07 10:50 UTC (permalink / raw)
  To: Mark-MC.Lee
  Cc: Bartosz Golaszewski, Rob Herring, David S . Miller,
	Matthias Brugger, Felix Fietkau, John Crispin, Sean Wang,
	Jakub Kicinski, Arnd Bergmann, Fabien Parent, linux-devicetree,
	LKML, netdev, arm-soc, linux-mediatek

czw., 7 maj 2020 o 11:46 Mark-MC.Lee <Mark-MC.Lee@mediatek.com> napisał(a):
>
> Hi Bartosz:
>  I think the naming of this driver and its Kconfig option is too generic
> that will confuse with current mediatek SoCs eth driver architecture(for
> all mt7xxx SoCs).
>   Since mtk_eth_mac.c is not a common MAC part for all mediatek SoC but
> only a specific eth driver for mt85xx, it will be more reasonable to
> name it as mt85xx_eth.c and change NET_MEDIATEK_MAC to
> NET_MEDIATEK_MT85XX. How do you think?
>

Hi Mark,

I actually consulted this with MediaTek and the name is their idea.
Many drivers in drivers/net/ethernet have very vague names. I guess
this isn't a problem.

Bart

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

* Re: [PATCH 06/11] net: ethernet: mtk-eth-mac: new driver
  2020-05-07 10:50     ` Bartosz Golaszewski
@ 2020-05-07 13:16       ` Andrew Lunn
  2020-05-07 17:01         ` Bartosz Golaszewski
  0 siblings, 1 reply; 40+ messages in thread
From: Andrew Lunn @ 2020-05-07 13:16 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Mark-MC.Lee, linux-devicetree, Felix Fietkau, Arnd Bergmann,
	netdev, Bartosz Golaszewski, Sean Wang, LKML, Fabien Parent,
	Rob Herring, linux-mediatek, John Crispin, Matthias Brugger,
	Jakub Kicinski, David S . Miller, arm-soc

On Thu, May 07, 2020 at 12:50:15PM +0200, Bartosz Golaszewski wrote:
> czw., 7 maj 2020 o 11:46 Mark-MC.Lee <Mark-MC.Lee@mediatek.com> napisał(a):
> >
> > Hi Bartosz:
> >  I think the naming of this driver and its Kconfig option is too generic
> > that will confuse with current mediatek SoCs eth driver architecture(for
> > all mt7xxx SoCs).
> >   Since mtk_eth_mac.c is not a common MAC part for all mediatek SoC but
> > only a specific eth driver for mt85xx, it will be more reasonable to
> > name it as mt85xx_eth.c and change NET_MEDIATEK_MAC to
> > NET_MEDIATEK_MT85XX. How do you think?
> >
> 
> Hi Mark,
> 
> I actually consulted this with MediaTek and the name is their idea.
> Many drivers in drivers/net/ethernet have very vague names. I guess
> this isn't a problem.

They have vague names, but they tend to be not confusing.

NET_MEDIATEK_MAC vs NET_MEDIATEK_SOC is confusing.

I think the proposed name, mt85xx_eth.c and NET_MEDIATEK_MT85XX is
good. Or some variant on this, mt8xxx?

    Andrew

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

* Re: [PATCH 05/11] net: core: provide devm_register_netdev()
  2020-05-07  9:25         ` Bartosz Golaszewski
@ 2020-05-07 16:53           ` Jakub Kicinski
  2020-05-07 17:03             ` Bartosz Golaszewski
  0 siblings, 1 reply; 40+ messages in thread
From: Jakub Kicinski @ 2020-05-07 16:53 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Bartosz Golaszewski, Rob Herring, David S . Miller,
	Matthias Brugger, John Crispin, Sean Wang, Mark Lee,
	Arnd Bergmann, Fabien Parent, devicetree,
	Linux Kernel Mailing List, netdev, Linux ARM, linux-mediatek,
	Heiner Kallweit

On Thu, 7 May 2020 11:25:01 +0200 Bartosz Golaszewski wrote:
> śr., 6 maj 2020 o 19:12 Jakub Kicinski <kuba@kernel.org> napisał(a):
> >
> > On Wed, 6 May 2020 08:39:47 +0200 Bartosz Golaszewski wrote:  
> > > wt., 5 maj 2020 o 19:31 Jakub Kicinski <kuba@kernel.org> napisał(a):  
> > > >
> > > > On Tue,  5 May 2020 16:02:25 +0200 Bartosz Golaszewski wrote:  
> > > > > From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> > > > >
> > > > > Provide devm_register_netdev() - a device resource managed variant
> > > > > of register_netdev(). This new helper will only work for net_device
> > > > > structs that have a parent device assigned and are devres managed too.
> > > > >
> > > > > Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>  
> > > >  
> > > > > diff --git a/net/core/dev.c b/net/core/dev.c
> > > > > index 522288177bbd..99db537c9468 100644
> > > > > --- a/net/core/dev.c
> > > > > +++ b/net/core/dev.c
> > > > > @@ -9519,6 +9519,54 @@ int register_netdev(struct net_device *dev)
> > > > >  }
> > > > >  EXPORT_SYMBOL(register_netdev);
> > > > >
> > > > > +struct netdevice_devres {
> > > > > +     struct net_device *ndev;
> > > > > +};  
> > > >
> > > > Is there really a need to define a structure if we only need a pointer?
> > > >  
> > >
> > > There is no need for that, but it really is more readable this way.
> > > Also: using a pointer directly doesn't save us any memory nor code
> > > here.  
> >
> > I don't care either way but devm_alloc_etherdev_mqs() and co. are using
> > the double pointer directly. Please make things consistent. Either do
> > the same, or define the structure in some header and convert other
> > helpers to also make use of it.  
> 
> In order to use devres_find() to check if struct net_device is managed
> in devm_register_netdev() I need to know the address of the release
> function used by devm_alloc_etherdev_mqs(). Do you mind if I move all
> networking devres routines (currently only devm_alloc_etherdev_mqs())
> into a separate .c file (e.g. under net/devres.c)?

To implement Edwin's suggestion? Makes sense, but I'm no expert, let's
also CC Heiner since he was asking about it last time.

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

* Re: [PATCH 06/11] net: ethernet: mtk-eth-mac: new driver
  2020-05-07 13:16       ` Andrew Lunn
@ 2020-05-07 17:01         ` Bartosz Golaszewski
  0 siblings, 0 replies; 40+ messages in thread
From: Bartosz Golaszewski @ 2020-05-07 17:01 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Mark-MC.Lee, linux-devicetree, Felix Fietkau, Arnd Bergmann,
	netdev, Bartosz Golaszewski, Sean Wang, LKML, Fabien Parent,
	Rob Herring, linux-mediatek, John Crispin, Matthias Brugger,
	Jakub Kicinski, David S . Miller, arm-soc

czw., 7 maj 2020 o 15:16 Andrew Lunn <andrew@lunn.ch> napisał(a):
>
> On Thu, May 07, 2020 at 12:50:15PM +0200, Bartosz Golaszewski wrote:
> > czw., 7 maj 2020 o 11:46 Mark-MC.Lee <Mark-MC.Lee@mediatek.com> napisał(a):
> > >
> > > Hi Bartosz:
> > >  I think the naming of this driver and its Kconfig option is too generic
> > > that will confuse with current mediatek SoCs eth driver architecture(for
> > > all mt7xxx SoCs).
> > >   Since mtk_eth_mac.c is not a common MAC part for all mediatek SoC but
> > > only a specific eth driver for mt85xx, it will be more reasonable to
> > > name it as mt85xx_eth.c and change NET_MEDIATEK_MAC to
> > > NET_MEDIATEK_MT85XX. How do you think?
> > >
> >
> > Hi Mark,
> >
> > I actually consulted this with MediaTek and the name is their idea.
> > Many drivers in drivers/net/ethernet have very vague names. I guess
> > this isn't a problem.
>
> They have vague names, but they tend to be not confusing.
>
> NET_MEDIATEK_MAC vs NET_MEDIATEK_SOC is confusing.
>
> I think the proposed name, mt85xx_eth.c and NET_MEDIATEK_MT85XX is
> good. Or some variant on this, mt8xxx?
>

I've just verified with MediaTek that this IP will be used in future
designs as well - even on ones that don't share the mt8* prefix. It
doesn't really have a name though by itself. How much confusion can it
cause anyway? People who want to compile this driver will know which
one to choose, right? It's not like it's an i2c component shared
across many board designs.

Bart

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

* Re: [PATCH 05/11] net: core: provide devm_register_netdev()
  2020-05-07 16:53           ` Jakub Kicinski
@ 2020-05-07 17:03             ` Bartosz Golaszewski
  2020-05-07 22:56               ` Jakub Kicinski
  0 siblings, 1 reply; 40+ messages in thread
From: Bartosz Golaszewski @ 2020-05-07 17:03 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Bartosz Golaszewski, Rob Herring, David S . Miller,
	Matthias Brugger, John Crispin, Sean Wang, Mark Lee,
	Arnd Bergmann, Fabien Parent, devicetree,
	Linux Kernel Mailing List, netdev, Linux ARM, linux-mediatek,
	Heiner Kallweit

czw., 7 maj 2020 o 18:53 Jakub Kicinski <kuba@kernel.org> napisał(a):
>
> On Thu, 7 May 2020 11:25:01 +0200 Bartosz Golaszewski wrote:
> > śr., 6 maj 2020 o 19:12 Jakub Kicinski <kuba@kernel.org> napisał(a):
> > >
> > > On Wed, 6 May 2020 08:39:47 +0200 Bartosz Golaszewski wrote:
> > > > wt., 5 maj 2020 o 19:31 Jakub Kicinski <kuba@kernel.org> napisał(a):
> > > > >
> > > > > On Tue,  5 May 2020 16:02:25 +0200 Bartosz Golaszewski wrote:
> > > > > > From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> > > > > >
> > > > > > Provide devm_register_netdev() - a device resource managed variant
> > > > > > of register_netdev(). This new helper will only work for net_device
> > > > > > structs that have a parent device assigned and are devres managed too.
> > > > > >
> > > > > > Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> > > > >
> > > > > > diff --git a/net/core/dev.c b/net/core/dev.c
> > > > > > index 522288177bbd..99db537c9468 100644
> > > > > > --- a/net/core/dev.c
> > > > > > +++ b/net/core/dev.c
> > > > > > @@ -9519,6 +9519,54 @@ int register_netdev(struct net_device *dev)
> > > > > >  }
> > > > > >  EXPORT_SYMBOL(register_netdev);
> > > > > >
> > > > > > +struct netdevice_devres {
> > > > > > +     struct net_device *ndev;
> > > > > > +};
> > > > >
> > > > > Is there really a need to define a structure if we only need a pointer?
> > > > >
> > > >
> > > > There is no need for that, but it really is more readable this way.
> > > > Also: using a pointer directly doesn't save us any memory nor code
> > > > here.
> > >
> > > I don't care either way but devm_alloc_etherdev_mqs() and co. are using
> > > the double pointer directly. Please make things consistent. Either do
> > > the same, or define the structure in some header and convert other
> > > helpers to also make use of it.
> >
> > In order to use devres_find() to check if struct net_device is managed
> > in devm_register_netdev() I need to know the address of the release
> > function used by devm_alloc_etherdev_mqs(). Do you mind if I move all
> > networking devres routines (currently only devm_alloc_etherdev_mqs())
> > into a separate .c file (e.g. under net/devres.c)?
>
> To implement Edwin's suggestion? Makes sense, but I'm no expert, let's
> also CC Heiner since he was asking about it last time.

Yes, because taking the last bit of priv_flags from net_device seems
to be more controversial but if net maintainers are fine with that I
can simply go with the current approach.

Bart

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

* Re: [PATCH 06/11] net: ethernet: mtk-eth-mac: new driver
  2020-05-07  5:55       ` Leon Romanovsky
@ 2020-05-07 22:50         ` Jakub Kicinski
  0 siblings, 0 replies; 40+ messages in thread
From: Jakub Kicinski @ 2020-05-07 22:50 UTC (permalink / raw)
  To: Leon Romanovsky
  Cc: Bartosz Golaszewski, Rob Herring, David S . Miller,
	Matthias Brugger, Felix Fietkau, John Crispin, Sean Wang,
	Mark Lee, Arnd Bergmann, Fabien Parent, devicetree, linux-kernel,
	linux-netdev, linux-arm-kernel, linux-mediatek,
	Bartosz Golaszewski

On Wed, May 06, 2020 at 12:23:29PM -0700, Jakub Kicinski wrote:
> Please trim your replies.  
> 
> Off-topic.
> 
> Is there any simple way to trim replies semi-automatically in VIM?
> 
> Right now, I'm doing it manually, but maybe there is some better
> way to do it.

I'm also doing it manually :(

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

* Re: [PATCH 05/11] net: core: provide devm_register_netdev()
  2020-05-07 17:03             ` Bartosz Golaszewski
@ 2020-05-07 22:56               ` Jakub Kicinski
  2020-05-08  5:54                 ` Heiner Kallweit
  0 siblings, 1 reply; 40+ messages in thread
From: Jakub Kicinski @ 2020-05-07 22:56 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Bartosz Golaszewski, Rob Herring, David S . Miller,
	Matthias Brugger, John Crispin, Sean Wang, Mark Lee,
	Arnd Bergmann, Fabien Parent, devicetree,
	Linux Kernel Mailing List, netdev, Linux ARM, linux-mediatek,
	Heiner Kallweit

On Thu, 7 May 2020 19:03:44 +0200 Bartosz Golaszewski wrote:
>> To implement Edwin's suggestion? Makes sense, but I'm no expert, let's
>> also CC Heiner since he was asking about it last time.  
> 
> Yes, because taking the last bit of priv_flags from net_device seems
> to be more controversial but if net maintainers are fine with that I
> can simply go with the current approach.

From my perspective what Edwin suggests makes sense. Apart from
little use for the bit after probe, it also seems cleaner for devres 
to be able to recognize managed objects based on its own state.

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

* Re: [PATCH 05/11] net: core: provide devm_register_netdev()
  2020-05-07 22:56               ` Jakub Kicinski
@ 2020-05-08  5:54                 ` Heiner Kallweit
  2020-05-08 18:39                   ` Bartosz Golaszewski
  0 siblings, 1 reply; 40+ messages in thread
From: Heiner Kallweit @ 2020-05-08  5:54 UTC (permalink / raw)
  To: Jakub Kicinski, Bartosz Golaszewski
  Cc: Bartosz Golaszewski, Rob Herring, David S . Miller,
	Matthias Brugger, John Crispin, Sean Wang, Mark Lee,
	Arnd Bergmann, Fabien Parent, devicetree,
	Linux Kernel Mailing List, netdev, Linux ARM, linux-mediatek

On 08.05.2020 00:56, Jakub Kicinski wrote:
> On Thu, 7 May 2020 19:03:44 +0200 Bartosz Golaszewski wrote:
>>> To implement Edwin's suggestion? Makes sense, but I'm no expert, let's
>>> also CC Heiner since he was asking about it last time.  
>>
>> Yes, because taking the last bit of priv_flags from net_device seems
>> to be more controversial but if net maintainers are fine with that I
>> can simply go with the current approach.
> 
> From my perspective what Edwin suggests makes sense. Apart from
> little use for the bit after probe, it also seems cleaner for devres 
> to be able to recognize managed objects based on its own state.
> 
What I was saying is that we should catch the case that a driver
author uses a device-managed register() w/o doing the same for the
alloc(). A core function should not assume that driver authors do
sane things only.
I don't have a strong preference how it should be done.
Considering what is being discussed, have a look at get_pci_dr() and
find_pci_dr(), they deal with managing which parts of the PCI
subsystem are device-managed.

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

* Re: [PATCH 05/11] net: core: provide devm_register_netdev()
  2020-05-08  5:54                 ` Heiner Kallweit
@ 2020-05-08 18:39                   ` Bartosz Golaszewski
  0 siblings, 0 replies; 40+ messages in thread
From: Bartosz Golaszewski @ 2020-05-08 18:39 UTC (permalink / raw)
  To: Heiner Kallweit
  Cc: Jakub Kicinski, Bartosz Golaszewski, Rob Herring,
	David S . Miller, Matthias Brugger, John Crispin, Sean Wang,
	Mark Lee, Arnd Bergmann, Fabien Parent, devicetree,
	Linux Kernel Mailing List, netdev, Linux ARM, linux-mediatek

pt., 8 maj 2020 o 07:54 Heiner Kallweit <hkallweit1@gmail.com> napisał(a):
>
> On 08.05.2020 00:56, Jakub Kicinski wrote:
> > On Thu, 7 May 2020 19:03:44 +0200 Bartosz Golaszewski wrote:
> >>> To implement Edwin's suggestion? Makes sense, but I'm no expert, let's
> >>> also CC Heiner since he was asking about it last time.
> >>
> >> Yes, because taking the last bit of priv_flags from net_device seems
> >> to be more controversial but if net maintainers are fine with that I
> >> can simply go with the current approach.
> >
> > From my perspective what Edwin suggests makes sense. Apart from
> > little use for the bit after probe, it also seems cleaner for devres
> > to be able to recognize managed objects based on its own state.
> >
> What I was saying is that we should catch the case that a driver
> author uses a device-managed register() w/o doing the same for the
> alloc(). A core function should not assume that driver authors do
> sane things only.
> I don't have a strong preference how it should be done.
> Considering what is being discussed, have a look at get_pci_dr() and
> find_pci_dr(), they deal with managing which parts of the PCI
> subsystem are device-managed.

Yes, I have - that's why I asked if anyone objects to me moving all
networking devres functions into their own source file. The reason for
that being: devres_find() needs to know the address of the release
function, meanwhile devm_register_netdev() would have to go into
net/core, while devm_alloc_etherdev() lives in net/ethernet.

Bart

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

* Re: [PATCH 01/11] dt-bindings: add a binding document for MediaTek PERICFG controller
  2020-05-05 14:02 ` [PATCH 01/11] dt-bindings: add a binding document for MediaTek PERICFG controller Bartosz Golaszewski
@ 2020-05-13  2:38   ` Rob Herring
  2020-05-13  8:09     ` Bartosz Golaszewski
  0 siblings, 1 reply; 40+ messages in thread
From: Rob Herring @ 2020-05-13  2:38 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: David S . Miller, Matthias Brugger, Felix Fietkau, John Crispin,
	Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann,
	Fabien Parent, devicetree, linux-kernel, netdev,
	linux-arm-kernel, linux-mediatek, Bartosz Golaszewski

On Tue, May 05, 2020 at 04:02:21PM +0200, Bartosz Golaszewski wrote:
> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> 
> This adds a binding document for the PERICFG controller present on
> MediaTek SoCs. For now the only variant supported is 'mt8516-pericfg'.
> 
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> ---
>  .../arm/mediatek/mediatek,pericfg.yaml        | 34 +++++++++++++++++++
>  1 file changed, 34 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.yaml
> 
> diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.yaml b/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.yaml
> new file mode 100644
> index 000000000000..74b2a6173ffb
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.yaml
> @@ -0,0 +1,34 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: "http://devicetree.org/schemas/arm/mediatek/mediatek,pericfg.yaml#"
> +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
> +
> +title: MediaTek Peripheral Configuration Controller
> +
> +maintainers:
> +  - Bartosz Golaszewski <bgolaszewski@baylibre.com>
> +
> +properties:
> +  compatible:
> +    oneOf:

Don't need oneOf.

> +      - items:
> +        - enum:
> +          - mediatek,pericfg

PERICFG is exactly the same register set and functions on all Mediatek 
SoCs? Needs to be more specific.

> +        - const: syscon
> +
> +  reg:
> +    maxItems: 1
> +
> +required:
> +  - compatible
> +  - reg
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    pericfg: pericfg@10003050 {
> +        compatible = "mediatek,mt8516-pericfg", "syscon";
> +        reg = <0 0x10003050 0 0x1000>;

Default for examples is 1 cell for addr and size.

> +    };
> -- 
> 2.25.0
> 

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

* Re: [PATCH 02/11] dt-bindings: new: add yaml bindings for MediaTek Ethernet MAC
  2020-05-05 14:02 ` [PATCH 02/11] dt-bindings: new: add yaml bindings for MediaTek Ethernet MAC Bartosz Golaszewski
@ 2020-05-13  2:41   ` Rob Herring
  0 siblings, 0 replies; 40+ messages in thread
From: Rob Herring @ 2020-05-13  2:41 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: David S . Miller, Matthias Brugger, Felix Fietkau, John Crispin,
	Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann,
	Fabien Parent, devicetree, linux-kernel, netdev,
	linux-arm-kernel, linux-mediatek, Bartosz Golaszewski

On Tue, May 05, 2020 at 04:02:22PM +0200, Bartosz Golaszewski wrote:
> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> 
> This adds yaml DT bindings for the MediaTek Ethernet MAC present on the
> mt8* family of SoCs.
> 
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> ---
>  .../bindings/net/mediatek,eth-mac.yaml        | 80 +++++++++++++++++++
>  1 file changed, 80 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/net/mediatek,eth-mac.yaml
> 
> diff --git a/Documentation/devicetree/bindings/net/mediatek,eth-mac.yaml b/Documentation/devicetree/bindings/net/mediatek,eth-mac.yaml
> new file mode 100644
> index 000000000000..7682fe9d8109
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/mediatek,eth-mac.yaml
> @@ -0,0 +1,80 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/net/mediatek,eth-mac.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek Ethernet MAC Controller
> +
> +maintainers:
> +  - Bartosz Golaszewski <bgolaszewski@baylibre.com>
> +
> +description:
> +  This Ethernet MAC is used on the MT8* family of SoCs from MediaTek.
> +  It's compliant with 802.3 standards and supports half- and full-duplex
> +  modes with flow-control as well as CRC offloading and VLAN tags.
> +
> +properties:
> +  compatible:
> +    enum:
> +      - mediatek,mt8516-eth
> +      - mediatek,mt8518-eth
> +      - mediatek,mt8175-eth
> +
> +  reg:
> +    maxItems: 1
> +
> +  interrupts:
> +    maxItems: 1
> +
> +  clocks:
> +    minItems: 3
> +    maxItems: 3
> +
> +  clock-names:
> +    additionalItems: false
> +    items:
> +      - const: core
> +      - const: reg
> +      - const: trans
> +
> +  mediatek,pericfg:
> +    $ref: /schemas/types.yaml#definitions/phandle
> +    description:
> +      Phandle to the device containing the PERICFG register range.

Perhaps say what it is used for?

> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - clocks
> +  - clock-names
> +  - mediatek,pericfg
> +  - phy-handle
> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +    #include <dt-bindings/clock/mt8516-clk.h>
> +
> +    ethernet: ethernet@11180000 {
> +        compatible = "mediatek,mt8516-eth";
> +        reg = <0 0x11180000 0 0x1000>;

Default addr and size is 1 cell.

> +        mediatek,pericfg = <&pericfg>;
> +        interrupts = <GIC_SPI 111 IRQ_TYPE_LEVEL_LOW>;
> +        clocks = <&topckgen CLK_TOP_RG_ETH>,
> +                 <&topckgen CLK_TOP_66M_ETH>,
> +                 <&topckgen CLK_TOP_133M_ETH>;
> +        clock-names = "core", "reg", "trans";
> +        phy-handle = <&eth_phy>;
> +        phy-mode = "rmii";
> +
> +        mdio {

Not documented.

> +            #address-cells = <1>;
> +            #size-cells = <0>;
> +
> +            eth_phy: ethernet-phy@0 {
> +                reg = <0>;
> +            };
> +        };
> +    };
> -- 
> 2.25.0
> 

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

* Re: [PATCH 01/11] dt-bindings: add a binding document for MediaTek PERICFG controller
  2020-05-13  2:38   ` Rob Herring
@ 2020-05-13  8:09     ` Bartosz Golaszewski
  0 siblings, 0 replies; 40+ messages in thread
From: Bartosz Golaszewski @ 2020-05-13  8:09 UTC (permalink / raw)
  To: Rob Herring
  Cc: David S . Miller, Matthias Brugger, Felix Fietkau, John Crispin,
	Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann,
	Fabien Parent, devicetree, Linux Kernel Mailing List, netdev,
	Linux ARM, linux-mediatek, Bartosz Golaszewski

śr., 13 maj 2020 o 04:38 Rob Herring <robh@kernel.org> napisał(a):
>
> On Tue, May 05, 2020 at 04:02:21PM +0200, Bartosz Golaszewski wrote:
> > From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> >
> > This adds a binding document for the PERICFG controller present on
> > MediaTek SoCs. For now the only variant supported is 'mt8516-pericfg'.
> >
> > Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> > ---
> >  .../arm/mediatek/mediatek,pericfg.yaml        | 34 +++++++++++++++++++
> >  1 file changed, 34 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.yaml b/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.yaml
> > new file mode 100644
> > index 000000000000..74b2a6173ffb
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.yaml
> > @@ -0,0 +1,34 @@
> > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: "http://devicetree.org/schemas/arm/mediatek/mediatek,pericfg.yaml#"
> > +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
> > +
> > +title: MediaTek Peripheral Configuration Controller
> > +
> > +maintainers:
> > +  - Bartosz Golaszewski <bgolaszewski@baylibre.com>
> > +
> > +properties:
> > +  compatible:
> > +    oneOf:
>
> Don't need oneOf.
>
> > +      - items:
> > +        - enum:
> > +          - mediatek,pericfg
>
> PERICFG is exactly the same register set and functions on all Mediatek
> SoCs? Needs to be more specific.
>
> > +        - const: syscon
> > +
> > +  reg:
> > +    maxItems: 1
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > +  - |
> > +    pericfg: pericfg@10003050 {
> > +        compatible = "mediatek,mt8516-pericfg", "syscon";
> > +        reg = <0 0x10003050 0 0x1000>;
>
> Default for examples is 1 cell for addr and size.
>
> > +    };
> > --
> > 2.25.0
> >

Hi Rob,

I somehow missed the fact that there already is an old-style txt
binding document for pericfg. I'll first convert it and then add the
new compatible.

Bart

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

end of thread, other threads:[~2020-05-13  8:09 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-05-05 14:02 [PATCH 00/11] mediatek: add support for MediaTek Ethernet MAC Bartosz Golaszewski
2020-05-05 14:02 ` [PATCH 01/11] dt-bindings: add a binding document for MediaTek PERICFG controller Bartosz Golaszewski
2020-05-13  2:38   ` Rob Herring
2020-05-13  8:09     ` Bartosz Golaszewski
2020-05-05 14:02 ` [PATCH 02/11] dt-bindings: new: add yaml bindings for MediaTek Ethernet MAC Bartosz Golaszewski
2020-05-13  2:41   ` Rob Herring
2020-05-05 14:02 ` [PATCH 03/11] net: ethernet: mediatek: rename Kconfig prompt Bartosz Golaszewski
2020-05-05 14:02 ` [PATCH 04/11] net: ethernet: mediatek: remove unnecessary spaces from Makefile Bartosz Golaszewski
2020-05-05 14:02 ` [PATCH 05/11] net: core: provide devm_register_netdev() Bartosz Golaszewski
2020-05-05 17:31   ` Jakub Kicinski
2020-05-06  6:39     ` Bartosz Golaszewski
2020-05-06 17:12       ` Jakub Kicinski
2020-05-07  9:25         ` Bartosz Golaszewski
2020-05-07 16:53           ` Jakub Kicinski
2020-05-07 17:03             ` Bartosz Golaszewski
2020-05-07 22:56               ` Jakub Kicinski
2020-05-08  5:54                 ` Heiner Kallweit
2020-05-08 18:39                   ` Bartosz Golaszewski
2020-05-05 19:25   ` Edwin Peer
2020-05-06  6:46     ` Bartosz Golaszewski
2020-05-06 18:20       ` Edwin Peer
2020-05-05 14:02 ` [PATCH 06/11] net: ethernet: mtk-eth-mac: new driver Bartosz Golaszewski
2020-05-05 17:47   ` Andrew Lunn
2020-05-06  7:02     ` Bartosz Golaszewski
2020-05-05 18:04   ` Jakub Kicinski
2020-05-06  7:09     ` Bartosz Golaszewski
2020-05-06 17:19       ` Jakub Kicinski
2020-05-06 19:16   ` Leon Romanovsky
2020-05-06 19:23     ` Jakub Kicinski
2020-05-07  5:55       ` Leon Romanovsky
2020-05-07 22:50         ` Jakub Kicinski
2020-05-06 19:24     ` Joe Perches
     [not found]   ` <1588844771.5921.27.camel@mtksdccf07>
2020-05-07 10:50     ` Bartosz Golaszewski
2020-05-07 13:16       ` Andrew Lunn
2020-05-07 17:01         ` Bartosz Golaszewski
2020-05-05 14:02 ` [PATCH 07/11] ARM64: dts: mediatek: add pericfg syscon to mt8516.dtsi Bartosz Golaszewski
2020-05-05 14:02 ` [PATCH 08/11] ARM64: dts: mediatek: add the ethernet node " Bartosz Golaszewski
2020-05-05 14:02 ` [PATCH 09/11] ARM64: dts: mediatek: add an alias for ethernet0 for pumpkin boards Bartosz Golaszewski
2020-05-05 14:02 ` [PATCH 10/11] ARM64: dts: mediatek: add ethernet pins " Bartosz Golaszewski
2020-05-05 14:02 ` [PATCH 11/11] ARM64: dts: mediatek: enable ethernet on " Bartosz Golaszewski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).