All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller
@ 2021-02-05 21:44 Rafał Miłecki
  2021-02-05 21:44 ` [PATCH net-next 2/2] net: broadcom: bcm4908enet: add BCM4908 controller driver Rafał Miłecki
  2021-02-07 22:26 ` [PATCH V2 net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller Rafał Miłecki
  0 siblings, 2 replies; 33+ messages in thread
From: Rafał Miłecki @ 2021-02-05 21:44 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Florian Fainelli, Randy Dunlap, Masahiro Yamada, netdev,
	devicetree, bcm-kernel-feedback-list, Rafał Miłecki

From: Rafał Miłecki <rafal@milecki.pl>

BCM4908 is a family of SoCs with integrated Ethernet controller.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
 .../bindings/net/brcm,bcm4908enet.yaml        | 45 +++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/brcm,bcm4908enet.yaml

diff --git a/Documentation/devicetree/bindings/net/brcm,bcm4908enet.yaml b/Documentation/devicetree/bindings/net/brcm,bcm4908enet.yaml
new file mode 100644
index 000000000000..5f12f51c5b19
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/brcm,bcm4908enet.yaml
@@ -0,0 +1,45 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/brcm,bcm4908enet.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Broadcom BCM4908 Ethernet controller
+
+description: Broadcom's Ethernet controller integrated into BCM4908 family SoCs
+
+maintainers:
+  - Rafał Miłecki <rafal@milecki.pl>
+
+properties:
+  compatible:
+    const: brcm,bcm4908enet
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    description: RX interrupt
+
+  interrupt-names:
+    const: rx
+
+required:
+  - reg
+  - interrupts
+  - interrupt-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    ethernet@80002000 {
+        compatible = "brcm,bcm4908enet";
+        reg = <0x80002000 0x1000>;
+
+        interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+        interrupt-names = "rx";
+    };
-- 
2.26.2


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

* [PATCH net-next 2/2] net: broadcom: bcm4908enet: add BCM4908 controller driver
  2021-02-05 21:44 [PATCH net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller Rafał Miłecki
@ 2021-02-05 21:44 ` Rafał Miłecki
  2021-02-05 23:47     ` kernel test robot
  2021-02-07 22:26 ` [PATCH V2 net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller Rafał Miłecki
  1 sibling, 1 reply; 33+ messages in thread
From: Rafał Miłecki @ 2021-02-05 21:44 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Florian Fainelli, Randy Dunlap, Masahiro Yamada, netdev,
	devicetree, bcm-kernel-feedback-list, Rafał Miłecki

From: Rafał Miłecki <rafal@milecki.pl>

BCM4908 SoCs family uses Ethernel controller that includes UniMAC but
uses different DMA engine (than other controllers) and requires
different programming.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
 MAINTAINERS                                 |   9 +
 drivers/net/ethernet/broadcom/Kconfig       |   7 +
 drivers/net/ethernet/broadcom/Makefile      |   1 +
 drivers/net/ethernet/broadcom/bcm4908enet.c | 674 ++++++++++++++++++++
 drivers/net/ethernet/broadcom/bcm4908enet.h |  96 +++
 5 files changed, 787 insertions(+)
 create mode 100644 drivers/net/ethernet/broadcom/bcm4908enet.c
 create mode 100644 drivers/net/ethernet/broadcom/bcm4908enet.h

diff --git a/MAINTAINERS b/MAINTAINERS
index d1b0057a9797..cbf4b94f89d4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3445,6 +3445,15 @@ F:	Documentation/devicetree/bindings/mips/brcm/
 F:	arch/mips/bcm47xx/*
 F:	arch/mips/include/asm/mach-bcm47xx/*
 
+BROADCOM BCM4908 ETHERNET DRIVER
+M:	Rafał Miłecki <rafal@milecki.pl>
+M:	bcm-kernel-feedback-list@broadcom.com
+L:	netdev@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/net/brcm,bcm4908enet.yaml
+F:	drivers/net/ethernet/broadcom/bcm4908enet.*
+F:	drivers/net/ethernet/broadcom/unimac.h
+
 BROADCOM BCM5301X ARM ARCHITECTURE
 M:	Hauke Mehrtens <hauke@hauke-m.de>
 M:	Rafał Miłecki <zajec5@gmail.com>
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index 4bdf8fbe75a6..686223438434 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -51,6 +51,13 @@ config B44_PCI
 	depends on B44_PCI_AUTOSELECT && B44_PCICORE_AUTOSELECT
 	default y
 
+config BCM4908ENET
+	tristate "Broadcom BCM4908 internal mac support"
+	default y
+	help
+	  This driver supports Ethernet controller integrated into Broadcom
+	  BCM4908 family SoCs.
+
 config BCM63XX_ENET
 	tristate "Broadcom 63xx internal mac support"
 	depends on BCM63XX
diff --git a/drivers/net/ethernet/broadcom/Makefile b/drivers/net/ethernet/broadcom/Makefile
index 7046ad6d3d0e..379012de3569 100644
--- a/drivers/net/ethernet/broadcom/Makefile
+++ b/drivers/net/ethernet/broadcom/Makefile
@@ -4,6 +4,7 @@
 #
 
 obj-$(CONFIG_B44) += b44.o
+obj-$(CONFIG_BCM4908ENET) += bcm4908enet.o
 obj-$(CONFIG_BCM63XX_ENET) += bcm63xx_enet.o
 obj-$(CONFIG_BCMGENET) += genet/
 obj-$(CONFIG_BNX2) += bnx2.o
diff --git a/drivers/net/ethernet/broadcom/bcm4908enet.c b/drivers/net/ethernet/broadcom/bcm4908enet.c
new file mode 100644
index 000000000000..786d3bf11b53
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/bcm4908enet.c
@@ -0,0 +1,674 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl>
+ */
+
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include "bcm4908enet.h"
+#include "unimac.h"
+
+#define ENET_DMA_CH_RX_CFG			ENET_DMA_CH0_CFG
+#define ENET_DMA_CH_TX_CFG			ENET_DMA_CH1_CFG
+#define ENET_DMA_CH_RX_STATE_RAM		ENET_DMA_CH0_STATE_RAM
+#define ENET_DMA_CH_TX_STATE_RAM		ENET_DMA_CH1_STATE_RAM
+
+#define ENET_TX_BDS_NUM				200
+#define ENET_RX_BDS_NUM				200
+#define ENET_RX_BDS_NUM_MAX			8192
+
+#define ENET_DMA_INT_DEFAULTS			(ENET_DMA_CH_CFG_INT_DONE | \
+						 ENET_DMA_CH_CFG_INT_NO_DESC | \
+						 ENET_DMA_CH_CFG_INT_BUFF_DONE)
+#define ENET_DMA_MAX_BURST_LEN			8 /* in 64 bit words */
+
+#define ENET_MTU_MIN				60
+#define ENET_MTU_MAX				1500 /* Is it possible to support 2044? */
+#define ENET_MTU_MAX_EXTRA_SIZE			32 /* L2 */
+
+struct bcm4908enet_dma_ring_bd {
+	__le32 ctl;
+	__le32 addr;
+} __packed;
+
+struct bcm4908enet_dma_ring_slot {
+	struct sk_buff *skb;
+	unsigned int len;
+	dma_addr_t dma_addr;
+};
+
+struct bcm4908enet_dma_ring {
+	int is_tx;
+	int read_idx;
+	int write_idx;
+	int length;
+	u16 cfg_block;
+	u16 st_ram_block;
+
+	union {
+		void *cpu_addr;
+		struct bcm4908enet_dma_ring_bd *buf_desc;
+	};
+	dma_addr_t dma_addr;
+
+	struct bcm4908enet_dma_ring_slot *slots;
+};
+
+struct bcm4908enet {
+	struct device *dev;
+	struct net_device *netdev;
+	struct napi_struct napi;
+	void __iomem *base;
+
+	struct bcm4908enet_dma_ring tx_ring;
+	struct bcm4908enet_dma_ring rx_ring;
+};
+
+/***
+ * R/W ops
+ */
+
+static inline u32 enet_read(struct bcm4908enet *enet, u16 offset)
+{
+	return readl(enet->base + offset);
+}
+
+static inline void enet_write(struct bcm4908enet *enet, u16 offset, u32 value)
+{
+	writel(value, enet->base + offset);
+}
+
+static inline void enet_maskset(struct bcm4908enet *enet, u16 offset, u32 mask, u32 set)
+{
+	u32 val;
+
+	WARN_ON(set & ~mask);
+
+	val = enet_read(enet, offset);
+	val = (val & ~mask) | (set & mask);
+	enet_write(enet, offset, val);
+}
+
+static inline void enet_set(struct bcm4908enet *enet, u16 offset, u32 set)
+{
+	enet_maskset(enet, offset, set, set);
+}
+
+static inline u32 enet_umac_read(struct bcm4908enet *enet, u16 offset)
+{
+	return enet_read(enet, ENET_UNIMAC + offset);
+}
+
+static inline void enet_umac_write(struct bcm4908enet *enet, u16 offset, u32 value)
+{
+	enet_write(enet, ENET_UNIMAC + offset, value);
+}
+
+static inline void enet_umac_maskset(struct bcm4908enet *enet, u16 offset, u32 mask, u32 set)
+{
+	enet_maskset(enet, ENET_UNIMAC + offset, mask, set);
+}
+
+static inline void enet_umac_set(struct bcm4908enet *enet, u16 offset, u32 set)
+{
+	enet_set(enet, ENET_UNIMAC + offset, set);
+}
+
+/***
+ * Helpers
+ */
+
+static void bcm4908enet_intrs_on(struct bcm4908enet *enet)
+{
+	enet_write(enet, ENET_DMA_CH_RX_CFG + ENET_DMA_CH_CFG_INT_MASK, ENET_DMA_INT_DEFAULTS);
+}
+
+static void bcm4908enet_intrs_off(struct bcm4908enet *enet)
+{
+	enet_write(enet, ENET_DMA_CH_RX_CFG + ENET_DMA_CH_CFG_INT_MASK, 0);
+}
+
+static void bcm4908enet_intrs_ack(struct bcm4908enet *enet)
+{
+	enet_write(enet, ENET_DMA_CH_RX_CFG + ENET_DMA_CH_CFG_INT_STAT, ENET_DMA_INT_DEFAULTS);
+}
+
+/***
+ * DMA
+ */
+
+static int bcm4908_dma_alloc_buf_descs(struct bcm4908enet *enet, struct bcm4908enet_dma_ring *ring)
+{
+	int size = ring->length * sizeof(struct bcm4908enet_dma_ring_bd);
+	struct device *dev = enet->dev;
+
+	ring->cpu_addr = dma_alloc_coherent(dev, size, &ring->dma_addr, GFP_KERNEL);
+	if (!ring->cpu_addr)
+		return -ENOMEM;
+
+	if (((uintptr_t)ring->cpu_addr) & (0x40 - 1)) {
+		dev_err(dev, "Invalid DMA ring alignment\n");
+		goto err_free_buf_descs;
+	}
+
+	ring->slots = kzalloc(ring->length * sizeof(*ring->slots), GFP_KERNEL);
+	if (!ring->slots)
+		goto err_free_buf_descs;
+
+	memset(ring->cpu_addr, 0, size);
+
+	ring->read_idx = 0;
+	ring->write_idx = 0;
+
+	return 0;
+
+err_free_buf_descs:
+	dma_free_coherent(dev, size, ring->cpu_addr, ring->dma_addr);
+	return -ENOMEM;
+}
+
+static void bcm4908enet_dma_free(struct bcm4908enet *enet)
+{
+	struct bcm4908enet_dma_ring *tx_ring = &enet->tx_ring;
+	struct bcm4908enet_dma_ring *rx_ring = &enet->rx_ring;
+	struct device *dev = enet->dev;
+	int size;
+
+	size = rx_ring->length * sizeof(struct bcm4908enet_dma_ring_bd);
+	if (rx_ring->cpu_addr)
+		dma_free_coherent(dev, size, rx_ring->cpu_addr, rx_ring->dma_addr);
+	kfree(rx_ring->slots);
+
+	size = tx_ring->length * sizeof(struct bcm4908enet_dma_ring_bd);
+	if (tx_ring->cpu_addr)
+		dma_free_coherent(dev, size, tx_ring->cpu_addr, tx_ring->dma_addr);
+	kfree(tx_ring->slots);
+}
+
+static int bcm4908enet_dma_alloc(struct bcm4908enet *enet)
+{
+	struct bcm4908enet_dma_ring *tx_ring = &enet->tx_ring;
+	struct bcm4908enet_dma_ring *rx_ring = &enet->rx_ring;
+	struct device *dev = enet->dev;
+	int err;
+
+	tx_ring->length = ENET_TX_BDS_NUM;
+	tx_ring->is_tx = 1;
+	tx_ring->cfg_block = ENET_DMA_CH_TX_CFG;
+	tx_ring->st_ram_block = ENET_DMA_CH_TX_STATE_RAM;
+	err = bcm4908_dma_alloc_buf_descs(enet, tx_ring);
+	if (err) {
+		dev_err(dev, "Failed to alloc TX buf descriptors: %d\n", err);
+		return err;
+	}
+
+	rx_ring->length = ENET_RX_BDS_NUM;
+	rx_ring->is_tx = 0;
+	rx_ring->cfg_block = ENET_DMA_CH_RX_CFG;
+	rx_ring->st_ram_block = ENET_DMA_CH_RX_STATE_RAM;
+	err = bcm4908_dma_alloc_buf_descs(enet, rx_ring);
+	if (err) {
+		dev_err(dev, "Failed to alloc RX buf descriptors: %d\n", err);
+		bcm4908enet_dma_free(enet);
+		return err;
+	}
+
+	return 0;
+}
+
+static void bcm4908enet_dma_reset(struct bcm4908enet *enet)
+{
+	struct bcm4908enet_dma_ring *rings[] = { &enet->rx_ring, &enet->tx_ring };
+	int i;
+
+	/* Disable the DMA controller and channel */
+	for (i = 0; i < ARRAY_SIZE(rings); i++)
+		enet_write(enet, rings[i]->cfg_block + ENET_DMA_CH_CFG, 0);
+	enet_maskset(enet, ENET_DMA_CONTROLLER_CFG, ENET_DMA_CTRL_CFG_MASTER_EN, 0);
+
+	/* Reset channels state */
+	for (i = 0; i < ARRAY_SIZE(rings); i++) {
+		struct bcm4908enet_dma_ring *ring = rings[i];
+
+		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_BASE_DESC_PTR, 0);
+		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_STATE_DATA, 0);
+		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_DESC_LEN_STATUS, 0);
+		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_DESC_BASE_BUFPTR, 0);
+	}
+}
+
+static int bcm4908enet_dma_alloc_rx_buf(struct bcm4908enet *enet, unsigned int idx)
+{
+	struct bcm4908enet_dma_ring_bd *buf_desc = &enet->rx_ring.buf_desc[idx];
+	struct bcm4908enet_dma_ring_slot *slot = &enet->rx_ring.slots[idx];
+	struct device *dev = enet->dev;
+	u32 tmp;
+	int err;
+
+	slot->len = ENET_MTU_MAX + ENET_MTU_MAX_EXTRA_SIZE;
+
+	slot->skb = netdev_alloc_skb(enet->netdev, slot->len);
+	if (!slot->skb)
+		return -ENOMEM;
+
+	slot->dma_addr = dma_map_single(dev, slot->skb->data, slot->len, DMA_FROM_DEVICE);
+	err = dma_mapping_error(dev, slot->dma_addr);
+	if (err) {
+		dev_err(dev, "Failed to map DMA buffer: %d\n", err);
+		kfree_skb(slot->skb);
+		slot->skb = NULL;
+		return err;
+	}
+
+	tmp = slot->len << DMA_CTL_LEN_DESC_BUFLENGTH_SHIFT;
+	tmp |= DMA_CTL_STATUS_OWN;
+	if (idx == enet->rx_ring.length - 1)
+		tmp |= DMA_CTL_STATUS_WRAP;
+	buf_desc->ctl = tmp;
+	buf_desc->addr = slot->dma_addr;
+
+	return 0;
+}
+
+static void bcm4908enet_dma_ring_init(struct bcm4908enet *enet,
+				      struct bcm4908enet_dma_ring *ring)
+{
+	int reset_channel = 0; /* We support only 1 main channel (with TX and RX) */
+	int reset_subch = ring->is_tx ? 1 : 0;
+
+	/* Reset the DMA channel */
+	enet_write(enet, ENET_DMA_CTRL_CHANNEL_RESET, BIT(reset_channel * 2 + reset_subch));
+	enet_write(enet, ENET_DMA_CTRL_CHANNEL_RESET, 0);
+
+	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG, 0);
+	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG_MAX_BURST, ENET_DMA_MAX_BURST_LEN);
+	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG_INT_MASK, 0);
+
+	enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_BASE_DESC_PTR,
+		   (uint32_t)ring->dma_addr);
+}
+
+static void bcm4908enet_dma_uninit(struct bcm4908enet *enet)
+{
+	struct bcm4908enet_dma_ring *rx_ring = &enet->rx_ring;
+	struct bcm4908enet_dma_ring_slot *slot;
+	struct device *dev = enet->dev;
+	int i;
+
+	for (i = rx_ring->length - 1; i >= 0; i--) {
+		slot = &rx_ring->slots[i];
+		if (!slot->skb)
+			continue;
+		dma_unmap_single(dev, slot->dma_addr, slot->len, DMA_FROM_DEVICE);
+		kfree_skb(slot->skb);
+		slot->skb = NULL;
+	}
+}
+
+static int bcm4908enet_dma_init(struct bcm4908enet *enet)
+{
+	struct bcm4908enet_dma_ring *rx_ring = &enet->rx_ring;
+	struct device *dev = enet->dev;
+	int err;
+	int i;
+
+	for (i = 0; i < rx_ring->length; i++) {
+		err = bcm4908enet_dma_alloc_rx_buf(enet, i);
+		if (err) {
+			dev_err(dev, "Failed to alloc RX buffer: %d\n", err);
+			bcm4908enet_dma_uninit(enet);
+			return err;
+		}
+	}
+
+	bcm4908enet_dma_ring_init(enet, &enet->tx_ring);
+	bcm4908enet_dma_ring_init(enet, &enet->rx_ring);
+
+	return 0;
+}
+
+static void bcm4908enet_dma_tx_ring_ensable(struct bcm4908enet *enet,
+					    struct bcm4908enet_dma_ring *ring)
+{
+	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG, ENET_DMA_CH_CFG_ENABLE);
+}
+
+static void bcm4908enet_dma_tx_ring_disable(struct bcm4908enet *enet,
+					    struct bcm4908enet_dma_ring *ring)
+{
+	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG, 0);
+}
+
+static void bcm4908enet_dma_rx_ring_enable(struct bcm4908enet *enet,
+					   struct bcm4908enet_dma_ring *ring)
+{
+	enet_set(enet, ring->cfg_block + ENET_DMA_CH_CFG, ENET_DMA_CH_CFG_ENABLE);
+}
+
+static void bcm4908enet_dma_rx_ring_disable(struct bcm4908enet *enet,
+					    struct bcm4908enet_dma_ring *ring)
+{
+	unsigned long deadline;
+	u32 tmp;
+
+	enet_maskset(enet, ring->cfg_block + ENET_DMA_CH_CFG, ENET_DMA_CH_CFG_ENABLE, 0);
+
+	deadline = jiffies + usecs_to_jiffies(2000);
+	do {
+		tmp = enet_read(enet, ring->cfg_block + ENET_DMA_CH_CFG);
+		if (!(tmp & ENET_DMA_CH_CFG_ENABLE))
+			return;
+		enet_maskset(enet, ring->cfg_block + ENET_DMA_CH_CFG, ENET_DMA_CH_CFG_ENABLE, 0);
+		usleep_range(10, 30);
+	} while (!time_after_eq(jiffies, deadline));
+
+	dev_warn(enet->dev, "Timeout waiting for DMA TX stop\n");
+}
+
+/***
+ * Ethernet driver
+ */
+
+static void bcm4908enet_gmac_init(struct bcm4908enet *enet)
+{
+	u32 cmd;
+
+	cmd = enet_umac_read(enet, UMAC_CMD);
+	enet_umac_write(enet, UMAC_CMD, cmd | CMD_SW_RESET);
+	enet_umac_write(enet, UMAC_CMD, cmd & ~CMD_SW_RESET);
+
+	enet_set(enet, ENET_FLUSH, ENET_FLUSH_RXFIFO_FLUSH | ENET_FLUSH_TXFIFO_FLUSH);
+	enet_maskset(enet, ENET_FLUSH, ENET_FLUSH_RXFIFO_FLUSH | ENET_FLUSH_TXFIFO_FLUSH, 0);
+
+	enet_set(enet, ENET_MIB_CTRL, ENET_MIB_CTRL_CLR_MIB);
+	enet_maskset(enet, ENET_MIB_CTRL, ENET_MIB_CTRL_CLR_MIB, 0);
+
+	cmd = enet_umac_read(enet, UMAC_CMD);
+	cmd &= ~(CMD_SPEED_MASK << CMD_SPEED_SHIFT);
+	cmd &= ~CMD_TX_EN;
+	cmd &= ~CMD_RX_EN;
+	cmd |= CMD_SPEED_1000 << CMD_SPEED_SHIFT;
+	enet_umac_write(enet, UMAC_CMD, cmd);
+
+	enet_maskset(enet, ENET_GMAC_STATUS,
+		     ENET_GMAC_STATUS_ETH_SPEED_MASK |
+		     ENET_GMAC_STATUS_HD |
+		     ENET_GMAC_STATUS_AUTO_CFG_EN |
+		     ENET_GMAC_STATUS_LINK_UP,
+		     ENET_GMAC_STATUS_ETH_SPEED_1000 |
+		     ENET_GMAC_STATUS_AUTO_CFG_EN |
+		     ENET_GMAC_STATUS_LINK_UP);
+}
+
+static irqreturn_t bcm4908enet_irq_handler(int irq, void *dev_id)
+{
+	struct bcm4908enet *enet = dev_id;
+
+	bcm4908enet_intrs_off(enet);
+	bcm4908enet_intrs_ack(enet);
+
+	napi_schedule(&enet->napi);
+
+	return IRQ_HANDLED;
+}
+
+static int bcm4908enet_open(struct net_device *netdev)
+{
+	struct bcm4908enet *enet = netdev_priv(netdev);
+	struct device *dev = enet->dev;
+	int err;
+
+	err = request_irq(netdev->irq, bcm4908enet_irq_handler, 0, "enet", enet);
+	if (err) {
+		dev_err(dev, "Failed to request IRQ %d: %d\n", netdev->irq, err);
+		return err;
+	}
+
+	bcm4908enet_gmac_init(enet);
+	bcm4908enet_dma_reset(enet);
+	bcm4908enet_dma_init(enet);
+
+	enet_umac_set(enet, UMAC_CMD, CMD_TX_EN | CMD_RX_EN);
+
+	enet_set(enet, ENET_DMA_CONTROLLER_CFG, ENET_DMA_CTRL_CFG_MASTER_EN);
+	enet_maskset(enet, ENET_DMA_CONTROLLER_CFG, ENET_DMA_CTRL_CFG_FLOWC_CH1_EN, 0);
+	bcm4908enet_dma_rx_ring_enable(enet, &enet->rx_ring);
+
+	napi_enable(&enet->napi);
+	netif_carrier_on(netdev);
+	netif_start_queue(netdev);
+
+	bcm4908enet_intrs_ack(enet);
+	bcm4908enet_intrs_on(enet);
+
+	return 0;
+}
+
+static int bcm4908enet_stop(struct net_device *netdev)
+{
+	struct bcm4908enet *enet = netdev_priv(netdev);
+
+	netif_stop_queue(netdev);
+	netif_carrier_off(netdev);
+	napi_disable(&enet->napi);
+
+	bcm4908enet_dma_rx_ring_disable(enet, &enet->rx_ring);
+	bcm4908enet_dma_tx_ring_disable(enet, &enet->tx_ring);
+
+	bcm4908enet_dma_uninit(enet);
+
+	free_irq(enet->netdev->irq, enet);
+
+	return 0;
+}
+
+static int bcm4908enet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct bcm4908enet *enet = netdev_priv(netdev);
+	struct bcm4908enet_dma_ring *ring = &enet->tx_ring;
+	struct bcm4908enet_dma_ring_slot *slot;
+	struct device *dev = enet->dev;
+	struct bcm4908enet_dma_ring_bd *buf_desc;
+	int free_buf_descs;
+	u32 tmp;
+
+	/* Free transmitted skbs */
+	while (ring->read_idx != ring->write_idx) {
+		buf_desc = &ring->buf_desc[ring->read_idx];
+		if (buf_desc->ctl & DMA_CTL_STATUS_OWN)
+			break;
+		slot = &ring->slots[ring->read_idx];
+
+		dma_unmap_single(dev, slot->dma_addr, slot->len, DMA_TO_DEVICE);
+		dev_kfree_skb(slot->skb);
+		if (++ring->read_idx == ring->length)
+			ring->read_idx = 0;
+	}
+
+	/* Don't use the last empty buf descriptor */
+	if (ring->read_idx <= ring->write_idx)
+		free_buf_descs = ring->read_idx - ring->write_idx + ring->length;
+	else
+		free_buf_descs = ring->read_idx - ring->write_idx;
+	if (free_buf_descs < 2)
+		return NETDEV_TX_BUSY;
+
+	/* Hardware removes OWN bit after sending data */
+	buf_desc = &ring->buf_desc[ring->write_idx];
+	if (unlikely(buf_desc->ctl & DMA_CTL_STATUS_OWN)) {
+		netif_stop_queue(netdev);
+		return NETDEV_TX_BUSY;
+	}
+
+	slot = &ring->slots[ring->write_idx];
+	slot->skb = skb;
+	slot->len = skb->len;
+	slot->dma_addr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE);
+	if (unlikely(dma_mapping_error(dev, slot->dma_addr)))
+		return NETDEV_TX_BUSY;
+
+	tmp = skb->len << DMA_CTL_LEN_DESC_BUFLENGTH_SHIFT;
+	tmp |= DMA_CTL_STATUS_OWN;
+	tmp |= DMA_CTL_STATUS_SOP;
+	tmp |= DMA_CTL_STATUS_EOP;
+	tmp |= DMA_CTL_STATUS_APPEND_CRC;
+	if (ring->write_idx + 1 == ring->length - 1)
+		tmp |= DMA_CTL_STATUS_WRAP;
+
+	buf_desc->addr = (uint32_t)slot->dma_addr;
+	buf_desc->ctl = tmp;
+
+	bcm4908enet_dma_tx_ring_ensable(enet, &enet->tx_ring);
+
+	if (++ring->write_idx == ring->length - 1)
+		ring->write_idx = 0;
+	enet->netdev->stats.tx_bytes += skb->len;
+	enet->netdev->stats.tx_packets++;
+
+	return NETDEV_TX_OK;
+}
+
+static int bcm4908enet_poll(struct napi_struct *napi, int weight)
+{
+	struct bcm4908enet *enet = container_of(napi, struct bcm4908enet, napi);
+	struct device *dev = enet->dev;
+	int handled = 0;
+
+	while (handled < weight) {
+		struct bcm4908enet_dma_ring_bd buf_desc;
+		struct bcm4908enet_dma_ring_slot slot;
+		int len;
+		int err;
+
+		buf_desc = enet->rx_ring.buf_desc[enet->rx_ring.read_idx];
+		if (buf_desc.ctl & DMA_CTL_STATUS_OWN)
+			break;
+
+		slot = enet->rx_ring.slots[enet->rx_ring.read_idx];
+
+		/* Provide new buffer before unpinning the old one */
+		err = bcm4908enet_dma_alloc_rx_buf(enet, enet->rx_ring.read_idx);
+		if (err)
+			break;
+
+		if (++enet->rx_ring.read_idx == enet->rx_ring.length)
+			enet->rx_ring.read_idx = 0;
+
+		len = (buf_desc.ctl & DMA_CTL_LEN_DESC_BUFLENGTH) >> DMA_CTL_LEN_DESC_BUFLENGTH_SHIFT;
+
+		if (len < ENET_MTU_MIN ||
+		    (buf_desc.ctl & (DMA_CTL_STATUS_SOP | DMA_CTL_STATUS_EOP)) != (DMA_CTL_STATUS_SOP | DMA_CTL_STATUS_EOP)) {
+			enet->netdev->stats.rx_dropped++;
+			break;
+		}
+
+		dma_unmap_single(dev, slot.dma_addr, slot.len, DMA_FROM_DEVICE);
+
+		skb_put(slot.skb, len - 4 + 2);
+		slot.skb->protocol = eth_type_trans(slot.skb, enet->netdev);
+		netif_receive_skb(slot.skb);
+
+		enet->netdev->stats.rx_packets++;
+		enet->netdev->stats.rx_bytes += len;
+	}
+
+	if (handled < weight) {
+		napi_complete_done(napi, handled);
+		bcm4908enet_intrs_on(enet);
+	}
+
+	return handled;
+}
+
+static const struct net_device_ops bcm96xx_netdev_ops = {
+	.ndo_open = bcm4908enet_open,
+	.ndo_stop = bcm4908enet_stop,
+	.ndo_start_xmit = bcm4908enet_start_xmit,
+	.ndo_set_mac_address = eth_mac_addr,
+};
+
+static int bcm4908enet_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct net_device *netdev;
+	struct bcm4908enet *enet;
+	int err;
+
+	netdev = devm_alloc_etherdev(dev, sizeof(*enet));
+	if (!netdev)
+		return -ENOMEM;
+
+	enet = netdev_priv(netdev);
+	enet->dev = dev;
+	enet->netdev = netdev;
+
+	enet->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(enet->base)) {
+		dev_err(dev, "Failed to map registers: %ld\n", PTR_ERR(enet->base));
+		return PTR_ERR(enet->base);
+	}
+
+	netdev->irq = platform_get_irq_byname(pdev, "rx");
+	if (netdev->irq < 0)
+		return netdev->irq;
+
+	dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+
+	err = bcm4908enet_dma_alloc(enet);
+	if (err)
+		return err;
+
+	SET_NETDEV_DEV(netdev, &pdev->dev);
+	eth_hw_addr_random(netdev);
+	netdev->netdev_ops = &bcm96xx_netdev_ops;
+	netdev->min_mtu = ETH_ZLEN;
+	netdev->mtu = ENET_MTU_MAX;
+	netdev->max_mtu = ENET_MTU_MAX;
+	netif_napi_add(netdev, &enet->napi, bcm4908enet_poll, 64);
+
+	err = register_netdev(netdev);
+	if (err) {
+		bcm4908enet_dma_free(enet);
+		return err;
+	}
+
+	platform_set_drvdata(pdev, enet);
+
+	return 0;
+}
+
+static int bcm4908enet_remove(struct platform_device *pdev)
+{
+	struct bcm4908enet *enet = platform_get_drvdata(pdev);
+
+	unregister_netdev(enet->netdev);
+	netif_napi_del(&enet->napi);
+	bcm4908enet_dma_free(enet);
+
+	return 0;
+}
+
+static const struct of_device_id bcm4908enet_of_match[] = {
+	{ .compatible = "brcm,bcm4908enet"},
+	{},
+};
+
+static struct platform_driver bcm4908enet_driver = {
+	.driver = {
+		.name = "bcm4908enet",
+		.of_match_table = bcm4908enet_of_match,
+	},
+	.probe	= bcm4908enet_probe,
+	.remove = bcm4908enet_remove,
+};
+module_platform_driver(bcm4908enet_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, bcm4908enet_of_match);
diff --git a/drivers/net/ethernet/broadcom/bcm4908enet.h b/drivers/net/ethernet/broadcom/bcm4908enet.h
new file mode 100644
index 000000000000..11aadf0715d3
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/bcm4908enet.h
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __BCM4908ENET_H
+#define __BCM4908ENET_H
+
+#define ENET_CONTROL					0x000
+#define ENET_MIB_CTRL					0x004
+#define  ENET_MIB_CTRL_CLR_MIB				0x00000001
+#define ENET_RX_ERR_MASK				0x008
+#define ENET_MIB_MAX_PKT_SIZE				0x00C
+#define  ENET_MIB_MAX_PKT_SIZE_VAL			0x00003fff
+#define ENET_DIAG_OUT					0x01c
+#define ENET_ENABLE_DROP_PKT				0x020
+#define ENET_IRQ_ENABLE					0x024
+#define  ENET_IRQ_ENABLE_OVFL				0x00000001
+#define ENET_GMAC_STATUS				0x028
+#define  ENET_GMAC_STATUS_ETH_SPEED_MASK		0x00000003
+#define  ENET_GMAC_STATUS_ETH_SPEED_10			0x00000000
+#define  ENET_GMAC_STATUS_ETH_SPEED_100			0x00000001
+#define  ENET_GMAC_STATUS_ETH_SPEED_1000		0x00000002
+#define  ENET_GMAC_STATUS_HD				0x00000004
+#define  ENET_GMAC_STATUS_AUTO_CFG_EN			0x00000008
+#define  ENET_GMAC_STATUS_LINK_UP			0x00000010
+#define ENET_IRQ_STATUS					0x02c
+#define  ENET_IRQ_STATUS_OVFL				0x00000001
+#define ENET_OVERFLOW_COUNTER				0x030
+#define ENET_FLUSH					0x034
+#define  ENET_FLUSH_RXFIFO_FLUSH			0x00000001
+#define  ENET_FLUSH_TXFIFO_FLUSH			0x00000002
+#define ENET_RSV_SELECT					0x038
+#define ENET_BP_FORCE					0x03c
+#define  ENET_BP_FORCE_FORCE				0x00000001
+#define ENET_DMA_RX_OK_TO_SEND_COUNT			0x040
+#define  ENET_DMA_RX_OK_TO_SEND_COUNT_VAL		0x0000000f
+#define ENET_TX_CRC_CTRL				0x044
+#define ENET_MIB					0x200
+#define ENET_UNIMAC					0x400
+#define ENET_DMA					0x800
+#define ENET_DMA_CONTROLLER_CFG				0x800
+#define  ENET_DMA_CTRL_CFG_MASTER_EN			0x00000001
+#define  ENET_DMA_CTRL_CFG_FLOWC_CH1_EN			0x00000002
+#define  ENET_DMA_CTRL_CFG_FLOWC_CH3_EN			0x00000004
+#define ENET_DMA_FLOWCTL_CH1_THRESH_LO			0x804
+#define ENET_DMA_FLOWCTL_CH1_THRESH_HI			0x808
+#define ENET_DMA_FLOWCTL_CH1_ALLOC			0x80c
+#define  ENET_DMA_FLOWCTL_CH1_ALLOC_FORCE		0x80000000
+#define ENET_DMA_FLOWCTL_CH3_THRESH_LO			0x810
+#define ENET_DMA_FLOWCTL_CH3_THRESH_HI			0x814
+#define ENET_DMA_FLOWCTL_CH3_ALLOC			0x818
+#define ENET_DMA_FLOWCTL_CH5_THRESH_LO			0x81C
+#define ENET_DMA_FLOWCTL_CH5_THRESH_HI			0x820
+#define ENET_DMA_FLOWCTL_CH5_ALLOC			0x824
+#define ENET_DMA_FLOWCTL_CH7_THRESH_LO			0x828
+#define ENET_DMA_FLOWCTL_CH7_THRESH_HI			0x82C
+#define ENET_DMA_FLOWCTL_CH7_ALLOC			0x830
+#define ENET_DMA_CTRL_CHANNEL_RESET			0x834
+#define ENET_DMA_CTRL_CHANNEL_DEBUG			0x838
+#define ENET_DMA_CTRL_GLOBAL_INTERRUPT_STATUS		0x840
+#define ENET_DMA_CTRL_GLOBAL_INTERRUPT_MASK		0x844
+#define ENET_DMA_CH0_CFG				0xa00		/* RX */
+#define ENET_DMA_CH1_CFG				0xa10		/* TX */
+#define ENET_DMA_CH0_STATE_RAM				0xc00		/* RX */
+#define ENET_DMA_CH1_STATE_RAM				0xc10		/* TX */
+
+#define ENET_DMA_CH_CFG					0x00		/* assorted configuration */
+#define  ENET_DMA_CH_CFG_ENABLE				0x00000001	/* set to enable channel */
+#define  ENET_DMA_CH_CFG_PKT_HALT			0x00000002	/* idle after an EOP flag is detected */
+#define  ENET_DMA_CH_CFG_BURST_HALT			0x00000004	/* idle after finish current memory burst */
+#define ENET_DMA_CH_CFG_INT_STAT			0x04		/* interrupts control and status */
+#define ENET_DMA_CH_CFG_INT_MASK			0x08		/* interrupts mask */
+#define  ENET_DMA_CH_CFG_INT_BUFF_DONE			0x00000001	/* buffer done */
+#define  ENET_DMA_CH_CFG_INT_DONE			0x00000002	/* packet xfer complete */
+#define  ENET_DMA_CH_CFG_INT_NO_DESC			0x00000004	/* no valid descriptors */
+#define  ENET_DMA_CH_CFG_INT_RX_ERROR			0x00000008	/* rxdma detect client protocol error */
+#define ENET_DMA_CH_CFG_MAX_BURST			0x0c		/* max burst length permitted */
+#define  ENET_DMA_CH_CFG_MAX_BURST_DESCSIZE_SEL		0x00040000	/* DMA Descriptor Size Selection */
+#define ENET_DMA_CH_CFG_SIZE				0x10
+
+#define ENET_DMA_CH_STATE_RAM_BASE_DESC_PTR		0x00		/* descriptor ring start address */
+#define ENET_DMA_CH_STATE_RAM_STATE_DATA		0x04		/* state/bytes done/ring offset */
+#define ENET_DMA_CH_STATE_RAM_DESC_LEN_STATUS		0x08		/* buffer descriptor status and len */
+#define ENET_DMA_CH_STATE_RAM_DESC_BASE_BUFPTR		0x0c		/* buffer descrpitor current processing */
+#define ENET_DMA_CH_STATE_RAM_SIZE			0x10
+
+#define DMA_CTL_STATUS_APPEND_CRC			0x00000100
+#define DMA_CTL_STATUS_APPEND_BRCM_TAG			0x00000200
+#define DMA_CTL_STATUS_PRIO				0x00000C00  /* Prio for Tx */
+#define DMA_CTL_STATUS_WRAP				0x00001000  /* */
+#define DMA_CTL_STATUS_SOP				0x00002000  /* first buffer in packet */
+#define DMA_CTL_STATUS_EOP				0x00004000  /* last buffer in packet */
+#define DMA_CTL_STATUS_OWN				0x00008000  /* cleared by DMA, set by SW */
+#define DMA_CTL_LEN_DESC_BUFLENGTH			0x0fff0000
+#define DMA_CTL_LEN_DESC_BUFLENGTH_SHIFT		16
+#define DMA_CTL_LEN_DESC_MULTICAST			0x40000000
+#define DMA_CTL_LEN_DESC_USEFPM				0x80000000
+
+#endif
-- 
2.26.2


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

* Re: [PATCH net-next 2/2] net: broadcom: bcm4908enet: add BCM4908 controller driver
  2021-02-05 21:44 ` [PATCH net-next 2/2] net: broadcom: bcm4908enet: add BCM4908 controller driver Rafał Miłecki
@ 2021-02-05 23:47     ` kernel test robot
  0 siblings, 0 replies; 33+ messages in thread
From: kernel test robot @ 2021-02-05 23:47 UTC (permalink / raw)
  To: Rafał Miłecki, David S . Miller, Jakub Kicinski, Rob Herring
  Cc: kbuild-all, Florian Fainelli, Randy Dunlap, Masahiro Yamada,
	netdev, devicetree, bcm-kernel-feedback-list,
	Rafał Miłecki

[-- Attachment #1: Type: text/plain, Size: 4788 bytes --]

Hi "Rafał,

I love your patch! Perhaps something to improve:

[auto build test WARNING on net-next/master]

url:    https://github.com/0day-ci/linux/commits/Rafa-Mi-ecki/dt-bindings-net-document-BCM4908-Ethernet-controller/20210206-055343
base:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git 6626a0266566c5aea16178c5e6cd7fc4db3f2f56
config: i386-randconfig-s001-20210205 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-15) 9.3.0
reproduce:
        # apt-get install sparse
        # sparse version: v0.6.3-215-g0fb77bb6-dirty
        # https://github.com/0day-ci/linux/commit/53a9af8e34620fcfd9a75ccc9c89862b5c96598d
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Rafa-Mi-ecki/dt-bindings-net-document-BCM4908-Ethernet-controller/20210206-055343
        git checkout 53a9af8e34620fcfd9a75ccc9c89862b5c96598d
        # save the attached .config to linux build tree
        make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' ARCH=i386 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>


"sparse warnings: (new ones prefixed by >>)"
>> drivers/net/ethernet/broadcom/bcm4908enet.c:274:23: sparse: sparse: incorrect type in assignment (different base types) @@     expected restricted __le32 [usertype] ctl @@     got unsigned int [assigned] [usertype] tmp @@
   drivers/net/ethernet/broadcom/bcm4908enet.c:274:23: sparse:     expected restricted __le32 [usertype] ctl
   drivers/net/ethernet/broadcom/bcm4908enet.c:274:23: sparse:     got unsigned int [assigned] [usertype] tmp
>> drivers/net/ethernet/broadcom/bcm4908enet.c:275:24: sparse: sparse: incorrect type in assignment (different base types) @@     expected restricted __le32 [usertype] addr @@     got unsigned int [usertype] dma_addr @@
   drivers/net/ethernet/broadcom/bcm4908enet.c:275:24: sparse:     expected restricted __le32 [usertype] addr
   drivers/net/ethernet/broadcom/bcm4908enet.c:275:24: sparse:     got unsigned int [usertype] dma_addr
>> drivers/net/ethernet/broadcom/bcm4908enet.c:485:29: sparse: sparse: restricted __le32 degrades to integer
   drivers/net/ethernet/broadcom/bcm4908enet.c:505:13: sparse: sparse: restricted __le32 degrades to integer
>> drivers/net/ethernet/broadcom/bcm4908enet.c:525:24: sparse: sparse: incorrect type in assignment (different base types) @@     expected restricted __le32 [usertype] addr @@     got unsigned int [usertype] @@
   drivers/net/ethernet/broadcom/bcm4908enet.c:525:24: sparse:     expected restricted __le32 [usertype] addr
   drivers/net/ethernet/broadcom/bcm4908enet.c:525:24: sparse:     got unsigned int [usertype]
   drivers/net/ethernet/broadcom/bcm4908enet.c:526:23: sparse: sparse: incorrect type in assignment (different base types) @@     expected restricted __le32 [usertype] ctl @@     got unsigned int [assigned] [usertype] tmp @@
   drivers/net/ethernet/broadcom/bcm4908enet.c:526:23: sparse:     expected restricted __le32 [usertype] ctl
   drivers/net/ethernet/broadcom/bcm4908enet.c:526:23: sparse:     got unsigned int [assigned] [usertype] tmp
   drivers/net/ethernet/broadcom/bcm4908enet.c:551:29: sparse: sparse: restricted __le32 degrades to integer
   drivers/net/ethernet/broadcom/bcm4908enet.c:564:32: sparse: sparse: restricted __le32 degrades to integer
   drivers/net/ethernet/broadcom/bcm4908enet.c:567:30: sparse: sparse: restricted __le32 degrades to integer

vim +274 drivers/net/ethernet/broadcom/bcm4908enet.c

   246	
   247	static int bcm4908enet_dma_alloc_rx_buf(struct bcm4908enet *enet, unsigned int idx)
   248	{
   249		struct bcm4908enet_dma_ring_bd *buf_desc = &enet->rx_ring.buf_desc[idx];
   250		struct bcm4908enet_dma_ring_slot *slot = &enet->rx_ring.slots[idx];
   251		struct device *dev = enet->dev;
   252		u32 tmp;
   253		int err;
   254	
   255		slot->len = ENET_MTU_MAX + ENET_MTU_MAX_EXTRA_SIZE;
   256	
   257		slot->skb = netdev_alloc_skb(enet->netdev, slot->len);
   258		if (!slot->skb)
   259			return -ENOMEM;
   260	
   261		slot->dma_addr = dma_map_single(dev, slot->skb->data, slot->len, DMA_FROM_DEVICE);
   262		err = dma_mapping_error(dev, slot->dma_addr);
   263		if (err) {
   264			dev_err(dev, "Failed to map DMA buffer: %d\n", err);
   265			kfree_skb(slot->skb);
   266			slot->skb = NULL;
   267			return err;
   268		}
   269	
   270		tmp = slot->len << DMA_CTL_LEN_DESC_BUFLENGTH_SHIFT;
   271		tmp |= DMA_CTL_STATUS_OWN;
   272		if (idx == enet->rx_ring.length - 1)
   273			tmp |= DMA_CTL_STATUS_WRAP;
 > 274		buf_desc->ctl = tmp;
 > 275		buf_desc->addr = slot->dma_addr;
   276	
   277		return 0;
   278	}
   279	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 28596 bytes --]

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

* Re: [PATCH net-next 2/2] net: broadcom: bcm4908enet: add BCM4908 controller driver
@ 2021-02-05 23:47     ` kernel test robot
  0 siblings, 0 replies; 33+ messages in thread
From: kernel test robot @ 2021-02-05 23:47 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 4873 bytes --]

Hi "Rafał,

I love your patch! Perhaps something to improve:

[auto build test WARNING on net-next/master]

url:    https://github.com/0day-ci/linux/commits/Rafa-Mi-ecki/dt-bindings-net-document-BCM4908-Ethernet-controller/20210206-055343
base:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git 6626a0266566c5aea16178c5e6cd7fc4db3f2f56
config: i386-randconfig-s001-20210205 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-15) 9.3.0
reproduce:
        # apt-get install sparse
        # sparse version: v0.6.3-215-g0fb77bb6-dirty
        # https://github.com/0day-ci/linux/commit/53a9af8e34620fcfd9a75ccc9c89862b5c96598d
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Rafa-Mi-ecki/dt-bindings-net-document-BCM4908-Ethernet-controller/20210206-055343
        git checkout 53a9af8e34620fcfd9a75ccc9c89862b5c96598d
        # save the attached .config to linux build tree
        make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' ARCH=i386 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>


