qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 10/10] arm: allwinner-h3: add EMAC ethernet device


From: Philippe Mathieu-Daudé
Subject: Re: [PATCH 10/10] arm: allwinner-h3: add EMAC ethernet device
Date: Wed, 4 Dec 2019 16:14:24 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.2.2

On 12/3/19 10:33 AM, KONRAD Frederic wrote:
Le 12/2/19 à 10:09 PM, Niek Linnenbank a écrit :
The Allwinner H3 System on Chip includes an Ethernet MAC (EMAC)
which provides 10M/100M/1000M Ethernet connectivity. This commit
adds support for the Allwinner H3 EMAC, including emulation for
the following functionality:

  * DMA transfers
  * MII interface
  * Transmit CRC calculation

Signed-off-by: Niek Linnenbank <address@hidden>
---
  hw/arm/Kconfig                     |   1 +
  hw/arm/allwinner-h3.c              |  17 +
  hw/arm/orangepi.c                  |   7 +
  hw/net/Kconfig                     |   3 +
  hw/net/Makefile.objs               |   1 +
  hw/net/allwinner-h3-emac.c         | 786 +++++++++++++++++++++++++++++
  hw/net/trace-events                |  10 +
  include/hw/arm/allwinner-h3.h      |   2 +
  include/hw/net/allwinner-h3-emac.h |  69 +++
  9 files changed, 896 insertions(+)
  create mode 100644 hw/net/allwinner-h3-emac.c
  create mode 100644 include/hw/net/allwinner-h3-emac.h

diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index ebf8d2325f..551cff3442 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -294,6 +294,7 @@ config ALLWINNER_A10
  config ALLWINNER_H3
      bool
      select ALLWINNER_A10_PIT
+    select ALLWINNER_H3_EMAC
      select SERIAL
      select ARM_TIMER
      select ARM_GIC
diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c
index c2972caf88..274b8548c0 100644
--- a/hw/arm/allwinner-h3.c
+++ b/hw/arm/allwinner-h3.c
@@ -53,6 +53,9 @@ static void aw_h3_init(Object *obj)
      sysbus_init_child_obj(obj, "mmc0", &s->mmc0, sizeof(s->mmc0),
                            TYPE_AW_H3_SDHOST);
+
+    sysbus_init_child_obj(obj, "emac", &s->emac, sizeof(s->emac),
+                          TYPE_AW_H3_EMAC);
  }
  static void aw_h3_realize(DeviceState *dev, Error **errp)
@@ -237,6 +240,20 @@ static void aw_h3_realize(DeviceState *dev, Error **errp)
          return;
      }
+    /* EMAC */
+    if (nd_table[0].used) {
+        qemu_check_nic_model(&nd_table[0], TYPE_AW_H3_EMAC);
+        qdev_set_nic_properties(DEVICE(&s->emac), &nd_table[0]);
+    }
+    object_property_set_bool(OBJECT(&s->emac), true, "realized", &err);
+    if (err != NULL) {
+        error_propagate(errp, err);
+        return;
+    }
+    sysbusdev = SYS_BUS_DEVICE(&s->emac);
+    sysbus_mmio_map(sysbusdev, 0, AW_H3_EMAC_BASE);
+    sysbus_connect_irq(sysbusdev, 0, s->irq[AW_H3_GIC_SPI_EMAC]);
+
      /* Universal Serial Bus */
      sysbus_create_simple(TYPE_AW_H3_EHCI, AW_H3_EHCI0_BASE,
                           s->irq[AW_H3_GIC_SPI_EHCI0]);
diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c
index dee3efaf08..8a61eb0e69 100644
--- a/hw/arm/orangepi.c
+++ b/hw/arm/orangepi.c
@@ -61,6 +61,13 @@ static void orangepi_init(MachineState *machine)
          exit(1);
      }
