[PATCH v3 07/11] include/hw/net: Implemented Classes and Masks for GMAC Descriptors

Nabih Estefan posted 11 patches 1 year, 1 month ago
Maintainers: Tyrone Ting <kfting@nuvoton.com>, Hao Wu <wuhaotsh@google.com>, Peter Maydell <peter.maydell@linaro.org>, Jason Wang <jasowang@redhat.com>, Thomas Huth <thuth@redhat.com>, Laurent Vivier <lvivier@redhat.com>, Paolo Bonzini <pbonzini@redhat.com>
There is a newer version of this series
[PATCH v3 07/11] include/hw/net: Implemented Classes and Masks for GMAC Descriptors
Posted by Nabih Estefan 1 year, 1 month ago
From: Nabih Estefan Diaz <nabihestefan@google.com>

 - Implemeted classes for GMAC Receive and Transmit Descriptors
 - Implemented Masks for said descriptors

Signed-off-by: Nabih Estefan Diaz <nabihestefan@google.com>
---
 hw/net/npcm_gmac.c           | 183 +++++++++++++++++++++++++++--------
 hw/net/trace-events          |   9 ++
 include/hw/net/npcm_gmac.h   |   2 -
 tests/qtest/npcm_gmac-test.c |   2 +-
 4 files changed, 150 insertions(+), 46 deletions(-)

diff --git a/hw/net/npcm_gmac.c b/hw/net/npcm_gmac.c
index 5ce632858d..6f8109e0ee 100644
--- a/hw/net/npcm_gmac.c
+++ b/hw/net/npcm_gmac.c
@@ -32,7 +32,7 @@
 REG32(NPCM_DMA_BUS_MODE, 0x1000)
 REG32(NPCM_DMA_XMT_POLL_DEMAND, 0x1004)
 REG32(NPCM_DMA_RCV_POLL_DEMAND, 0x1008)
-REG32(NPCM_DMA_RCV_BASE_ADDR, 0x100c)
+REG32(NPCM_DMA_RX_BASE_ADDR, 0x100c)
 REG32(NPCM_DMA_TX_BASE_ADDR, 0x1010)
 REG32(NPCM_DMA_STATUS, 0x1014)
 REG32(NPCM_DMA_CONTROL, 0x1018)
