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
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
>
>
© 2016 - 2026 Red Hat, Inc.