"sparse warnings: (new ones prefixed by >>)"
>> drivers/net/ethernet/broadcom/bcm4908enet.c:274:23: sparse: sparse: incorrect type in assignment (different base types) @@     expected restricted __le32 [usertype] ctl @@     got unsigned int [assigned] [usertype] tmp @@
   drivers/net/ethernet/broadcom/bcm4908enet.c:274:23: sparse:     expected restricted __le32 [usertype] ctl
   drivers/net/ethernet/broadcom/bcm4908enet.c:274:23: sparse:     got unsigned int [assigned] [usertype] tmp
>> drivers/net/ethernet/broadcom/bcm4908enet.c:275:24: sparse: sparse: incorrect type in assignment (different base types) @@     expected restricted __le32 [usertype] addr @@     got unsigned int [usertype] dma_addr @@
   drivers/net/ethernet/broadcom/bcm4908enet.c:275:24: sparse:     expected restricted __le32 [usertype] addr
   drivers/net/ethernet/broadcom/bcm4908enet.c:275:24: sparse:     got unsigned int [usertype] dma_addr
>> drivers/net/ethernet/broadcom/bcm4908enet.c:485:29: sparse: sparse: restricted __le32 degrades to integer
   drivers/net/ethernet/broadcom/bcm4908enet.c:505:13: sparse: sparse: restricted __le32 degrades to integer
>> drivers/net/ethernet/broadcom/bcm4908enet.c:525:24: sparse: sparse: incorrect type in assignment (different base types) @@     expected restricted __le32 [usertype] addr @@     got unsigned int [usertype] @@
   drivers/net/ethernet/broadcom/bcm4908enet.c:525:24: sparse:     expected restricted __le32 [usertype] addr
   drivers/net/ethernet/broadcom/bcm4908enet.c:525:24: sparse:     got unsigned int [usertype]
   drivers/net/ethernet/broadcom/bcm4908enet.c:526:23: sparse: sparse: incorrect type in assignment (different base types) @@     expected restricted __le32 [usertype] ctl @@     got unsigned int [assigned] [usertype] tmp @@
   drivers/net/ethernet/broadcom/bcm4908enet.c:526:23: sparse:     expected restricted __le32 [usertype] ctl
   drivers/net/ethernet/broadcom/bcm4908enet.c:526:23: sparse:     got unsigned int [assigned] [usertype] tmp
   drivers/net/ethernet/broadcom/bcm4908enet.c:551:29: sparse: sparse: restricted __le32 degrades to integer
   drivers/net/ethernet/broadcom/bcm4908enet.c:564:32: sparse: sparse: restricted __le32 degrades to integer
   drivers/net/ethernet/broadcom/bcm4908enet.c:567:30: sparse: sparse: restricted __le32 degrades to integer

vim +274 drivers/net/ethernet/broadcom/bcm4908enet.c

   246	
   247	static int bcm4908enet_dma_alloc_rx_buf(struct bcm4908enet *enet, unsigned int idx)
   248	{
   249		struct bcm4908enet_dma_ring_bd *buf_desc = &enet->rx_ring.buf_desc[idx];
   250		struct bcm4908enet_dma_ring_slot *slot = &enet->rx_ring.slots[idx];
   251		struct device *dev = enet->dev;
   252		u32 tmp;
   253		int err;
   254	
   255		slot->len = ENET_MTU_MAX + ENET_MTU_MAX_EXTRA_SIZE;
   256	
   257		slot->skb = netdev_alloc_skb(enet->netdev, slot->len);
   258		if (!slot->skb)
   259			return -ENOMEM;
   260	
   261		slot->dma_addr = dma_map_single(dev, slot->skb->data, slot->len, DMA_FROM_DEVICE);
   262		err = dma_mapping_error(dev, slot->dma_addr);
   263		if (err) {
   264			dev_err(dev, "Failed to map DMA buffer: %d\n", err);
   265			kfree_skb(slot->skb);
   266			slot->skb = NULL;
   267			return err;
   268		}
   269	
   270		tmp = slot->len << DMA_CTL_LEN_DESC_BUFLENGTH_SHIFT;
   271		tmp |= DMA_CTL_STATUS_OWN;
   272		if (idx == enet->rx_ring.length - 1)
   273			tmp |= DMA_CTL_STATUS_WRAP;
 > 274		buf_desc->ctl = tmp;
 > 275		buf_desc->addr = slot->dma_addr;
   276	
   277		return 0;
   278	}
   279	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 28596 bytes --]

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