@@ -91,7 +91,8 @@ REG32(NPCM_GMAC_PTP_TTSR, 0x71c)
 #define NPCM_DMA_BUS_MODE_SWR               BIT(0)
 
 static const uint32_t npcm_gmac_cold_reset_values[NPCM_GMAC_NR_REGS] = {
-    [R_NPCM_GMAC_VERSION]         = 0x00001037,
+    /* Reduce version to 3.2 so that the kernel can enable interrupt. */
+    [R_NPCM_GMAC_VERSION]         = 0x00001032,
     [R_NPCM_GMAC_TIMER_CTRL]      = 0x03e80000,
     [R_NPCM_GMAC_MAC0_ADDR_HI]    = 0x8000ffff,
     [R_NPCM_GMAC_MAC0_ADDR_LO]    = 0xffffffff,
@@ -125,12 +126,12 @@ static const uint16_t phy_reg_init[] = {
     [MII_EXTSTAT]   = 0x3000, /* 1000BASTE_T full-duplex capable */
 };
 
-static void npcm_gmac_soft_reset(NPCMGMACState *s)
+static void npcm_gmac_soft_reset(NPCMGMACState *gmac)
 {
-    memcpy(s->regs, npcm_gmac_cold_reset_values,
+    memcpy(gmac->regs, npcm_gmac_cold_reset_values,
            NPCM_GMAC_NR_REGS * sizeof(uint32_t));
     /* Clear reset bits */
-    s->regs[R_NPCM_DMA_BUS_MODE] &= ~NPCM_DMA_BUS_MODE_SWR;
+    gmac->regs[R_NPCM_DMA_BUS_MODE] &= ~NPCM_DMA_BUS_MODE_SWR;
 }
 
 static void gmac_phy_set_link(NPCMGMACState *s, bool active)
@@ -148,11 +149,53 @@ static bool gmac_can_receive(NetClientState *nc)
     return true;
 }
 
-static ssize_t gmac_receive(NetClientState *nc, const uint8_t *buf, size_t len1)
+/*
+ * Function that updates the GMAC IRQ
+ * It find the logical OR of the enabled bits for NIS (if enabled)
+ * It find the logical OR of the enabled bits for AIS (if enabled)
+ */
+static void gmac_update_irq(NPCMGMACState *gmac)
 {
-    return 0;
+    /*
+     * Check if the normal interrupts summery is enabled
+     * if so, add the bits for the summary that are enabled
+     */
+    if (gmac->regs[R_NPCM_DMA_INTR_ENA] & gmac->regs[R_NPCM_DMA_STATUS] &
+        (NPCM_DMA_INTR_ENAB_NIE_BITS))
+    {
+        gmac->regs[R_NPCM_DMA_STATUS] |=  NPCM_DMA_STATUS_NIS;
+    }
+    /*
+     * Check if the abnormal interrupts summery is enabled
+     * if so, add the bits for the summary that are enabled
+     */
+    if (gmac->regs[R_NPCM_DMA_INTR_ENA] & gmac->regs[R_NPCM_DMA_STATUS] &
+        (NPCM_DMA_INTR_ENAB_AIE_BITS))
+    {
+        gmac->regs[R_NPCM_DMA_STATUS] |=  NPCM_DMA_STATUS_AIS;
+    }
+
+    /* Get the logical OR of both normal and abnormal interrupts */
+    int level = !!((gmac->regs[R_NPCM_DMA_STATUS] &
+                    gmac->regs[R_NPCM_DMA_INTR_ENA] &
+                    NPCM_DMA_STATUS_NIS) |
+                   (gmac->regs[R_NPCM_DMA_STATUS] &
+                   gmac->regs[R_NPCM_DMA_INTR_ENA] &
+                   NPCM_DMA_STATUS_AIS));
+
+    /* Set the IRQ */
+    trace_npcm_gmac_update_irq(DEVICE(gmac)->canonical_path,
+                               gmac->regs[R_NPCM_DMA_STATUS],
+                               gmac->regs[R_NPCM_DMA_INTR_ENA],
+                               level);
+    qemu_set_irq(gmac->irq, level);
 }
 
+static ssize_t gmac_receive(NetClientState *nc, const uint8_t *buf, size_t len)
+{
+    /* Placeholder */
+    return 0;
+}
 static void gmac_cleanup(NetClientState *nc)
 {
     /* Nothing to do yet. */
@@ -166,7 +209,7 @@ static void gmac_set_link(NetClientState *nc)
     gmac_phy_set_link(s, !nc->link_down);
 }
 
-static void npcm_gmac_mdio_access(NPCMGMACState *s, uint16_t v)
+static void npcm_gmac_mdio_access(NPCMGMACState *gmac, uint16_t v)
 {
     bool busy = v & NPCM_GMAC_MII_ADDR_BUSY;
     uint8_t is_write;
@@ -183,33 +226,38 @@ static void npcm_gmac_mdio_access(NPCMGMACState *s, uint16_t v)
 
 
         if (v & NPCM_GMAC_MII_ADDR_WRITE) {
-            data = s->regs[R_NPCM_GMAC_MII_DATA];
+            data = gmac->regs[R_NPCM_GMAC_MII_DATA];
             /* Clear reset bit for BMCR register */
             switch (gr) {
             case MII_BMCR:
                 data &= ~MII_BMCR_RESET;
-                /* Complete auto-negotiation immediately and set as complete */
-                if (data & MII_BMCR_AUTOEN) {
+                /* Autonegotiation is a W1C bit*/
+                if (data & MII_BMCR_ANRESTART) {
                     /* Tells autonegotiation to not restart again */
                     data &= ~MII_BMCR_ANRESTART;
+                }
+                if ((data & MII_BMCR_AUTOEN) &&
+                    !(gmac->phy_regs[pa][MII_BMSR] & MII_BMSR_AN_COMP)) {
                     /* sets autonegotiation as complete */
-                    s->phy_regs[pa][MII_BMSR] |= MII_BMSR_AN_COMP;
+                    gmac->phy_regs[pa][MII_BMSR] |= MII_BMSR_AN_COMP;
+                    /* Resolve AN automatically->need to set this */
+                    gmac->phy_regs[0][MII_ANLPAR] = 0x0000;
                 }
             }
-            s->phy_regs[pa][gr] = data;
+            gmac->phy_regs[pa][gr] = data;
         } else {
-            data = s->phy_regs[pa][gr];
-            s->regs[R_NPCM_GMAC_MII_DATA] = data;
+            data = gmac->phy_regs[pa][gr];
+            gmac->regs[R_NPCM_GMAC_MII_DATA] = data;
         }
-        trace_npcm_gmac_mdio_access(DEVICE(s)->canonical_path, is_write, pa,
-                                    gr, data);
+        trace_npcm_gmac_mdio_access(DEVICE(gmac)->canonical_path, is_write, pa,
+                                        gr, data);
     }
-    s->regs[R_NPCM_GMAC_MII_ADDR] = v & ~NPCM_GMAC_MII_ADDR_BUSY;
+    gmac->regs[R_NPCM_GMAC_MII_ADDR] = v & ~NPCM_GMAC_MII_ADDR_BUSY;
 }
 
 static uint64_t npcm_gmac_read(void *opaque, hwaddr offset, unsigned size)
 {
-    NPCMGMACState *s = opaque;
+    NPCMGMACState *gmac = opaque;
     uint32_t v = 0;
 
     switch (offset) {
@@ -218,22 +266,25 @@ static uint64_t npcm_gmac_read(void *opaque, hwaddr offset, unsigned size)
     case A_NPCM_DMA_RCV_POLL_DEMAND:
         qemu_log_mask(LOG_GUEST_ERROR,
                       "%s: Read of write-only reg: offset: 0x%04" HWADDR_PRIx
-                      "\n", DEVICE(s)->canonical_path, offset);
+                      "\n", DEVICE(gmac)->canonical_path, offset);
         break;
 
     default:
-        v = s->regs[offset / sizeof(uint32_t)];
+        v = gmac->regs[offset / sizeof(uint32_t)];
     }
-    trace_npcm_gmac_reg_read(DEVICE(s)->canonical_path, offset, v);
+
+    trace_npcm_gmac_reg_read(DEVICE(gmac)->canonical_path, offset, v);
     return v;
 }
 
 static void npcm_gmac_write(void *opaque, hwaddr offset,
                               uint64_t v, unsigned size)
 {
-    NPCMGMACState *s = opaque;
+    NPCMGMACState *gmac = opaque;
+    uint32_t prev;
+
+    trace_npcm_gmac_reg_write(DEVICE(gmac)->canonical_path, offset, v);
 
-    trace_npcm_gmac_reg_write(DEVICE(s)->canonical_path, offset, v);
     switch (offset) {
     /* Read only registers */
     case A_NPCM_GMAC_VERSION:
@@ -250,25 +301,44 @@ static void npcm_gmac_write(void *opaque, hwaddr offset,
         qemu_log_mask(LOG_GUEST_ERROR,
                       "%s: Write of read-only reg: offset: 0x%04" HWADDR_PRIx
                       ", value: 0x%04" PRIx64 "\n",
-                      DEVICE(s)->canonical_path, offset, v);
+                      DEVICE(gmac)->canonical_path, offset, v);
+        break;
+
+    case A_NPCM_GMAC_MAC_CONFIG:
+        prev = gmac->regs[offset / sizeof(uint32_t)];
+        gmac->regs[offset / sizeof(uint32_t)] = v;
+
+        /* If transmit is being enabled for first time, update desc addr */
+        if (~(prev & NPCM_GMAC_MAC_CONFIG_TX_EN) &
+             (v & NPCM_GMAC_MAC_CONFIG_TX_EN)) {
+            gmac->regs[R_NPCM_DMA_HOST_TX_DESC] =
+                gmac->regs[R_NPCM_DMA_TX_BASE_ADDR];
+        }
+
+        /* If receive is being enabled for first time, update desc addr */
+        if (~(prev & NPCM_GMAC_MAC_CONFIG_RX_EN) &
+             (v & NPCM_GMAC_MAC_CONFIG_RX_EN)) {
+            gmac->regs[R_NPCM_DMA_HOST_RX_DESC] =
+                gmac->regs[R_NPCM_DMA_RX_BASE_ADDR];
+        }
         break;
 
     case A_NPCM_GMAC_MII_ADDR:
-        npcm_gmac_mdio_access(s, v);
+        npcm_gmac_mdio_access(gmac, v);
         break;
 
     case A_NPCM_GMAC_MAC0_ADDR_HI:
-        s->regs[offset / sizeof(uint32_t)] = v;
-        s->conf.macaddr.a[0] = v >> 8;
-        s->conf.macaddr.a[1] = v >> 0;
+        gmac->regs[offset / sizeof(uint32_t)] = v;
+        gmac->conf.macaddr.a[0] = v >> 8;
+        gmac->conf.macaddr.a[1] = v >> 0;
         break;
 
     case A_NPCM_GMAC_MAC0_ADDR_LO:
-        s->regs[offset / sizeof(uint32_t)] = v;
-        s->conf.macaddr.a[2] = v >> 24;
-        s->conf.macaddr.a[3] = v >> 16;
-        s->conf.macaddr.a[4] = v >> 8;
-        s->conf.macaddr.a[5] = v >> 0;
+        gmac->regs[offset / sizeof(uint32_t)] = v;
+        gmac->conf.macaddr.a[2] = v >> 24;
+        gmac->conf.macaddr.a[3] = v >> 16;
+        gmac->conf.macaddr.a[4] = v >> 8;
+        gmac->conf.macaddr.a[5] = v >> 0;
         break;
 
     case A_NPCM_GMAC_MAC1_ADDR_HI:
@@ -277,33 +347,60 @@ static void npcm_gmac_write(void *opaque, hwaddr offset,
     case A_NPCM_GMAC_MAC2_ADDR_LO:
     case A_NPCM_GMAC_MAC3_ADDR_HI:
     case A_NPCM_GMAC_MAC3_ADDR_LO:
-        s->regs[offset / sizeof(uint32_t)] = v;
+        gmac->regs[offset / sizeof(uint32_t)] = v;
         qemu_log_mask(LOG_UNIMP,
                       "%s: Only MAC Address 0 is supported. This request "
-                      "is ignored.\n", DEVICE(s)->canonical_path);
+                      "is ignored.\n", DEVICE(gmac)->canonical_path);
         break;
 
     case A_NPCM_DMA_BUS_MODE:
-        s->regs[offset / sizeof(uint32_t)] = v;
+        gmac->regs[offset / sizeof(uint32_t)] = v;
         if (v & NPCM_DMA_BUS_MODE_SWR) {
-            npcm_gmac_soft_reset(s);
+            npcm_gmac_soft_reset(gmac);
+        }
+        break;
+
+    case A_NPCM_DMA_RCV_POLL_DEMAND:
+        /* We dont actually care about the value */
+        break;
+
+    case A_NPCM_DMA_STATUS:
+        /* Check that RO bits are not written to */
+        if (NPCM_DMA_STATUS_RO_MASK(v)) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "%s: Write of read-only bits of reg: offset: 0x%04"
+                           HWADDR_PRIx ", value: 0x%04" PRIx64 "\n",
+                           DEVICE(gmac)->canonical_path, offset, v);
+        } else {
+            /* for W1c bits, implement W1C */
+            gmac->regs[offset / sizeof(uint32_t)] &=
+                ~NPCM_DMA_STATUS_W1C_MASK(v);
+            if (v & NPCM_DMA_STATUS_NIS_BITS) {
+                gmac->regs[offset / sizeof(uint32_t)] &= ~NPCM_DMA_STATUS_NIS;
+            }
+            if (v & NPCM_DMA_STATUS_AIS_BITS) {
+                gmac->regs[offset / sizeof(uint32_t)] &= ~NPCM_DMA_STATUS_AIS;
+            }
         }
         break;
 
     default:
-        s->regs[offset / sizeof(uint32_t)] = v;
+        gmac->regs[offset / sizeof(uint32_t)] = v;
         break;
     }
+
+    gmac_update_irq(gmac);
 }
 
 static void npcm_gmac_reset(DeviceState *dev)
 {
-    NPCMGMACState *s = NPCM_GMAC(dev);
+    NPCMGMACState *gmac = NPCM_GMAC(dev);
 
-    npcm_gmac_soft_reset(s);
-    memcpy(s->phy_regs[0], phy_reg_init, sizeof(phy_reg_init));
+    npcm_gmac_soft_reset(gmac);
+    memcpy(gmac->phy_regs[0], phy_reg_init, sizeof(phy_reg_init));
 
-    trace_npcm_gmac_reset(DEVICE(s)->canonical_path, s->phy_regs[0][MII_BMSR]);
+    trace_npcm_gmac_reset(DEVICE(gmac)->canonical_path,
+                          gmac->phy_regs[0][MII_BMSR]);
 }
 
 static NetClientInfo net_npcm_gmac_info = {
diff --git a/hw/net/trace-events b/hw/net/trace-events
index 1dbb5d2d64..2843f1eaf8 100644
--- a/hw/net/trace-events
+++ b/hw/net/trace-events
@@ -472,6 +472,15 @@ npcm_gmac_reg_write(const char *name, uint64_t offset, uint32_t value) "%s: offs
 npcm_gmac_mdio_access(const char *name, uint8_t is_write, uint8_t pa, uint8_t gr, uint16_t val) "%s: is_write: %" PRIu8 " pa: %" PRIu8 " gr: %" PRIu8 " val: 0x%04" PRIx16
 npcm_gmac_reset(const char *name, uint16_t value) "%s: phy_regs[0][1]: 0x%04" PRIx16
 npcm_gmac_set_link(bool active) "Set link: active=%u"
+npcm_gmac_update_irq(const char *name, uint32_t status, uint32_t intr_en, int level) "%s: Status Reg: 0x%04" PRIX32 " Interrupt Enable Reg: 0x%04" PRIX32 " IRQ Set: %d"
+npcm_gmac_packet_desc_read(const char* name, uint32_t desc_addr) "%s: attempting to read descriptor @0x%04" PRIX32
+npcm_gmac_packet_receive(const char* name, uint32_t len) "%s: RX packet length: 0x%04" PRIX32
+npcm_gmac_packet_receiving_buffer(const char* name, uint32_t buf_len, uint32_t rx_buf_addr) "%s: Receiving into Buffer size: 0x%04" PRIX32 " at address 0x%04" PRIX32
+npcm_gmac_packet_received(const char* name, uint32_t len) "%s: Reception finished, packet left: 0x%04" PRIX32
+npcm_gmac_packet_transmit(const char* name, uint16_t len) "%s: TX transmission start, packed length 0x%04" PRIX16
+npcm_gmac_packet_sent(const char* name, uint16_t len) "%s: TX packet sent!, length: 0x%04" PRIX16
+npcm_gmac_debug_desc_data(const char* name, void* addr, uint32_t des0, uint32_t des1, uint32_t des2, uint32_t des3)"%s: Address: %p Descriptor 0: 0x%04" PRIX32 " Descriptor 1: 0x%04" PRIX32 "Descriptor 2: 0x%04" PRIX32 " Descriptor 3: 0x%04" PRIX32
+npcm_gmac_packet_tx_desc_data(const char* name, uint32_t tdes0, uint32_t tdes1) "%s: Tdes0: 0x%04" PRIX32 " Tdes1: 0x%04" PRIX32
 
 # npcm_pcs.c
 npcm_pcs_reg_read(const char *name, uint16_t indirect_access_baes, uint64_t offset, uint16_t value) "%s: IND: 0x%02" PRIx16 " offset: 0x%04" PRIx64 " value: 0x%04" PRIx16
diff --git a/include/hw/net/npcm_gmac.h b/include/hw/net/npcm_gmac.h
index a92a654278..e5729e83ea 100644
--- a/include/hw/net/npcm_gmac.h
+++ b/include/hw/net/npcm_gmac.h
@@ -37,8 +37,6 @@ struct NPCMGMACRxDesc {
 /* RDES2 and RDES3 are buffer address pointers */
 /* Owner: 0 = software, 1 = gmac */
 #define RX_DESC_RDES0_OWNER_MASK BIT(31)
-/* Owner*/
-#define RX_DESC_RDES0_OWNER_SHIFT 31
 /* Destination Address Filter Fail */
 #define RX_DESC_RDES0_DEST_ADDR_FILT_FAIL_MASK BIT(30)
 /* Frame length*/
diff --git a/tests/qtest/npcm_gmac-test.c b/tests/qtest/npcm_gmac-test.c
index 30d27e8dcc..84511fd915 100644
--- a/tests/qtest/npcm_gmac-test.c
+++ b/tests/qtest/npcm_gmac-test.c
@@ -154,7 +154,7 @@ static void test_init(gconstpointer test_data)
     CHECK_REG32(NPCM_GMAC_MII_DATA, 0);
     CHECK_REG32(NPCM_GMAC_FLOW_CTRL, 0);
     CHECK_REG32(NPCM_GMAC_VLAN_FLAG, 0);
-    CHECK_REG32(NPCM_GMAC_VERSION, 0x00001037);
+    CHECK_REG32(NPCM_GMAC_VERSION, 0x00001032);
     CHECK_REG32(NPCM_GMAC_WAKEUP_FILTER, 0);
     CHECK_REG32(NPCM_GMAC_PMT, 0);
     CHECK_REG32(NPCM_GMAC_LPI_CTRL, 0);
-- 
2.42.0.655.g421f12c284-goog
Re: [PATCH v3 07/11] include/hw/net: Implemented Classes and Masks for GMAC Descriptors
Posted by Hao Wu 1 year, 1 month ago
On Tue, Oct 17, 2023 at 4:04 PM Nabih Estefan <nabihestefan@google.com>
wrote:

> From: Nabih Estefan Diaz <nabihestefan@google.com>
>
>  - Implemeted classes for GMAC Receive and Transmit Descriptors
>  - Implemented Masks for said descriptors
>
> Signed-off-by: Nabih Estefan Diaz <nabihestefan@google.com>
>
Reviewed-by: Hao Wu <wuhaotsh@google.com>

> ---
>  hw/net/npcm_gmac.c           | 183 +++++++++++++++++++++++++++--------
>  hw/net/trace-events          |   9 ++
>  include/hw/net/npcm_gmac.h   |   2 -
>  tests/qtest/npcm_gmac-test.c |   2 +-
>  4 files changed, 150 insertions(+), 46 deletions(-)
>
> diff --git a/hw/net/npcm_gmac.c b/hw/net/npcm_gmac.c
> index 5ce632858d..6f8109e0ee 100644
> --- a/hw/net/npcm_gmac.c
> +++ b/hw/net/npcm_gmac.c
> @@ -32,7 +32,7 @@
>  REG32(NPCM_DMA_BUS_MODE, 0x1000)
>  REG32(NPCM_DMA_XMT_POLL_DEMAND, 0x1004)
>  REG32(NPCM_DMA_RCV_POLL_DEMAND, 0x1008)
> -REG32(NPCM_DMA_RCV_BASE_ADDR, 0x100c)
> +REG32(NPCM_DMA_RX_BASE_ADDR, 0x100c)
>  REG32(NPCM_DMA_TX_BASE_ADDR, 0x1010)
>  REG32(NPCM_DMA_STATUS, 0x1014)
>  REG32(NPCM_DMA_CONTROL, 0x1018)
> @@ -91,7 +91,8 @@ REG32(NPCM_GMAC_PTP_TTSR, 0x71c)
>  #define NPCM_DMA_BUS_MODE_SWR               BIT(0)
>
>  static const uint32_t npcm_gmac_cold_reset_values[NPCM_GMAC_NR_REGS] = {
> -    [R_NPCM_GMAC_VERSION]         = 0x00001037,
> +    /* Reduce version to 3.2 so that the kernel can enable interrupt. */
> +    [R_NPCM_GMAC_VERSION]         = 0x00001032,
>      [R_NPCM_GMAC_TIMER_CTRL]      = 0x03e80000,
>      [R_NPCM_GMAC_MAC0_ADDR_HI]    = 0x8000ffff,
>      [R_NPCM_GMAC_MAC0_ADDR_LO]    = 0xffffffff,
> @@ -125,12 +126,12 @@ static const uint16_t phy_reg_init[] = {
>      [MII_EXTSTAT]   = 0x3000, /* 1000BASTE_T full-duplex capable */
>  };
>
> -static void npcm_gmac_soft_reset(NPCMGMACState *s)
> +static void npcm_gmac_soft_reset(NPCMGMACState *gmac)
>  {
> -    memcpy(s->regs, npcm_gmac_cold_reset_values,
> +    memcpy(gmac->regs, npcm_gmac_cold_reset_values,
>             NPCM_GMAC_NR_REGS * sizeof(uint32_t));
>      /* Clear reset bits */
> -    s->regs[R_NPCM_DMA_BUS_MODE] &= ~NPCM_DMA_BUS_MODE_SWR;
> +    gmac->regs[R_NPCM_DMA_BUS_MODE] &= ~NPCM_DMA_BUS_MODE_SWR;
>  }
>
>  static void gmac_phy_set_link(NPCMGMACState *s, bool active)
> @@ -148,11 +149,53 @@ static bool gmac_can_receive(NetClientState *nc)
>      return true;
>  }
>
> -static ssize_t gmac_receive(NetClientState *nc, const uint8_t *buf,
> size_t len1)
> +/*
> + * Function that updates the GMAC IRQ
> + * It find the logical OR of the enabled bits for NIS (if enabled)
> + * It find the logical OR of the enabled bits for AIS (if enabled)
> + */
> +static void gmac_update_irq(NPCMGMACState *gmac)
>  {
> -    return 0;
> +    /*
> +     * Check if the normal interrupts summery is enabled
> +     * if so, add the bits for the summary that are enabled
> +     */
> +    if (gmac->regs[R_NPCM_DMA_INTR_ENA] & gmac->regs[R_NPCM_DMA_STATUS] &
> +        (NPCM_DMA_INTR_ENAB_NIE_BITS))
> +    {
> +        gmac->regs[R_NPCM_DMA_STATUS] |=  NPCM_DMA_STATUS_NIS;
> +    }
> +    /*
> +     * Check if the abnormal interrupts summery is enabled
> +     * if so, add the bits for the summary that are enabled
> +     */
> +    if (gmac->regs[R_NPCM_DMA_INTR_ENA] & gmac->regs[R_NPCM_DMA_STATUS] &
> +        (NPCM_DMA_INTR_ENAB_AIE_BITS))
> +    {
> +        gmac->regs[R_NPCM_DMA_STATUS] |=  NPCM_DMA_STATUS_AIS;
> +    }
> +
> +    /* Get the logical OR of both normal and abnormal interrupts */
> +    int level = !!((gmac->regs[R_NPCM_DMA_STATUS] &
> +                    gmac->regs[R_NPCM_DMA_INTR_ENA] &
> +                    NPCM_DMA_STATUS_NIS) |
> +                   (gmac->regs[R_NPCM_DMA_STATUS] &
> +                   gmac->regs[R_NPCM_DMA_INTR_ENA] &
> +                   NPCM_DMA_STATUS_AIS));
> +
> +    /* Set the IRQ */
> +    trace_npcm_gmac_update_irq(DEVICE(gmac)->canonical_path,
> +                               gmac->regs[R_NPCM_DMA_STATUS],
> +                               gmac->regs[R_NPCM_DMA_INTR_ENA],
> +                               level);
> +    qemu_set_irq(gmac->irq, level);
>  }
>
> +static ssize_t gmac_receive(NetClientState *nc, const uint8_t *buf,
> size_t len)
> +{
> +    /* Placeholder */
> +    return 0;
> +}
>  static void gmac_cleanup(NetClientState *nc)
>  {
>      /* Nothing to do yet. */
> @@ -166,7 +209,7 @@ static void gmac_set_link(NetClientState *nc)
>      gmac_phy_set_link(s, !nc->link_down);
>  }
>
> -static void npcm_gmac_mdio_access(NPCMGMACState *s, uint16_t v)
> +static void npcm_gmac_mdio_access(NPCMGMACState *gmac, uint16_t v)
>  {
>      bool busy = v & NPCM_GMAC_MII_ADDR_BUSY;
>      uint8_t is_write;
> @@ -183,33 +226,38 @@ static void npcm_gmac_mdio_access(NPCMGMACState *s,
> uint16_t v)
>
>
>          if (v & NPCM_GMAC_MII_ADDR_WRITE) {
> -            data = s->regs[R_NPCM_GMAC_MII_DATA];
> +            data = gmac->regs[R_NPCM_GMAC_MII_DATA];
>              /* Clear reset bit for BMCR register */
>              switch (gr) {
>              case MII_BMCR:
>                  data &= ~MII_BMCR_RESET;
> -                /* Complete auto-negotiation immediately and set as
> complete */
> -                if (data & MII_BMCR_AUTOEN) {
> +                /* Autonegotiation is a W1C bit*/
> +                if (data & MII_BMCR_ANRESTART) {
>                      /* Tells autonegotiation to not restart again */
>                      data &= ~MII_BMCR_ANRESTART;
> +                }
> +                if ((data & MII_BMCR_AUTOEN) &&
> +                    !(gmac->phy_regs[pa][MII_BMSR] & MII_BMSR_AN_COMP)) {
>                      /* sets autonegotiation as complete */
> -                    s->phy_regs[pa][MII_BMSR] |= MII_BMSR_AN_COMP;
> +                    gmac->phy_regs[pa][MII_BMSR] |= MII_BMSR_AN_COMP;
> +                    /* Resolve AN automatically->need to set this */
> +                    gmac->phy_regs[0][MII_ANLPAR] = 0x0000;
>                  }
>              }
> -            s->phy_regs[pa][gr] = data;
> +            gmac->phy_regs[pa][gr] = data;
>          } else {
> -            data = s->phy_regs[pa][gr];
> -            s->regs[R_NPCM_GMAC_MII_DATA] = data;
> +            data = gmac->phy_regs[pa][gr];
> +            gmac->regs[R_NPCM_GMAC_MII_DATA] = data;
>          }
> -        trace_npcm_gmac_mdio_access(DEVICE(s)->canonical_path, is_write,
> pa,
> -                                    gr, data);
> +        trace_npcm_gmac_mdio_access(DEVICE(gmac)->canonical_path,
> is_write, pa,
> +                                        gr, data);
>      }
> -    s->regs[R_NPCM_GMAC_MII_ADDR] = v & ~NPCM_GMAC_MII_ADDR_BUSY;
> +    gmac->regs[R_NPCM_GMAC_MII_ADDR] = v & ~NPCM_GMAC_MII_ADDR_BUSY;
>  }
>
>  static uint64_t npcm_gmac_read(void *opaque, hwaddr offset, unsigned size)
>  {
> -    NPCMGMACState *s = opaque;
> +    NPCMGMACState *gmac = opaque;
>      uint32_t v = 0;
>
>      switch (offset) {
> @@ -218,22 +266,25 @@ static uint64_t npcm_gmac_read(void *opaque, hwaddr
> offset, unsigned size)
>      case A_NPCM_DMA_RCV_POLL_DEMAND:
>          qemu_log_mask(LOG_GUEST_ERROR,
>                        "%s: Read of write-only reg: offset: 0x%04"
> HWADDR_PRIx
> -                      "\n", DEVICE(s)->canonical_path, offset);
> +                      "\n", DEVICE(gmac)->canonical_path, offset);
>          break;
>
>      default:
> -        v = s->regs[offset / sizeof(uint32_t)];
> +        v = gmac->regs[offset / sizeof(uint32_t)];
>      }
> -    trace_npcm_gmac_reg_read(DEVICE(s)->canonical_path, offset, v);
> +
> +    trace_npcm_gmac_reg_read(DEVICE(gmac)->canonical_path, offset, v);
>      return v;
>  }
>
>  static void npcm_gmac_write(void *opaque, hwaddr offset,
>                                uint64_t v, unsigned size)
>  {
> -    NPCMGMACState *s = opaque;
> +    NPCMGMACState *gmac = opaque;
> +    uint32_t prev;
> +
> +    trace_npcm_gmac_reg_write(DEVICE(gmac)->canonical_path, offset, v);
>
> -    trace_npcm_gmac_reg_write(DEVICE(s)->canonical_path, offset, v);
>      switch (offset) {
>      /* Read only registers */
>      case A_NPCM_GMAC_VERSION:
> @@ -250,25 +301,44 @@ static void npcm_gmac_write(void *opaque, hwaddr
> offset,
>          qemu_log_mask(LOG_GUEST_ERROR,
>                        "%s: Write of read-only reg: offset: 0x%04"
> HWADDR_PRIx
>                        ", value: 0x%04" PRIx64 "\n",
> -                      DEVICE(s)->canonical_path, offset, v);
> +                      DEVICE(gmac)->canonical_path, offset, v);
> +        break;
> +
> +    case A_NPCM_GMAC_MAC_CONFIG:
> +        prev = gmac->regs[offset / sizeof(uint32_t)];
> +        gmac->regs[offset / sizeof(uint32_t)] = v;
> +
> +        /* If transmit is being enabled for first time, update desc addr
> */
> +        if (~(prev & NPCM_GMAC_MAC_CONFIG_TX_EN) &
> +             (v & NPCM_GMAC_MAC_CONFIG_TX_EN)) {
> +            gmac->regs[R_NPCM_DMA_HOST_TX_DESC] =
> +                gmac->regs[R_NPCM_DMA_TX_BASE_ADDR];
> +        }
> +
> +        /* If receive is being enabled for first time, update desc addr */
> +        if (~(prev & NPCM_GMAC_MAC_CONFIG_RX_EN) &
> +             (v & NPCM_GMAC_MAC_CONFIG_RX_EN)) {
> +            gmac->regs[R_NPCM_DMA_HOST_RX_DESC] =
> +                gmac->regs[R_NPCM_DMA_RX_BASE_ADDR];
> +        }
>          break;
>
>      case A_NPCM_GMAC_MII_ADDR:
> -        npcm_gmac_mdio_access(s, v);
> +        npcm_gmac_mdio_access(gmac, v);
>          break;
>
>      case A_NPCM_GMAC_MAC0_ADDR_HI:
> -        s->regs[offset / sizeof(uint32_t)] = v;
> -        s->conf.macaddr.a[0] = v >> 8;
> -        s->conf.macaddr.a[1] = v >> 0;
> +        gmac->regs[offset / sizeof(uint32_t)] = v;
> +        gmac->conf.macaddr.a[0] = v >> 8;
> +        gmac->conf.macaddr.a[1] = v >> 0;
>          break;
>
>      case A_NPCM_GMAC_MAC0_ADDR_LO:
> -        s->regs[offset / sizeof(uint32_t)] = v;
> -        s->conf.macaddr.a[2] = v >> 24;
> -        s->conf.macaddr.a[3] = v >> 16;
> -        s->conf.macaddr.a[4] = v >> 8;
> -        s->conf.macaddr.a[5] = v >> 0;
> +        gmac->regs[offset / sizeof(uint32_t)] = v;
> +        gmac->conf.macaddr.a[2] = v >> 24;
> +        gmac->conf.macaddr.a[3] = v >> 16;
> +        gmac->conf.macaddr.a[4] = v >> 8;
> +        gmac->conf.macaddr.a[5] = v >> 0;
>          break;
>
>      case A_NPCM_GMAC_MAC1_ADDR_HI:
> @@ -277,33 +347,60 @@ static void npcm_gmac_write(void *opaque, hwaddr
> offset,
>      case A_NPCM_GMAC_MAC2_ADDR_LO:
>      case A_NPCM_GMAC_MAC3_ADDR_HI:
>      case A_NPCM_GMAC_MAC3_ADDR_LO:
> -        s->regs[offset / sizeof(uint32_t)] = v;
> +        gmac->regs[offset / sizeof(uint32_t)] = v;
>          qemu_log_mask(LOG_UNIMP,
>                        "%s: Only MAC Address 0 is supported. This request "
> -                      "is ignored.\n", DEVICE(s)->canonical_path);
> +                      "is ignored.\n", DEVICE(gmac)->canonical_path);
>          break;
>
>      case A_NPCM_DMA_BUS_MODE:
> -        s->regs[offset / sizeof(uint32_t)] = v;
> +        gmac->regs[offset / sizeof(uint32_t)] = v;
>          if (v & NPCM_DMA_BUS_MODE_SWR) {
> -            npcm_gmac_soft_reset(s);
> +            npcm_gmac_soft_reset(gmac);
> +        }
> +        break;
> +
> +    case A_NPCM_DMA_RCV_POLL_DEMAND:
> +        /* We dont actually care about the value */
> +        break;
> +
> +    case A_NPCM_DMA_STATUS:
> +        /* Check that RO bits are not written to */
> +        if (NPCM_DMA_STATUS_RO_MASK(v)) {
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "%s: Write of read-only bits of reg: offset:
> 0x%04"
> +                           HWADDR_PRIx ", value: 0x%04" PRIx64 "\n",
> +                           DEVICE(gmac)->canonical_path, offset, v);
> +        } else {
> +            /* for W1c bits, implement W1C */
> +            gmac->regs[offset / sizeof(uint32_t)] &=
> +                ~NPCM_DMA_STATUS_W1C_MASK(v);
> +            if (v & NPCM_DMA_STATUS_NIS_BITS) {
> +                gmac->regs[offset / sizeof(uint32_t)] &=
> ~NPCM_DMA_STATUS_NIS;
> +            }
> +            if (v & NPCM_DMA_STATUS_AIS_BITS) {
> +                gmac->regs[offset / sizeof(uint32_t)] &=
> ~NPCM_DMA_STATUS_AIS;
> +            }
>          }
>          break;
>
>      default:
> -        s->regs[offset / sizeof(uint32_t)] = v;
> +        gmac->regs[offset / sizeof(uint32_t)] = v;
>          break;
>      }
> +
> +    gmac_update_irq(gmac);
>  }
>
>  static void npcm_gmac_reset(DeviceState *dev)
>  {
> -    NPCMGMACState *s = NPCM_GMAC(dev);
> +    NPCMGMACState *gmac = NPCM_GMAC(dev);
>
> -    npcm_gmac_soft_reset(s);
> -    memcpy(s->phy_regs[0], phy_reg_init, sizeof(phy_reg_init));
> +    npcm_gmac_soft_reset(gmac);
> +    memcpy(gmac->phy_regs[0], phy_reg_init, sizeof(phy_reg_init));
>
> -    trace_npcm_gmac_reset(DEVICE(s)->canonical_path,
> s->phy_regs[0][MII_BMSR]);
> +    trace_npcm_gmac_reset(DEVICE(gmac)->canonical_path,
> +                          gmac->phy_regs[0][MII_BMSR]);
>  }
>
>  static NetClientInfo net_npcm_gmac_info = {
> diff --git a/hw/net/trace-events b/hw/net/trace-events
> index 1dbb5d2d64..2843f1eaf8 100644
> --- a/hw/net/trace-events
> +++ b/hw/net/trace-events
> @@ -472,6 +472,15 @@ npcm_gmac_reg_write(const char *name, uint64_t
> offset, uint32_t value) "%s: offs
>  npcm_gmac_mdio_access(const char *name, uint8_t is_write, uint8_t pa,
> uint8_t gr, uint16_t val) "%s: is_write: %" PRIu8 " pa: %" PRIu8 " gr: %"
> PRIu8 " val: 0x%04" PRIx16
>  npcm_gmac_reset(const char *name, uint16_t value) "%s: phy_regs[0][1]:
> 0x%04" PRIx16
>  npcm_gmac_set_link(bool active) "Set link: active=%u"
> +npcm_gmac_update_irq(const char *name, uint32_t status, uint32_t intr_en,
> int level) "%s: Status Reg: 0x%04" PRIX32 " Interrupt Enable Reg: 0x%04"
> PRIX32 " IRQ Set: %d"
> +npcm_gmac_packet_desc_read(const char* name, uint32_t desc_addr) "%s:
> attempting to read descriptor @0x%04" PRIX32
> +npcm_gmac_packet_receive(const char* name, uint32_t len) "%s: RX packet
> length: 0x%04" PRIX32
> +npcm_gmac_packet_receiving_buffer(const char* name, uint32_t buf_len,
> uint32_t rx_buf_addr) "%s: Receiving into Buffer size: 0x%04" PRIX32 " at
> address 0x%04" PRIX32
> +npcm_gmac_packet_received(const char* name, uint32_t len) "%s: Reception
> finished, packet left: 0x%04" PRIX32
> +npcm_gmac_packet_transmit(const char* name, uint16_t len) "%s: TX
> transmission start, packed length 0x%04" PRIX16
> +npcm_gmac_packet_sent(const char* name, uint16_t len) "%s: TX packet
> sent!, length: 0x%04" PRIX16
> +npcm_gmac_debug_desc_data(const char* name, void* addr, uint32_t des0,
> uint32_t des1, uint32_t des2, uint32_t des3)"%s: Address: %p Descriptor 0:
> 0x%04" PRIX32 " Descriptor 1: 0x%04" PRIX32 "Descriptor 2: 0x%04" PRIX32 "
> Descriptor 3: 0x%04" PRIX32
> +npcm_gmac_packet_tx_desc_data(const char* name, uint32_t tdes0, uint32_t
> tdes1) "%s: Tdes0: 0x%04" PRIX32 " Tdes1: 0x%04" PRIX32
>
>  # npcm_pcs.c
>  npcm_pcs_reg_read(const char *name, uint16_t indirect_access_baes,
> uint64_t offset, uint16_t value) "%s: IND: 0x%02" PRIx16 " offset: 0x%04"
> PRIx64 " value: 0x%04" PRIx16
> diff --git a/include/hw/net/npcm_gmac.h b/include/hw/net/npcm_gmac.h
> index a92a654278..e5729e83ea 100644
> --- a/include/hw/net/npcm_gmac.h
> +++ b/include/hw/net/npcm_gmac.h
> @@ -37,8 +37,6 @@ struct NPCMGMACRxDesc {
>  /* RDES2 and RDES3 are buffer address pointers */
>  /* Owner: 0 = software, 1 = gmac */
>  #define RX_DESC_RDES0_OWNER_MASK BIT(31)
> -/* Owner*/
> -#define RX_DESC_RDES0_OWNER_SHIFT 31
>  /* Destination Address Filter Fail */
>  #define RX_DESC_RDES0_DEST_ADDR_FILT_FAIL_MASK BIT(30)
>  /* Frame length*/
> diff --git a/tests/qtest/npcm_gmac-test.c b/tests/qtest/npcm_gmac-test.c
> index 30d27e8dcc..84511fd915 100644
> --- a/tests/qtest/npcm_gmac-test.c
> +++ b/tests/qtest/npcm_gmac-test.c
> @@ -154,7 +154,7 @@ static void test_init(gconstpointer test_data)
>      CHECK_REG32(NPCM_GMAC_MII_DATA, 0);
>      CHECK_REG32(NPCM_GMAC_FLOW_CTRL, 0);
>      CHECK_REG32(NPCM_GMAC_VLAN_FLAG, 0);
> -    CHECK_REG32(NPCM_GMAC_VERSION, 0x00001037);
> +    CHECK_REG32(NPCM_GMAC_VERSION, 0x00001032);
>      CHECK_REG32(NPCM_GMAC_WAKEUP_FILTER, 0);
>      CHECK_REG32(NPCM_GMAC_PMT, 0);
>      CHECK_REG32(NPCM_GMAC_LPI_CTRL, 0);
> --
> 2.42.0.655.g421f12c284-goog
>
>