+    /* Setup EMAC properties */
+    object_property_set_int(OBJECT(&s->h3->emac), 1, "phy-addr", &err);
+    if (err != NULL) {
+        error_reportf_err(err, "Couldn't set phy address: ");
+        exit(1);
+    }
+
      /* Mark H3 object realized */
      object_property_set_bool(OBJECT(s->h3), true, "realized", &err);
      if (err != NULL) {
diff --git a/hw/net/Kconfig b/hw/net/Kconfig
index 3856417d42..36d3923992 100644
--- a/hw/net/Kconfig
+++ b/hw/net/Kconfig
@@ -74,6 +74,9 @@ config MIPSNET
  config ALLWINNER_EMAC
      bool
+config ALLWINNER_H3_EMAC
+    bool
+
  config IMX_FEC
      bool
diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs
index 7907d2c199..5548deb07a 100644
--- a/hw/net/Makefile.objs
+++ b/hw/net/Makefile.objs
@@ -23,6 +23,7 @@ common-obj-$(CONFIG_XGMAC) += xgmac.o
  common-obj-$(CONFIG_MIPSNET) += mipsnet.o
  common-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.o
  common-obj-$(CONFIG_ALLWINNER_EMAC) += allwinner_emac.o
+common-obj-$(CONFIG_ALLWINNER_H3_EMAC) += allwinner-h3-emac.o
  common-obj-$(CONFIG_IMX_FEC) += imx_fec.o
  common-obj-$(CONFIG_CADENCE) += cadence_gem.o
diff --git a/hw/net/allwinner-h3-emac.c b/hw/net/allwinner-h3-emac.c
new file mode 100644
index 0000000000..37f6f44406
--- /dev/null
+++ b/hw/net/allwinner-h3-emac.c
@@ -0,0 +1,786 @@
+/*
+ * Allwinner H3 EMAC emulation
+ *
+ * Copyright (C) 2019 Niek Linnenbank <address@hidden>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/sysbus.h"
+#include "migration/vmstate.h"
+#include "net/net.h"
+#include "hw/irq.h"
+#include "hw/qdev-properties.h"
+#include "qemu/log.h"
+#include "trace.h"
+#include "net/checksum.h"
+#include "qemu/module.h"
+#include "exec/cpu-common.h"
+#include "hw/net/allwinner-h3-emac.h"
+
+/* EMAC register offsets */
+#define REG_BASIC_CTL_0        (0x0000) /* Basic Control 0 */
+#define REG_BASIC_CTL_1        (0x0004) /* Basic Control 1 */
+#define REG_INT_STA            (0x0008) /* Interrupt Status */
+#define REG_INT_EN             (0x000C) /* Interrupt Enable */
+#define REG_TX_CTL_0           (0x0010) /* Transmit Control 0 */
+#define REG_TX_CTL_1           (0x0014) /* Transmit Control 1 */
+#define REG_TX_FLOW_CTL        (0x001C) /* Transmit Flow Control */
+#define REG_TX_DMA_DESC_LIST   (0x0020) /* Transmit Descriptor List Address */
+#define REG_RX_CTL_0           (0x0024) /* Receive Control 0 */
+#define REG_RX_CTL_1           (0x0028) /* Receive Control 1 */
+#define REG_RX_DMA_DESC_LIST   (0x0034) /* Receive Descriptor List Address */
+#define REG_FRM_FLT            (0x0038) /* Receive Frame Filter */
+#define REG_RX_HASH_0          (0x0040) /* Receive Hash Table 0 */
+#define REG_RX_HASH_1          (0x0044) /* Receive Hash Table 1 */
+#define REG_MII_CMD            (0x0048) /* Management Interface Command */
+#define REG_MII_DATA           (0x004C) /* Management Interface Data */
+#define REG_ADDR_HIGH          (0x0050) /* MAC Address High */
+#define REG_ADDR_LOW           (0x0054) /* MAC Address Low */
+#define REG_TX_DMA_STA         (0x00B0) /* Transmit DMA Status */
+#define REG_TX_CUR_DESC        (0x00B4) /* Transmit Current Descriptor */
+#define REG_TX_CUR_BUF         (0x00B8) /* Transmit Current Buffer */
+#define REG_RX_DMA_STA         (0x00C0) /* Receive DMA Status */
+#define REG_RX_CUR_DESC        (0x00C4) /* Receive Current Descriptor */
+#define REG_RX_CUR_BUF         (0x00C8) /* Receive Current Buffer */
+#define REG_RGMII_STA          (0x00D0) /* RGMII Status */
+
+/* EMAC register flags */
+#define BASIC_CTL0_100Mbps     (0b11 << 2)
+#define BASIC_CTL0_FD          (1 << 0)
+#define BASIC_CTL1_SOFTRST     (1 << 0)
+
+#define INT_STA_RGMII_LINK     (1 << 16)
+#define INT_STA_RX_EARLY       (1 << 13)
+#define INT_STA_RX_OVERFLOW    (1 << 12)
+#define INT_STA_RX_TIMEOUT     (1 << 11)
+#define INT_STA_RX_DMA_STOP    (1 << 10)
+#define INT_STA_RX_BUF_UA      (1 << 9)
+#define INT_STA_RX             (1 << 8)
+#define INT_STA_TX_EARLY       (1 << 5)
+#define INT_STA_TX_UNDERFLOW   (1 << 4)
+#define INT_STA_TX_TIMEOUT     (1 << 3)
+#define INT_STA_TX_BUF_UA      (1 << 2)
+#define INT_STA_TX_DMA_STOP    (1 << 1)
+#define INT_STA_TX             (1 << 0)
+
+#define INT_EN_RX_EARLY        (1 << 13)
+#define INT_EN_RX_OVERFLOW     (1 << 12)
+#define INT_EN_RX_TIMEOUT      (1 << 11)
+#define INT_EN_RX_DMA_STOP     (1 << 10)
+#define INT_EN_RX_BUF_UA       (1 << 9)
+#define INT_EN_RX              (1 << 8)
+#define INT_EN_TX_EARLY        (1 << 5)
+#define INT_EN_TX_UNDERFLOW    (1 << 4)
+#define INT_EN_TX_TIMEOUT      (1 << 3)
+#define INT_EN_TX_BUF_UA       (1 << 2)
+#define INT_EN_TX_DMA_STOP     (1 << 1)
+#define INT_EN_TX              (1 << 0)
+
+#define TX_CTL0_TX_EN          (1 << 31)
+#define TX_CTL1_TX_DMA_START   (1 << 31)
+#define TX_CTL1_TX_DMA_EN      (1 << 30)
+#define TX_CTL1_TX_FLUSH       (1 << 0)
+
+#define RX_CTL0_RX_EN          (1 << 31)
+#define RX_CTL0_STRIP_FCS      (1 << 28)
+#define RX_CTL0_CRC_IPV4       (1 << 27)
+
+#define RX_CTL1_RX_DMA_START   (1 << 31)
+#define RX_CTL1_RX_DMA_EN      (1 << 30)
+#define RX_CTL1_RX_MD          (1 << 1)
+
+#define RX_FRM_FLT_DIS_ADDR    (1 << 31)
+
+#define MII_CMD_PHY_ADDR_SHIFT (12)
+#define MII_CMD_PHY_ADDR_MASK  (0xf000)
+#define MII_CMD_PHY_REG_SHIFT  (4)
+#define MII_CMD_PHY_REG_MASK   (0xf0)
+#define MII_CMD_PHY_RW         (1 << 1)
+#define MII_CMD_PHY_BUSY       (1 << 0)
+
+#define TX_DMA_STA_STOP        (0b000)
+#define TX_DMA_STA_RUN_FETCH   (0b001)
+#define TX_DMA_STA_WAIT_STA    (0b010)
+
+#define RX_DMA_STA_STOP        (0b000)
+#define RX_DMA_STA_RUN_FETCH   (0b001)
+#define RX_DMA_STA_WAIT_FRM    (0b011)
+
+#define RGMII_LINK_UP          (1 << 3)
+#define RGMII_FD               (1 << 0)
+
+/* EMAC register reset values */
+#define REG_BASIC_CTL_1_RST    (0x08000000)
+
+/* EMAC constants */
+#define AW_H3_EMAC_MIN_PKT_SZ  (64)
+
+/* Transmit/receive frame descriptor */
+typedef struct FrameDescriptor {
+    uint32_t status;
+    uint32_t status2;
+    uint32_t addr;
+    uint32_t next;
+} FrameDescriptor;
+
+/* Frame descriptor flags */
+#define DESC_STATUS_CTL                 (1 << 31)
+#define DESC_STATUS2_BUF_SIZE_MASK      (0x7ff)
+
+/* Transmit frame descriptor flags */
+#define TX_DESC_STATUS_LENGTH_ERR       (1 << 14)
+#define TX_DESC_STATUS2_FIRST_DESC      (1 << 29)
+#define TX_DESC_STATUS2_LAST_DESC       (1 << 30)
+#define TX_DESC_STATUS2_CHECKSUM_MASK   (0x3 << 27)
+
+/* Receive frame descriptor flags */
+#define RX_DESC_STATUS_FIRST_DESC       (1 << 9)
+#define RX_DESC_STATUS_LAST_DESC        (1 << 8)
+#define RX_DESC_STATUS_FRM_LEN_MASK     (0x3fff0000)
+#define RX_DESC_STATUS_FRM_LEN_SHIFT    (16)
+#define RX_DESC_STATUS_NO_BUF           (1 << 14)
+#define RX_DESC_STATUS_HEADER_ERR       (1 << 7)
+#define RX_DESC_STATUS_LENGTH_ERR       (1 << 4)
+#define RX_DESC_STATUS_CRC_ERR          (1 << 1)
+#define RX_DESC_STATUS_PAYLOAD_ERR      (1 << 0)
+#define RX_DESC_STATUS2_RX_INT_CTL      (1 << 31)
+
+/* MII register offsets */
+#define MII_REG_CR                      (0x0)
+#define MII_REG_ST                      (0x1)
+#define MII_REG_ID_HIGH                 (0x2)
+#define MII_REG_ID_LOW                  (0x3)
+
+/* MII register flags */
+#define MII_REG_CR_RESET                (1 << 15)
+#define MII_REG_CR_POWERDOWN            (1 << 11)
+#define MII_REG_CR_10Mbit               (0)
+#define MII_REG_CR_100Mbit              (1 << 13)
+#define MII_REG_CR_1000Mbit             (1 << 6)
+#define MII_REG_CR_AUTO_NEG             (1 << 12)
+#define MII_REG_CR_AUTO_NEG_RESTART     (1 << 9)
+#define MII_REG_CR_FULLDUPLEX           (1 << 8)
+
+#define MII_REG_ST_100BASE_T4           (1 << 15)
+#define MII_REG_ST_100BASE_X_FD         (1 << 14)
+#define MII_REG_ST_100BASE_X_HD         (1 << 13)
+#define MII_REG_ST_10_FD                (1 << 12)
+#define MII_REG_ST_10_HD                (1 << 11)
+#define MII_REG_ST_100BASE_T2_FD        (1 << 10)
+#define MII_REG_ST_100BASE_T2_HD        (1 << 9)
+#define MII_REG_ST_AUTONEG_COMPLETE     (1 << 5)
+#define MII_REG_ST_AUTONEG_AVAIL        (1 << 3)
+#define MII_REG_ST_LINK_UP              (1 << 2)
+
+/* MII constants */
+#define MII_PHY_ID_HIGH                 (0x0044)
+#define MII_PHY_ID_LOW                  (0x1400)

I wonder if we can't share all those mii stuff accross the network adapters
instead of redoing the work everytime. I've some patches about it I may post
them sometimes.

I started that too, salvaging patches from Grant Likely and Sai Pavan Boddu, but I'm doing this in my hobbyist time so progress is slow. I estimate I'v 80% of the work done. Basically it adds a MDIO QBUS (as SD/I2C) and we can plug multiple QDEV slaves. Benefits are easily tracing of the MDIO activity, and ability to interchange the master/slaves for testing (think libqos qgraph).




reply via email to

[Prev in Thread] Current Thread [Next in Thread]