* [PATCH V2 net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller
  2021-02-05 21:44 [PATCH net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller Rafał Miłecki
  2021-02-05 21:44 ` [PATCH net-next 2/2] net: broadcom: bcm4908enet: add BCM4908 controller driver Rafał Miłecki
@ 2021-02-07 22:26 ` Rafał Miłecki
  2021-02-07 22:26   ` [PATCH V2 net-next 2/2] net: broadcom: bcm4908enet: add BCM4908 controller driver Rafał Miłecki
  2021-02-09 21:43   ` [PATCH V2 net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller Rob Herring
  1 sibling, 2 replies; 33+ messages in thread
From: Rafał Miłecki @ 2021-02-07 22:26 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Florian Fainelli, Randy Dunlap, Masahiro Yamada, netdev,
	devicetree, bcm-kernel-feedback-list, Rafał Miłecki

From: Rafał Miłecki <rafal@milecki.pl>

BCM4908 is a family of SoCs with integrated Ethernet controller.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
 .../bindings/net/brcm,bcm4908enet.yaml        | 45 +++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/brcm,bcm4908enet.yaml

diff --git a/Documentation/devicetree/bindings/net/brcm,bcm4908enet.yaml b/Documentation/devicetree/bindings/net/brcm,bcm4908enet.yaml
new file mode 100644
index 000000000000..5f12f51c5b19
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/brcm,bcm4908enet.yaml
@@ -0,0 +1,45 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/brcm,bcm4908enet.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Broadcom BCM4908 Ethernet controller
+
+description: Broadcom's Ethernet controller integrated into BCM4908 family SoCs
+
+maintainers:
+  - Rafał Miłecki <rafal@milecki.pl>
+
+properties:
+  compatible:
+    const: brcm,bcm4908enet
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    description: RX interrupt
+
+  interrupt-names:
+    const: rx
+
+required:
+  - reg
+  - interrupts
+  - interrupt-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    ethernet@80002000 {
+        compatible = "brcm,bcm4908enet";
+        reg = <0x80002000 0x1000>;
+
+        interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+        interrupt-names = "rx";
+    };
-- 
2.26.2


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

* [PATCH V2 net-next 2/2] net: broadcom: bcm4908enet: add BCM4908 controller driver
  2021-02-07 22:26 ` [PATCH V2 net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller Rafał Miłecki
@ 2021-02-07 22:26   ` Rafał Miłecki
  2021-02-09 23:01     ` [PATCH V3 net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller Rafał Miłecki
  2021-02-09 21:43   ` [PATCH V2 net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller Rob Herring
  1 sibling, 1 reply; 33+ messages in thread
From: Rafał Miłecki @ 2021-02-07 22:26 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Florian Fainelli, Randy Dunlap, Masahiro Yamada, netdev,
	devicetree, bcm-kernel-feedback-list, Rafał Miłecki

From: Rafał Miłecki <rafal@milecki.pl>

BCM4908 SoCs family uses Ethernel controller that includes UniMAC but
uses different DMA engine (than other controllers) and requires
different programming.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
V2: Use cpu_to_le32()
    Reported-by: kernel test robot <lkp@intel.com>
    Add "depends" to the Kconfig
---
 MAINTAINERS                                 |   9 +
 drivers/net/ethernet/broadcom/Kconfig       |   8 +
 drivers/net/ethernet/broadcom/Makefile      |   1 +
 drivers/net/ethernet/broadcom/bcm4908enet.c | 676 ++++++++++++++++++++
 drivers/net/ethernet/broadcom/bcm4908enet.h |  96 +++
 5 files changed, 790 insertions(+)
 create mode 100644 drivers/net/ethernet/broadcom/bcm4908enet.c
 create mode 100644 drivers/net/ethernet/broadcom/bcm4908enet.h

diff --git a/MAINTAINERS b/MAINTAINERS
index d1b0057a9797..cbf4b94f89d4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3445,6 +3445,15 @@ F:	Documentation/devicetree/bindings/mips/brcm/
 F:	arch/mips/bcm47xx/*
 F:	arch/mips/include/asm/mach-bcm47xx/*
 
+BROADCOM BCM4908 ETHERNET DRIVER
+M:	Rafał Miłecki <rafal@milecki.pl>
+M:	bcm-kernel-feedback-list@broadcom.com
+L:	netdev@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/net/brcm,bcm4908enet.yaml
+F:	drivers/net/ethernet/broadcom/bcm4908enet.*
+F:	drivers/net/ethernet/broadcom/unimac.h
+
 BROADCOM BCM5301X ARM ARCHITECTURE
 M:	Hauke Mehrtens <hauke@hauke-m.de>
 M:	Rafał Miłecki <zajec5@gmail.com>
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index 4bdf8fbe75a6..bcf9e0a410fd 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -51,6 +51,14 @@ config B44_PCI
 	depends on B44_PCI_AUTOSELECT && B44_PCICORE_AUTOSELECT
 	default y
 
+config BCM4908ENET
+	tristate "Broadcom BCM4908 internal mac support"
+	depends on ARCH_BCM4908 || COMPILE_TEST
+	default y
+	help
+	  This driver supports Ethernet controller integrated into Broadcom
+	  BCM4908 family SoCs.
+
 config BCM63XX_ENET
 	tristate "Broadcom 63xx internal mac support"
 	depends on BCM63XX
diff --git a/drivers/net/ethernet/broadcom/Makefile b/drivers/net/ethernet/broadcom/Makefile
index 7046ad6d3d0e..379012de3569 100644
--- a/drivers/net/ethernet/broadcom/Makefile
+++ b/drivers/net/ethernet/broadcom/Makefile
@@ -4,6 +4,7 @@
 #
 
 obj-$(CONFIG_B44) += b44.o
+obj-$(CONFIG_BCM4908ENET) += bcm4908enet.o
 obj-$(CONFIG_BCM63XX_ENET) += bcm63xx_enet.o
 obj-$(CONFIG_BCMGENET) += genet/
 obj-$(CONFIG_BNX2) += bnx2.o
diff --git a/drivers/net/ethernet/broadcom/bcm4908enet.c b/drivers/net/ethernet/broadcom/bcm4908enet.c
new file mode 100644
index 000000000000..d68b328e7596
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/bcm4908enet.c
@@ -0,0 +1,676 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl>
+ */
+
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include "bcm4908enet.h"
+#include "unimac.h"
+
+#define ENET_DMA_CH_RX_CFG			ENET_DMA_CH0_CFG
+#define ENET_DMA_CH_TX_CFG			ENET_DMA_CH1_CFG
+#define ENET_DMA_CH_RX_STATE_RAM		ENET_DMA_CH0_STATE_RAM
+#define ENET_DMA_CH_TX_STATE_RAM		ENET_DMA_CH1_STATE_RAM
+
+#define ENET_TX_BDS_NUM				200
+#define ENET_RX_BDS_NUM				200
+#define ENET_RX_BDS_NUM_MAX			8192
+
+#define ENET_DMA_INT_DEFAULTS			(ENET_DMA_CH_CFG_INT_DONE | \
+						 ENET_DMA_CH_CFG_INT_NO_DESC | \
+						 ENET_DMA_CH_CFG_INT_BUFF_DONE)
+#define ENET_DMA_MAX_BURST_LEN			8 /* in 64 bit words */
+
+#define ENET_MTU_MIN				60
+#define ENET_MTU_MAX				1500 /* Is it possible to support 2044? */
+#define ENET_MTU_MAX_EXTRA_SIZE			32 /* L2 */
+
+struct bcm4908enet_dma_ring_bd {
+	__le32 ctl;
+	__le32 addr;
+} __packed;
+
+struct bcm4908enet_dma_ring_slot {
+	struct sk_buff *skb;
+	unsigned int len;
+	dma_addr_t dma_addr;
+};
+
+struct bcm4908enet_dma_ring {
+	int is_tx;
+	int read_idx;
+	int write_idx;
+	int length;
+	u16 cfg_block;
+	u16 st_ram_block;
+
+	union {
+		void *cpu_addr;
+		struct bcm4908enet_dma_ring_bd *buf_desc;
+	};
+	dma_addr_t dma_addr;
+
+	struct bcm4908enet_dma_ring_slot *slots;
+};
+
+struct bcm4908enet {
+	struct device *dev;
+	struct net_device *netdev;
+	struct napi_struct napi;
+	void __iomem *base;
+
+	struct bcm4908enet_dma_ring tx_ring;
+	struct bcm4908enet_dma_ring rx_ring;
+};
+
+/***
+ * R/W ops
+ */
+
+static inline u32 enet_read(struct bcm4908enet *enet, u16 offset)
+{
+	return readl(enet->base + offset);
+}
+
+static inline void enet_write(struct bcm4908enet *enet, u16 offset, u32 value)
+{
+	writel(value, enet->base + offset);
+}
+
+static inline void enet_maskset(struct bcm4908enet *enet, u16 offset, u32 mask, u32 set)
+{
+	u32 val;
+
+	WARN_ON(set & ~mask);
+
+	val = enet_read(enet, offset);
+	val = (val & ~mask) | (set & mask);
+	enet_write(enet, offset, val);
+}
+
+static inline void enet_set(struct bcm4908enet *enet, u16 offset, u32 set)
+{
+	enet_maskset(enet, offset, set, set);
+}
+
+static inline u32 enet_umac_read(struct bcm4908enet *enet, u16 offset)
+{
+	return enet_read(enet, ENET_UNIMAC + offset);
+}
+
+static inline void enet_umac_write(struct bcm4908enet *enet, u16 offset, u32 value)
+{
+	enet_write(enet, ENET_UNIMAC + offset, value);
+}
+
+static inline void enet_umac_maskset(struct bcm4908enet *enet, u16 offset, u32 mask, u32 set)
+{
+	enet_maskset(enet, ENET_UNIMAC + offset, mask, set);
+}
+
+static inline void enet_umac_set(struct bcm4908enet *enet, u16 offset, u32 set)
+{
+	enet_set(enet, ENET_UNIMAC + offset, set);
+}
+
+/***
+ * Helpers
+ */
+
+static void bcm4908enet_intrs_on(struct bcm4908enet *enet)
+{
+	enet_write(enet, ENET_DMA_CH_RX_CFG + ENET_DMA_CH_CFG_INT_MASK, ENET_DMA_INT_DEFAULTS);
+}
+
+static void bcm4908enet_intrs_off(struct bcm4908enet *enet)
+{
+	enet_write(enet, ENET_DMA_CH_RX_CFG + ENET_DMA_CH_CFG_INT_MASK, 0);
+}
+
+static void bcm4908enet_intrs_ack(struct bcm4908enet *enet)
+{
+	enet_write(enet, ENET_DMA_CH_RX_CFG + ENET_DMA_CH_CFG_INT_STAT, ENET_DMA_INT_DEFAULTS);
+}
+
+/***
+ * DMA
+ */
+
+static int bcm4908_dma_alloc_buf_descs(struct bcm4908enet *enet, struct bcm4908enet_dma_ring *ring)
+{
+	int size = ring->length * sizeof(struct bcm4908enet_dma_ring_bd);
+	struct device *dev = enet->dev;
+
+	ring->cpu_addr = dma_alloc_coherent(dev, size, &ring->dma_addr, GFP_KERNEL);
+	if (!ring->cpu_addr)
+		return -ENOMEM;
+
+	if (((uintptr_t)ring->cpu_addr) & (0x40 - 1)) {
+		dev_err(dev, "Invalid DMA ring alignment\n");
+		goto err_free_buf_descs;
+	}
+
+	ring->slots = kzalloc(ring->length * sizeof(*ring->slots), GFP_KERNEL);
+	if (!ring->slots)
+		goto err_free_buf_descs;
+
+	memset(ring->cpu_addr, 0, size);
+
+	ring->read_idx = 0;
+	ring->write_idx = 0;
+
+	return 0;
+
+err_free_buf_descs:
+	dma_free_coherent(dev, size, ring->cpu_addr, ring->dma_addr);
+	return -ENOMEM;
+}
+
+static void bcm4908enet_dma_free(struct bcm4908enet *enet)
+{
+	struct bcm4908enet_dma_ring *tx_ring = &enet->tx_ring;
+	struct bcm4908enet_dma_ring *rx_ring = &enet->rx_ring;
+	struct device *dev = enet->dev;
+	int size;
+
+	size = rx_ring->length * sizeof(struct bcm4908enet_dma_ring_bd);
+	if (rx_ring->cpu_addr)
+		dma_free_coherent(dev, size, rx_ring->cpu_addr, rx_ring->dma_addr);
+	kfree(rx_ring->slots);
+
+	size = tx_ring->length * sizeof(struct bcm4908enet_dma_ring_bd);
+	if (tx_ring->cpu_addr)
+		dma_free_coherent(dev, size, tx_ring->cpu_addr, tx_ring->dma_addr);
+	kfree(tx_ring->slots);
+}
+
+static int bcm4908enet_dma_alloc(struct bcm4908enet *enet)
+{
+	struct bcm4908enet_dma_ring *tx_ring = &enet->tx_ring;
+	struct bcm4908enet_dma_ring *rx_ring = &enet->rx_ring;
+	struct device *dev = enet->dev;
+	int err;
+
+	tx_ring->length = ENET_TX_BDS_NUM;
+	tx_ring->is_tx = 1;
+	tx_ring->cfg_block = ENET_DMA_CH_TX_CFG;
+	tx_ring->st_ram_block = ENET_DMA_CH_TX_STATE_RAM;
+	err = bcm4908_dma_alloc_buf_descs(enet, tx_ring);
+	if (err) {
+		dev_err(dev, "Failed to alloc TX buf descriptors: %d\n", err);
+		return err;
+	}
+
+	rx_ring->length = ENET_RX_BDS_NUM;
+	rx_ring->is_tx = 0;
+	rx_ring->cfg_block = ENET_DMA_CH_RX_CFG;
+	rx_ring->st_ram_block = ENET_DMA_CH_RX_STATE_RAM;
+	err = bcm4908_dma_alloc_buf_descs(enet, rx_ring);
+	if (err) {
+		dev_err(dev, "Failed to alloc RX buf descriptors: %d\n", err);
+		bcm4908enet_dma_free(enet);
+		return err;
+	}
+
+	return 0;
+}
+
+static void bcm4908enet_dma_reset(struct bcm4908enet *enet)
+{
+	struct bcm4908enet_dma_ring *rings[] = { &enet->rx_ring, &enet->tx_ring };
+	int i;
+
+	/* Disable the DMA controller and channel */
+	for (i = 0; i < ARRAY_SIZE(rings); i++)
+		enet_write(enet, rings[i]->cfg_block + ENET_DMA_CH_CFG, 0);
+	enet_maskset(enet, ENET_DMA_CONTROLLER_CFG, ENET_DMA_CTRL_CFG_MASTER_EN, 0);
+
+	/* Reset channels state */
+	for (i = 0; i < ARRAY_SIZE(rings); i++) {
+		struct bcm4908enet_dma_ring *ring = rings[i];
+
+		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_BASE_DESC_PTR, 0);
+		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_STATE_DATA, 0);
+		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_DESC_LEN_STATUS, 0);
+		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_DESC_BASE_BUFPTR, 0);
+	}
+}
+
+static int bcm4908enet_dma_alloc_rx_buf(struct bcm4908enet *enet, unsigned int idx)
+{
+	struct bcm4908enet_dma_ring_bd *buf_desc = &enet->rx_ring.buf_desc[idx];
+	struct bcm4908enet_dma_ring_slot *slot = &enet->rx_ring.slots[idx];
+	struct device *dev = enet->dev;
+	u32 tmp;
+	int err;
+
+	slot->len = ENET_MTU_MAX + ENET_MTU_MAX_EXTRA_SIZE;
+
+	slot->skb = netdev_alloc_skb(enet->netdev, slot->len);
+	if (!slot->skb)
+		return -ENOMEM;
+
+	slot->dma_addr = dma_map_single(dev, slot->skb->data, slot->len, DMA_FROM_DEVICE);
+	err = dma_mapping_error(dev, slot->dma_addr);
+	if (err) {
+		dev_err(dev, "Failed to map DMA buffer: %d\n", err);
+		kfree_skb(slot->skb);
+		slot->skb = NULL;
+		return err;
+	}
+
+	tmp = slot->len << DMA_CTL_LEN_DESC_BUFLENGTH_SHIFT;
+	tmp |= DMA_CTL_STATUS_OWN;
+	if (idx == enet->rx_ring.length - 1)
+		tmp |= DMA_CTL_STATUS_WRAP;
+	buf_desc->ctl = cpu_to_le32(tmp);
+	buf_desc->addr = cpu_to_le32(slot->dma_addr);
+
+	return 0;
+}
+
+static void bcm4908enet_dma_ring_init(struct bcm4908enet *enet,
+				      struct bcm4908enet_dma_ring *ring)
+{
+	int reset_channel = 0; /* We support only 1 main channel (with TX and RX) */
+	int reset_subch = ring->is_tx ? 1 : 0;
+
+	/* Reset the DMA channel */
+	enet_write(enet, ENET_DMA_CTRL_CHANNEL_RESET, BIT(reset_channel * 2 + reset_subch));
+	enet_write(enet, ENET_DMA_CTRL_CHANNEL_RESET, 0);
+
+	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG, 0);
+	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG_MAX_BURST, ENET_DMA_MAX_BURST_LEN);
+	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG_INT_MASK, 0);
+
+	enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_BASE_DESC_PTR,
+		   (uint32_t)ring->dma_addr);
+}
+
+static void bcm4908enet_dma_uninit(struct bcm4908enet *enet)
+{
+	struct bcm4908enet_dma_ring *rx_ring = &enet->rx_ring;
+	struct bcm4908enet_dma_ring_slot *slot;
+	struct device *dev = enet->dev;
+	int i;
+
+	for (i = rx_ring->length - 1; i >= 0; i--) {
+		slot = &rx_ring->slots[i];
+		if (!slot->skb)
+			continue;
+		dma_unmap_single(dev, slot->dma_addr, slot->len, DMA_FROM_DEVICE);
+		kfree_skb(slot->skb);
+		slot->skb = NULL;
+	}
+}
+
+static int bcm4908enet_dma_init(struct bcm4908enet *enet)
+{
+	struct bcm4908enet_dma_ring *rx_ring = &enet->rx_ring;
+	struct device *dev = enet->dev;
+	int err;
+	int i;
+
+	for (i = 0; i < rx_ring->length; i++) {
+		err = bcm4908enet_dma_alloc_rx_buf(enet, i);
+		if (err) {
+			dev_err(dev, "Failed to alloc RX buffer: %d\n", err);
+			bcm4908enet_dma_uninit(enet);
+			return err;
+		}
+	}
+
+	bcm4908enet_dma_ring_init(enet, &enet->tx_ring);
+	bcm4908enet_dma_ring_init(enet, &enet->rx_ring);
+
+	return 0;
+}
+
+static void bcm4908enet_dma_tx_ring_ensable(struct bcm4908enet *enet,
+					    struct bcm4908enet_dma_ring *ring)
+{
+	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG, ENET_DMA_CH_CFG_ENABLE);
+}
+
+static void bcm4908enet_dma_tx_ring_disable(struct bcm4908enet *enet,
+					    struct bcm4908enet_dma_ring *ring)
+{
+	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG, 0);
+}
+
+static void bcm4908enet_dma_rx_ring_enable(struct bcm4908enet *enet,
+					   struct bcm4908enet_dma_ring *ring)
+{
+	enet_set(enet, ring->cfg_block + ENET_DMA_CH_CFG, ENET_DMA_CH_CFG_ENABLE);
+}
+
+static void bcm4908enet_dma_rx_ring_disable(struct bcm4908enet *enet,
+					    struct bcm4908enet_dma_ring *ring)
+{
+	unsigned long deadline;
+	u32 tmp;
+
+	enet_maskset(enet, ring->cfg_block + ENET_DMA_CH_CFG, ENET_DMA_CH_CFG_ENABLE, 0);
+
+	deadline = jiffies + usecs_to_jiffies(2000);
+	do {
+		tmp = enet_read(enet, ring->cfg_block + ENET_DMA_CH_CFG);
+		if (!(tmp & ENET_DMA_CH_CFG_ENABLE))
+			return;
+		enet_maskset(enet, ring->cfg_block + ENET_DMA_CH_CFG, ENET_DMA_CH_CFG_ENABLE, 0);
+		usleep_range(10, 30);
+	} while (!time_after_eq(jiffies, deadline));
+
+	dev_warn(enet->dev, "Timeout waiting for DMA TX stop\n");
+}
+
+/***
+ * Ethernet driver
+ */
+
+static void bcm4908enet_gmac_init(struct bcm4908enet *enet)
+{
+	u32 cmd;
+
+	cmd = enet_umac_read(enet, UMAC_CMD);
+	enet_umac_write(enet, UMAC_CMD, cmd | CMD_SW_RESET);
+	enet_umac_write(enet, UMAC_CMD, cmd & ~CMD_SW_RESET);
+
+	enet_set(enet, ENET_FLUSH, ENET_FLUSH_RXFIFO_FLUSH | ENET_FLUSH_TXFIFO_FLUSH);
+	enet_maskset(enet, ENET_FLUSH, ENET_FLUSH_RXFIFO_FLUSH | ENET_FLUSH_TXFIFO_FLUSH, 0);
+
+	enet_set(enet, ENET_MIB_CTRL, ENET_MIB_CTRL_CLR_MIB);
+	enet_maskset(enet, ENET_MIB_CTRL, ENET_MIB_CTRL_CLR_MIB, 0);
+
+	cmd = enet_umac_read(enet, UMAC_CMD);
+	cmd &= ~(CMD_SPEED_MASK << CMD_SPEED_SHIFT);
+	cmd &= ~CMD_TX_EN;
+	cmd &= ~CMD_RX_EN;
+	cmd |= CMD_SPEED_1000 << CMD_SPEED_SHIFT;
+	enet_umac_write(enet, UMAC_CMD, cmd);
+
+	enet_maskset(enet, ENET_GMAC_STATUS,
+		     ENET_GMAC_STATUS_ETH_SPEED_MASK |
+		     ENET_GMAC_STATUS_HD |
+		     ENET_GMAC_STATUS_AUTO_CFG_EN |
+		     ENET_GMAC_STATUS_LINK_UP,
+		     ENET_GMAC_STATUS_ETH_SPEED_1000 |
+		     ENET_GMAC_STATUS_AUTO_CFG_EN |
+		     ENET_GMAC_STATUS_LINK_UP);
+}
+
+static irqreturn_t bcm4908enet_irq_handler(int irq, void *dev_id)
+{
+	struct bcm4908enet *enet = dev_id;
+
+	bcm4908enet_intrs_off(enet);
+	bcm4908enet_intrs_ack(enet);
+
+	napi_schedule(&enet->napi);
+
+	return IRQ_HANDLED;
+}
+
+static int bcm4908enet_open(struct net_device *netdev)
+{
+	struct bcm4908enet *enet = netdev_priv(netdev);
+	struct device *dev = enet->dev;
+	int err;
+
+	err = request_irq(netdev->irq, bcm4908enet_irq_handler, 0, "enet", enet);
+	if (err) {
+		dev_err(dev, "Failed to request IRQ %d: %d\n", netdev->irq, err);
+		return err;
+	}
+
+	bcm4908enet_gmac_init(enet);
+	bcm4908enet_dma_reset(enet);
+	bcm4908enet_dma_init(enet);
+
+	enet_umac_set(enet, UMAC_CMD, CMD_TX_EN | CMD_RX_EN);
+
+	enet_set(enet, ENET_DMA_CONTROLLER_CFG, ENET_DMA_CTRL_CFG_MASTER_EN);
+	enet_maskset(enet, ENET_DMA_CONTROLLER_CFG, ENET_DMA_CTRL_CFG_FLOWC_CH1_EN, 0);
+	bcm4908enet_dma_rx_ring_enable(enet, &enet->rx_ring);
+
+	napi_enable(&enet->napi);
+	netif_carrier_on(netdev);
+	netif_start_queue(netdev);
+
+	bcm4908enet_intrs_ack(enet);
+	bcm4908enet_intrs_on(enet);
+
+	return 0;
+}
+
+static int bcm4908enet_stop(struct net_device *netdev)
+{
+	struct bcm4908enet *enet = netdev_priv(netdev);
+
+	netif_stop_queue(netdev);
+	netif_carrier_off(netdev);
+	napi_disable(&enet->napi);
+
+	bcm4908enet_dma_rx_ring_disable(enet, &enet->rx_ring);
+	bcm4908enet_dma_tx_ring_disable(enet, &enet->tx_ring);
+
+	bcm4908enet_dma_uninit(enet);
+
+	free_irq(enet->netdev->irq, enet);
+
+	return 0;
+}
+
+static int bcm4908enet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct bcm4908enet *enet = netdev_priv(netdev);
+	struct bcm4908enet_dma_ring *ring = &enet->tx_ring;
+	struct bcm4908enet_dma_ring_slot *slot;
+	struct device *dev = enet->dev;
+	struct bcm4908enet_dma_ring_bd *buf_desc;
+	int free_buf_descs;
+	u32 tmp;
+
+	/* Free transmitted skbs */
+	while (ring->read_idx != ring->write_idx) {
+		buf_desc = &ring->buf_desc[ring->read_idx];
+		if (buf_desc->ctl & DMA_CTL_STATUS_OWN)
+			break;
+		slot = &ring->slots[ring->read_idx];
+
+		dma_unmap_single(dev, slot->dma_addr, slot->len, DMA_TO_DEVICE);
+		dev_kfree_skb(slot->skb);
+		if (++ring->read_idx == ring->length)
+			ring->read_idx = 0;
+	}
+
+	/* Don't use the last empty buf descriptor */
+	if (ring->read_idx <= ring->write_idx)
+		free_buf_descs = ring->read_idx - ring->write_idx + ring->length;
+	else
+		free_buf_descs = ring->read_idx - ring->write_idx;
+	if (free_buf_descs < 2)
+		return NETDEV_TX_BUSY;
+
+	/* Hardware removes OWN bit after sending data */
+	buf_desc = &ring->buf_desc[ring->write_idx];
+	if (unlikely(le32_to_cpu(buf_desc->ctl) & DMA_CTL_STATUS_OWN)) {
+		netif_stop_queue(netdev);
+		return NETDEV_TX_BUSY;
+	}
+
+	slot = &ring->slots[ring->write_idx];
+	slot->skb = skb;
+	slot->len = skb->len;
+	slot->dma_addr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE);
+	if (unlikely(dma_mapping_error(dev, slot->dma_addr)))
+		return NETDEV_TX_BUSY;
+
+	tmp = skb->len << DMA_CTL_LEN_DESC_BUFLENGTH_SHIFT;
+	tmp |= DMA_CTL_STATUS_OWN;
+	tmp |= DMA_CTL_STATUS_SOP;
+	tmp |= DMA_CTL_STATUS_EOP;
+	tmp |= DMA_CTL_STATUS_APPEND_CRC;
+	if (ring->write_idx + 1 == ring->length - 1)
+		tmp |= DMA_CTL_STATUS_WRAP;
+
+	buf_desc->addr = cpu_to_le32((uint32_t)slot->dma_addr);
+	buf_desc->ctl = cpu_to_le32(tmp);
+
+	bcm4908enet_dma_tx_ring_ensable(enet, &enet->tx_ring);
+
+	if (++ring->write_idx == ring->length - 1)
+		ring->write_idx = 0;
+	enet->netdev->stats.tx_bytes += skb->len;
+	enet->netdev->stats.tx_packets++;
+
+	return NETDEV_TX_OK;
+}
+
+static int bcm4908enet_poll(struct napi_struct *napi, int weight)
+{
+	struct bcm4908enet *enet = container_of(napi, struct bcm4908enet, napi);
+	struct device *dev = enet->dev;
+	int handled = 0;
+
+	while (handled < weight) {
+		struct bcm4908enet_dma_ring_bd *buf_desc;
+		struct bcm4908enet_dma_ring_slot slot;
+		u32 ctl;
+		int len;
+		int err;
+
+		buf_desc = &enet->rx_ring.buf_desc[enet->rx_ring.read_idx];
+		ctl = le32_to_cpu(buf_desc->ctl);
+		if (ctl & DMA_CTL_STATUS_OWN)
+			break;
+
+		slot = enet->rx_ring.slots[enet->rx_ring.read_idx];
+
+		/* Provide new buffer before unpinning the old one */
+		err = bcm4908enet_dma_alloc_rx_buf(enet, enet->rx_ring.read_idx);
+		if (err)
+			break;
+
+		if (++enet->rx_ring.read_idx == enet->rx_ring.length)
+			enet->rx_ring.read_idx = 0;
+
+		len = (ctl & DMA_CTL_LEN_DESC_BUFLENGTH) >> DMA_CTL_LEN_DESC_BUFLENGTH_SHIFT;
+
+		if (len < ENET_MTU_MIN ||
+		    (ctl & (DMA_CTL_STATUS_SOP | DMA_CTL_STATUS_EOP)) != (DMA_CTL_STATUS_SOP | DMA_CTL_STATUS_EOP)) {
+			enet->netdev->stats.rx_dropped++;
+			break;
+		}
+
+		dma_unmap_single(dev, slot.dma_addr, slot.len, DMA_FROM_DEVICE);
+
+		skb_put(slot.skb, len - 4 + 2);
+		slot.skb->protocol = eth_type_trans(slot.skb, enet->netdev);
+		netif_receive_skb(slot.skb);
+
+		enet->netdev->stats.rx_packets++;
+		enet->netdev->stats.rx_bytes += len;
+	}
+
+	if (handled < weight) {
+		napi_complete_done(napi, handled);
+		bcm4908enet_intrs_on(enet);
+	}
+
+	return handled;
+}
+
+static const struct net_device_ops bcm96xx_netdev_ops = {
+	.ndo_open = bcm4908enet_open,
+	.ndo_stop = bcm4908enet_stop,
+	.ndo_start_xmit = bcm4908enet_start_xmit,
+	.ndo_set_mac_address = eth_mac_addr,
+};
+
+static int bcm4908enet_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct net_device *netdev;
+	struct bcm4908enet *enet;
+	int err;
+
+	netdev = devm_alloc_etherdev(dev, sizeof(*enet));
+	if (!netdev)
+		return -ENOMEM;
+
+	enet = netdev_priv(netdev);
+	enet->dev = dev;
+	enet->netdev = netdev;
+
+	enet->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(enet->base)) {
+		dev_err(dev, "Failed to map registers: %ld\n", PTR_ERR(enet->base));
+		return PTR_ERR(enet->base);
+	}
+
+	netdev->irq = platform_get_irq_byname(pdev, "rx");
+	if (netdev->irq < 0)
+		return netdev->irq;
+
+	dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+
+	err = bcm4908enet_dma_alloc(enet);
+	if (err)
+		return err;
+
+	SET_NETDEV_DEV(netdev, &pdev->dev);
+	eth_hw_addr_random(netdev);
+	netdev->netdev_ops = &bcm96xx_netdev_ops;
+	netdev->min_mtu = ETH_ZLEN;
+	netdev->mtu = ENET_MTU_MAX;
+	netdev->max_mtu = ENET_MTU_MAX;
+	netif_napi_add(netdev, &enet->napi, bcm4908enet_poll, 64);
+
+	err = register_netdev(netdev);
+	if (err) {
+		bcm4908enet_dma_free(enet);
+		return err;
+	}
+
+	platform_set_drvdata(pdev, enet);
+
+	return 0;
+}
+
+static int bcm4908enet_remove(struct platform_device *pdev)
+{
+	struct bcm4908enet *enet = platform_get_drvdata(pdev);
+
+	unregister_netdev(enet->netdev);
+	netif_napi_del(&enet->napi);
+	bcm4908enet_dma_free(enet);
+
+	return 0;
+}
+
+static const struct of_device_id bcm4908enet_of_match[] = {
+	{ .compatible = "brcm,bcm4908enet"},
+	{},
+};
+
+static struct platform_driver bcm4908enet_driver = {
+	.driver = {
+		.name = "bcm4908enet",
+		.of_match_table = bcm4908enet_of_match,
+	},
+	.probe	= bcm4908enet_probe,
+	.remove = bcm4908enet_remove,
+};
+module_platform_driver(bcm4908enet_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, bcm4908enet_of_match);
diff --git a/drivers/net/ethernet/broadcom/bcm4908enet.h b/drivers/net/ethernet/broadcom/bcm4908enet.h
new file mode 100644
index 000000000000..11aadf0715d3
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/bcm4908enet.h
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __BCM4908ENET_H
+#define __BCM4908ENET_H
+
+#define ENET_CONTROL					0x000
+#define ENET_MIB_CTRL					0x004
+#define  ENET_MIB_CTRL_CLR_MIB				0x00000001
+#define ENET_RX_ERR_MASK				0x008
+#define ENET_MIB_MAX_PKT_SIZE				0x00C
+#define  ENET_MIB_MAX_PKT_SIZE_VAL			0x00003fff
+#define ENET_DIAG_OUT					0x01c
+#define ENET_ENABLE_DROP_PKT				0x020
+#define ENET_IRQ_ENABLE					0x024
+#define  ENET_IRQ_ENABLE_OVFL				0x00000001
+#define ENET_GMAC_STATUS				0x028
+#define  ENET_GMAC_STATUS_ETH_SPEED_MASK		0x00000003
+#define  ENET_GMAC_STATUS_ETH_SPEED_10			0x00000000
+#define  ENET_GMAC_STATUS_ETH_SPEED_100			0x00000001
+#define  ENET_GMAC_STATUS_ETH_SPEED_1000		0x00000002
+#define  ENET_GMAC_STATUS_HD				0x00000004
+#define  ENET_GMAC_STATUS_AUTO_CFG_EN			0x00000008
+#define  ENET_GMAC_STATUS_LINK_UP			0x00000010
+#define ENET_IRQ_STATUS					0x02c
+#define  ENET_IRQ_STATUS_OVFL				0x00000001
+#define ENET_OVERFLOW_COUNTER				0x030
+#define ENET_FLUSH					0x034
+#define  ENET_FLUSH_RXFIFO_FLUSH			0x00000001
+#define  ENET_FLUSH_TXFIFO_FLUSH			0x00000002
+#define ENET_RSV_SELECT					0x038
+#define ENET_BP_FORCE					0x03c
+#define  ENET_BP_FORCE_FORCE				0x00000001
+#define ENET_DMA_RX_OK_TO_SEND_COUNT			0x040
+#define  ENET_DMA_RX_OK_TO_SEND_COUNT_VAL		0x0000000f
+#define ENET_TX_CRC_CTRL				0x044
+#define ENET_MIB					0x200
+#define ENET_UNIMAC					0x400
+#define ENET_DMA					0x800
+#define ENET_DMA_CONTROLLER_CFG				0x800
+#define  ENET_DMA_CTRL_CFG_MASTER_EN			0x00000001
+#define  ENET_DMA_CTRL_CFG_FLOWC_CH1_EN			0x00000002
+#define  ENET_DMA_CTRL_CFG_FLOWC_CH3_EN			0x00000004
+#define ENET_DMA_FLOWCTL_CH1_THRESH_LO			0x804
+#define ENET_DMA_FLOWCTL_CH1_THRESH_HI			0x808
+#define ENET_DMA_FLOWCTL_CH1_ALLOC			0x80c
+#define  ENET_DMA_FLOWCTL_CH1_ALLOC_FORCE		0x80000000
+#define ENET_DMA_FLOWCTL_CH3_THRESH_LO			0x810
+#define ENET_DMA_FLOWCTL_CH3_THRESH_HI			0x814
+#define ENET_DMA_FLOWCTL_CH3_ALLOC			0x818
+#define ENET_DMA_FLOWCTL_CH5_THRESH_LO			0x81C
+#define ENET_DMA_FLOWCTL_CH5_THRESH_HI			0x820
+#define ENET_DMA_FLOWCTL_CH5_ALLOC			0x824
+#define ENET_DMA_FLOWCTL_CH7_THRESH_LO			0x828
+#define ENET_DMA_FLOWCTL_CH7_THRESH_HI			0x82C
+#define ENET_DMA_FLOWCTL_CH7_ALLOC			0x830
+#define ENET_DMA_CTRL_CHANNEL_RESET			0x834
+#define ENET_DMA_CTRL_CHANNEL_DEBUG			0x838
+#define ENET_DMA_CTRL_GLOBAL_INTERRUPT_STATUS		0x840
+#define ENET_DMA_CTRL_GLOBAL_INTERRUPT_MASK		0x844
+#define ENET_DMA_CH0_CFG				0xa00		/* RX */
+#define ENET_DMA_CH1_CFG				0xa10		/* TX */
+#define ENET_DMA_CH0_STATE_RAM				0xc00		/* RX */
+#define ENET_DMA_CH1_STATE_RAM				0xc10		/* TX */
+
+#define ENET_DMA_CH_CFG					0x00		/* assorted configuration */
+#define  ENET_DMA_CH_CFG_ENABLE				0x00000001	/* set to enable channel */
+#define  ENET_DMA_CH_CFG_PKT_HALT			0x00000002	/* idle after an EOP flag is detected */
+#define  ENET_DMA_CH_CFG_BURST_HALT			0x00000004	/* idle after finish current memory burst */
+#define ENET_DMA_CH_CFG_INT_STAT			0x04		/* interrupts control and status */
+#define ENET_DMA_CH_CFG_INT_MASK			0x08		/* interrupts mask */
+#define  ENET_DMA_CH_CFG_INT_BUFF_DONE			0x00000001	/* buffer done */
+#define  ENET_DMA_CH_CFG_INT_DONE			0x00000002	/* packet xfer complete */
+#define  ENET_DMA_CH_CFG_INT_NO_DESC			0x00000004	/* no valid descriptors */
+#define  ENET_DMA_CH_CFG_INT_RX_ERROR			0x00000008	/* rxdma detect client protocol error */
+#define ENET_DMA_CH_CFG_MAX_BURST			0x0c		/* max burst length permitted */
+#define  ENET_DMA_CH_CFG_MAX_BURST_DESCSIZE_SEL		0x00040000	/* DMA Descriptor Size Selection */
+#define ENET_DMA_CH_CFG_SIZE				0x10
+
+#define ENET_DMA_CH_STATE_RAM_BASE_DESC_PTR		0x00		/* descriptor ring start address */
+#define ENET_DMA_CH_STATE_RAM_STATE_DATA		0x04		/* state/bytes done/ring offset */
+#define ENET_DMA_CH_STATE_RAM_DESC_LEN_STATUS		0x08		/* buffer descriptor status and len */
+#define ENET_DMA_CH_STATE_RAM_DESC_BASE_BUFPTR		0x0c		/* buffer descrpitor current processing */
+#define ENET_DMA_CH_STATE_RAM_SIZE			0x10
+
+#define DMA_CTL_STATUS_APPEND_CRC			0x00000100
+#define DMA_CTL_STATUS_APPEND_BRCM_TAG			0x00000200
+#define DMA_CTL_STATUS_PRIO				0x00000C00  /* Prio for Tx */
+#define DMA_CTL_STATUS_WRAP				0x00001000  /* */
+#define DMA_CTL_STATUS_SOP				0x00002000  /* first buffer in packet */
+#define DMA_CTL_STATUS_EOP				0x00004000  /* last buffer in packet */
+#define DMA_CTL_STATUS_OWN				0x00008000  /* cleared by DMA, set by SW */
+#define DMA_CTL_LEN_DESC_BUFLENGTH			0x0fff0000
+#define DMA_CTL_LEN_DESC_BUFLENGTH_SHIFT		16
+#define DMA_CTL_LEN_DESC_MULTICAST			0x40000000
+#define DMA_CTL_LEN_DESC_USEFPM				0x80000000
+
+#endif
-- 
2.26.2


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

* Re: [PATCH V2 net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller
  2021-02-07 22:26 ` [PATCH V2 net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller Rafał Miłecki
  2021-02-07 22:26   ` [PATCH V2 net-next 2/2] net: broadcom: bcm4908enet: add BCM4908 controller driver Rafał Miłecki
@ 2021-02-09 21:43   ` Rob Herring
  2021-02-09 22:07     ` Rafał Miłecki
  1 sibling, 1 reply; 33+ messages in thread
From: Rob Herring @ 2021-02-09 21:43 UTC (permalink / raw)
  To: Rafał Miłecki
  Cc: David S . Miller, Jakub Kicinski, Florian Fainelli, Randy Dunlap,
	Masahiro Yamada, netdev, devicetree, bcm-kernel-feedback-list,
	Rafał Miłecki

On Sun, Feb 07, 2021 at 11:26:31PM +0100, Rafał Miłecki wrote:
> From: Rafał Miłecki <rafal@milecki.pl>
> 
> BCM4908 is a family of SoCs with integrated Ethernet controller.
> 
> Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
> ---
>  .../bindings/net/brcm,bcm4908enet.yaml        | 45 +++++++++++++++++++
>  1 file changed, 45 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/net/brcm,bcm4908enet.yaml
> 
> diff --git a/Documentation/devicetree/bindings/net/brcm,bcm4908enet.yaml b/Documentation/devicetree/bindings/net/brcm,bcm4908enet.yaml
> new file mode 100644
> index 000000000000..5f12f51c5b19
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/brcm,bcm4908enet.yaml
> @@ -0,0 +1,45 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/net/brcm,bcm4908enet.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Broadcom BCM4908 Ethernet controller
> +
> +description: Broadcom's Ethernet controller integrated into BCM4908 family SoCs
> +
> +maintainers:
> +  - Rafał Miłecki <rafal@milecki.pl>
> +

allOf:
  - $ref: 'ethernet-controller.yaml#'

> +properties:
> +  compatible:
> +    const: brcm,bcm4908enet

Normal convention is 'brcm,bcm4908-enet'. (And update the filename/$id)

> +
> +  reg:
> +    maxItems: 1
> +
> +  interrupts:
> +    description: RX interrupt
> +
> +  interrupt-names:
> +    const: rx

Don't really need *-names when only 1 possible entry.

> +
> +required:
> +  - reg
> +  - interrupts
> +  - interrupt-names
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +
> +    ethernet@80002000 {
> +        compatible = "brcm,bcm4908enet";
> +        reg = <0x80002000 0x1000>;
> +
> +        interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
> +        interrupt-names = "rx";
> +    };
> -- 
> 2.26.2
> 

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

* Re: [PATCH V2 net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller
  2021-02-09 21:43   ` [PATCH V2 net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller Rob Herring
@ 2021-02-09 22:07     ` Rafał Miłecki
  0 siblings, 0 replies; 33+ messages in thread
From: Rafał Miłecki @ 2021-02-09 22:07 UTC (permalink / raw)
  To: Rob Herring, Rafał Miłecki
  Cc: David S . Miller, Jakub Kicinski, Florian Fainelli, Randy Dunlap,
	Masahiro Yamada, netdev, devicetree, bcm-kernel-feedback-list

On 09.02.2021 22:43, Rob Herring wrote:
> On Sun, Feb 07, 2021 at 11:26:31PM +0100, Rafał Miłecki wrote:
>> From: Rafał Miłecki <rafal@milecki.pl>
>>
>> BCM4908 is a family of SoCs with integrated Ethernet controller.
>>
>> Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
>> ---
>>   .../bindings/net/brcm,bcm4908enet.yaml        | 45 +++++++++++++++++++
>>   1 file changed, 45 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/net/brcm,bcm4908enet.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/net/brcm,bcm4908enet.yaml b/Documentation/devicetree/bindings/net/brcm,bcm4908enet.yaml
>> new file mode 100644
>> index 000000000000..5f12f51c5b19
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/net/brcm,bcm4908enet.yaml
>> @@ -0,0 +1,45 @@
>> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/net/brcm,bcm4908enet.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Broadcom BCM4908 Ethernet controller
>> +
>> +description: Broadcom's Ethernet controller integrated into BCM4908 family SoCs
>> +
>> +maintainers:
>> +  - Rafał Miłecki <rafal@milecki.pl>
>> +
> 
> allOf:
>    - $ref: 'ethernet-controller.yaml#'

Thanks!


>> +properties:
>> +  compatible:
>> +    const: brcm,bcm4908enet
> 
> Normal convention is 'brcm,bcm4908-enet'. (And update the filename/$id)

Is it? ;) It seems we have:
brcm,bcmgenet (not brcm,bcmg-enet)
fsl-enetc (not e.g. fsl-enet-c)
xilinx_axienet (not xilinx_axi-enet)
apm,xgene1-sgenet (not apm,xgene1-sg-enet)

Of course, as you seem to prefer *-enet, I'll make it so! V3 soon.


>> +
>> +  reg:
>> +    maxItems: 1
>> +
>> +  interrupts:
>> +    description: RX interrupt
>> +
>> +  interrupt-names:
>> +    const: rx
> 
> Don't really need *-names when only 1 possible entry.

I think this controller may have some more interrupts (I don't know about). We can "interrupt-names" later, when we find them out.

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

* [PATCH V3 net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller
  2021-02-07 22:26   ` [PATCH V2 net-next 2/2] net: broadcom: bcm4908enet: add BCM4908 controller driver Rafał Miłecki
@ 2021-02-09 23:01     ` Rafał Miłecki
  2021-02-09 23:01       ` [PATCH V3 net-next 2/2] net: broadcom: bcm4908_enet: add BCM4908 controller driver Rafał Miłecki
  0 siblings, 1 reply; 33+ messages in thread
From: Rafał Miłecki @ 2021-02-09 23:01 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Florian Fainelli, Randy Dunlap, Masahiro Yamada, netdev,
	devicetree, bcm-kernel-feedback-list, Rafał Miłecki

From: Rafał Miłecki <rafal@milecki.pl>

BCM4908 is a family of SoCs with integrated Ethernet controller.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
V3: Use ethernet-controller.yaml#
    Rename "compatible" value (use "-")
    Drop "interrupt-names" until it's needed
---
 .../bindings/net/brcm,bcm4908-enet.yaml       | 43 +++++++++++++++++++
 1 file changed, 43 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/brcm,bcm4908-enet.yaml

diff --git a/Documentation/devicetree/bindings/net/brcm,bcm4908-enet.yaml b/Documentation/devicetree/bindings/net/brcm,bcm4908-enet.yaml
new file mode 100644
index 000000000000..5050974c8550
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/brcm,bcm4908-enet.yaml
@@ -0,0 +1,43 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/brcm,bcm4908-enet.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Broadcom BCM4908 Ethernet controller
+
+description: Broadcom's Ethernet controller integrated into BCM4908 family SoCs
+
+maintainers:
+  - Rafał Miłecki <rafal@milecki.pl>
+
+allOf:
+  - $ref: ethernet-controller.yaml#
+
+properties:
+  compatible:
+    const: brcm,bcm4908-enet
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    description: RX interrupt
+
+required:
+  - reg
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    ethernet@80002000 {
+        compatible = "brcm,bcm4908-enet";
+        reg = <0x80002000 0x1000>;
+
+        interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+    };
-- 
2.26.2


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

* [PATCH V3 net-next 2/2] net: broadcom: bcm4908_enet: add BCM4908 controller driver
  2021-02-09 23:01     ` [PATCH V3 net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller Rafał Miłecki
@ 2021-02-09 23:01       ` Rafał Miłecki
  2021-02-10  2:39         ` Andrew Lunn
                           ` (2 more replies)
  0 siblings, 3 replies; 33+ messages in thread
From: Rafał Miłecki @ 2021-02-09 23:01 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Florian Fainelli, Randy Dunlap, Masahiro Yamada, netdev,
	devicetree, bcm-kernel-feedback-list, Rafał Miłecki

From: Rafał Miłecki <rafal@milecki.pl>

BCM4908 SoCs family uses Ethernel controller that includes UniMAC but
uses different DMA engine (than other controllers) and requires
different programming.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
V2: Use cpu_to_le32()
    Reported-by: kernel test robot <lkp@intel.com>
    Add "depends" to the Kconfig
V3: Rename using "_enet" (with underscore)
    One more cpu_to_le32()
    Replace magic number with ETH_FCS_LEN
    Add kfree_skb() to fix potential memory leak
---
 MAINTAINERS                                  |   9 +
 drivers/net/ethernet/broadcom/Kconfig        |   8 +
 drivers/net/ethernet/broadcom/Makefile       |   1 +
 drivers/net/ethernet/broadcom/bcm4908_enet.c | 678 +++++++++++++++++++
 drivers/net/ethernet/broadcom/bcm4908_enet.h |  96 +++
 5 files changed, 792 insertions(+)
 create mode 100644 drivers/net/ethernet/broadcom/bcm4908_enet.c
 create mode 100644 drivers/net/ethernet/broadcom/bcm4908_enet.h

diff --git a/MAINTAINERS b/MAINTAINERS
index d1b0057a9797..0e2489c630f8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3445,6 +3445,15 @@ F:	Documentation/devicetree/bindings/mips/brcm/
 F:	arch/mips/bcm47xx/*
 F:	arch/mips/include/asm/mach-bcm47xx/*
 
+BROADCOM BCM4908 ETHERNET DRIVER
+M:	Rafał Miłecki <rafal@milecki.pl>
+M:	bcm-kernel-feedback-list@broadcom.com
+L:	netdev@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/net/brcm,bcm4908-enet.yaml
+F:	drivers/net/ethernet/broadcom/bcm4908_enet.*
+F:	drivers/net/ethernet/broadcom/unimac.h
+
 BROADCOM BCM5301X ARM ARCHITECTURE
 M:	Hauke Mehrtens <hauke@hauke-m.de>
 M:	Rafał Miłecki <zajec5@gmail.com>
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index 4bdf8fbe75a6..d1e439cc2eab 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -51,6 +51,14 @@ config B44_PCI
 	depends on B44_PCI_AUTOSELECT && B44_PCICORE_AUTOSELECT
 	default y
 
+config BCM4908_ENET
+	tristate "Broadcom BCM4908 internal mac support"
+	depends on ARCH_BCM4908 || COMPILE_TEST
+	default ARCH_BCM4908
+	help
+	  This driver supports Ethernet controller integrated into Broadcom
+	  BCM4908 family SoCs.
+
 config BCM63XX_ENET
 	tristate "Broadcom 63xx internal mac support"
 	depends on BCM63XX
diff --git a/drivers/net/ethernet/broadcom/Makefile b/drivers/net/ethernet/broadcom/Makefile
index 7046ad6d3d0e..0ddfb5b5d53c 100644
--- a/drivers/net/ethernet/broadcom/Makefile
+++ b/drivers/net/ethernet/broadcom/Makefile
@@ -4,6 +4,7 @@
 #
 
 obj-$(CONFIG_B44) += b44.o
+obj-$(CONFIG_BCM4908_ENET) += bcm4908_enet.o
 obj-$(CONFIG_BCM63XX_ENET) += bcm63xx_enet.o
 obj-$(CONFIG_BCMGENET) += genet/
 obj-$(CONFIG_BNX2) += bnx2.o
diff --git a/drivers/net/ethernet/broadcom/bcm4908_enet.c b/drivers/net/ethernet/broadcom/bcm4908_enet.c
new file mode 100644
index 000000000000..f1d719908e24
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/bcm4908_enet.c
@@ -0,0 +1,678 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl>
+ */
+
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include "bcm4908_enet.h"
+#include "unimac.h"
+
+#define ENET_DMA_CH_RX_CFG			ENET_DMA_CH0_CFG
+#define ENET_DMA_CH_TX_CFG			ENET_DMA_CH1_CFG
+#define ENET_DMA_CH_RX_STATE_RAM		ENET_DMA_CH0_STATE_RAM
+#define ENET_DMA_CH_TX_STATE_RAM		ENET_DMA_CH1_STATE_RAM
+
+#define ENET_TX_BDS_NUM				200
+#define ENET_RX_BDS_NUM				200
+#define ENET_RX_BDS_NUM_MAX			8192
+
+#define ENET_DMA_INT_DEFAULTS			(ENET_DMA_CH_CFG_INT_DONE | \
+						 ENET_DMA_CH_CFG_INT_NO_DESC | \
+						 ENET_DMA_CH_CFG_INT_BUFF_DONE)
+#define ENET_DMA_MAX_BURST_LEN			8 /* in 64 bit words */
+
+#define ENET_MTU_MIN				60
+#define ENET_MTU_MAX				1500 /* Is it possible to support 2044? */
+#define ENET_MTU_MAX_EXTRA_SIZE			32 /* L2 */
+
+struct bcm4908_enet_dma_ring_bd {
+	__le32 ctl;
+	__le32 addr;
+} __packed;
+
+struct bcm4908_enet_dma_ring_slot {
+	struct sk_buff *skb;
+	unsigned int len;
+	dma_addr_t dma_addr;
+};
+
+struct bcm4908_enet_dma_ring {
+	int is_tx;
+	int read_idx;
+	int write_idx;
+	int length;
+	u16 cfg_block;
+	u16 st_ram_block;
+
+	union {
+		void *cpu_addr;
+		struct bcm4908_enet_dma_ring_bd *buf_desc;
+	};
+	dma_addr_t dma_addr;
+
+	struct bcm4908_enet_dma_ring_slot *slots;
+};
+
+struct bcm4908_enet {
+	struct device *dev;
+	struct net_device *netdev;
+	struct napi_struct napi;
+	void __iomem *base;
+
+	struct bcm4908_enet_dma_ring tx_ring;
+	struct bcm4908_enet_dma_ring rx_ring;
+};
+
+/***
+ * R/W ops
+ */
+
+static inline u32 enet_read(struct bcm4908_enet *enet, u16 offset)
+{
+	return readl(enet->base + offset);
+}
+
+static inline void enet_write(struct bcm4908_enet *enet, u16 offset, u32 value)
+{
+	writel(value, enet->base + offset);
+}
+
+static inline void enet_maskset(struct bcm4908_enet *enet, u16 offset, u32 mask, u32 set)
+{
+	u32 val;
+
+	WARN_ON(set & ~mask);
+
+	val = enet_read(enet, offset);
+	val = (val & ~mask) | (set & mask);
+	enet_write(enet, offset, val);
+}
+
+static inline void enet_set(struct bcm4908_enet *enet, u16 offset, u32 set)
+{
+	enet_maskset(enet, offset, set, set);
+}
+
+static inline u32 enet_umac_read(struct bcm4908_enet *enet, u16 offset)
+{
+	return enet_read(enet, ENET_UNIMAC + offset);
+}
+
+static inline void enet_umac_write(struct bcm4908_enet *enet, u16 offset, u32 value)
+{
+	enet_write(enet, ENET_UNIMAC + offset, value);
+}
+
+static inline void enet_umac_maskset(struct bcm4908_enet *enet, u16 offset, u32 mask, u32 set)
+{
+	enet_maskset(enet, ENET_UNIMAC + offset, mask, set);
+}
+
+static inline void enet_umac_set(struct bcm4908_enet *enet, u16 offset, u32 set)
+{
+	enet_set(enet, ENET_UNIMAC + offset, set);
+}
+
+/***
+ * Helpers
+ */
+
+static void bcm4908_enet_intrs_on(struct bcm4908_enet *enet)
+{
+	enet_write(enet, ENET_DMA_CH_RX_CFG + ENET_DMA_CH_CFG_INT_MASK, ENET_DMA_INT_DEFAULTS);
+}
+
+static void bcm4908_enet_intrs_off(struct bcm4908_enet *enet)
+{
+	enet_write(enet, ENET_DMA_CH_RX_CFG + ENET_DMA_CH_CFG_INT_MASK, 0);
+}
+
+static void bcm4908_enet_intrs_ack(struct bcm4908_enet *enet)
+{
+	enet_write(enet, ENET_DMA_CH_RX_CFG + ENET_DMA_CH_CFG_INT_STAT, ENET_DMA_INT_DEFAULTS);
+}
+
+/***
+ * DMA
+ */
+
+static int bcm4908_dma_alloc_buf_descs(struct bcm4908_enet *enet,
+				       struct bcm4908_enet_dma_ring *ring)
+{
+	int size = ring->length * sizeof(struct bcm4908_enet_dma_ring_bd);
+	struct device *dev = enet->dev;
+
+	ring->cpu_addr = dma_alloc_coherent(dev, size, &ring->dma_addr, GFP_KERNEL);
+	if (!ring->cpu_addr)
+		return -ENOMEM;
+
+	if (((uintptr_t)ring->cpu_addr) & (0x40 - 1)) {
+		dev_err(dev, "Invalid DMA ring alignment\n");
+		goto err_free_buf_descs;
+	}
+
+	ring->slots = kzalloc(ring->length * sizeof(*ring->slots), GFP_KERNEL);
+	if (!ring->slots)
+		goto err_free_buf_descs;
+
+	memset(ring->cpu_addr, 0, size);
+
+	ring->read_idx = 0;
+	ring->write_idx = 0;
+
+	return 0;
+
+err_free_buf_descs:
+	dma_free_coherent(dev, size, ring->cpu_addr, ring->dma_addr);
+	return -ENOMEM;
+}
+
+static void bcm4908_enet_dma_free(struct bcm4908_enet *enet)
+{
+	struct bcm4908_enet_dma_ring *tx_ring = &enet->tx_ring;
+	struct bcm4908_enet_dma_ring *rx_ring = &enet->rx_ring;
+	struct device *dev = enet->dev;
+	int size;
+
+	size = rx_ring->length * sizeof(struct bcm4908_enet_dma_ring_bd);
+	if (rx_ring->cpu_addr)
+		dma_free_coherent(dev, size, rx_ring->cpu_addr, rx_ring->dma_addr);
+	kfree(rx_ring->slots);
+
+	size = tx_ring->length * sizeof(struct bcm4908_enet_dma_ring_bd);
+	if (tx_ring->cpu_addr)
+		dma_free_coherent(dev, size, tx_ring->cpu_addr, tx_ring->dma_addr);
+	kfree(tx_ring->slots);
+}
+
+static int bcm4908_enet_dma_alloc(struct bcm4908_enet *enet)
+{
+	struct bcm4908_enet_dma_ring *tx_ring = &enet->tx_ring;
+	struct bcm4908_enet_dma_ring *rx_ring = &enet->rx_ring;
+	struct device *dev = enet->dev;
+	int err;
+
+	tx_ring->length = ENET_TX_BDS_NUM;
+	tx_ring->is_tx = 1;
+	tx_ring->cfg_block = ENET_DMA_CH_TX_CFG;
+	tx_ring->st_ram_block = ENET_DMA_CH_TX_STATE_RAM;
+	err = bcm4908_dma_alloc_buf_descs(enet, tx_ring);
+	if (err) {
+		dev_err(dev, "Failed to alloc TX buf descriptors: %d\n", err);
+		return err;
+	}
+
+	rx_ring->length = ENET_RX_BDS_NUM;
+	rx_ring->is_tx = 0;
+	rx_ring->cfg_block = ENET_DMA_CH_RX_CFG;
+	rx_ring->st_ram_block = ENET_DMA_CH_RX_STATE_RAM;
+	err = bcm4908_dma_alloc_buf_descs(enet, rx_ring);
+	if (err) {
+		dev_err(dev, "Failed to alloc RX buf descriptors: %d\n", err);
+		bcm4908_enet_dma_free(enet);
+		return err;
+	}
+
+	return 0;
+}
+
+static void bcm4908_enet_dma_reset(struct bcm4908_enet *enet)
+{
+	struct bcm4908_enet_dma_ring *rings[] = { &enet->rx_ring, &enet->tx_ring };
+	int i;
+
+	/* Disable the DMA controller and channel */
+	for (i = 0; i < ARRAY_SIZE(rings); i++)
+		enet_write(enet, rings[i]->cfg_block + ENET_DMA_CH_CFG, 0);
+	enet_maskset(enet, ENET_DMA_CONTROLLER_CFG, ENET_DMA_CTRL_CFG_MASTER_EN, 0);
+
+	/* Reset channels state */
+	for (i = 0; i < ARRAY_SIZE(rings); i++) {
+		struct bcm4908_enet_dma_ring *ring = rings[i];
+
+		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_BASE_DESC_PTR, 0);
+		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_STATE_DATA, 0);
+		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_DESC_LEN_STATUS, 0);
+		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_DESC_BASE_BUFPTR, 0);
+	}
+}
+
+static int bcm4908_enet_dma_alloc_rx_buf(struct bcm4908_enet *enet, unsigned int idx)
+{
+	struct bcm4908_enet_dma_ring_bd *buf_desc = &enet->rx_ring.buf_desc[idx];
+	struct bcm4908_enet_dma_ring_slot *slot = &enet->rx_ring.slots[idx];
+	struct device *dev = enet->dev;
+	u32 tmp;
+	int err;
+
+	slot->len = ENET_MTU_MAX + ENET_MTU_MAX_EXTRA_SIZE;
+
+	slot->skb = netdev_alloc_skb(enet->netdev, slot->len);
+	if (!slot->skb)
+		return -ENOMEM;
+
+	slot->dma_addr = dma_map_single(dev, slot->skb->data, slot->len, DMA_FROM_DEVICE);
+	err = dma_mapping_error(dev, slot->dma_addr);
+	if (err) {
+		dev_err(dev, "Failed to map DMA buffer: %d\n", err);
+		kfree_skb(slot->skb);
+		slot->skb = NULL;
+		return err;
+	}
+
+	tmp = slot->len << DMA_CTL_LEN_DESC_BUFLENGTH_SHIFT;
+	tmp |= DMA_CTL_STATUS_OWN;
+	if (idx == enet->rx_ring.length - 1)
+		tmp |= DMA_CTL_STATUS_WRAP;
+	buf_desc->ctl = cpu_to_le32(tmp);
+	buf_desc->addr = cpu_to_le32(slot->dma_addr);
+
+	return 0;
+}
+
+static void bcm4908_enet_dma_ring_init(struct bcm4908_enet *enet,
+				       struct bcm4908_enet_dma_ring *ring)
+{
+	int reset_channel = 0; /* We support only 1 main channel (with TX and RX) */
+	int reset_subch = ring->is_tx ? 1 : 0;
+
+	/* Reset the DMA channel */
+	enet_write(enet, ENET_DMA_CTRL_CHANNEL_RESET, BIT(reset_channel * 2 + reset_subch));
+	enet_write(enet, ENET_DMA_CTRL_CHANNEL_RESET, 0);
+
+	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG, 0);
+	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG_MAX_BURST, ENET_DMA_MAX_BURST_LEN);
+	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG_INT_MASK, 0);
+
+	enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_BASE_DESC_PTR,
+		   (uint32_t)ring->dma_addr);
+}
+
+static void bcm4908_enet_dma_uninit(struct bcm4908_enet *enet)
+{
+	struct bcm4908_enet_dma_ring *rx_ring = &enet->rx_ring;
+	struct bcm4908_enet_dma_ring_slot *slot;
+	struct device *dev = enet->dev;
+	int i;
+
+	for (i = rx_ring->length - 1; i >= 0; i--) {
+		slot = &rx_ring->slots[i];
+		if (!slot->skb)
+			continue;
+		dma_unmap_single(dev, slot->dma_addr, slot->len, DMA_FROM_DEVICE);
+		kfree_skb(slot->skb);
+		slot->skb = NULL;
+	}
+}
+
+static int bcm4908_enet_dma_init(struct bcm4908_enet *enet)
+{
+	struct bcm4908_enet_dma_ring *rx_ring = &enet->rx_ring;
+	struct device *dev = enet->dev;
+	int err;
+	int i;
+
+	for (i = 0; i < rx_ring->length; i++) {
+		err = bcm4908_enet_dma_alloc_rx_buf(enet, i);
+		if (err) {
+			dev_err(dev, "Failed to alloc RX buffer: %d\n", err);
+			bcm4908_enet_dma_uninit(enet);
+			return err;
+		}
+	}
+
+	bcm4908_enet_dma_ring_init(enet, &enet->tx_ring);
+	bcm4908_enet_dma_ring_init(enet, &enet->rx_ring);
+
+	return 0;
+}
+
+static void bcm4908_enet_dma_tx_ring_ensable(struct bcm4908_enet *enet,
+					     struct bcm4908_enet_dma_ring *ring)
+{
+	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG, ENET_DMA_CH_CFG_ENABLE);
+}
+
+static void bcm4908_enet_dma_tx_ring_disable(struct bcm4908_enet *enet,
+					     struct bcm4908_enet_dma_ring *ring)
+{
+	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG, 0);
+}
+
+static void bcm4908_enet_dma_rx_ring_enable(struct bcm4908_enet *enet,
+					    struct bcm4908_enet_dma_ring *ring)
+{
+	enet_set(enet, ring->cfg_block + ENET_DMA_CH_CFG, ENET_DMA_CH_CFG_ENABLE);
+}
+
+static void bcm4908_enet_dma_rx_ring_disable(struct bcm4908_enet *enet,
+					     struct bcm4908_enet_dma_ring *ring)
+{
+	unsigned long deadline;
+	u32 tmp;
+
+	enet_maskset(enet, ring->cfg_block + ENET_DMA_CH_CFG, ENET_DMA_CH_CFG_ENABLE, 0);
+
+	deadline = jiffies + usecs_to_jiffies(2000);
+	do {
+		tmp = enet_read(enet, ring->cfg_block + ENET_DMA_CH_CFG);
+		if (!(tmp & ENET_DMA_CH_CFG_ENABLE))
+			return;
+		enet_maskset(enet, ring->cfg_block + ENET_DMA_CH_CFG, ENET_DMA_CH_CFG_ENABLE, 0);
+		usleep_range(10, 30);
+	} while (!time_after_eq(jiffies, deadline));
+
+	dev_warn(enet->dev, "Timeout waiting for DMA TX stop\n");
+}
+
+/***
+ * Ethernet driver
+ */
+
+static void bcm4908_enet_gmac_init(struct bcm4908_enet *enet)
+{
+	u32 cmd;
+
+	cmd = enet_umac_read(enet, UMAC_CMD);
+	enet_umac_write(enet, UMAC_CMD, cmd | CMD_SW_RESET);
+	enet_umac_write(enet, UMAC_CMD, cmd & ~CMD_SW_RESET);
+
+	enet_set(enet, ENET_FLUSH, ENET_FLUSH_RXFIFO_FLUSH | ENET_FLUSH_TXFIFO_FLUSH);
+	enet_maskset(enet, ENET_FLUSH, ENET_FLUSH_RXFIFO_FLUSH | ENET_FLUSH_TXFIFO_FLUSH, 0);
+
+	enet_set(enet, ENET_MIB_CTRL, ENET_MIB_CTRL_CLR_MIB);
+	enet_maskset(enet, ENET_MIB_CTRL, ENET_MIB_CTRL_CLR_MIB, 0);
+
+	cmd = enet_umac_read(enet, UMAC_CMD);
+	cmd &= ~(CMD_SPEED_MASK << CMD_SPEED_SHIFT);
+	cmd &= ~CMD_TX_EN;
+	cmd &= ~CMD_RX_EN;
+	cmd |= CMD_SPEED_1000 << CMD_SPEED_SHIFT;
+	enet_umac_write(enet, UMAC_CMD, cmd);
+
+	enet_maskset(enet, ENET_GMAC_STATUS,
+		     ENET_GMAC_STATUS_ETH_SPEED_MASK |
+		     ENET_GMAC_STATUS_HD |
+		     ENET_GMAC_STATUS_AUTO_CFG_EN |
+		     ENET_GMAC_STATUS_LINK_UP,
+		     ENET_GMAC_STATUS_ETH_SPEED_1000 |
+		     ENET_GMAC_STATUS_AUTO_CFG_EN |
+		     ENET_GMAC_STATUS_LINK_UP);
+}
+
+static irqreturn_t bcm4908_enet_irq_handler(int irq, void *dev_id)
+{
+	struct bcm4908_enet *enet = dev_id;
+
+	bcm4908_enet_intrs_off(enet);
+	bcm4908_enet_intrs_ack(enet);
+
+	napi_schedule(&enet->napi);
+
+	return IRQ_HANDLED;
+}
+
+static int bcm4908_enet_open(struct net_device *netdev)
+{
+	struct bcm4908_enet *enet = netdev_priv(netdev);
+	struct device *dev = enet->dev;
+	int err;
+
+	err = request_irq(netdev->irq, bcm4908_enet_irq_handler, 0, "enet", enet);
+	if (err) {
+		dev_err(dev, "Failed to request IRQ %d: %d\n", netdev->irq, err);
+		return err;
+	}
+
+	bcm4908_enet_gmac_init(enet);
+	bcm4908_enet_dma_reset(enet);
+	bcm4908_enet_dma_init(enet);
+
+	enet_umac_set(enet, UMAC_CMD, CMD_TX_EN | CMD_RX_EN);
+
+	enet_set(enet, ENET_DMA_CONTROLLER_CFG, ENET_DMA_CTRL_CFG_MASTER_EN);
+	enet_maskset(enet, ENET_DMA_CONTROLLER_CFG, ENET_DMA_CTRL_CFG_FLOWC_CH1_EN, 0);
+	bcm4908_enet_dma_rx_ring_enable(enet, &enet->rx_ring);
+
+	napi_enable(&enet->napi);
+	netif_carrier_on(netdev);
+	netif_start_queue(netdev);
+
+	bcm4908_enet_intrs_ack(enet);
+	bcm4908_enet_intrs_on(enet);
+
+	return 0;
+}
+
+static int bcm4908_enet_stop(struct net_device *netdev)
+{
+	struct bcm4908_enet *enet = netdev_priv(netdev);
+
+	netif_stop_queue(netdev);
+	netif_carrier_off(netdev);
+	napi_disable(&enet->napi);
+
+	bcm4908_enet_dma_rx_ring_disable(enet, &enet->rx_ring);
+	bcm4908_enet_dma_tx_ring_disable(enet, &enet->tx_ring);
+
+	bcm4908_enet_dma_uninit(enet);
+
+	free_irq(enet->netdev->irq, enet);
+
+	return 0;
+}
+
+static int bcm4908_enet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct bcm4908_enet *enet = netdev_priv(netdev);
+	struct bcm4908_enet_dma_ring *ring = &enet->tx_ring;
+	struct bcm4908_enet_dma_ring_slot *slot;
+	struct device *dev = enet->dev;
+	struct bcm4908_enet_dma_ring_bd *buf_desc;
+	int free_buf_descs;
+	u32 tmp;
+
+	/* Free transmitted skbs */
+	while (ring->read_idx != ring->write_idx) {
+		buf_desc = &ring->buf_desc[ring->read_idx];
+		if (le32_to_cpu(buf_desc->ctl) & DMA_CTL_STATUS_OWN)
+			break;
+		slot = &ring->slots[ring->read_idx];
+
+		dma_unmap_single(dev, slot->dma_addr, slot->len, DMA_TO_DEVICE);
+		dev_kfree_skb(slot->skb);
+		if (++ring->read_idx == ring->length)
+			ring->read_idx = 0;
+	}
+
+	/* Don't use the last empty buf descriptor */
+	if (ring->read_idx <= ring->write_idx)
+		free_buf_descs = ring->read_idx - ring->write_idx + ring->length;
+	else
+		free_buf_descs = ring->read_idx - ring->write_idx;
+	if (free_buf_descs < 2)
+		return NETDEV_TX_BUSY;
+
+	/* Hardware removes OWN bit after sending data */
+	buf_desc = &ring->buf_desc[ring->write_idx];
+	if (unlikely(le32_to_cpu(buf_desc->ctl) & DMA_CTL_STATUS_OWN)) {
+		netif_stop_queue(netdev);
+		return NETDEV_TX_BUSY;
+	}
+
+	slot = &ring->slots[ring->write_idx];
+	slot->skb = skb;
+	slot->len = skb->len;
+	slot->dma_addr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE);
+	if (unlikely(dma_mapping_error(dev, slot->dma_addr)))
+		return NETDEV_TX_BUSY;
+
+	tmp = skb->len << DMA_CTL_LEN_DESC_BUFLENGTH_SHIFT;
+	tmp |= DMA_CTL_STATUS_OWN;
+	tmp |= DMA_CTL_STATUS_SOP;
+	tmp |= DMA_CTL_STATUS_EOP;
+	tmp |= DMA_CTL_STATUS_APPEND_CRC;
+	if (ring->write_idx + 1 == ring->length - 1)
+		tmp |= DMA_CTL_STATUS_WRAP;
+
+	buf_desc->addr = cpu_to_le32((uint32_t)slot->dma_addr);
+	buf_desc->ctl = cpu_to_le32(tmp);
+
+	bcm4908_enet_dma_tx_ring_ensable(enet, &enet->tx_ring);
+
+	if (++ring->write_idx == ring->length - 1)
+		ring->write_idx = 0;
+	enet->netdev->stats.tx_bytes += skb->len;
+	enet->netdev->stats.tx_packets++;
+
+	return NETDEV_TX_OK;
+}
+
+static int bcm4908_enet_poll(struct napi_struct *napi, int weight)
+{
+	struct bcm4908_enet *enet = container_of(napi, struct bcm4908_enet, napi);
+	struct device *dev = enet->dev;
+	int handled = 0;
+
+	while (handled < weight) {
+		struct bcm4908_enet_dma_ring_bd *buf_desc;
+		struct bcm4908_enet_dma_ring_slot slot;
+		u32 ctl;
+		int len;
+		int err;
+
+		buf_desc = &enet->rx_ring.buf_desc[enet->rx_ring.read_idx];
+		ctl = le32_to_cpu(buf_desc->ctl);
+		if (ctl & DMA_CTL_STATUS_OWN)
+			break;
+
+		slot = enet->rx_ring.slots[enet->rx_ring.read_idx];
+
+		/* Provide new buffer before unpinning the old one */
+		err = bcm4908_enet_dma_alloc_rx_buf(enet, enet->rx_ring.read_idx);
+		if (err)
+			break;
+
+		if (++enet->rx_ring.read_idx == enet->rx_ring.length)
+			enet->rx_ring.read_idx = 0;
+
+		len = (ctl & DMA_CTL_LEN_DESC_BUFLENGTH) >> DMA_CTL_LEN_DESC_BUFLENGTH_SHIFT;
+
+		if (len < ENET_MTU_MIN ||
+		    (ctl & (DMA_CTL_STATUS_SOP | DMA_CTL_STATUS_EOP)) != (DMA_CTL_STATUS_SOP | DMA_CTL_STATUS_EOP)) {
+			kfree(slot.skb);
+			enet->netdev->stats.rx_dropped++;
+			break;
+		}
+
+		dma_unmap_single(dev, slot.dma_addr, slot.len, DMA_FROM_DEVICE);
+
+		skb_put(slot.skb, len - ETH_FCS_LEN);
+		slot.skb->protocol = eth_type_trans(slot.skb, enet->netdev);
+		netif_receive_skb(slot.skb);
+
+		enet->netdev->stats.rx_packets++;
+		enet->netdev->stats.rx_bytes += len;
+	}
+
+	if (handled < weight) {
+		napi_complete_done(napi, handled);
+		bcm4908_enet_intrs_on(enet);
+	}
+
+	return handled;
+}
+
+static const struct net_device_ops bcm4908_enet_netdev_ops = {
+	.ndo_open = bcm4908_enet_open,
+	.ndo_stop = bcm4908_enet_stop,
+	.ndo_start_xmit = bcm4908_enet_start_xmit,
+	.ndo_set_mac_address = eth_mac_addr,
+};
+
+static int bcm4908_enet_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct net_device *netdev;
+	struct bcm4908_enet *enet;
+	int err;
+
+	netdev = devm_alloc_etherdev(dev, sizeof(*enet));
+	if (!netdev)
+		return -ENOMEM;
+
+	enet = netdev_priv(netdev);
+	enet->dev = dev;
+	enet->netdev = netdev;
+
+	enet->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(enet->base)) {
+		dev_err(dev, "Failed to map registers: %ld\n", PTR_ERR(enet->base));
+		return PTR_ERR(enet->base);
+	}
+
+	netdev->irq = platform_get_irq(pdev, 0);
+	if (netdev->irq < 0)
+		return netdev->irq;
+
+	dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+
+	err = bcm4908_enet_dma_alloc(enet);
+	if (err)
+		return err;
+
+	SET_NETDEV_DEV(netdev, &pdev->dev);
+	eth_hw_addr_random(netdev);
+	netdev->netdev_ops = &bcm4908_enet_netdev_ops;
+	netdev->min_mtu = ETH_ZLEN;
+	netdev->mtu = ENET_MTU_MAX;
+	netdev->max_mtu = ENET_MTU_MAX;
+	netif_napi_add(netdev, &enet->napi, bcm4908_enet_poll, 64);
+
+	err = register_netdev(netdev);
+	if (err) {
+		bcm4908_enet_dma_free(enet);
+		return err;
+	}
+
+	platform_set_drvdata(pdev, enet);
+
+	return 0;
+}
+
+static int bcm4908_enet_remove(struct platform_device *pdev)
+{
+	struct bcm4908_enet *enet = platform_get_drvdata(pdev);
+
+	unregister_netdev(enet->netdev);
+	netif_napi_del(&enet->napi);
+	bcm4908_enet_dma_free(enet);
+
+	return 0;
+}
+
+static const struct of_device_id bcm4908_enet_of_match[] = {
+	{ .compatible = "brcm,bcm4908-enet"},
+	{},
+};
+
+static struct platform_driver bcm4908_enet_driver = {
+	.driver = {
+		.name = "bcm4908_enet",
+		.of_match_table = bcm4908_enet_of_match,
+	},
+	.probe	= bcm4908_enet_probe,
+	.remove = bcm4908_enet_remove,
+};
+module_platform_driver(bcm4908_enet_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, bcm4908_enet_of_match);
diff --git a/drivers/net/ethernet/broadcom/bcm4908_enet.h b/drivers/net/ethernet/broadcom/bcm4908_enet.h
new file mode 100644
index 000000000000..8a3ede2da537
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/bcm4908_enet.h
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __BCM4908_ENET_H
+#define __BCM4908_ENET_H
+
+#define ENET_CONTROL					0x000
+#define ENET_MIB_CTRL					0x004
+#define  ENET_MIB_CTRL_CLR_MIB				0x00000001
+#define ENET_RX_ERR_MASK				0x008
+#define ENET_MIB_MAX_PKT_SIZE				0x00C
+#define  ENET_MIB_MAX_PKT_SIZE_VAL			0x00003fff
+#define ENET_DIAG_OUT					0x01c
+#define ENET_ENABLE_DROP_PKT				0x020
+#define ENET_IRQ_ENABLE					0x024
+#define  ENET_IRQ_ENABLE_OVFL				0x00000001
+#define ENET_GMAC_STATUS				0x028
+#define  ENET_GMAC_STATUS_ETH_SPEED_MASK		0x00000003
+#define  ENET_GMAC_STATUS_ETH_SPEED_10			0x00000000
+#define  ENET_GMAC_STATUS_ETH_SPEED_100			0x00000001
+#define  ENET_GMAC_STATUS_ETH_SPEED_1000		0x00000002
+#define  ENET_GMAC_STATUS_HD				0x00000004
+#define  ENET_GMAC_STATUS_AUTO_CFG_EN			0x00000008
+#define  ENET_GMAC_STATUS_LINK_UP			0x00000010
+#define ENET_IRQ_STATUS					0x02c
+#define  ENET_IRQ_STATUS_OVFL				0x00000001
+#define ENET_OVERFLOW_COUNTER				0x030
+#define ENET_FLUSH					0x034
+#define  ENET_FLUSH_RXFIFO_FLUSH			0x00000001
+#define  ENET_FLUSH_TXFIFO_FLUSH			0x00000002
+#define ENET_RSV_SELECT					0x038
+#define ENET_BP_FORCE					0x03c
+#define  ENET_BP_FORCE_FORCE				0x00000001
+#define ENET_DMA_RX_OK_TO_SEND_COUNT			0x040
+#define  ENET_DMA_RX_OK_TO_SEND_COUNT_VAL		0x0000000f
+#define ENET_TX_CRC_CTRL				0x044
+#define ENET_MIB					0x200
+#define ENET_UNIMAC					0x400
+#define ENET_DMA					0x800
+#define ENET_DMA_CONTROLLER_CFG				0x800
+#define  ENET_DMA_CTRL_CFG_MASTER_EN			0x00000001
+#define  ENET_DMA_CTRL_CFG_FLOWC_CH1_EN			0x00000002
+#define  ENET_DMA_CTRL_CFG_FLOWC_CH3_EN			0x00000004
+#define ENET_DMA_FLOWCTL_CH1_THRESH_LO			0x804
+#define ENET_DMA_FLOWCTL_CH1_THRESH_HI			0x808
+#define ENET_DMA_FLOWCTL_CH1_ALLOC			0x80c
+#define  ENET_DMA_FLOWCTL_CH1_ALLOC_FORCE		0x80000000
+#define ENET_DMA_FLOWCTL_CH3_THRESH_LO			0x810
+#define ENET_DMA_FLOWCTL_CH3_THRESH_HI			0x814
+#define ENET_DMA_FLOWCTL_CH3_ALLOC			0x818
+#define ENET_DMA_FLOWCTL_CH5_THRESH_LO			0x81C
+#define ENET_DMA_FLOWCTL_CH5_THRESH_HI			0x820
+#define ENET_DMA_FLOWCTL_CH5_ALLOC			0x824
+#define ENET_DMA_FLOWCTL_CH7_THRESH_LO			0x828
+#define ENET_DMA_FLOWCTL_CH7_THRESH_HI			0x82C
+#define ENET_DMA_FLOWCTL_CH7_ALLOC			0x830
+#define ENET_DMA_CTRL_CHANNEL_RESET			0x834
+#define ENET_DMA_CTRL_CHANNEL_DEBUG			0x838
+#define ENET_DMA_CTRL_GLOBAL_INTERRUPT_STATUS		0x840
+#define ENET_DMA_CTRL_GLOBAL_INTERRUPT_MASK		0x844
+#define ENET_DMA_CH0_CFG				0xa00		/* RX */
+#define ENET_DMA_CH1_CFG				0xa10		/* TX */
+#define ENET_DMA_CH0_STATE_RAM				0xc00		/* RX */
+#define ENET_DMA_CH1_STATE_RAM				0xc10		/* TX */
+
+#define ENET_DMA_CH_CFG					0x00		/* assorted configuration */
+#define  ENET_DMA_CH_CFG_ENABLE				0x00000001	/* set to enable channel */
+#define  ENET_DMA_CH_CFG_PKT_HALT			0x00000002	/* idle after an EOP flag is detected */
+#define  ENET_DMA_CH_CFG_BURST_HALT			0x00000004	/* idle after finish current memory burst */
+#define ENET_DMA_CH_CFG_INT_STAT			0x04		/* interrupts control and status */
+#define ENET_DMA_CH_CFG_INT_MASK			0x08		/* interrupts mask */
+#define  ENET_DMA_CH_CFG_INT_BUFF_DONE			0x00000001	/* buffer done */
+#define  ENET_DMA_CH_CFG_INT_DONE			0x00000002	/* packet xfer complete */
+#define  ENET_DMA_CH_CFG_INT_NO_DESC			0x00000004	/* no valid descriptors */
+#define  ENET_DMA_CH_CFG_INT_RX_ERROR			0x00000008	/* rxdma detect client protocol error */
+#define ENET_DMA_CH_CFG_MAX_BURST			0x0c		/* max burst length permitted */
+#define  ENET_DMA_CH_CFG_MAX_BURST_DESCSIZE_SEL		0x00040000	/* DMA Descriptor Size Selection */
+#define ENET_DMA_CH_CFG_SIZE				0x10
+
+#define ENET_DMA_CH_STATE_RAM_BASE_DESC_PTR		0x00		/* descriptor ring start address */
+#define ENET_DMA_CH_STATE_RAM_STATE_DATA		0x04		/* state/bytes done/ring offset */
+#define ENET_DMA_CH_STATE_RAM_DESC_LEN_STATUS		0x08		/* buffer descriptor status and len */
+#define ENET_DMA_CH_STATE_RAM_DESC_BASE_BUFPTR		0x0c		/* buffer descrpitor current processing */
+#define ENET_DMA_CH_STATE_RAM_SIZE			0x10
+
+#define DMA_CTL_STATUS_APPEND_CRC			0x00000100
+#define DMA_CTL_STATUS_APPEND_BRCM_TAG			0x00000200
+#define DMA_CTL_STATUS_PRIO				0x00000C00  /* Prio for Tx */
+#define DMA_CTL_STATUS_WRAP				0x00001000  /* */
+#define DMA_CTL_STATUS_SOP				0x00002000  /* first buffer in packet */
+#define DMA_CTL_STATUS_EOP				0x00004000  /* last buffer in packet */
+#define DMA_CTL_STATUS_OWN				0x00008000  /* cleared by DMA, set by SW */
+#define DMA_CTL_LEN_DESC_BUFLENGTH			0x0fff0000
+#define DMA_CTL_LEN_DESC_BUFLENGTH_SHIFT		16
+#define DMA_CTL_LEN_DESC_MULTICAST			0x40000000
+#define DMA_CTL_LEN_DESC_USEFPM				0x80000000
+
+#endif
-- 
2.26.2


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

* Re: [PATCH V3 net-next 2/2] net: broadcom: bcm4908_enet: add BCM4908 controller driver
  2021-02-09 23:01       ` [PATCH V3 net-next 2/2] net: broadcom: bcm4908_enet: add BCM4908 controller driver Rafał Miłecki
@ 2021-02-10  2:39         ` Andrew Lunn
  2021-02-10  7:57           ` Rafał Miłecki
  2021-02-10  9:47         ` [PATCH V4 net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller Rafał Miłecki
  2021-02-11 12:12         ` [PATCH net-next 5.12 0/8] bcm4908_enet: post-review fixes Rafał Miłecki
  2 siblings, 1 reply; 33+ messages in thread
From: Andrew Lunn @ 2021-02-10  2:39 UTC (permalink / raw)
  To: Rafał Miłecki
  Cc: David S . Miller, Jakub Kicinski, Rob Herring, Florian Fainelli,
	Randy Dunlap, Masahiro Yamada, netdev, devicetree,
	bcm-kernel-feedback-list, Rafał Miłecki

> +static inline u32 enet_read(struct bcm4908_enet *enet, u16 offset)
> +{
> +	return readl(enet->base + offset);
> +}

No inline functions in C files please. Let the compiler decide.

> +static int bcm4908_dma_alloc_buf_descs(struct bcm4908_enet *enet,
> +				       struct bcm4908_enet_dma_ring *ring)
> +{
> +	int size = ring->length * sizeof(struct bcm4908_enet_dma_ring_bd);
> +	struct device *dev = enet->dev;
> +
> +	ring->cpu_addr = dma_alloc_coherent(dev, size, &ring->dma_addr, GFP_KERNEL);
> +	if (!ring->cpu_addr)
> +		return -ENOMEM;
> +
> +	if (((uintptr_t)ring->cpu_addr) & (0x40 - 1)) {
> +		dev_err(dev, "Invalid DMA ring alignment\n");
> +		goto err_free_buf_descs;
> +	}
> +
> +	ring->slots = kzalloc(ring->length * sizeof(*ring->slots), GFP_KERNEL);
> +	if (!ring->slots)
> +		goto err_free_buf_descs;
> +
> +	memset(ring->cpu_addr, 0, size);

It looks like dma_alloc_coherent() will perform a clear. See __dma_alloc_from_coherent()

> +static void bcm4908_enet_dma_reset(struct bcm4908_enet *enet)
> +{
> +	struct bcm4908_enet_dma_ring *rings[] = { &enet->rx_ring, &enet->tx_ring };
> +	int i;
> +
> +	/* Disable the DMA controller and channel */
> +	for (i = 0; i < ARRAY_SIZE(rings); i++)
> +		enet_write(enet, rings[i]->cfg_block + ENET_DMA_CH_CFG, 0);
> +	enet_maskset(enet, ENET_DMA_CONTROLLER_CFG, ENET_DMA_CTRL_CFG_MASTER_EN, 0);

Is there a need to wait for any in flight DMA transfers to complete
before you go further? Or is that what
bcm4908_enet_dma_rx_ring_disable() is doing?

> +
> +	/* Reset channels state */
> +	for (i = 0; i < ARRAY_SIZE(rings); i++) {
> +		struct bcm4908_enet_dma_ring *ring = rings[i];
> +
> +		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_BASE_DESC_PTR, 0);
> +		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_STATE_DATA, 0);
> +		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_DESC_LEN_STATUS, 0);
> +		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_DESC_BASE_BUFPTR, 0);
> +	}
> +}
> +
> +static void bcm4908_enet_dma_tx_ring_ensable(struct bcm4908_enet *enet,
> +					     struct bcm4908_enet_dma_ring *ring)

enable not ensable?

> +static int bcm4908_enet_open(struct net_device *netdev)
> +{
> +	struct bcm4908_enet *enet = netdev_priv(netdev);
> +	struct device *dev = enet->dev;
> +	int err;
> +
> +	err = request_irq(netdev->irq, bcm4908_enet_irq_handler, 0, "enet", enet);
> +	if (err) {
> +		dev_err(dev, "Failed to request IRQ %d: %d\n", netdev->irq, err);
> +		return err;
> +	}
> +
> +	bcm4908_enet_gmac_init(enet);
> +	bcm4908_enet_dma_reset(enet);
> +	bcm4908_enet_dma_init(enet);
> +
> +	enet_umac_set(enet, UMAC_CMD, CMD_TX_EN | CMD_RX_EN);
> +
> +	enet_set(enet, ENET_DMA_CONTROLLER_CFG, ENET_DMA_CTRL_CFG_MASTER_EN);
> +	enet_maskset(enet, ENET_DMA_CONTROLLER_CFG, ENET_DMA_CTRL_CFG_FLOWC_CH1_EN, 0);
> +	bcm4908_enet_dma_rx_ring_enable(enet, &enet->rx_ring);
> +
> +	napi_enable(&enet->napi);
> +	netif_carrier_on(netdev);
> +	netif_start_queue(netdev);
> +
> +	bcm4908_enet_intrs_ack(enet);
> +	bcm4908_enet_intrs_on(enet);
> +
> +	return 0;
> +}

No PHY handling? It would be normal to connect the phy in open.

   Andrew

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

* Re: [PATCH V3 net-next 2/2] net: broadcom: bcm4908_enet: add BCM4908 controller driver
  2021-02-10  2:39         ` Andrew Lunn
@ 2021-02-10  7:57           ` Rafał Miłecki
  0 siblings, 0 replies; 33+ messages in thread
From: Rafał Miłecki @ 2021-02-10  7:57 UTC (permalink / raw)
  To: Andrew Lunn, Rafał Miłecki
  Cc: David S . Miller, Jakub Kicinski, Rob Herring, Florian Fainelli,
	Randy Dunlap, Masahiro Yamada, netdev, devicetree,
	bcm-kernel-feedback-list

On 10.02.2021 03:39, Andrew Lunn wrote:
>> +static inline u32 enet_read(struct bcm4908_enet *enet, u16 offset)
>> +{
>> +	return readl(enet->base + offset);
>> +}
> 
> No inline functions in C files please. Let the compiler decide.

According to the kernel's coding style (coding-style.rst) inline should
*not* be used for 3+ LOC functions in general. According to that, I should
only fix my enet_maskset() which isn't 1 LOC indeed.

If that Documentation is outdated and/or inaccurate, could you propose a
change for it, please? That rule comes from 2006 (a771f2b82aa2), so I
understand it may need updating. We should have that officially documented
though, to avoid per-tree or per-maintainer rules for stuff like this.

Personally I don't have enough compiler knowledge to propose and/or discuss
such stuff. That's why I prefer following Documentation written by smarter
ones ;)


>> +static int bcm4908_dma_alloc_buf_descs(struct bcm4908_enet *enet,
>> +				       struct bcm4908_enet_dma_ring *ring)
>> +{
>> +	int size = ring->length * sizeof(struct bcm4908_enet_dma_ring_bd);
>> +	struct device *dev = enet->dev;
>> +
>> +	ring->cpu_addr = dma_alloc_coherent(dev, size, &ring->dma_addr, GFP_KERNEL);
>> +	if (!ring->cpu_addr)
>> +		return -ENOMEM;
>> +
>> +	if (((uintptr_t)ring->cpu_addr) & (0x40 - 1)) {
>> +		dev_err(dev, "Invalid DMA ring alignment\n");
>> +		goto err_free_buf_descs;
>> +	}
>> +
>> +	ring->slots = kzalloc(ring->length * sizeof(*ring->slots), GFP_KERNEL);
>> +	if (!ring->slots)
>> +		goto err_free_buf_descs;
>> +
>> +	memset(ring->cpu_addr, 0, size);
> 
> It looks like dma_alloc_coherent() will perform a clear. See __dma_alloc_from_coherent()

Thanks!


>> +static void bcm4908_enet_dma_reset(struct bcm4908_enet *enet)
>> +{
>> +	struct bcm4908_enet_dma_ring *rings[] = { &enet->rx_ring, &enet->tx_ring };
>> +	int i;
>> +
>> +	/* Disable the DMA controller and channel */
>> +	for (i = 0; i < ARRAY_SIZE(rings); i++)
>> +		enet_write(enet, rings[i]->cfg_block + ENET_DMA_CH_CFG, 0);
>> +	enet_maskset(enet, ENET_DMA_CONTROLLER_CFG, ENET_DMA_CTRL_CFG_MASTER_EN, 0);
> 
> Is there a need to wait for any in flight DMA transfers to complete
> before you go further? Or is that what
> bcm4908_enet_dma_rx_ring_disable() is doing?

bcm4908_enet_dma_rx_ring_disable() checks for DMA to "confirm" it got stopped.


>> +
>> +	/* Reset channels state */
>> +	for (i = 0; i < ARRAY_SIZE(rings); i++) {
>> +		struct bcm4908_enet_dma_ring *ring = rings[i];
>> +
>> +		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_BASE_DESC_PTR, 0);
>> +		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_STATE_DATA, 0);
>> +		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_DESC_LEN_STATUS, 0);
>> +		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_DESC_BASE_BUFPTR, 0);
>> +	}
>> +}
>> +
>> +static void bcm4908_enet_dma_tx_ring_ensable(struct bcm4908_enet *enet,
>> +					     struct bcm4908_enet_dma_ring *ring)
> 
> enable not ensable?

Absolutely :)


>> +static int bcm4908_enet_open(struct net_device *netdev)
>> +{
>> +	struct bcm4908_enet *enet = netdev_priv(netdev);
>> +	struct device *dev = enet->dev;
>> +	int err;
>> +
>> +	err = request_irq(netdev->irq, bcm4908_enet_irq_handler, 0, "enet", enet);
>> +	if (err) {
>> +		dev_err(dev, "Failed to request IRQ %d: %d\n", netdev->irq, err);
>> +		return err;
>> +	}
>> +
>> +	bcm4908_enet_gmac_init(enet);
>> +	bcm4908_enet_dma_reset(enet);
>> +	bcm4908_enet_dma_init(enet);
>> +
>> +	enet_umac_set(enet, UMAC_CMD, CMD_TX_EN | CMD_RX_EN);
>> +
>> +	enet_set(enet, ENET_DMA_CONTROLLER_CFG, ENET_DMA_CTRL_CFG_MASTER_EN);
>> +	enet_maskset(enet, ENET_DMA_CONTROLLER_CFG, ENET_DMA_CTRL_CFG_FLOWC_CH1_EN, 0);
>> +	bcm4908_enet_dma_rx_ring_enable(enet, &enet->rx_ring);
>> +
>> +	napi_enable(&enet->napi);
>> +	netif_carrier_on(netdev);
>> +	netif_start_queue(netdev);
>> +
>> +	bcm4908_enet_intrs_ack(enet);
>> +	bcm4908_enet_intrs_on(enet);
>> +
>> +	return 0;
>> +}
> 
> No PHY handling? It would be normal to connect the phy in open.

I believe so, this controller is integrated into SoC and is always connected
to the (internal) switch port. It uses a fixed link.

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

* [PATCH V4 net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller
  2021-02-09 23:01       ` [PATCH V3 net-next 2/2] net: broadcom: bcm4908_enet: add BCM4908 controller driver Rafał Miłecki
  2021-02-10  2:39         ` Andrew Lunn
@ 2021-02-10  9:47         ` Rafał Miłecki
  2021-02-10  9:47           ` [PATCH V4 net-next 2/2] net: broadcom: bcm4908_enet: add BCM4908 controller driver Rafał Miłecki
  2021-02-11 12:12         ` [PATCH net-next 5.12 0/8] bcm4908_enet: post-review fixes Rafał Miłecki
  2 siblings, 1 reply; 33+ messages in thread
From: Rafał Miłecki @ 2021-02-10  9:47 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Florian Fainelli, Randy Dunlap, Masahiro Yamada, netdev,
	devicetree, bcm-kernel-feedback-list, Rafał Miłecki

From: Rafał Miłecki <rafal@milecki.pl>

BCM4908 is a family of SoCs with integrated Ethernet controller.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
V3: Use ethernet-controller.yaml#
    Rename "compatible" value (use "-")
    Drop "interrupt-names" until it's needed
---
 .../bindings/net/brcm,bcm4908-enet.yaml       | 43 +++++++++++++++++++
 1 file changed, 43 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/brcm,bcm4908-enet.yaml

diff --git a/Documentation/devicetree/bindings/net/brcm,bcm4908-enet.yaml b/Documentation/devicetree/bindings/net/brcm,bcm4908-enet.yaml
new file mode 100644
index 000000000000..5050974c8550
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/brcm,bcm4908-enet.yaml
@@ -0,0 +1,43 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/brcm,bcm4908-enet.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Broadcom BCM4908 Ethernet controller
+
+description: Broadcom's Ethernet controller integrated into BCM4908 family SoCs
+
+maintainers:
+  - Rafał Miłecki <rafal@milecki.pl>
+
+allOf:
+  - $ref: ethernet-controller.yaml#
+
+properties:
+  compatible:
+    const: brcm,bcm4908-enet
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    description: RX interrupt
+
+required:
+  - reg
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    ethernet@80002000 {
+        compatible = "brcm,bcm4908-enet";
+        reg = <0x80002000 0x1000>;
+
+        interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+    };
-- 
2.26.2


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

* [PATCH V4 net-next 2/2] net: broadcom: bcm4908_enet: add BCM4908 controller driver
  2021-02-10  9:47         ` [PATCH V4 net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller Rafał Miłecki
@ 2021-02-10  9:47           ` Rafał Miłecki
  2021-02-11  0:44             ` Andrew Lunn
  0 siblings, 1 reply; 33+ messages in thread
From: Rafał Miłecki @ 2021-02-10  9:47 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Florian Fainelli, Randy Dunlap, Masahiro Yamada, netdev,
	devicetree, bcm-kernel-feedback-list, Rafał Miłecki

From: Rafał Miłecki <rafal@milecki.pl>

BCM4908 SoCs family has integrated Ethernel controller that includes
UniMAC but uses different DMA engine (than other controllers) and
requires different programming.

Ethernet controller in BCM4908 is always connected to the internal SF2
switch's port and uses fixed link.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
V2: Use cpu_to_le32()
    Reported-by: kernel test robot <lkp@intel.com>
    Add "depends" to the Kconfig
V3: Rename using "_enet" (with underscore)
    One more cpu_to_le32()
    Replace magic number with ETH_FCS_LEN
    Add kfree_skb() to fix potential memory leak
V4: Drop "inline" from C functions
    Drop unneeded memset() call
    Drop unused enet_umac_maskset()
    Fix typo in "enable"
    Update commit description
---
 MAINTAINERS                                  |   9 +
 drivers/net/ethernet/broadcom/Kconfig        |   8 +
 drivers/net/ethernet/broadcom/Makefile       |   1 +
 drivers/net/ethernet/broadcom/bcm4908_enet.c | 671 +++++++++++++++++++
 drivers/net/ethernet/broadcom/bcm4908_enet.h |  96 +++
 5 files changed, 785 insertions(+)
 create mode 100644 drivers/net/ethernet/broadcom/bcm4908_enet.c
 create mode 100644 drivers/net/ethernet/broadcom/bcm4908_enet.h

diff --git a/MAINTAINERS b/MAINTAINERS
index d1b0057a9797..0e2489c630f8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3445,6 +3445,15 @@ F:	Documentation/devicetree/bindings/mips/brcm/
 F:	arch/mips/bcm47xx/*
 F:	arch/mips/include/asm/mach-bcm47xx/*
 
+BROADCOM BCM4908 ETHERNET DRIVER
+M:	Rafał Miłecki <rafal@milecki.pl>
+M:	bcm-kernel-feedback-list@broadcom.com
+L:	netdev@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/net/brcm,bcm4908-enet.yaml
+F:	drivers/net/ethernet/broadcom/bcm4908_enet.*
+F:	drivers/net/ethernet/broadcom/unimac.h
+
 BROADCOM BCM5301X ARM ARCHITECTURE
 M:	Hauke Mehrtens <hauke@hauke-m.de>
 M:	Rafał Miłecki <zajec5@gmail.com>
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index 4bdf8fbe75a6..d1e439cc2eab 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -51,6 +51,14 @@ config B44_PCI
 	depends on B44_PCI_AUTOSELECT && B44_PCICORE_AUTOSELECT
 	default y
 
+config BCM4908_ENET
+	tristate "Broadcom BCM4908 internal mac support"
+	depends on ARCH_BCM4908 || COMPILE_TEST
+	default ARCH_BCM4908
+	help
+	  This driver supports Ethernet controller integrated into Broadcom
+	  BCM4908 family SoCs.
+
 config BCM63XX_ENET
 	tristate "Broadcom 63xx internal mac support"
 	depends on BCM63XX
diff --git a/drivers/net/ethernet/broadcom/Makefile b/drivers/net/ethernet/broadcom/Makefile
index 7046ad6d3d0e..0ddfb5b5d53c 100644
--- a/drivers/net/ethernet/broadcom/Makefile
+++ b/drivers/net/ethernet/broadcom/Makefile
@@ -4,6 +4,7 @@
 #
 
 obj-$(CONFIG_B44) += b44.o
+obj-$(CONFIG_BCM4908_ENET) += bcm4908_enet.o
 obj-$(CONFIG_BCM63XX_ENET) += bcm63xx_enet.o
 obj-$(CONFIG_BCMGENET) += genet/
 obj-$(CONFIG_BNX2) += bnx2.o
diff --git a/drivers/net/ethernet/broadcom/bcm4908_enet.c b/drivers/net/ethernet/broadcom/bcm4908_enet.c
new file mode 100644
index 000000000000..414809c5b923
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/bcm4908_enet.c
@@ -0,0 +1,671 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2021 Rafał Miłecki <rafal@milecki.pl>
+ */
+
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include "bcm4908_enet.h"
+#include "unimac.h"
+
+#define ENET_DMA_CH_RX_CFG			ENET_DMA_CH0_CFG
+#define ENET_DMA_CH_TX_CFG			ENET_DMA_CH1_CFG
+#define ENET_DMA_CH_RX_STATE_RAM		ENET_DMA_CH0_STATE_RAM
+#define ENET_DMA_CH_TX_STATE_RAM		ENET_DMA_CH1_STATE_RAM
+
+#define ENET_TX_BDS_NUM				200
+#define ENET_RX_BDS_NUM				200
+#define ENET_RX_BDS_NUM_MAX			8192
+
+#define ENET_DMA_INT_DEFAULTS			(ENET_DMA_CH_CFG_INT_DONE | \
+						 ENET_DMA_CH_CFG_INT_NO_DESC | \
+						 ENET_DMA_CH_CFG_INT_BUFF_DONE)
+#define ENET_DMA_MAX_BURST_LEN			8 /* in 64 bit words */
+
+#define ENET_MTU_MIN				60
+#define ENET_MTU_MAX				1500 /* Is it possible to support 2044? */
+#define ENET_MTU_MAX_EXTRA_SIZE			32 /* L2 */
+
+struct bcm4908_enet_dma_ring_bd {
+	__le32 ctl;
+	__le32 addr;
+} __packed;
+
+struct bcm4908_enet_dma_ring_slot {
+	struct sk_buff *skb;
+	unsigned int len;
+	dma_addr_t dma_addr;
+};
+
+struct bcm4908_enet_dma_ring {
+	int is_tx;
+	int read_idx;
+	int write_idx;
+	int length;
+	u16 cfg_block;
+	u16 st_ram_block;
+
+	union {
+		void *cpu_addr;
+		struct bcm4908_enet_dma_ring_bd *buf_desc;
+	};
+	dma_addr_t dma_addr;
+
+	struct bcm4908_enet_dma_ring_slot *slots;
+};
+
+struct bcm4908_enet {
+	struct device *dev;
+	struct net_device *netdev;
+	struct napi_struct napi;
+	void __iomem *base;
+
+	struct bcm4908_enet_dma_ring tx_ring;
+	struct bcm4908_enet_dma_ring rx_ring;
+};
+
+/***
+ * R/W ops
+ */
+
+static u32 enet_read(struct bcm4908_enet *enet, u16 offset)
+{
+	return readl(enet->base + offset);
+}
+
+static void enet_write(struct bcm4908_enet *enet, u16 offset, u32 value)
+{
+	writel(value, enet->base + offset);
+}
+
+static void enet_maskset(struct bcm4908_enet *enet, u16 offset, u32 mask, u32 set)
+{
+	u32 val;
+
+	WARN_ON(set & ~mask);
+
+	val = enet_read(enet, offset);
+	val = (val & ~mask) | (set & mask);
+	enet_write(enet, offset, val);
+}
+
+static void enet_set(struct bcm4908_enet *enet, u16 offset, u32 set)
+{
+	enet_maskset(enet, offset, set, set);
+}
+
+static u32 enet_umac_read(struct bcm4908_enet *enet, u16 offset)
+{
+	return enet_read(enet, ENET_UNIMAC + offset);
+}
+
+static void enet_umac_write(struct bcm4908_enet *enet, u16 offset, u32 value)
+{
+	enet_write(enet, ENET_UNIMAC + offset, value);
+}
+
+static void enet_umac_set(struct bcm4908_enet *enet, u16 offset, u32 set)
+{
+	enet_set(enet, ENET_UNIMAC + offset, set);
+}
+
+/***
+ * Helpers
+ */
+
+static void bcm4908_enet_intrs_on(struct bcm4908_enet *enet)
+{
+	enet_write(enet, ENET_DMA_CH_RX_CFG + ENET_DMA_CH_CFG_INT_MASK, ENET_DMA_INT_DEFAULTS);
+}
+
+static void bcm4908_enet_intrs_off(struct bcm4908_enet *enet)
+{
+	enet_write(enet, ENET_DMA_CH_RX_CFG + ENET_DMA_CH_CFG_INT_MASK, 0);
+}
+
+static void bcm4908_enet_intrs_ack(struct bcm4908_enet *enet)
+{
+	enet_write(enet, ENET_DMA_CH_RX_CFG + ENET_DMA_CH_CFG_INT_STAT, ENET_DMA_INT_DEFAULTS);
+}
+
+/***
+ * DMA
+ */
+
+static int bcm4908_dma_alloc_buf_descs(struct bcm4908_enet *enet,
+				       struct bcm4908_enet_dma_ring *ring)
+{
+	int size = ring->length * sizeof(struct bcm4908_enet_dma_ring_bd);
+	struct device *dev = enet->dev;
+
+	ring->cpu_addr = dma_alloc_coherent(dev, size, &ring->dma_addr, GFP_KERNEL);
+	if (!ring->cpu_addr)
+		return -ENOMEM;
+
+	if (((uintptr_t)ring->cpu_addr) & (0x40 - 1)) {
+		dev_err(dev, "Invalid DMA ring alignment\n");
+		goto err_free_buf_descs;
+	}
+
+	ring->slots = kzalloc(ring->length * sizeof(*ring->slots), GFP_KERNEL);
+	if (!ring->slots)
+		goto err_free_buf_descs;
+
+	ring->read_idx = 0;
+	ring->write_idx = 0;
+
+	return 0;
+
+err_free_buf_descs:
+	dma_free_coherent(dev, size, ring->cpu_addr, ring->dma_addr);
+	return -ENOMEM;
+}
+
+static void bcm4908_enet_dma_free(struct bcm4908_enet *enet)
+{
+	struct bcm4908_enet_dma_ring *tx_ring = &enet->tx_ring;
+	struct bcm4908_enet_dma_ring *rx_ring = &enet->rx_ring;
+	struct device *dev = enet->dev;
+	int size;
+
+	size = rx_ring->length * sizeof(struct bcm4908_enet_dma_ring_bd);
+	if (rx_ring->cpu_addr)
+		dma_free_coherent(dev, size, rx_ring->cpu_addr, rx_ring->dma_addr);
+	kfree(rx_ring->slots);
+
+	size = tx_ring->length * sizeof(struct bcm4908_enet_dma_ring_bd);
+	if (tx_ring->cpu_addr)
+		dma_free_coherent(dev, size, tx_ring->cpu_addr, tx_ring->dma_addr);
+	kfree(tx_ring->slots);
+}
+
+static int bcm4908_enet_dma_alloc(struct bcm4908_enet *enet)
+{
+	struct bcm4908_enet_dma_ring *tx_ring = &enet->tx_ring;
+	struct bcm4908_enet_dma_ring *rx_ring = &enet->rx_ring;
+	struct device *dev = enet->dev;
+	int err;
+
+	tx_ring->length = ENET_TX_BDS_NUM;
+	tx_ring->is_tx = 1;
+	tx_ring->cfg_block = ENET_DMA_CH_TX_CFG;
+	tx_ring->st_ram_block = ENET_DMA_CH_TX_STATE_RAM;
+	err = bcm4908_dma_alloc_buf_descs(enet, tx_ring);
+	if (err) {
+		dev_err(dev, "Failed to alloc TX buf descriptors: %d\n", err);
+		return err;
+	}
+
+	rx_ring->length = ENET_RX_BDS_NUM;
+	rx_ring->is_tx = 0;
+	rx_ring->cfg_block = ENET_DMA_CH_RX_CFG;
+	rx_ring->st_ram_block = ENET_DMA_CH_RX_STATE_RAM;
+	err = bcm4908_dma_alloc_buf_descs(enet, rx_ring);
+	if (err) {
+		dev_err(dev, "Failed to alloc RX buf descriptors: %d\n", err);
+		bcm4908_enet_dma_free(enet);
+		return err;
+	}
+
+	return 0;
+}
+
+static void bcm4908_enet_dma_reset(struct bcm4908_enet *enet)
+{
+	struct bcm4908_enet_dma_ring *rings[] = { &enet->rx_ring, &enet->tx_ring };
+	int i;
+
+	/* Disable the DMA controller and channel */
+	for (i = 0; i < ARRAY_SIZE(rings); i++)
+		enet_write(enet, rings[i]->cfg_block + ENET_DMA_CH_CFG, 0);
+	enet_maskset(enet, ENET_DMA_CONTROLLER_CFG, ENET_DMA_CTRL_CFG_MASTER_EN, 0);
+
+	/* Reset channels state */
+	for (i = 0; i < ARRAY_SIZE(rings); i++) {
+		struct bcm4908_enet_dma_ring *ring = rings[i];
+
+		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_BASE_DESC_PTR, 0);
+		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_STATE_DATA, 0);
+		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_DESC_LEN_STATUS, 0);
+		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_DESC_BASE_BUFPTR, 0);
+	}
+}
+
+static int bcm4908_enet_dma_alloc_rx_buf(struct bcm4908_enet *enet, unsigned int idx)
+{
+	struct bcm4908_enet_dma_ring_bd *buf_desc = &enet->rx_ring.buf_desc[idx];
+	struct bcm4908_enet_dma_ring_slot *slot = &enet->rx_ring.slots[idx];
+	struct device *dev = enet->dev;
+	u32 tmp;
+	int err;
+
+	slot->len = ENET_MTU_MAX + ENET_MTU_MAX_EXTRA_SIZE;
+
+	slot->skb = netdev_alloc_skb(enet->netdev, slot->len);
+	if (!slot->skb)
+		return -ENOMEM;
+
+	slot->dma_addr = dma_map_single(dev, slot->skb->data, slot->len, DMA_FROM_DEVICE);
+	err = dma_mapping_error(dev, slot->dma_addr);
+	if (err) {
+		dev_err(dev, "Failed to map DMA buffer: %d\n", err);
+		kfree_skb(slot->skb);
+		slot->skb = NULL;
+		return err;
+	}
+
+	tmp = slot->len << DMA_CTL_LEN_DESC_BUFLENGTH_SHIFT;
+	tmp |= DMA_CTL_STATUS_OWN;
+	if (idx == enet->rx_ring.length - 1)
+		tmp |= DMA_CTL_STATUS_WRAP;
+	buf_desc->ctl = cpu_to_le32(tmp);
+	buf_desc->addr = cpu_to_le32(slot->dma_addr);
+
+	return 0;
+}
+
+static void bcm4908_enet_dma_ring_init(struct bcm4908_enet *enet,
+				       struct bcm4908_enet_dma_ring *ring)
+{
+	int reset_channel = 0; /* We support only 1 main channel (with TX and RX) */
+	int reset_subch = ring->is_tx ? 1 : 0;
+
+	/* Reset the DMA channel */
+	enet_write(enet, ENET_DMA_CTRL_CHANNEL_RESET, BIT(reset_channel * 2 + reset_subch));
+	enet_write(enet, ENET_DMA_CTRL_CHANNEL_RESET, 0);
+
+	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG, 0);
+	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG_MAX_BURST, ENET_DMA_MAX_BURST_LEN);
+	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG_INT_MASK, 0);
+
+	enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_BASE_DESC_PTR,
+		   (uint32_t)ring->dma_addr);
+}
+
+static void bcm4908_enet_dma_uninit(struct bcm4908_enet *enet)
+{
+	struct bcm4908_enet_dma_ring *rx_ring = &enet->rx_ring;
+	struct bcm4908_enet_dma_ring_slot *slot;
+	struct device *dev = enet->dev;
+	int i;
+
+	for (i = rx_ring->length - 1; i >= 0; i--) {
+		slot = &rx_ring->slots[i];
+		if (!slot->skb)
+			continue;
+		dma_unmap_single(dev, slot->dma_addr, slot->len, DMA_FROM_DEVICE);
+		kfree_skb(slot->skb);
+		slot->skb = NULL;
+	}
+}
+
+static int bcm4908_enet_dma_init(struct bcm4908_enet *enet)
+{
+	struct bcm4908_enet_dma_ring *rx_ring = &enet->rx_ring;
+	struct device *dev = enet->dev;
+	int err;
+	int i;
+
+	for (i = 0; i < rx_ring->length; i++) {
+		err = bcm4908_enet_dma_alloc_rx_buf(enet, i);
+		if (err) {
+			dev_err(dev, "Failed to alloc RX buffer: %d\n", err);
+			bcm4908_enet_dma_uninit(enet);
+			return err;
+		}
+	}
+
+	bcm4908_enet_dma_ring_init(enet, &enet->tx_ring);
+	bcm4908_enet_dma_ring_init(enet, &enet->rx_ring);
+
+	return 0;
+}
+
+static void bcm4908_enet_dma_tx_ring_enable(struct bcm4908_enet *enet,
+					    struct bcm4908_enet_dma_ring *ring)
+{
+	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG, ENET_DMA_CH_CFG_ENABLE);
+}
+
+static void bcm4908_enet_dma_tx_ring_disable(struct bcm4908_enet *enet,
+					     struct bcm4908_enet_dma_ring *ring)
+{
+	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG, 0);
+}
+
+static void bcm4908_enet_dma_rx_ring_enable(struct bcm4908_enet *enet,
+					    struct bcm4908_enet_dma_ring *ring)
+{
+	enet_set(enet, ring->cfg_block + ENET_DMA_CH_CFG, ENET_DMA_CH_CFG_ENABLE);
+}
+
+static void bcm4908_enet_dma_rx_ring_disable(struct bcm4908_enet *enet,
+					     struct bcm4908_enet_dma_ring *ring)
+{
+	unsigned long deadline;
+	u32 tmp;
+
+	enet_maskset(enet, ring->cfg_block + ENET_DMA_CH_CFG, ENET_DMA_CH_CFG_ENABLE, 0);
+
+	deadline = jiffies + usecs_to_jiffies(2000);
+	do {
+		tmp = enet_read(enet, ring->cfg_block + ENET_DMA_CH_CFG);
+		if (!(tmp & ENET_DMA_CH_CFG_ENABLE))
+			return;
+		enet_maskset(enet, ring->cfg_block + ENET_DMA_CH_CFG, ENET_DMA_CH_CFG_ENABLE, 0);
+		usleep_range(10, 30);
+	} while (!time_after_eq(jiffies, deadline));
+
+	dev_warn(enet->dev, "Timeout waiting for DMA TX stop\n");
+}
+
+/***
+ * Ethernet driver
+ */
+
+static void bcm4908_enet_gmac_init(struct bcm4908_enet *enet)
+{
+	u32 cmd;
+
+	cmd = enet_umac_read(enet, UMAC_CMD);
+	enet_umac_write(enet, UMAC_CMD, cmd | CMD_SW_RESET);
+	enet_umac_write(enet, UMAC_CMD, cmd & ~CMD_SW_RESET);
+
+	enet_set(enet, ENET_FLUSH, ENET_FLUSH_RXFIFO_FLUSH | ENET_FLUSH_TXFIFO_FLUSH);
+	enet_maskset(enet, ENET_FLUSH, ENET_FLUSH_RXFIFO_FLUSH | ENET_FLUSH_TXFIFO_FLUSH, 0);
+
+	enet_set(enet, ENET_MIB_CTRL, ENET_MIB_CTRL_CLR_MIB);
+	enet_maskset(enet, ENET_MIB_CTRL, ENET_MIB_CTRL_CLR_MIB, 0);
+
+	cmd = enet_umac_read(enet, UMAC_CMD);
+	cmd &= ~(CMD_SPEED_MASK << CMD_SPEED_SHIFT);
+	cmd &= ~CMD_TX_EN;
+	cmd &= ~CMD_RX_EN;
+	cmd |= CMD_SPEED_1000 << CMD_SPEED_SHIFT;
+	enet_umac_write(enet, UMAC_CMD, cmd);
+
+	enet_maskset(enet, ENET_GMAC_STATUS,
+		     ENET_GMAC_STATUS_ETH_SPEED_MASK |
+		     ENET_GMAC_STATUS_HD |
+		     ENET_GMAC_STATUS_AUTO_CFG_EN |
+		     ENET_GMAC_STATUS_LINK_UP,
+		     ENET_GMAC_STATUS_ETH_SPEED_1000 |
+		     ENET_GMAC_STATUS_AUTO_CFG_EN |
+		     ENET_GMAC_STATUS_LINK_UP);
+}
+
+static irqreturn_t bcm4908_enet_irq_handler(int irq, void *dev_id)
+{
+	struct bcm4908_enet *enet = dev_id;
+
+	bcm4908_enet_intrs_off(enet);
+	bcm4908_enet_intrs_ack(enet);
+
+	napi_schedule(&enet->napi);
+
+	return IRQ_HANDLED;
+}
+
+static int bcm4908_enet_open(struct net_device *netdev)
+{
+	struct bcm4908_enet *enet = netdev_priv(netdev);
+	struct device *dev = enet->dev;
+	int err;
+
+	err = request_irq(netdev->irq, bcm4908_enet_irq_handler, 0, "enet", enet);
+	if (err) {
+		dev_err(dev, "Failed to request IRQ %d: %d\n", netdev->irq, err);
+		return err;
+	}
+
+	bcm4908_enet_gmac_init(enet);
+	bcm4908_enet_dma_reset(enet);
+	bcm4908_enet_dma_init(enet);
+
+	enet_umac_set(enet, UMAC_CMD, CMD_TX_EN | CMD_RX_EN);
+
+	enet_set(enet, ENET_DMA_CONTROLLER_CFG, ENET_DMA_CTRL_CFG_MASTER_EN);
+	enet_maskset(enet, ENET_DMA_CONTROLLER_CFG, ENET_DMA_CTRL_CFG_FLOWC_CH1_EN, 0);
+	bcm4908_enet_dma_rx_ring_enable(enet, &enet->rx_ring);
+
+	napi_enable(&enet->napi);
+	netif_carrier_on(netdev);
+	netif_start_queue(netdev);
+
+	bcm4908_enet_intrs_ack(enet);
+	bcm4908_enet_intrs_on(enet);
+
+	return 0;
+}
+
+static int bcm4908_enet_stop(struct net_device *netdev)
+{
+	struct bcm4908_enet *enet = netdev_priv(netdev);
+
+	netif_stop_queue(netdev);
+	netif_carrier_off(netdev);
+	napi_disable(&enet->napi);
+
+	bcm4908_enet_dma_rx_ring_disable(enet, &enet->rx_ring);
+	bcm4908_enet_dma_tx_ring_disable(enet, &enet->tx_ring);
+
+	bcm4908_enet_dma_uninit(enet);
+
+	free_irq(enet->netdev->irq, enet);
+
+	return 0;
+}
+
+static int bcm4908_enet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct bcm4908_enet *enet = netdev_priv(netdev);
+	struct bcm4908_enet_dma_ring *ring = &enet->tx_ring;
+	struct bcm4908_enet_dma_ring_slot *slot;
+	struct device *dev = enet->dev;
+	struct bcm4908_enet_dma_ring_bd *buf_desc;
+	int free_buf_descs;
+	u32 tmp;
+
+	/* Free transmitted skbs */
+	while (ring->read_idx != ring->write_idx) {
+		buf_desc = &ring->buf_desc[ring->read_idx];
+		if (le32_to_cpu(buf_desc->ctl) & DMA_CTL_STATUS_OWN)
+			break;
+		slot = &ring->slots[ring->read_idx];
+
+		dma_unmap_single(dev, slot->dma_addr, slot->len, DMA_TO_DEVICE);
+		dev_kfree_skb(slot->skb);
+		if (++ring->read_idx == ring->length)
+			ring->read_idx = 0;
+	}
+
+	/* Don't use the last empty buf descriptor */
+	if (ring->read_idx <= ring->write_idx)
+		free_buf_descs = ring->read_idx - ring->write_idx + ring->length;
+	else
+		free_buf_descs = ring->read_idx - ring->write_idx;
+	if (free_buf_descs < 2)
+		return NETDEV_TX_BUSY;
+
+	/* Hardware removes OWN bit after sending data */
+	buf_desc = &ring->buf_desc[ring->write_idx];
+	if (unlikely(le32_to_cpu(buf_desc->ctl) & DMA_CTL_STATUS_OWN)) {
+		netif_stop_queue(netdev);
+		return NETDEV_TX_BUSY;
+	}
+
+	slot = &ring->slots[ring->write_idx];
+	slot->skb = skb;
+	slot->len = skb->len;
+	slot->dma_addr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE);
+	if (unlikely(dma_mapping_error(dev, slot->dma_addr)))
+		return NETDEV_TX_BUSY;
+
+	tmp = skb->len << DMA_CTL_LEN_DESC_BUFLENGTH_SHIFT;
+	tmp |= DMA_CTL_STATUS_OWN;
+	tmp |= DMA_CTL_STATUS_SOP;
+	tmp |= DMA_CTL_STATUS_EOP;
+	tmp |= DMA_CTL_STATUS_APPEND_CRC;
+	if (ring->write_idx + 1 == ring->length - 1)
+		tmp |= DMA_CTL_STATUS_WRAP;
+
+	buf_desc->addr = cpu_to_le32((uint32_t)slot->dma_addr);
+	buf_desc->ctl = cpu_to_le32(tmp);
+
+	bcm4908_enet_dma_tx_ring_enable(enet, &enet->tx_ring);
+
+	if (++ring->write_idx == ring->length - 1)
+		ring->write_idx = 0;
+	enet->netdev->stats.tx_bytes += skb->len;
+	enet->netdev->stats.tx_packets++;
+
+	return NETDEV_TX_OK;
+}
+
+static int bcm4908_enet_poll(struct napi_struct *napi, int weight)
+{
+	struct bcm4908_enet *enet = container_of(napi, struct bcm4908_enet, napi);
+	struct device *dev = enet->dev;
+	int handled = 0;
+
+	while (handled < weight) {
+		struct bcm4908_enet_dma_ring_bd *buf_desc;
+		struct bcm4908_enet_dma_ring_slot slot;
+		u32 ctl;
+		int len;
+		int err;
+
+		buf_desc = &enet->rx_ring.buf_desc[enet->rx_ring.read_idx];
+		ctl = le32_to_cpu(buf_desc->ctl);
+		if (ctl & DMA_CTL_STATUS_OWN)
+			break;
+
+		slot = enet->rx_ring.slots[enet->rx_ring.read_idx];
+
+		/* Provide new buffer before unpinning the old one */
+		err = bcm4908_enet_dma_alloc_rx_buf(enet, enet->rx_ring.read_idx);
+		if (err)
+			break;
+
+		if (++enet->rx_ring.read_idx == enet->rx_ring.length)
+			enet->rx_ring.read_idx = 0;
+
+		len = (ctl & DMA_CTL_LEN_DESC_BUFLENGTH) >> DMA_CTL_LEN_DESC_BUFLENGTH_SHIFT;
+
+		if (len < ENET_MTU_MIN ||
+		    (ctl & (DMA_CTL_STATUS_SOP | DMA_CTL_STATUS_EOP)) != (DMA_CTL_STATUS_SOP | DMA_CTL_STATUS_EOP)) {
+			kfree(slot.skb);
+			enet->netdev->stats.rx_dropped++;
+			break;
+		}
+
+		dma_unmap_single(dev, slot.dma_addr, slot.len, DMA_FROM_DEVICE);
+
+		skb_put(slot.skb, len - ETH_FCS_LEN);
+		slot.skb->protocol = eth_type_trans(slot.skb, enet->netdev);
+		netif_receive_skb(slot.skb);
+
+		enet->netdev->stats.rx_packets++;
+		enet->netdev->stats.rx_bytes += len;
+	}
+
+	if (handled < weight) {
+		napi_complete_done(napi, handled);
+		bcm4908_enet_intrs_on(enet);
+	}
+
+	return handled;
+}
+
+static const struct net_device_ops bcm4908_enet_netdev_ops = {
+	.ndo_open = bcm4908_enet_open,
+	.ndo_stop = bcm4908_enet_stop,
+	.ndo_start_xmit = bcm4908_enet_start_xmit,
+	.ndo_set_mac_address = eth_mac_addr,
+};
+
+static int bcm4908_enet_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct net_device *netdev;
+	struct bcm4908_enet *enet;
+	int err;
+
+	netdev = devm_alloc_etherdev(dev, sizeof(*enet));
+	if (!netdev)
+		return -ENOMEM;
+
+	enet = netdev_priv(netdev);
+	enet->dev = dev;
+	enet->netdev = netdev;
+
+	enet->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(enet->base)) {
+		dev_err(dev, "Failed to map registers: %ld\n", PTR_ERR(enet->base));
+		return PTR_ERR(enet->base);
+	}
+
+	netdev->irq = platform_get_irq(pdev, 0);
+	if (netdev->irq < 0)
+		return netdev->irq;
+
+	dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+
+	err = bcm4908_enet_dma_alloc(enet);
+	if (err)
+		return err;
+
+	SET_NETDEV_DEV(netdev, &pdev->dev);
+	eth_hw_addr_random(netdev);
+	netdev->netdev_ops = &bcm4908_enet_netdev_ops;
+	netdev->min_mtu = ETH_ZLEN;
+	netdev->mtu = ENET_MTU_MAX;
+	netdev->max_mtu = ENET_MTU_MAX;
+	netif_napi_add(netdev, &enet->napi, bcm4908_enet_poll, 64);
+
+	err = register_netdev(netdev);
+	if (err) {
+		bcm4908_enet_dma_free(enet);
+		return err;
+	}
+
+	platform_set_drvdata(pdev, enet);
+
+	return 0;
+}
+
+static int bcm4908_enet_remove(struct platform_device *pdev)
+{
+	struct bcm4908_enet *enet = platform_get_drvdata(pdev);
+
+	unregister_netdev(enet->netdev);
+	netif_napi_del(&enet->napi);
+	bcm4908_enet_dma_free(enet);
+
+	return 0;
+}
+
+static const struct of_device_id bcm4908_enet_of_match[] = {
+	{ .compatible = "brcm,bcm4908-enet"},
+	{},
+};
+
+static struct platform_driver bcm4908_enet_driver = {
+	.driver = {
+		.name = "bcm4908_enet",
+		.of_match_table = bcm4908_enet_of_match,
+	},
+	.probe	= bcm4908_enet_probe,
+	.remove = bcm4908_enet_remove,
+};
+module_platform_driver(bcm4908_enet_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, bcm4908_enet_of_match);
diff --git a/drivers/net/ethernet/broadcom/bcm4908_enet.h b/drivers/net/ethernet/broadcom/bcm4908_enet.h
new file mode 100644
index 000000000000..8a3ede2da537
--- /dev/null
+++ b/drivers/net/ethernet/broadcom/bcm4908_enet.h
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __BCM4908_ENET_H
+#define __BCM4908_ENET_H
+
+#define ENET_CONTROL					0x000
+#define ENET_MIB_CTRL					0x004
+#define  ENET_MIB_CTRL_CLR_MIB				0x00000001
+#define ENET_RX_ERR_MASK				0x008
+#define ENET_MIB_MAX_PKT_SIZE				0x00C
+#define  ENET_MIB_MAX_PKT_SIZE_VAL			0x00003fff
+#define ENET_DIAG_OUT					0x01c
+#define ENET_ENABLE_DROP_PKT				0x020
+#define ENET_IRQ_ENABLE					0x024
+#define  ENET_IRQ_ENABLE_OVFL				0x00000001
+#define ENET_GMAC_STATUS				0x028
+#define  ENET_GMAC_STATUS_ETH_SPEED_MASK		0x00000003
+#define  ENET_GMAC_STATUS_ETH_SPEED_10			0x00000000
+#define  ENET_GMAC_STATUS_ETH_SPEED_100			0x00000001
+#define  ENET_GMAC_STATUS_ETH_SPEED_1000		0x00000002
+#define  ENET_GMAC_STATUS_HD				0x00000004
+#define  ENET_GMAC_STATUS_AUTO_CFG_EN			0x00000008
+#define  ENET_GMAC_STATUS_LINK_UP			0x00000010
+#define ENET_IRQ_STATUS					0x02c
+#define  ENET_IRQ_STATUS_OVFL				0x00000001
+#define ENET_OVERFLOW_COUNTER				0x030
+#define ENET_FLUSH					0x034
+#define  ENET_FLUSH_RXFIFO_FLUSH			0x00000001
+#define  ENET_FLUSH_TXFIFO_FLUSH			0x00000002
+#define ENET_RSV_SELECT					0x038
+#define ENET_BP_FORCE					0x03c
+#define  ENET_BP_FORCE_FORCE				0x00000001
+#define ENET_DMA_RX_OK_TO_SEND_COUNT			0x040
+#define  ENET_DMA_RX_OK_TO_SEND_COUNT_VAL		0x0000000f
+#define ENET_TX_CRC_CTRL				0x044
+#define ENET_MIB					0x200
+#define ENET_UNIMAC					0x400
+#define ENET_DMA					0x800
+#define ENET_DMA_CONTROLLER_CFG				0x800
+#define  ENET_DMA_CTRL_CFG_MASTER_EN			0x00000001
+#define  ENET_DMA_CTRL_CFG_FLOWC_CH1_EN			0x00000002
+#define  ENET_DMA_CTRL_CFG_FLOWC_CH3_EN			0x00000004
+#define ENET_DMA_FLOWCTL_CH1_THRESH_LO			0x804
+#define ENET_DMA_FLOWCTL_CH1_THRESH_HI			0x808
+#define ENET_DMA_FLOWCTL_CH1_ALLOC			0x80c
+#define  ENET_DMA_FLOWCTL_CH1_ALLOC_FORCE		0x80000000
+#define ENET_DMA_FLOWCTL_CH3_THRESH_LO			0x810
+#define ENET_DMA_FLOWCTL_CH3_THRESH_HI			0x814
+#define ENET_DMA_FLOWCTL_CH3_ALLOC			0x818
+#define ENET_DMA_FLOWCTL_CH5_THRESH_LO			0x81C
+#define ENET_DMA_FLOWCTL_CH5_THRESH_HI			0x820
+#define ENET_DMA_FLOWCTL_CH5_ALLOC			0x824
+#define ENET_DMA_FLOWCTL_CH7_THRESH_LO			0x828
+#define ENET_DMA_FLOWCTL_CH7_THRESH_HI			0x82C
+#define ENET_DMA_FLOWCTL_CH7_ALLOC			0x830
+#define ENET_DMA_CTRL_CHANNEL_RESET			0x834
+#define ENET_DMA_CTRL_CHANNEL_DEBUG			0x838
+#define ENET_DMA_CTRL_GLOBAL_INTERRUPT_STATUS		0x840
+#define ENET_DMA_CTRL_GLOBAL_INTERRUPT_MASK		0x844
+#define ENET_DMA_CH0_CFG				0xa00		/* RX */
+#define ENET_DMA_CH1_CFG				0xa10		/* TX */
+#define ENET_DMA_CH0_STATE_RAM				0xc00		/* RX */
+#define ENET_DMA_CH1_STATE_RAM				0xc10		/* TX */
+
+#define ENET_DMA_CH_CFG					0x00		/* assorted configuration */
+#define  ENET_DMA_CH_CFG_ENABLE				0x00000001	/* set to enable channel */
+#define  ENET_DMA_CH_CFG_PKT_HALT			0x00000002	/* idle after an EOP flag is detected */
+#define  ENET_DMA_CH_CFG_BURST_HALT			0x00000004	/* idle after finish current memory burst */
+#define ENET_DMA_CH_CFG_INT_STAT			0x04		/* interrupts control and status */
+#define ENET_DMA_CH_CFG_INT_MASK			0x08		/* interrupts mask */
+#define  ENET_DMA_CH_CFG_INT_BUFF_DONE			0x00000001	/* buffer done */
+#define  ENET_DMA_CH_CFG_INT_DONE			0x00000002	/* packet xfer complete */
+#define  ENET_DMA_CH_CFG_INT_NO_DESC			0x00000004	/* no valid descriptors */
+#define  ENET_DMA_CH_CFG_INT_RX_ERROR			0x00000008	/* rxdma detect client protocol error */
+#define ENET_DMA_CH_CFG_MAX_BURST			0x0c		/* max burst length permitted */
+#define  ENET_DMA_CH_CFG_MAX_BURST_DESCSIZE_SEL		0x00040000	/* DMA Descriptor Size Selection */
+#define ENET_DMA_CH_CFG_SIZE				0x10
+
+#define ENET_DMA_CH_STATE_RAM_BASE_DESC_PTR		0x00		/* descriptor ring start address */
+#define ENET_DMA_CH_STATE_RAM_STATE_DATA		0x04		/* state/bytes done/ring offset */
+#define ENET_DMA_CH_STATE_RAM_DESC_LEN_STATUS		0x08		/* buffer descriptor status and len */
+#define ENET_DMA_CH_STATE_RAM_DESC_BASE_BUFPTR		0x0c		/* buffer descrpitor current processing */
+#define ENET_DMA_CH_STATE_RAM_SIZE			0x10
+
+#define DMA_CTL_STATUS_APPEND_CRC			0x00000100
+#define DMA_CTL_STATUS_APPEND_BRCM_TAG			0x00000200
+#define DMA_CTL_STATUS_PRIO				0x00000C00  /* Prio for Tx */
+#define DMA_CTL_STATUS_WRAP				0x00001000  /* */
+#define DMA_CTL_STATUS_SOP				0x00002000  /* first buffer in packet */
+#define DMA_CTL_STATUS_EOP				0x00004000  /* last buffer in packet */
+#define DMA_CTL_STATUS_OWN				0x00008000  /* cleared by DMA, set by SW */
+#define DMA_CTL_LEN_DESC_BUFLENGTH			0x0fff0000
+#define DMA_CTL_LEN_DESC_BUFLENGTH_SHIFT		16
+#define DMA_CTL_LEN_DESC_MULTICAST			0x40000000
+#define DMA_CTL_LEN_DESC_USEFPM				0x80000000
+
+#endif
-- 
2.26.2


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

* Re: [PATCH V4 net-next 2/2] net: broadcom: bcm4908_enet: add BCM4908 controller driver
  2021-02-10  9:47           ` [PATCH V4 net-next 2/2] net: broadcom: bcm4908_enet: add BCM4908 controller driver Rafał Miłecki
@ 2021-02-11  0:44             ` Andrew Lunn
  0 siblings, 0 replies; 33+ messages in thread
From: Andrew Lunn @ 2021-02-11  0:44 UTC (permalink / raw)
  To: Rafał Miłecki
  Cc: David S . Miller, Jakub Kicinski, Rob Herring, Florian Fainelli,
	Randy Dunlap, Masahiro Yamada, netdev, devicetree,
	bcm-kernel-feedback-list, Rafał Miłecki

On Wed, Feb 10, 2021 at 10:47:02AM +0100, Rafał Miłecki wrote:
> From: Rafał Miłecki <rafal@milecki.pl>
> 
> BCM4908 SoCs family has integrated Ethernel controller that includes
> UniMAC but uses different DMA engine (than other controllers) and
> requires different programming.
> 
> Ethernet controller in BCM4908 is always connected to the internal SF2
> switch's port and uses fixed link.
> 
> Signed-off-by: Rafał Miłecki <rafal@milecki.pl>

Reviewed-by: Andrew Lunn <andrew@lunn.ch>

    Andrew

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

* [PATCH net-next 5.12 0/8] bcm4908_enet: post-review fixes
  2021-02-09 23:01       ` [PATCH V3 net-next 2/2] net: broadcom: bcm4908_enet: add BCM4908 controller driver Rafał Miłecki
  2021-02-10  2:39         ` Andrew Lunn
  2021-02-10  9:47         ` [PATCH V4 net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller Rafał Miłecki
@ 2021-02-11 12:12         ` Rafał Miłecki
  2021-02-11 12:12           ` [PATCH net-next 5.12 1/8] dt-bindings: net: rename BCM4908 Ethernet binding Rafał Miłecki
                             ` (8 more replies)
  2 siblings, 9 replies; 33+ messages in thread
From: Rafał Miłecki @ 2021-02-11 12:12 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Florian Fainelli, Randy Dunlap, Masahiro Yamada, netdev,
	devicetree, bcm-kernel-feedback-list, Andrew Lunn,
	Rafał Miłecki

From: Rafał Miłecki <rafal@milecki.pl>

V2 of my BCM4908 Ethernet patchset was applied to the net-next.git and
it was later that is received some extra reviews. I'm sending patches
that handle pointed out issues.

David: earler I missed that V2 was applied and I sent V3 and V4 of my
inital patchset. Sorry for that. I think it's the best to ignore V3 and
V4 I sent and proceed with this fixes patchset instead.

Rafał Miłecki (8):
  dt-bindings: net: rename BCM4908 Ethernet binding
  dt-bindings: net: bcm4908-enet: include ethernet-controller.yaml
  net: broadcom: rename BCM4908 driver & update DT binding
  net: broadcom: bcm4908_enet: drop unneeded memset()
  net: broadcom: bcm4908_enet: drop "inline" from C functions
  net: broadcom: bcm4908_enet: fix minor typos
  net: broadcom: bcm4908_enet: fix received skb length
  net: broadcom: bcm4908_enet: fix endianness in xmit code

 ...cm4908enet.yaml => brcm,bcm4908-enet.yaml} |   9 +-
 MAINTAINERS                                   |   4 +-
 drivers/net/ethernet/broadcom/Kconfig         |   2 +-
 drivers/net/ethernet/broadcom/Makefile        |   2 +-
 .../{bcm4908enet.c => bcm4908_enet.c}         | 228 +++++++++---------
 .../{bcm4908enet.h => bcm4908_enet.h}         |   4 +-
 6 files changed, 123 insertions(+), 126 deletions(-)
 rename Documentation/devicetree/bindings/net/{brcm,bcm4908enet.yaml => brcm,bcm4908-enet.yaml} (81%)
 rename drivers/net/ethernet/broadcom/{bcm4908enet.c => bcm4908_enet.c} (67%)
 rename drivers/net/ethernet/broadcom/{bcm4908enet.h => bcm4908_enet.h} (98%)

-- 
2.26.2


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

* [PATCH net-next 5.12 1/8] dt-bindings: net: rename BCM4908 Ethernet binding
  2021-02-11 12:12         ` [PATCH net-next 5.12 0/8] bcm4908_enet: post-review fixes Rafał Miłecki
@ 2021-02-11 12:12           ` Rafał Miłecki
  2021-02-11 17:44             ` Florian Fainelli
  2021-02-11 12:12           ` [PATCH net-next 5.12 2/8] dt-bindings: net: bcm4908-enet: include ethernet-controller.yaml Rafał Miłecki
                             ` (7 subsequent siblings)
  8 siblings, 1 reply; 33+ messages in thread
From: Rafał Miłecki @ 2021-02-11 12:12 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Florian Fainelli, Randy Dunlap, Masahiro Yamada, netdev,
	devicetree, bcm-kernel-feedback-list, Andrew Lunn,
	Rafał Miłecki, Rob Herring

From: Rafał Miłecki <rafal@milecki.pl>

Rob pointed out that a normal convention is "brcm,bcm4908-enet" so
update whole binding to match it.

Suggested-by: Rob Herring <robh@kernel.org>
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
 .../net/{brcm,bcm4908enet.yaml => brcm,bcm4908-enet.yaml}   | 6 +++---
 MAINTAINERS                                                 | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)
 rename Documentation/devicetree/bindings/net/{brcm,bcm4908enet.yaml => brcm,bcm4908-enet.yaml} (85%)

diff --git a/Documentation/devicetree/bindings/net/brcm,bcm4908enet.yaml b/Documentation/devicetree/bindings/net/brcm,bcm4908-enet.yaml
similarity index 85%
rename from Documentation/devicetree/bindings/net/brcm,bcm4908enet.yaml
rename to Documentation/devicetree/bindings/net/brcm,bcm4908-enet.yaml
index 5f12f51c5b19..c70f222365c0 100644
--- a/Documentation/devicetree/bindings/net/brcm,bcm4908enet.yaml
+++ b/Documentation/devicetree/bindings/net/brcm,bcm4908-enet.yaml
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
 %YAML 1.2
 ---
-$id: http://devicetree.org/schemas/net/brcm,bcm4908enet.yaml#
+$id: http://devicetree.org/schemas/net/brcm,bcm4908-enet.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
 title: Broadcom BCM4908 Ethernet controller
@@ -13,7 +13,7 @@ maintainers:
 
 properties:
   compatible:
-    const: brcm,bcm4908enet
+    const: brcm,bcm4908-enet
 
   reg:
     maxItems: 1
@@ -37,7 +37,7 @@ examples:
     #include <dt-bindings/interrupt-controller/arm-gic.h>
 
     ethernet@80002000 {
-        compatible = "brcm,bcm4908enet";
+        compatible = "brcm,bcm4908-enet";
         reg = <0x80002000 0x1000>;
 
         interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/MAINTAINERS b/MAINTAINERS
index 0bbd95b73c39..63fb312dedcf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3450,7 +3450,7 @@ M:	Rafał Miłecki <rafal@milecki.pl>
 M:	bcm-kernel-feedback-list@broadcom.com
 L:	netdev@vger.kernel.org
 S:	Maintained
-F:	Documentation/devicetree/bindings/net/brcm,bcm4908enet.yaml
+F:	Documentation/devicetree/bindings/net/brcm,bcm4908-enet.yaml
 F:	drivers/net/ethernet/broadcom/bcm4908enet.*
 F:	drivers/net/ethernet/broadcom/unimac.h
 
-- 
2.26.2


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

* [PATCH net-next 5.12 2/8] dt-bindings: net: bcm4908-enet: include ethernet-controller.yaml
  2021-02-11 12:12         ` [PATCH net-next 5.12 0/8] bcm4908_enet: post-review fixes Rafał Miłecki
  2021-02-11 12:12           ` [PATCH net-next 5.12 1/8] dt-bindings: net: rename BCM4908 Ethernet binding Rafał Miłecki
@ 2021-02-11 12:12           ` Rafał Miłecki
  2021-02-11 17:44             ` Florian Fainelli
  2021-02-11 12:12           ` [PATCH net-next 5.12 3/8] net: broadcom: rename BCM4908 driver & update DT binding Rafał Miłecki
                             ` (6 subsequent siblings)
  8 siblings, 1 reply; 33+ messages in thread
From: Rafał Miłecki @ 2021-02-11 12:12 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Florian Fainelli, Randy Dunlap, Masahiro Yamada, netdev,
	devicetree, bcm-kernel-feedback-list, Andrew Lunn,
	Rafał Miłecki, Rob Herring

From: Rafał Miłecki <rafal@milecki.pl>

It should be /included/ by every Ethernet controller binding. It adds
support for various generic properties.

Suggested-by: Rob Herring <robh@kernel.org>
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
 Documentation/devicetree/bindings/net/brcm,bcm4908-enet.yaml | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/net/brcm,bcm4908-enet.yaml b/Documentation/devicetree/bindings/net/brcm,bcm4908-enet.yaml
index c70f222365c0..79c38ea14237 100644
--- a/Documentation/devicetree/bindings/net/brcm,bcm4908-enet.yaml
+++ b/Documentation/devicetree/bindings/net/brcm,bcm4908-enet.yaml
@@ -11,6 +11,9 @@ description: Broadcom's Ethernet controller integrated into BCM4908 family SoCs
 maintainers:
   - Rafał Miłecki <rafal@milecki.pl>
 
+allOf:
+  - $ref: ethernet-controller.yaml#
+
 properties:
   compatible:
     const: brcm,bcm4908-enet
-- 
2.26.2


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

* [PATCH net-next 5.12 3/8] net: broadcom: rename BCM4908 driver & update DT binding
  2021-02-11 12:12         ` [PATCH net-next 5.12 0/8] bcm4908_enet: post-review fixes Rafał Miłecki
  2021-02-11 12:12           ` [PATCH net-next 5.12 1/8] dt-bindings: net: rename BCM4908 Ethernet binding Rafał Miłecki
  2021-02-11 12:12           ` [PATCH net-next 5.12 2/8] dt-bindings: net: bcm4908-enet: include ethernet-controller.yaml Rafał Miłecki
@ 2021-02-11 12:12           ` Rafał Miłecki
  2021-02-11 17:44             ` Florian Fainelli
  2021-02-11 12:12           ` [PATCH net-next 5.12 4/8] net: broadcom: bcm4908_enet: drop unneeded memset() Rafał Miłecki
                             ` (5 subsequent siblings)
  8 siblings, 1 reply; 33+ messages in thread
From: Rafał Miłecki @ 2021-02-11 12:12 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Florian Fainelli, Randy Dunlap, Masahiro Yamada, netdev,
	devicetree, bcm-kernel-feedback-list, Andrew Lunn,
	Rafał Miłecki

From: Rafał Miłecki <rafal@milecki.pl>

compatible string was updated to match normal naming convention so
update driver as well

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
 MAINTAINERS                                   |   2 +-
 drivers/net/ethernet/broadcom/Kconfig         |   2 +-
 drivers/net/ethernet/broadcom/Makefile        |   2 +-
 .../{bcm4908enet.c => bcm4908_enet.c}         | 215 +++++++++---------
 .../{bcm4908enet.h => bcm4908_enet.h}         |   4 +-
 5 files changed, 113 insertions(+), 112 deletions(-)
 rename drivers/net/ethernet/broadcom/{bcm4908enet.c => bcm4908_enet.c} (68%)
 rename drivers/net/ethernet/broadcom/{bcm4908enet.h => bcm4908_enet.h} (98%)

diff --git a/MAINTAINERS b/MAINTAINERS
index 63fb312dedcf..9016541d6555 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3451,7 +3451,7 @@ M:	bcm-kernel-feedback-list@broadcom.com
 L:	netdev@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/net/brcm,bcm4908-enet.yaml
-F:	drivers/net/ethernet/broadcom/bcm4908enet.*
+F:	drivers/net/ethernet/broadcom/bcm4908_enet.*
 F:	drivers/net/ethernet/broadcom/unimac.h
 
 BROADCOM BCM5301X ARM ARCHITECTURE
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index bcf9e0a410fd..f8a168b73307 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -51,7 +51,7 @@ config B44_PCI
 	depends on B44_PCI_AUTOSELECT && B44_PCICORE_AUTOSELECT
 	default y
 
-config BCM4908ENET
+config BCM4908_ENET
 	tristate "Broadcom BCM4908 internal mac support"
 	depends on ARCH_BCM4908 || COMPILE_TEST
 	default y
diff --git a/drivers/net/ethernet/broadcom/Makefile b/drivers/net/ethernet/broadcom/Makefile
index 379012de3569..0ddfb5b5d53c 100644
--- a/drivers/net/ethernet/broadcom/Makefile
+++ b/drivers/net/ethernet/broadcom/Makefile
@@ -4,7 +4,7 @@
 #
 
 obj-$(CONFIG_B44) += b44.o
-obj-$(CONFIG_BCM4908ENET) += bcm4908enet.o
+obj-$(CONFIG_BCM4908_ENET) += bcm4908_enet.o
 obj-$(CONFIG_BCM63XX_ENET) += bcm63xx_enet.o
 obj-$(CONFIG_BCMGENET) += genet/
 obj-$(CONFIG_BNX2) += bnx2.o
diff --git a/drivers/net/ethernet/broadcom/bcm4908enet.c b/drivers/net/ethernet/broadcom/bcm4908_enet.c
similarity index 68%
rename from drivers/net/ethernet/broadcom/bcm4908enet.c
rename to drivers/net/ethernet/broadcom/bcm4908_enet.c
index d68b328e7596..e56348eb188f 100644
--- a/drivers/net/ethernet/broadcom/bcm4908enet.c
+++ b/drivers/net/ethernet/broadcom/bcm4908_enet.c
@@ -12,7 +12,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 
-#include "bcm4908enet.h"
+#include "bcm4908_enet.h"
 #include "unimac.h"
 
 #define ENET_DMA_CH_RX_CFG			ENET_DMA_CH0_CFG
@@ -33,18 +33,18 @@
 #define ENET_MTU_MAX				1500 /* Is it possible to support 2044? */
 #define ENET_MTU_MAX_EXTRA_SIZE			32 /* L2 */
 
-struct bcm4908enet_dma_ring_bd {
+struct bcm4908_enet_dma_ring_bd {
 	__le32 ctl;
 	__le32 addr;
 } __packed;
 
-struct bcm4908enet_dma_ring_slot {
+struct bcm4908_enet_dma_ring_slot {
 	struct sk_buff *skb;
 	unsigned int len;
 	dma_addr_t dma_addr;
 };
 
-struct bcm4908enet_dma_ring {
+struct bcm4908_enet_dma_ring {
 	int is_tx;
 	int read_idx;
 	int write_idx;
@@ -54,38 +54,38 @@ struct bcm4908enet_dma_ring {
 
 	union {
 		void *cpu_addr;
-		struct bcm4908enet_dma_ring_bd *buf_desc;
+		struct bcm4908_enet_dma_ring_bd *buf_desc;
 	};
 	dma_addr_t dma_addr;
 
-	struct bcm4908enet_dma_ring_slot *slots;
+	struct bcm4908_enet_dma_ring_slot *slots;
 };
 
-struct bcm4908enet {
+struct bcm4908_enet {
 	struct device *dev;
 	struct net_device *netdev;
 	struct napi_struct napi;
 	void __iomem *base;
 
-	struct bcm4908enet_dma_ring tx_ring;
-	struct bcm4908enet_dma_ring rx_ring;
+	struct bcm4908_enet_dma_ring tx_ring;
+	struct bcm4908_enet_dma_ring rx_ring;
 };
 
 /***
  * R/W ops
  */
 
-static inline u32 enet_read(struct bcm4908enet *enet, u16 offset)
+static inline u32 enet_read(struct bcm4908_enet *enet, u16 offset)
 {
 	return readl(enet->base + offset);
 }
 
-static inline void enet_write(struct bcm4908enet *enet, u16 offset, u32 value)
+static inline void enet_write(struct bcm4908_enet *enet, u16 offset, u32 value)
 {
 	writel(value, enet->base + offset);
 }
 
-static inline void enet_maskset(struct bcm4908enet *enet, u16 offset, u32 mask, u32 set)
+static inline void enet_maskset(struct bcm4908_enet *enet, u16 offset, u32 mask, u32 set)
 {
 	u32 val;
 
@@ -96,27 +96,27 @@ static inline void enet_maskset(struct bcm4908enet *enet, u16 offset, u32 mask,
 	enet_write(enet, offset, val);
 }
 
-static inline void enet_set(struct bcm4908enet *enet, u16 offset, u32 set)
+static inline void enet_set(struct bcm4908_enet *enet, u16 offset, u32 set)
 {
 	enet_maskset(enet, offset, set, set);
 }
 
-static inline u32 enet_umac_read(struct bcm4908enet *enet, u16 offset)
+static inline u32 enet_umac_read(struct bcm4908_enet *enet, u16 offset)
 {
 	return enet_read(enet, ENET_UNIMAC + offset);
 }
 
-static inline void enet_umac_write(struct bcm4908enet *enet, u16 offset, u32 value)
+static inline void enet_umac_write(struct bcm4908_enet *enet, u16 offset, u32 value)
 {
 	enet_write(enet, ENET_UNIMAC + offset, value);
 }
 
-static inline void enet_umac_maskset(struct bcm4908enet *enet, u16 offset, u32 mask, u32 set)
+static inline void enet_umac_maskset(struct bcm4908_enet *enet, u16 offset, u32 mask, u32 set)
 {
 	enet_maskset(enet, ENET_UNIMAC + offset, mask, set);
 }
 
-static inline void enet_umac_set(struct bcm4908enet *enet, u16 offset, u32 set)
+static inline void enet_umac_set(struct bcm4908_enet *enet, u16 offset, u32 set)
 {
 	enet_set(enet, ENET_UNIMAC + offset, set);
 }
@@ -125,17 +125,17 @@ static inline void enet_umac_set(struct bcm4908enet *enet, u16 offset, u32 set)
  * Helpers
  */
 
-static void bcm4908enet_intrs_on(struct bcm4908enet *enet)
+static void bcm4908_enet_intrs_on(struct bcm4908_enet *enet)
 {
 	enet_write(enet, ENET_DMA_CH_RX_CFG + ENET_DMA_CH_CFG_INT_MASK, ENET_DMA_INT_DEFAULTS);
 }
 
-static void bcm4908enet_intrs_off(struct bcm4908enet *enet)
+static void bcm4908_enet_intrs_off(struct bcm4908_enet *enet)
 {
 	enet_write(enet, ENET_DMA_CH_RX_CFG + ENET_DMA_CH_CFG_INT_MASK, 0);
 }
 
-static void bcm4908enet_intrs_ack(struct bcm4908enet *enet)
+static void bcm4908_enet_intrs_ack(struct bcm4908_enet *enet)
 {
 	enet_write(enet, ENET_DMA_CH_RX_CFG + ENET_DMA_CH_CFG_INT_STAT, ENET_DMA_INT_DEFAULTS);
 }
@@ -144,9 +144,10 @@ static void bcm4908enet_intrs_ack(struct bcm4908enet *enet)
  * DMA
  */
 
-static int bcm4908_dma_alloc_buf_descs(struct bcm4908enet *enet, struct bcm4908enet_dma_ring *ring)
+static int bcm4908_dma_alloc_buf_descs(struct bcm4908_enet *enet,
+				       struct bcm4908_enet_dma_ring *ring)
 {
-	int size = ring->length * sizeof(struct bcm4908enet_dma_ring_bd);
+	int size = ring->length * sizeof(struct bcm4908_enet_dma_ring_bd);
 	struct device *dev = enet->dev;
 
 	ring->cpu_addr = dma_alloc_coherent(dev, size, &ring->dma_addr, GFP_KERNEL);
@@ -174,28 +175,28 @@ static int bcm4908_dma_alloc_buf_descs(struct bcm4908enet *enet, struct bcm4908e
 	return -ENOMEM;
 }
 
-static void bcm4908enet_dma_free(struct bcm4908enet *enet)
+static void bcm4908_enet_dma_free(struct bcm4908_enet *enet)
 {
-	struct bcm4908enet_dma_ring *tx_ring = &enet->tx_ring;
-	struct bcm4908enet_dma_ring *rx_ring = &enet->rx_ring;
+	struct bcm4908_enet_dma_ring *tx_ring = &enet->tx_ring;
+	struct bcm4908_enet_dma_ring *rx_ring = &enet->rx_ring;
 	struct device *dev = enet->dev;
 	int size;
 
-	size = rx_ring->length * sizeof(struct bcm4908enet_dma_ring_bd);
+	size = rx_ring->length * sizeof(struct bcm4908_enet_dma_ring_bd);
 	if (rx_ring->cpu_addr)
 		dma_free_coherent(dev, size, rx_ring->cpu_addr, rx_ring->dma_addr);
 	kfree(rx_ring->slots);
 
-	size = tx_ring->length * sizeof(struct bcm4908enet_dma_ring_bd);
+	size = tx_ring->length * sizeof(struct bcm4908_enet_dma_ring_bd);
 	if (tx_ring->cpu_addr)
 		dma_free_coherent(dev, size, tx_ring->cpu_addr, tx_ring->dma_addr);
 	kfree(tx_ring->slots);
 }
 
-static int bcm4908enet_dma_alloc(struct bcm4908enet *enet)
+static int bcm4908_enet_dma_alloc(struct bcm4908_enet *enet)
 {
-	struct bcm4908enet_dma_ring *tx_ring = &enet->tx_ring;
-	struct bcm4908enet_dma_ring *rx_ring = &enet->rx_ring;
+	struct bcm4908_enet_dma_ring *tx_ring = &enet->tx_ring;
+	struct bcm4908_enet_dma_ring *rx_ring = &enet->rx_ring;
 	struct device *dev = enet->dev;
 	int err;
 
@@ -216,16 +217,16 @@ static int bcm4908enet_dma_alloc(struct bcm4908enet *enet)
 	err = bcm4908_dma_alloc_buf_descs(enet, rx_ring);
 	if (err) {
 		dev_err(dev, "Failed to alloc RX buf descriptors: %d\n", err);
-		bcm4908enet_dma_free(enet);
+		bcm4908_enet_dma_free(enet);
 		return err;
 	}
 
 	return 0;
 }
 
-static void bcm4908enet_dma_reset(struct bcm4908enet *enet)
+static void bcm4908_enet_dma_reset(struct bcm4908_enet *enet)
 {
-	struct bcm4908enet_dma_ring *rings[] = { &enet->rx_ring, &enet->tx_ring };
+	struct bcm4908_enet_dma_ring *rings[] = { &enet->rx_ring, &enet->tx_ring };
 	int i;
 
 	/* Disable the DMA controller and channel */
@@ -235,7 +236,7 @@ static void bcm4908enet_dma_reset(struct bcm4908enet *enet)
 
 	/* Reset channels state */
 	for (i = 0; i < ARRAY_SIZE(rings); i++) {
-		struct bcm4908enet_dma_ring *ring = rings[i];
+		struct bcm4908_enet_dma_ring *ring = rings[i];
 
 		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_BASE_DESC_PTR, 0);
 		enet_write(enet, ring->st_ram_block + ENET_DMA_CH_STATE_RAM_STATE_DATA, 0);
@@ -244,10 +245,10 @@ static void bcm4908enet_dma_reset(struct bcm4908enet *enet)
 	}
 }
 
-static int bcm4908enet_dma_alloc_rx_buf(struct bcm4908enet *enet, unsigned int idx)
+static int bcm4908_enet_dma_alloc_rx_buf(struct bcm4908_enet *enet, unsigned int idx)
 {
-	struct bcm4908enet_dma_ring_bd *buf_desc = &enet->rx_ring.buf_desc[idx];
-	struct bcm4908enet_dma_ring_slot *slot = &enet->rx_ring.slots[idx];
+	struct bcm4908_enet_dma_ring_bd *buf_desc = &enet->rx_ring.buf_desc[idx];
+	struct bcm4908_enet_dma_ring_slot *slot = &enet->rx_ring.slots[idx];
 	struct device *dev = enet->dev;
 	u32 tmp;
 	int err;
@@ -277,8 +278,8 @@ static int bcm4908enet_dma_alloc_rx_buf(struct bcm4908enet *enet, unsigned int i
 	return 0;
 }
 
-static void bcm4908enet_dma_ring_init(struct bcm4908enet *enet,
-				      struct bcm4908enet_dma_ring *ring)
+static void bcm4908_enet_dma_ring_init(struct bcm4908_enet *enet,
+				       struct bcm4908_enet_dma_ring *ring)
 {
 	int reset_channel = 0; /* We support only 1 main channel (with TX and RX) */
 	int reset_subch = ring->is_tx ? 1 : 0;
@@ -295,10 +296,10 @@ static void bcm4908enet_dma_ring_init(struct bcm4908enet *enet,
 		   (uint32_t)ring->dma_addr);
 }
 
-static void bcm4908enet_dma_uninit(struct bcm4908enet *enet)
+static void bcm4908_enet_dma_uninit(struct bcm4908_enet *enet)
 {
-	struct bcm4908enet_dma_ring *rx_ring = &enet->rx_ring;
-	struct bcm4908enet_dma_ring_slot *slot;
+	struct bcm4908_enet_dma_ring *rx_ring = &enet->rx_ring;
+	struct bcm4908_enet_dma_ring_slot *slot;
 	struct device *dev = enet->dev;
 	int i;
 
@@ -312,48 +313,48 @@ static void bcm4908enet_dma_uninit(struct bcm4908enet *enet)
 	}
 }
 
-static int bcm4908enet_dma_init(struct bcm4908enet *enet)
+static int bcm4908_enet_dma_init(struct bcm4908_enet *enet)
 {
-	struct bcm4908enet_dma_ring *rx_ring = &enet->rx_ring;
+	struct bcm4908_enet_dma_ring *rx_ring = &enet->rx_ring;
 	struct device *dev = enet->dev;
 	int err;
 	int i;
 
 	for (i = 0; i < rx_ring->length; i++) {
-		err = bcm4908enet_dma_alloc_rx_buf(enet, i);
+		err = bcm4908_enet_dma_alloc_rx_buf(enet, i);
 		if (err) {
 			dev_err(dev, "Failed to alloc RX buffer: %d\n", err);
-			bcm4908enet_dma_uninit(enet);
+			bcm4908_enet_dma_uninit(enet);
 			return err;
 		}
 	}
 
-	bcm4908enet_dma_ring_init(enet, &enet->tx_ring);
-	bcm4908enet_dma_ring_init(enet, &enet->rx_ring);
+	bcm4908_enet_dma_ring_init(enet, &enet->tx_ring);
+	bcm4908_enet_dma_ring_init(enet, &enet->rx_ring);
 
 	return 0;
 }
 
-static void bcm4908enet_dma_tx_ring_ensable(struct bcm4908enet *enet,
-					    struct bcm4908enet_dma_ring *ring)
+static void bcm4908_enet_dma_tx_ring_ensable(struct bcm4908_enet *enet,
+					     struct bcm4908_enet_dma_ring *ring)
 {
 	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG, ENET_DMA_CH_CFG_ENABLE);
 }
 
-static void bcm4908enet_dma_tx_ring_disable(struct bcm4908enet *enet,
-					    struct bcm4908enet_dma_ring *ring)
+static void bcm4908_enet_dma_tx_ring_disable(struct bcm4908_enet *enet,
+					     struct bcm4908_enet_dma_ring *ring)
 {
 	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG, 0);
 }
 
-static void bcm4908enet_dma_rx_ring_enable(struct bcm4908enet *enet,
-					   struct bcm4908enet_dma_ring *ring)
+static void bcm4908_enet_dma_rx_ring_enable(struct bcm4908_enet *enet,
+					    struct bcm4908_enet_dma_ring *ring)
 {
 	enet_set(enet, ring->cfg_block + ENET_DMA_CH_CFG, ENET_DMA_CH_CFG_ENABLE);
 }
 
-static void bcm4908enet_dma_rx_ring_disable(struct bcm4908enet *enet,
-					    struct bcm4908enet_dma_ring *ring)
+static void bcm4908_enet_dma_rx_ring_disable(struct bcm4908_enet *enet,
+					     struct bcm4908_enet_dma_ring *ring)
 {
 	unsigned long deadline;
 	u32 tmp;
@@ -376,7 +377,7 @@ static void bcm4908enet_dma_rx_ring_disable(struct bcm4908enet *enet,
  * Ethernet driver
  */
 
-static void bcm4908enet_gmac_init(struct bcm4908enet *enet)
+static void bcm4908_enet_gmac_init(struct bcm4908_enet *enet)
 {
 	u32 cmd;
 
@@ -407,75 +408,75 @@ static void bcm4908enet_gmac_init(struct bcm4908enet *enet)
 		     ENET_GMAC_STATUS_LINK_UP);
 }
 
-static irqreturn_t bcm4908enet_irq_handler(int irq, void *dev_id)
+static irqreturn_t bcm4908_enet_irq_handler(int irq, void *dev_id)
 {
-	struct bcm4908enet *enet = dev_id;
+	struct bcm4908_enet *enet = dev_id;
 
-	bcm4908enet_intrs_off(enet);
-	bcm4908enet_intrs_ack(enet);
+	bcm4908_enet_intrs_off(enet);
+	bcm4908_enet_intrs_ack(enet);
 
 	napi_schedule(&enet->napi);
 
 	return IRQ_HANDLED;
 }
 
-static int bcm4908enet_open(struct net_device *netdev)
+static int bcm4908_enet_open(struct net_device *netdev)
 {
-	struct bcm4908enet *enet = netdev_priv(netdev);
+	struct bcm4908_enet *enet = netdev_priv(netdev);
 	struct device *dev = enet->dev;
 	int err;
 
-	err = request_irq(netdev->irq, bcm4908enet_irq_handler, 0, "enet", enet);
+	err = request_irq(netdev->irq, bcm4908_enet_irq_handler, 0, "enet", enet);
 	if (err) {
 		dev_err(dev, "Failed to request IRQ %d: %d\n", netdev->irq, err);
 		return err;
 	}
 
-	bcm4908enet_gmac_init(enet);
-	bcm4908enet_dma_reset(enet);
-	bcm4908enet_dma_init(enet);
+	bcm4908_enet_gmac_init(enet);
+	bcm4908_enet_dma_reset(enet);
+	bcm4908_enet_dma_init(enet);
 
 	enet_umac_set(enet, UMAC_CMD, CMD_TX_EN | CMD_RX_EN);
 
 	enet_set(enet, ENET_DMA_CONTROLLER_CFG, ENET_DMA_CTRL_CFG_MASTER_EN);
 	enet_maskset(enet, ENET_DMA_CONTROLLER_CFG, ENET_DMA_CTRL_CFG_FLOWC_CH1_EN, 0);
-	bcm4908enet_dma_rx_ring_enable(enet, &enet->rx_ring);
+	bcm4908_enet_dma_rx_ring_enable(enet, &enet->rx_ring);
 
 	napi_enable(&enet->napi);
 	netif_carrier_on(netdev);
 	netif_start_queue(netdev);
 
-	bcm4908enet_intrs_ack(enet);
-	bcm4908enet_intrs_on(enet);
+	bcm4908_enet_intrs_ack(enet);
+	bcm4908_enet_intrs_on(enet);
 
 	return 0;
 }
 
-static int bcm4908enet_stop(struct net_device *netdev)
+static int bcm4908_enet_stop(struct net_device *netdev)
 {
-	struct bcm4908enet *enet = netdev_priv(netdev);
+	struct bcm4908_enet *enet = netdev_priv(netdev);
 
 	netif_stop_queue(netdev);
 	netif_carrier_off(netdev);
 	napi_disable(&enet->napi);
 
-	bcm4908enet_dma_rx_ring_disable(enet, &enet->rx_ring);
-	bcm4908enet_dma_tx_ring_disable(enet, &enet->tx_ring);
+	bcm4908_enet_dma_rx_ring_disable(enet, &enet->rx_ring);
+	bcm4908_enet_dma_tx_ring_disable(enet, &enet->tx_ring);
 
-	bcm4908enet_dma_uninit(enet);
+	bcm4908_enet_dma_uninit(enet);
 
 	free_irq(enet->netdev->irq, enet);
 
 	return 0;
 }
 
-static int bcm4908enet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+static int bcm4908_enet_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
-	struct bcm4908enet *enet = netdev_priv(netdev);
-	struct bcm4908enet_dma_ring *ring = &enet->tx_ring;
-	struct bcm4908enet_dma_ring_slot *slot;
+	struct bcm4908_enet *enet = netdev_priv(netdev);
+	struct bcm4908_enet_dma_ring *ring = &enet->tx_ring;
+	struct bcm4908_enet_dma_ring_slot *slot;
 	struct device *dev = enet->dev;
-	struct bcm4908enet_dma_ring_bd *buf_desc;
+	struct bcm4908_enet_dma_ring_bd *buf_desc;
 	int free_buf_descs;
 	u32 tmp;
 
@@ -525,7 +526,7 @@ static int bcm4908enet_start_xmit(struct sk_buff *skb, struct net_device *netdev
 	buf_desc->addr = cpu_to_le32((uint32_t)slot->dma_addr);
 	buf_desc->ctl = cpu_to_le32(tmp);
 
-	bcm4908enet_dma_tx_ring_ensable(enet, &enet->tx_ring);
+	bcm4908_enet_dma_tx_ring_ensable(enet, &enet->tx_ring);
 
 	if (++ring->write_idx == ring->length - 1)
 		ring->write_idx = 0;
@@ -535,15 +536,15 @@ static int bcm4908enet_start_xmit(struct sk_buff *skb, struct net_device *netdev
 	return NETDEV_TX_OK;
 }
 
-static int bcm4908enet_poll(struct napi_struct *napi, int weight)
+static int bcm4908_enet_poll(struct napi_struct *napi, int weight)
 {
-	struct bcm4908enet *enet = container_of(napi, struct bcm4908enet, napi);
+	struct bcm4908_enet *enet = container_of(napi, struct bcm4908_enet, napi);
 	struct device *dev = enet->dev;
 	int handled = 0;
 
 	while (handled < weight) {
-		struct bcm4908enet_dma_ring_bd *buf_desc;
-		struct bcm4908enet_dma_ring_slot slot;
+		struct bcm4908_enet_dma_ring_bd *buf_desc;
+		struct bcm4908_enet_dma_ring_slot slot;
 		u32 ctl;
 		int len;
 		int err;
@@ -556,7 +557,7 @@ static int bcm4908enet_poll(struct napi_struct *napi, int weight)
 		slot = enet->rx_ring.slots[enet->rx_ring.read_idx];
 
 		/* Provide new buffer before unpinning the old one */
-		err = bcm4908enet_dma_alloc_rx_buf(enet, enet->rx_ring.read_idx);
+		err = bcm4908_enet_dma_alloc_rx_buf(enet, enet->rx_ring.read_idx);
 		if (err)
 			break;
 
@@ -583,24 +584,24 @@ static int bcm4908enet_poll(struct napi_struct *napi, int weight)
 
 	if (handled < weight) {
 		napi_complete_done(napi, handled);
-		bcm4908enet_intrs_on(enet);
+		bcm4908_enet_intrs_on(enet);
 	}
 
 	return handled;
 }
 
 static const struct net_device_ops bcm96xx_netdev_ops = {
-	.ndo_open = bcm4908enet_open,
-	.ndo_stop = bcm4908enet_stop,
-	.ndo_start_xmit = bcm4908enet_start_xmit,
+	.ndo_open = bcm4908_enet_open,
+	.ndo_stop = bcm4908_enet_stop,
+	.ndo_start_xmit = bcm4908_enet_start_xmit,
 	.ndo_set_mac_address = eth_mac_addr,
 };
 
-static int bcm4908enet_probe(struct platform_device *pdev)
+static int bcm4908_enet_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct net_device *netdev;
-	struct bcm4908enet *enet;
+	struct bcm4908_enet *enet;
 	int err;
 
 	netdev = devm_alloc_etherdev(dev, sizeof(*enet));
@@ -623,7 +624,7 @@ static int bcm4908enet_probe(struct platform_device *pdev)
 
 	dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
 
-	err = bcm4908enet_dma_alloc(enet);
+	err = bcm4908_enet_dma_alloc(enet);
 	if (err)
 		return err;
 
@@ -633,11 +634,11 @@ static int bcm4908enet_probe(struct platform_device *pdev)
 	netdev->min_mtu = ETH_ZLEN;
 	netdev->mtu = ENET_MTU_MAX;
 	netdev->max_mtu = ENET_MTU_MAX;
-	netif_napi_add(netdev, &enet->napi, bcm4908enet_poll, 64);
+	netif_napi_add(netdev, &enet->napi, bcm4908_enet_poll, 64);
 
 	err = register_netdev(netdev);
 	if (err) {
-		bcm4908enet_dma_free(enet);
+		bcm4908_enet_dma_free(enet);
 		return err;
 	}
 
@@ -646,31 +647,31 @@ static int bcm4908enet_probe(struct platform_device *pdev)
 	return 0;
 }
 
-static int bcm4908enet_remove(struct platform_device *pdev)
+static int bcm4908_enet_remove(struct platform_device *pdev)
 {
-	struct bcm4908enet *enet = platform_get_drvdata(pdev);
+	struct bcm4908_enet *enet = platform_get_drvdata(pdev);
 
 	unregister_netdev(enet->netdev);
 	netif_napi_del(&enet->napi);
-	bcm4908enet_dma_free(enet);
+	bcm4908_enet_dma_free(enet);
 
 	return 0;
 }
 
-static const struct of_device_id bcm4908enet_of_match[] = {
-	{ .compatible = "brcm,bcm4908enet"},
+static const struct of_device_id bcm4908_enet_of_match[] = {
+	{ .compatible = "brcm,bcm4908-enet"},
 	{},
 };
 
-static struct platform_driver bcm4908enet_driver = {
+static struct platform_driver bcm4908_enet_driver = {
 	.driver = {
-		.name = "bcm4908enet",
-		.of_match_table = bcm4908enet_of_match,
+		.name = "bcm4908_enet",
+		.of_match_table = bcm4908_enet_of_match,
 	},
-	.probe	= bcm4908enet_probe,
-	.remove = bcm4908enet_remove,
+	.probe	= bcm4908_enet_probe,
+	.remove = bcm4908_enet_remove,
 };
-module_platform_driver(bcm4908enet_driver);
+module_platform_driver(bcm4908_enet_driver);
 
 MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, bcm4908enet_of_match);
+MODULE_DEVICE_TABLE(of, bcm4908_enet_of_match);
diff --git a/drivers/net/ethernet/broadcom/bcm4908enet.h b/drivers/net/ethernet/broadcom/bcm4908_enet.h
similarity index 98%
rename from drivers/net/ethernet/broadcom/bcm4908enet.h
rename to drivers/net/ethernet/broadcom/bcm4908_enet.h
index 11aadf0715d3..8a3ede2da537 100644
--- a/drivers/net/ethernet/broadcom/bcm4908enet.h
+++ b/drivers/net/ethernet/broadcom/bcm4908_enet.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
-#ifndef __BCM4908ENET_H
-#define __BCM4908ENET_H
+#ifndef __BCM4908_ENET_H
+#define __BCM4908_ENET_H
 
 #define ENET_CONTROL					0x000
 #define ENET_MIB_CTRL					0x004
-- 
2.26.2


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

* [PATCH net-next 5.12 4/8] net: broadcom: bcm4908_enet: drop unneeded memset()
  2021-02-11 12:12         ` [PATCH net-next 5.12 0/8] bcm4908_enet: post-review fixes Rafał Miłecki
                             ` (2 preceding siblings ...)
  2021-02-11 12:12           ` [PATCH net-next 5.12 3/8] net: broadcom: rename BCM4908 driver & update DT binding Rafał Miłecki
@ 2021-02-11 12:12           ` Rafał Miłecki
  2021-02-11 17:45             ` Florian Fainelli
  2021-02-11 12:12           ` [PATCH net-next 5.12 5/8] net: broadcom: bcm4908_enet: drop "inline" from C functions Rafał Miłecki
                             ` (4 subsequent siblings)
  8 siblings, 1 reply; 33+ messages in thread
From: Rafał Miłecki @ 2021-02-11 12:12 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Florian Fainelli, Randy Dunlap, Masahiro Yamada, netdev,
	devicetree, bcm-kernel-feedback-list, Andrew Lunn,
	Rafał Miłecki

From: Rafał Miłecki <rafal@milecki.pl>

dma_alloc_coherent takes care of zeroing allocated memory

Suggested-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/broadcom/bcm4908_enet.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bcm4908_enet.c b/drivers/net/ethernet/broadcom/bcm4908_enet.c
index e56348eb188f..f4e31646d50f 100644
--- a/drivers/net/ethernet/broadcom/bcm4908_enet.c
+++ b/drivers/net/ethernet/broadcom/bcm4908_enet.c
@@ -163,8 +163,6 @@ static int bcm4908_dma_alloc_buf_descs(struct bcm4908_enet *enet,
 	if (!ring->slots)
 		goto err_free_buf_descs;
 
-	memset(ring->cpu_addr, 0, size);
-
 	ring->read_idx = 0;
 	ring->write_idx = 0;
 
-- 
2.26.2


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

* [PATCH net-next 5.12 5/8] net: broadcom: bcm4908_enet: drop "inline" from C functions
  2021-02-11 12:12         ` [PATCH net-next 5.12 0/8] bcm4908_enet: post-review fixes Rafał Miłecki
                             ` (3 preceding siblings ...)
  2021-02-11 12:12           ` [PATCH net-next 5.12 4/8] net: broadcom: bcm4908_enet: drop unneeded memset() Rafał Miłecki
@ 2021-02-11 12:12           ` Rafał Miłecki
  2021-02-11 17:45             ` Florian Fainelli
  2021-02-11 12:12           ` [PATCH net-next 5.12 6/8] net: broadcom: bcm4908_enet: fix minor typos Rafał Miłecki
                             ` (3 subsequent siblings)
  8 siblings, 1 reply; 33+ messages in thread
From: Rafał Miłecki @ 2021-02-11 12:12 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Florian Fainelli, Randy Dunlap, Masahiro Yamada, netdev,
	devicetree, bcm-kernel-feedback-list, Andrew Lunn,
	Rafał Miłecki

From: Rafał Miłecki <rafal@milecki.pl>

It seems preferred to let compiler optimize code if applicable.
While at it drop unused enet_umac_maskset().

Suggested-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/broadcom/bcm4908_enet.c | 19 +++++++------------
 1 file changed, 7 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bcm4908_enet.c b/drivers/net/ethernet/broadcom/bcm4908_enet.c
index f4e31646d50f..7d619aa9410a 100644
--- a/drivers/net/ethernet/broadcom/bcm4908_enet.c
+++ b/drivers/net/ethernet/broadcom/bcm4908_enet.c
@@ -75,17 +75,17 @@ struct bcm4908_enet {
  * R/W ops
  */
 
-static inline u32 enet_read(struct bcm4908_enet *enet, u16 offset)
+static u32 enet_read(struct bcm4908_enet *enet, u16 offset)
 {
 	return readl(enet->base + offset);
 }
 
-static inline void enet_write(struct bcm4908_enet *enet, u16 offset, u32 value)
+static void enet_write(struct bcm4908_enet *enet, u16 offset, u32 value)
 {
 	writel(value, enet->base + offset);
 }
 
-static inline void enet_maskset(struct bcm4908_enet *enet, u16 offset, u32 mask, u32 set)
+static void enet_maskset(struct bcm4908_enet *enet, u16 offset, u32 mask, u32 set)
 {
 	u32 val;
 
@@ -96,27 +96,22 @@ static inline void enet_maskset(struct bcm4908_enet *enet, u16 offset, u32 mask,
 	enet_write(enet, offset, val);
 }
 
-static inline void enet_set(struct bcm4908_enet *enet, u16 offset, u32 set)
+static void enet_set(struct bcm4908_enet *enet, u16 offset, u32 set)
 {
 	enet_maskset(enet, offset, set, set);
 }
 
-static inline u32 enet_umac_read(struct bcm4908_enet *enet, u16 offset)
+static u32 enet_umac_read(struct bcm4908_enet *enet, u16 offset)
 {
 	return enet_read(enet, ENET_UNIMAC + offset);
 }
 
-static inline void enet_umac_write(struct bcm4908_enet *enet, u16 offset, u32 value)
+static void enet_umac_write(struct bcm4908_enet *enet, u16 offset, u32 value)
 {
 	enet_write(enet, ENET_UNIMAC + offset, value);
 }
 
-static inline void enet_umac_maskset(struct bcm4908_enet *enet, u16 offset, u32 mask, u32 set)
-{
-	enet_maskset(enet, ENET_UNIMAC + offset, mask, set);
-}
-
-static inline void enet_umac_set(struct bcm4908_enet *enet, u16 offset, u32 set)
+static void enet_umac_set(struct bcm4908_enet *enet, u16 offset, u32 set)
 {
 	enet_set(enet, ENET_UNIMAC + offset, set);
 }
-- 
2.26.2


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

* [PATCH net-next 5.12 6/8] net: broadcom: bcm4908_enet: fix minor typos
  2021-02-11 12:12         ` [PATCH net-next 5.12 0/8] bcm4908_enet: post-review fixes Rafał Miłecki
                             ` (4 preceding siblings ...)
  2021-02-11 12:12           ` [PATCH net-next 5.12 5/8] net: broadcom: bcm4908_enet: drop "inline" from C functions Rafał Miłecki
@ 2021-02-11 12:12           ` Rafał Miłecki
  2021-02-11 17:46             ` Florian Fainelli
  2021-02-11 12:12           ` [PATCH net-next 5.12 7/8] net: broadcom: bcm4908_enet: fix received skb length Rafał Miłecki
                             ` (2 subsequent siblings)
  8 siblings, 1 reply; 33+ messages in thread
From: Rafał Miłecki @ 2021-02-11 12:12 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Florian Fainelli, Randy Dunlap, Masahiro Yamada, netdev,
	devicetree, bcm-kernel-feedback-list, Andrew Lunn,
	Rafał Miłecki

From: Rafał Miłecki <rafal@milecki.pl>

1. Fix "ensable" typo noticed by Andrew
2. Fix chipset name in the struct net_device_ops variable

Suggested-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/broadcom/bcm4908_enet.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bcm4908_enet.c b/drivers/net/ethernet/broadcom/bcm4908_enet.c
index 7d619aa9410a..47c1b7d827c5 100644
--- a/drivers/net/ethernet/broadcom/bcm4908_enet.c
+++ b/drivers/net/ethernet/broadcom/bcm4908_enet.c
@@ -328,8 +328,8 @@ static int bcm4908_enet_dma_init(struct bcm4908_enet *enet)
 	return 0;
 }
 
-static void bcm4908_enet_dma_tx_ring_ensable(struct bcm4908_enet *enet,
-					     struct bcm4908_enet_dma_ring *ring)
+static void bcm4908_enet_dma_tx_ring_enable(struct bcm4908_enet *enet,
+					    struct bcm4908_enet_dma_ring *ring)
 {
 	enet_write(enet, ring->cfg_block + ENET_DMA_CH_CFG, ENET_DMA_CH_CFG_ENABLE);
 }
@@ -519,7 +519,7 @@ static int bcm4908_enet_start_xmit(struct sk_buff *skb, struct net_device *netde
 	buf_desc->addr = cpu_to_le32((uint32_t)slot->dma_addr);
 	buf_desc->ctl = cpu_to_le32(tmp);
 
-	bcm4908_enet_dma_tx_ring_ensable(enet, &enet->tx_ring);
+	bcm4908_enet_dma_tx_ring_enable(enet, &enet->tx_ring);
 
 	if (++ring->write_idx == ring->length - 1)
 		ring->write_idx = 0;
@@ -583,7 +583,7 @@ static int bcm4908_enet_poll(struct napi_struct *napi, int weight)
 	return handled;
 }
 
-static const struct net_device_ops bcm96xx_netdev_ops = {
+static const struct net_device_ops bcm4908_enet_netdev_ops = {
 	.ndo_open = bcm4908_enet_open,
 	.ndo_stop = bcm4908_enet_stop,
 	.ndo_start_xmit = bcm4908_enet_start_xmit,
@@ -623,7 +623,7 @@ static int bcm4908_enet_probe(struct platform_device *pdev)
 
 	SET_NETDEV_DEV(netdev, &pdev->dev);
 	eth_hw_addr_random(netdev);
-	netdev->netdev_ops = &bcm96xx_netdev_ops;
+	netdev->netdev_ops = &bcm4908_enet_netdev_ops;
 	netdev->min_mtu = ETH_ZLEN;
 	netdev->mtu = ENET_MTU_MAX;
 	netdev->max_mtu = ENET_MTU_MAX;
-- 
2.26.2


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

* [PATCH net-next 5.12 7/8] net: broadcom: bcm4908_enet: fix received skb length
  2021-02-11 12:12         ` [PATCH net-next 5.12 0/8] bcm4908_enet: post-review fixes Rafał Miłecki
                             ` (5 preceding siblings ...)
  2021-02-11 12:12           ` [PATCH net-next 5.12 6/8] net: broadcom: bcm4908_enet: fix minor typos Rafał Miłecki
@ 2021-02-11 12:12           ` Rafał Miłecki
  2021-02-11 17:46             ` Florian Fainelli
  2021-02-11 12:12           ` [PATCH net-next 5.12 8/8] net: broadcom: bcm4908_enet: fix endianness in xmit code Rafał Miłecki
  2021-02-11 23:10           ` [PATCH net-next 5.12 0/8] bcm4908_enet: post-review fixes patchwork-bot+netdevbpf
  8 siblings, 1 reply; 33+ messages in thread
From: Rafał Miłecki @ 2021-02-11 12:12 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Florian Fainelli, Randy Dunlap, Masahiro Yamada, netdev,
	devicetree, bcm-kernel-feedback-list, Andrew Lunn,
	Rafał Miłecki

From: Rafał Miłecki <rafal@milecki.pl>

Use ETH_FCS_LEN instead of magic value and drop incorrect + 2

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
 drivers/net/ethernet/broadcom/bcm4908_enet.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/broadcom/bcm4908_enet.c b/drivers/net/ethernet/broadcom/bcm4908_enet.c
index 47c1b7d827c5..2e825db3b2f1 100644
--- a/drivers/net/ethernet/broadcom/bcm4908_enet.c
+++ b/drivers/net/ethernet/broadcom/bcm4908_enet.c
@@ -567,7 +567,7 @@ static int bcm4908_enet_poll(struct napi_struct *napi, int weight)
 
 		dma_unmap_single(dev, slot.dma_addr, slot.len, DMA_FROM_DEVICE);
 
-		skb_put(slot.skb, len - 4 + 2);
+		skb_put(slot.skb, len - ETH_FCS_LEN);
 		slot.skb->protocol = eth_type_trans(slot.skb, enet->netdev);
 		netif_receive_skb(slot.skb);
 
-- 
2.26.2


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

* [PATCH net-next 5.12 8/8] net: broadcom: bcm4908_enet: fix endianness in xmit code
  2021-02-11 12:12         ` [PATCH net-next 5.12 0/8] bcm4908_enet: post-review fixes Rafał Miłecki
                             ` (6 preceding siblings ...)
  2021-02-11 12:12           ` [PATCH net-next 5.12 7/8] net: broadcom: bcm4908_enet: fix received skb length Rafał Miłecki
@ 2021-02-11 12:12           ` Rafał Miłecki
  2021-02-11 17:46             ` Florian Fainelli
  2021-02-11 23:10           ` [PATCH net-next 5.12 0/8] bcm4908_enet: post-review fixes patchwork-bot+netdevbpf
  8 siblings, 1 reply; 33+ messages in thread
From: Rafał Miłecki @ 2021-02-11 12:12 UTC (permalink / raw)
  To: David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Florian Fainelli, Randy Dunlap, Masahiro Yamada, netdev,
	devicetree, bcm-kernel-feedback-list, Andrew Lunn,
	Rafał Miłecki

From: Rafał Miłecki <rafal@milecki.pl>

Use le32_to_cpu() for reading __le32 struct field filled by hw.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
 drivers/net/ethernet/broadcom/bcm4908_enet.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/broadcom/bcm4908_enet.c b/drivers/net/ethernet/broadcom/bcm4908_enet.c
index 2e825db3b2f1..0da8c8c73ba7 100644
--- a/drivers/net/ethernet/broadcom/bcm4908_enet.c
+++ b/drivers/net/ethernet/broadcom/bcm4908_enet.c
@@ -476,7 +476,7 @@ static int bcm4908_enet_start_xmit(struct sk_buff *skb, struct net_device *netde
 	/* Free transmitted skbs */
 	while (ring->read_idx != ring->write_idx) {
 		buf_desc = &ring->buf_desc[ring->read_idx];
-		if (buf_desc->ctl & DMA_CTL_STATUS_OWN)
+		if (le32_to_cpu(buf_desc->ctl) & DMA_CTL_STATUS_OWN)
 			break;
 		slot = &ring->slots[ring->read_idx];
 
-- 
2.26.2


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

* Re: [PATCH net-next 5.12 1/8] dt-bindings: net: rename BCM4908 Ethernet binding
  2021-02-11 12:12           ` [PATCH net-next 5.12 1/8] dt-bindings: net: rename BCM4908 Ethernet binding Rafał Miłecki
@ 2021-02-11 17:44             ` Florian Fainelli
  0 siblings, 0 replies; 33+ messages in thread
From: Florian Fainelli @ 2021-02-11 17:44 UTC (permalink / raw)
  To: Rafał Miłecki, David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Randy Dunlap, Masahiro Yamada, netdev, devicetree,
	bcm-kernel-feedback-list, Andrew Lunn, Rafał Miłecki,
	Rob Herring

On 2/11/21 4:12 AM, Rafał Miłecki wrote:
> From: Rafał Miłecki <rafal@milecki.pl>
> 
> Rob pointed out that a normal convention is "brcm,bcm4908-enet" so
> update whole binding to match it.
> 
> Suggested-by: Rob Herring <robh@kernel.org>
> Signed-off-by: Rafał Miłecki <rafal@milecki.pl>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

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

* Re: [PATCH net-next 5.12 2/8] dt-bindings: net: bcm4908-enet: include ethernet-controller.yaml
  2021-02-11 12:12           ` [PATCH net-next 5.12 2/8] dt-bindings: net: bcm4908-enet: include ethernet-controller.yaml Rafał Miłecki
@ 2021-02-11 17:44             ` Florian Fainelli
  0 siblings, 0 replies; 33+ messages in thread
From: Florian Fainelli @ 2021-02-11 17:44 UTC (permalink / raw)
  To: Rafał Miłecki, David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Randy Dunlap, Masahiro Yamada, netdev, devicetree,
	bcm-kernel-feedback-list, Andrew Lunn, Rafał Miłecki,
	Rob Herring

On 2/11/21 4:12 AM, Rafał Miłecki wrote:
> From: Rafał Miłecki <rafal@milecki.pl>
> 
> It should be /included/ by every Ethernet controller binding. It adds
> support for various generic properties.
> 
> Suggested-by: Rob Herring <robh@kernel.org>
> Signed-off-by: Rafał Miłecki <rafal@milecki.pl>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

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

* Re: [PATCH net-next 5.12 3/8] net: broadcom: rename BCM4908 driver & update DT binding
  2021-02-11 12:12           ` [PATCH net-next 5.12 3/8] net: broadcom: rename BCM4908 driver & update DT binding Rafał Miłecki
@ 2021-02-11 17:44             ` Florian Fainelli
  0 siblings, 0 replies; 33+ messages in thread
From: Florian Fainelli @ 2021-02-11 17:44 UTC (permalink / raw)
  To: Rafał Miłecki, David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Randy Dunlap, Masahiro Yamada, netdev, devicetree,
	bcm-kernel-feedback-list, Andrew Lunn, Rafał Miłecki

On 2/11/21 4:12 AM, Rafał Miłecki wrote:
> From: Rafał Miłecki <rafal@milecki.pl>
> 
> compatible string was updated to match normal naming convention so
> update driver as well
> 
> Signed-off-by: Rafał Miłecki <rafal@milecki.pl>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

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

* Re: [PATCH net-next 5.12 4/8] net: broadcom: bcm4908_enet: drop unneeded memset()
  2021-02-11 12:12           ` [PATCH net-next 5.12 4/8] net: broadcom: bcm4908_enet: drop unneeded memset() Rafał Miłecki
@ 2021-02-11 17:45             ` Florian Fainelli
  0 siblings, 0 replies; 33+ messages in thread
From: Florian Fainelli @ 2021-02-11 17:45 UTC (permalink / raw)
  To: Rafał Miłecki, David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Randy Dunlap, Masahiro Yamada, netdev, devicetree,
	bcm-kernel-feedback-list, Andrew Lunn, Rafał Miłecki

On 2/11/21 4:12 AM, Rafał Miłecki wrote:
> From: Rafał Miłecki <rafal@milecki.pl>
> 
> dma_alloc_coherent takes care of zeroing allocated memory
> 
> Suggested-by: Andrew Lunn <andrew@lunn.ch>
> Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
> Reviewed-by: Andrew Lunn <andrew@lunn.ch>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

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

* Re: [PATCH net-next 5.12 5/8] net: broadcom: bcm4908_enet: drop "inline" from C functions
  2021-02-11 12:12           ` [PATCH net-next 5.12 5/8] net: broadcom: bcm4908_enet: drop "inline" from C functions Rafał Miłecki
@ 2021-02-11 17:45             ` Florian Fainelli
  0 siblings, 0 replies; 33+ messages in thread
From: Florian Fainelli @ 2021-02-11 17:45 UTC (permalink / raw)
  To: Rafał Miłecki, David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Randy Dunlap, Masahiro Yamada, netdev, devicetree,
	bcm-kernel-feedback-list, Andrew Lunn, Rafał Miłecki

On 2/11/21 4:12 AM, Rafał Miłecki wrote:
> From: Rafał Miłecki <rafal@milecki.pl>
> 
> It seems preferred to let compiler optimize code if applicable.
> While at it drop unused enet_umac_maskset().
> 
> Suggested-by: Andrew Lunn <andrew@lunn.ch>
> Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
> Reviewed-by: Andrew Lunn <andrew@lunn.ch>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

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

* Re: [PATCH net-next 5.12 6/8] net: broadcom: bcm4908_enet: fix minor typos
  2021-02-11 12:12           ` [PATCH net-next 5.12 6/8] net: broadcom: bcm4908_enet: fix minor typos Rafał Miłecki
@ 2021-02-11 17:46             ` Florian Fainelli
  0 siblings, 0 replies; 33+ messages in thread
From: Florian Fainelli @ 2021-02-11 17:46 UTC (permalink / raw)
  To: Rafał Miłecki, David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Randy Dunlap, Masahiro Yamada, netdev, devicetree,
	bcm-kernel-feedback-list, Andrew Lunn, Rafał Miłecki

On 2/11/21 4:12 AM, Rafał Miłecki wrote:
> From: Rafał Miłecki <rafal@milecki.pl>
> 
> 1. Fix "ensable" typo noticed by Andrew
> 2. Fix chipset name in the struct net_device_ops variable
> 
> Suggested-by: Andrew Lunn <andrew@lunn.ch>
> Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
> Reviewed-by: Andrew Lunn <andrew@lunn.ch>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

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

* Re: [PATCH net-next 5.12 7/8] net: broadcom: bcm4908_enet: fix received skb length
  2021-02-11 12:12           ` [PATCH net-next 5.12 7/8] net: broadcom: bcm4908_enet: fix received skb length Rafał Miłecki
@ 2021-02-11 17:46             ` Florian Fainelli
  0 siblings, 0 replies; 33+ messages in thread
From: Florian Fainelli @ 2021-02-11 17:46 UTC (permalink / raw)
  To: Rafał Miłecki, David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Randy Dunlap, Masahiro Yamada, netdev, devicetree,
	bcm-kernel-feedback-list, Andrew Lunn, Rafał Miłecki

On 2/11/21 4:12 AM, Rafał Miłecki wrote:
> From: Rafał Miłecki <rafal@milecki.pl>
> 
> Use ETH_FCS_LEN instead of magic value and drop incorrect + 2
> 
> Signed-off-by: Rafał Miłecki <rafal@milecki.pl>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

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

* Re: [PATCH net-next 5.12 8/8] net: broadcom: bcm4908_enet: fix endianness in xmit code
  2021-02-11 12:12           ` [PATCH net-next 5.12 8/8] net: broadcom: bcm4908_enet: fix endianness in xmit code Rafał Miłecki
@ 2021-02-11 17:46             ` Florian Fainelli
  0 siblings, 0 replies; 33+ messages in thread
From: Florian Fainelli @ 2021-02-11 17:46 UTC (permalink / raw)
  To: Rafał Miłecki, David S . Miller, Jakub Kicinski, Rob Herring
  Cc: Randy Dunlap, Masahiro Yamada, netdev, devicetree,
	bcm-kernel-feedback-list, Andrew Lunn, Rafał Miłecki

On 2/11/21 4:12 AM, Rafał Miłecki wrote:
> From: Rafał Miłecki <rafal@milecki.pl>
> 
> Use le32_to_cpu() for reading __le32 struct field filled by hw.
> 
> Signed-off-by: Rafał Miłecki <rafal@milecki.pl>

Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
-- 
Florian

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

* Re: [PATCH net-next 5.12 0/8] bcm4908_enet: post-review fixes
  2021-02-11 12:12         ` [PATCH net-next 5.12 0/8] bcm4908_enet: post-review fixes Rafał Miłecki
                             ` (7 preceding siblings ...)
  2021-02-11 12:12           ` [PATCH net-next 5.12 8/8] net: broadcom: bcm4908_enet: fix endianness in xmit code Rafał Miłecki
@ 2021-02-11 23:10           ` patchwork-bot+netdevbpf
  8 siblings, 0 replies; 33+ messages in thread
From: patchwork-bot+netdevbpf @ 2021-02-11 23:10 UTC (permalink / raw)
  To: =?utf-8?b?UmFmYcWCIE1pxYJlY2tpIDx6YWplYzVAZ21haWwuY29tPg==?=
  Cc: davem, kuba, robh+dt, f.fainelli, rdunlap, masahiroy, netdev,
	devicetree, bcm-kernel-feedback-list, andrew, rafal

Hello:

This series was applied to netdev/net-next.git (refs/heads/master):

On Thu, 11 Feb 2021 13:12:31 +0100 you wrote:
> From: Rafał Miłecki <rafal@milecki.pl>
> 
> V2 of my BCM4908 Ethernet patchset was applied to the net-next.git and
> it was later that is received some extra reviews. I'm sending patches
> that handle pointed out issues.
> 
> David: earler I missed that V2 was applied and I sent V3 and V4 of my
> inital patchset. Sorry for that. I think it's the best to ignore V3 and
> V4 I sent and proceed with this fixes patchset instead.
> 
> [...]

Here is the summary with links:
  - [net-next,5.12,1/8] dt-bindings: net: rename BCM4908 Ethernet binding
    https://git.kernel.org/netdev/net-next/c/6710c5b0674f
  - [net-next,5.12,2/8] dt-bindings: net: bcm4908-enet: include ethernet-controller.yaml
    https://git.kernel.org/netdev/net-next/c/f08b5cf1eb1f
  - [net-next,5.12,3/8] net: broadcom: rename BCM4908 driver & update DT binding
    https://git.kernel.org/netdev/net-next/c/9d61d138ab30
  - [net-next,5.12,4/8] net: broadcom: bcm4908_enet: drop unneeded memset()
    https://git.kernel.org/netdev/net-next/c/af263af64683
  - [net-next,5.12,5/8] net: broadcom: bcm4908_enet: drop "inline" from C functions
    https://git.kernel.org/netdev/net-next/c/7b778ae4eb9c
  - [net-next,5.12,6/8] net: broadcom: bcm4908_enet: fix minor typos
    https://git.kernel.org/netdev/net-next/c/e39488117203
  - [net-next,5.12,7/8] net: broadcom: bcm4908_enet: fix received skb length
    https://git.kernel.org/netdev/net-next/c/195e2d9febfb
  - [net-next,5.12,8/8] net: broadcom: bcm4908_enet: fix endianness in xmit code
    https://git.kernel.org/netdev/net-next/c/bdd70b997799

You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



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

end of thread, other threads:[~2021-02-11 23:11 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-05 21:44 [PATCH net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller Rafał Miłecki
2021-02-05 21:44 ` [PATCH net-next 2/2] net: broadcom: bcm4908enet: add BCM4908 controller driver Rafał Miłecki
2021-02-05 23:47   ` kernel test robot
2021-02-05 23:47     ` kernel test robot
2021-02-07 22:26 ` [PATCH V2 net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller Rafał Miłecki
2021-02-07 22:26   ` [PATCH V2 net-next 2/2] net: broadcom: bcm4908enet: add BCM4908 controller driver Rafał Miłecki
2021-02-09 23:01     ` [PATCH V3 net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller Rafał Miłecki
2021-02-09 23:01       ` [PATCH V3 net-next 2/2] net: broadcom: bcm4908_enet: add BCM4908 controller driver Rafał Miłecki
2021-02-10  2:39         ` Andrew Lunn
2021-02-10  7:57           ` Rafał Miłecki
2021-02-10  9:47         ` [PATCH V4 net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller Rafał Miłecki
2021-02-10  9:47           ` [PATCH V4 net-next 2/2] net: broadcom: bcm4908_enet: add BCM4908 controller driver Rafał Miłecki
2021-02-11  0:44             ` Andrew Lunn
2021-02-11 12:12         ` [PATCH net-next 5.12 0/8] bcm4908_enet: post-review fixes Rafał Miłecki
2021-02-11 12:12           ` [PATCH net-next 5.12 1/8] dt-bindings: net: rename BCM4908 Ethernet binding Rafał Miłecki
2021-02-11 17:44             ` Florian Fainelli
2021-02-11 12:12           ` [PATCH net-next 5.12 2/8] dt-bindings: net: bcm4908-enet: include ethernet-controller.yaml Rafał Miłecki
2021-02-11 17:44             ` Florian Fainelli
2021-02-11 12:12           ` [PATCH net-next 5.12 3/8] net: broadcom: rename BCM4908 driver & update DT binding Rafał Miłecki
2021-02-11 17:44             ` Florian Fainelli
2021-02-11 12:12           ` [PATCH net-next 5.12 4/8] net: broadcom: bcm4908_enet: drop unneeded memset() Rafał Miłecki
2021-02-11 17:45             ` Florian Fainelli
2021-02-11 12:12           ` [PATCH net-next 5.12 5/8] net: broadcom: bcm4908_enet: drop "inline" from C functions Rafał Miłecki
2021-02-11 17:45             ` Florian Fainelli
2021-02-11 12:12           ` [PATCH net-next 5.12 6/8] net: broadcom: bcm4908_enet: fix minor typos Rafał Miłecki
2021-02-11 17:46             ` Florian Fainelli
2021-02-11 12:12           ` [PATCH net-next 5.12 7/8] net: broadcom: bcm4908_enet: fix received skb length Rafał Miłecki
2021-02-11 17:46             ` Florian Fainelli
2021-02-11 12:12           ` [PATCH net-next 5.12 8/8] net: broadcom: bcm4908_enet: fix endianness in xmit code Rafał Miłecki
2021-02-11 17:46             ` Florian Fainelli
2021-02-11 23:10           ` [PATCH net-next 5.12 0/8] bcm4908_enet: post-review fixes patchwork-bot+netdevbpf
2021-02-09 21:43   ` [PATCH V2 net-next 1/2] dt-bindings: net: document BCM4908 Ethernet controller Rob Herring
2021-02-09 22:07     ` Rafał Miłecki

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