From 86cda64f7016647b1677d76e96ba2dded9941b4a Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 19 Jun 2025 01:55:06 -0700 Subject: [PATCH 01/16] nvnet: Fix register stringification --- hw/xbox/mcpx/nvnet/nvnet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/xbox/mcpx/nvnet/nvnet.c b/hw/xbox/mcpx/nvnet/nvnet.c index 01ee0c9849..2a4007f921 100644 --- a/hw/xbox/mcpx/nvnet/nvnet.c +++ b/hw/xbox/mcpx/nvnet/nvnet.c @@ -82,7 +82,7 @@ struct RingDesc { #define R(r) \ case r: \ - return stringify(r); + return #r; static const char *nvnet_get_reg_name(hwaddr addr) { From 14a95ddb7f68fc8327e026204710f6300b3ed8a6 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 19 Jun 2025 01:55:06 -0700 Subject: [PATCH 02/16] nvnet: Move nvnet_dump_ring_descriptors down --- hw/xbox/mcpx/nvnet/nvnet.c | 66 +++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/hw/xbox/mcpx/nvnet/nvnet.c b/hw/xbox/mcpx/nvnet/nvnet.c index 2a4007f921..17bf2a8286 100644 --- a/hw/xbox/mcpx/nvnet/nvnet.c +++ b/hw/xbox/mcpx/nvnet/nvnet.c @@ -149,39 +149,6 @@ static const char *nvnet_get_phy_reg_name(uint8_t reg) #undef R -static void nvnet_dump_ring_descriptors(NvNetState *s) -{ -#if NVNET_DEBUG - struct RingDesc desc; - PCIDevice *d = PCI_DEVICE(s); - - NVNET_DPRINTF("------------------------------------------------\n"); - for (int i = 0; i < s->tx_ring_size; i++) { - dma_addr_t tx_ring_addr = nvnet_get_reg(s, NVNET_TX_RING_PHYS_ADDR, 4); - tx_ring_addr += i * sizeof(desc); - pci_dma_read(d, tx_ring_addr, &desc, sizeof(desc)); - NVNET_DPRINTF("TX: Dumping ring desc %d (%" HWADDR_PRIx "): ", i, - tx_ring_addr); - NVNET_DPRINTF("Buffer: 0x%x, ", desc.packet_buffer); - NVNET_DPRINTF("Length: 0x%x, ", desc.length); - NVNET_DPRINTF("Flags: 0x%x\n", desc.flags); - } - NVNET_DPRINTF("------------------------------------------------\n"); - - for (int i = 0; i < s->rx_ring_size; i++) { - dma_addr_t rx_ring_addr = nvnet_get_reg(s, NVNET_RX_RING_PHYS_ADDR, 4); - rx_ring_addr += i * sizeof(desc); - pci_dma_read(d, rx_ring_addr, &desc, sizeof(desc)); - NVNET_DPRINTF("RX: Dumping ring desc %d (%" HWADDR_PRIx "): ", i, - rx_ring_addr); - NVNET_DPRINTF("Buffer: 0x%x, ", desc.packet_buffer); - NVNET_DPRINTF("Length: 0x%x, ", desc.length); - NVNET_DPRINTF("Flags: 0x%x\n", desc.flags); - } - NVNET_DPRINTF("------------------------------------------------\n"); -#endif -} - static uint32_t nvnet_get_reg(NvNetState *s, hwaddr addr, unsigned int size) { assert(addr < MMIO_SIZE); @@ -595,6 +562,39 @@ static uint64_t nvnet_mmio_read(void *opaque, hwaddr addr, unsigned int size) return retval; } +static void nvnet_dump_ring_descriptors(NvNetState *s) +{ +#if NVNET_DEBUG + struct RingDesc desc; + PCIDevice *d = PCI_DEVICE(s); + + NVNET_DPRINTF("------------------------------------------------\n"); + for (int i = 0; i < s->tx_ring_size; i++) { + dma_addr_t tx_ring_addr = nvnet_get_reg(s, NVNET_TX_RING_PHYS_ADDR, 4); + tx_ring_addr += i * sizeof(desc); + pci_dma_read(d, tx_ring_addr, &desc, sizeof(desc)); + NVNET_DPRINTF("TX: Dumping ring desc %d (%" HWADDR_PRIx "): ", i, + tx_ring_addr); + NVNET_DPRINTF("Buffer: 0x%x, ", desc.packet_buffer); + NVNET_DPRINTF("Length: 0x%x, ", desc.length); + NVNET_DPRINTF("Flags: 0x%x\n", desc.flags); + } + NVNET_DPRINTF("------------------------------------------------\n"); + + for (int i = 0; i < s->rx_ring_size; i++) { + dma_addr_t rx_ring_addr = nvnet_get_reg(s, NVNET_RX_RING_PHYS_ADDR, 4); + rx_ring_addr += i * sizeof(desc); + pci_dma_read(d, rx_ring_addr, &desc, sizeof(desc)); + NVNET_DPRINTF("RX: Dumping ring desc %d (%" HWADDR_PRIx "): ", i, + rx_ring_addr); + NVNET_DPRINTF("Buffer: 0x%x, ", desc.packet_buffer); + NVNET_DPRINTF("Length: 0x%x, ", desc.length); + NVNET_DPRINTF("Flags: 0x%x\n", desc.flags); + } + NVNET_DPRINTF("------------------------------------------------\n"); +#endif +} + static void nvnet_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned int size) { From e43cf90c74e493d327063611a6a52745c0d54f51 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 19 Jun 2025 01:55:06 -0700 Subject: [PATCH 03/16] nvnet: Simplify nvnet_mmio_write --- hw/xbox/mcpx/nvnet/nvnet.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/hw/xbox/mcpx/nvnet/nvnet.c b/hw/xbox/mcpx/nvnet/nvnet.c index 17bf2a8286..7fc6acac82 100644 --- a/hw/xbox/mcpx/nvnet/nvnet.c +++ b/hw/xbox/mcpx/nvnet/nvnet.c @@ -599,20 +599,18 @@ static void nvnet_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned int size) { NvNetState *s = NVNET(opaque); - uint32_t temp; + nvnet_set_reg(s, addr, val, size); trace_nvnet_reg_write(addr, nvnet_get_reg_name(addr & ~3), size, val); switch (addr) { case NVNET_RING_SIZE: - nvnet_set_reg(s, addr, val, size); s->rx_ring_size = GET_MASK(val, NVNET_RING_SIZE_RX) + 1; s->tx_ring_size = GET_MASK(val, NVNET_RING_SIZE_TX) + 1; break; case NVNET_MDIO_ADDR: assert(size == 4); - nvnet_set_reg(s, addr, val, size); if (val & NVNET_MDIO_ADDR_WRITE) { nvnet_mdio_write(s); } else { @@ -643,7 +641,7 @@ static void nvnet_mmio_write(void *opaque, hwaddr addr, uint64_t val, nvnet_set_reg(s, NVNET_IRQ_STATUS, 0, 4); break; } else if (val == 0) { - temp = nvnet_get_reg(s, NVNET_UNKNOWN_SETUP_REG3, 4); + uint32_t temp = nvnet_get_reg(s, NVNET_UNKNOWN_SETUP_REG3, 4); if (temp == NVNET_UNKNOWN_SETUP_REG3_VAL1) { /* forcedeth waits for this bit to be set... */ nvnet_set_reg(s, NVNET_UNKNOWN_SETUP_REG5, @@ -651,12 +649,9 @@ static void nvnet_mmio_write(void *opaque, hwaddr addr, uint64_t val, break; } } - - nvnet_set_reg(s, NVNET_TX_RX_CONTROL, val, size); break; case NVNET_IRQ_MASK: - nvnet_set_reg(s, addr, val, size); nvnet_update_irq(s); break; @@ -666,7 +661,6 @@ static void nvnet_mmio_write(void *opaque, hwaddr addr, uint64_t val, break; default: - nvnet_set_reg(s, addr, val, size); break; } } From 3fc128d929a35be533c237fd4f815043e040ebc4 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 19 Jun 2025 01:55:06 -0700 Subject: [PATCH 04/16] nvnet: Fix phy_{addr,reg} sizes in nvnet_mdio_{read,write} --- hw/xbox/mcpx/nvnet/nvnet.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/xbox/mcpx/nvnet/nvnet.c b/hw/xbox/mcpx/nvnet/nvnet.c index 7fc6acac82..963a2540a5 100644 --- a/hw/xbox/mcpx/nvnet/nvnet.c +++ b/hw/xbox/mcpx/nvnet/nvnet.c @@ -516,8 +516,8 @@ static void nvnet_mdio_read(NvNetState *s) { uint32_t mdio_addr = nvnet_get_reg(s, NVNET_MDIO_ADDR, 4); uint32_t mdio_data = -1; - uint32_t phy_addr = GET_MASK(mdio_addr, NVNET_MDIO_ADDR_PHYADDR); - uint32_t phy_reg = GET_MASK(mdio_addr, NVNET_MDIO_ADDR_PHYREG); + uint8_t phy_addr = GET_MASK(mdio_addr, NVNET_MDIO_ADDR_PHYADDR); + uint8_t phy_reg = GET_MASK(mdio_addr, NVNET_MDIO_ADDR_PHYREG); if (phy_addr == PHY_ADDR) { mdio_data = nvnet_phy_reg_read(s, phy_reg); @@ -532,8 +532,8 @@ static void nvnet_mdio_write(NvNetState *s) { uint32_t mdio_addr = nvnet_get_reg(s, NVNET_MDIO_ADDR, 4); uint32_t mdio_data = nvnet_get_reg(s, NVNET_MDIO_DATA, 4); - uint32_t phy_addr = GET_MASK(mdio_addr, NVNET_MDIO_ADDR_PHYADDR); - uint32_t phy_reg = GET_MASK(mdio_addr, NVNET_MDIO_ADDR_PHYREG); + uint8_t phy_addr = GET_MASK(mdio_addr, NVNET_MDIO_ADDR_PHYADDR); + uint8_t phy_reg = GET_MASK(mdio_addr, NVNET_MDIO_ADDR_PHYREG); if (phy_addr == PHY_ADDR) { nvnet_phy_reg_write(s, phy_reg, mdio_data); From bf72b3b33ac4724988f531d6fdfc2633336b8e47 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 19 Jun 2025 01:55:06 -0700 Subject: [PATCH 05/16] nvnet: Remove more useless comments --- hw/xbox/mcpx/nvnet/nvnet.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/xbox/mcpx/nvnet/nvnet.c b/hw/xbox/mcpx/nvnet/nvnet.c index 963a2540a5..c18506aae4 100644 --- a/hw/xbox/mcpx/nvnet/nvnet.c +++ b/hw/xbox/mcpx/nvnet/nvnet.c @@ -264,7 +264,6 @@ static ssize_t nvnet_dma_packet_to_guest(NvNetState *s, const uint8_t *buf, NVNET_DPRINTF("Length: 0x%x, ", desc.length); NVNET_DPRINTF("Flags: 0x%x\n", desc.flags); - /* Trigger interrupt */ NVNET_DPRINTF("Triggering interrupt\n"); uint32_t irq_status = nvnet_get_reg(s, NVNET_IRQ_STATUS, 4); nvnet_set_reg(s, NVNET_IRQ_STATUS, irq_status | NVNET_IRQ_STATUS_RX, 4); @@ -296,7 +295,6 @@ static ssize_t nvnet_dma_packet_from_guest(NvNetState *s) 4); for (int i = 0; i < s->tx_ring_size; i++) { - /* Read ring descriptor */ struct RingDesc desc; s->tx_ring_index %= s->tx_ring_size; dma_addr_t tx_ring_addr = nvnet_get_reg(s, NVNET_TX_RING_PHYS_ADDR, 4); From fded775222f337d0fd2483d4cd1a89392204a6ee Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 19 Jun 2025 01:55:06 -0700 Subject: [PATCH 06/16] nvnet: Clean up idle bit management --- hw/xbox/mcpx/nvnet/nvnet.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/hw/xbox/mcpx/nvnet/nvnet.c b/hw/xbox/mcpx/nvnet/nvnet.c index c18506aae4..2fc4303b41 100644 --- a/hw/xbox/mcpx/nvnet/nvnet.c +++ b/hw/xbox/mcpx/nvnet/nvnet.c @@ -225,10 +225,8 @@ static ssize_t nvnet_dma_packet_to_guest(NvNetState *s, const uint8_t *buf, PCIDevice *d = PCI_DEVICE(s); bool did_receive = false; - nvnet_set_reg(s, NVNET_TX_RX_CONTROL, - nvnet_get_reg(s, NVNET_TX_RX_CONTROL, 4) & - ~NVNET_TX_RX_CONTROL_IDLE, - 4); + uint32_t ctrl = nvnet_get_reg(s, NVNET_TX_RX_CONTROL, 4); + nvnet_set_reg(s, NVNET_TX_RX_CONTROL, ctrl & ~NVNET_TX_RX_CONTROL_IDLE, 4); for (int i = 0; i < s->rx_ring_size; i++) { struct RingDesc desc; @@ -272,9 +270,8 @@ static ssize_t nvnet_dma_packet_to_guest(NvNetState *s, const uint8_t *buf, break; } - nvnet_set_reg( - s, NVNET_TX_RX_CONTROL, - nvnet_get_reg(s, NVNET_TX_RX_CONTROL, 4) | NVNET_TX_RX_CONTROL_IDLE, 4); + ctrl = nvnet_get_reg(s, NVNET_TX_RX_CONTROL, 4); + nvnet_set_reg(s, NVNET_TX_RX_CONTROL, ctrl | NVNET_TX_RX_CONTROL_IDLE, 4); if (did_receive) { return size; @@ -289,10 +286,8 @@ static ssize_t nvnet_dma_packet_from_guest(NvNetState *s) PCIDevice *d = PCI_DEVICE(s); bool packet_sent = false; - nvnet_set_reg(s, NVNET_TX_RX_CONTROL, - nvnet_get_reg(s, NVNET_TX_RX_CONTROL, 4) & - ~NVNET_TX_RX_CONTROL_IDLE, - 4); + uint32_t ctrl = nvnet_get_reg(s, NVNET_TX_RX_CONTROL, 4); + nvnet_set_reg(s, NVNET_TX_RX_CONTROL, ctrl & ~NVNET_TX_RX_CONTROL_IDLE, 4); for (int i = 0; i < s->tx_ring_size; i++) { struct RingDesc desc; @@ -346,9 +341,8 @@ static ssize_t nvnet_dma_packet_from_guest(NvNetState *s) nvnet_update_irq(s); } - nvnet_set_reg( - s, NVNET_TX_RX_CONTROL, - nvnet_get_reg(s, NVNET_TX_RX_CONTROL, 4) | NVNET_TX_RX_CONTROL_IDLE, 4); + ctrl = nvnet_get_reg(s, NVNET_TX_RX_CONTROL, 4); + nvnet_set_reg(s, NVNET_TX_RX_CONTROL, ctrl | NVNET_TX_RX_CONTROL_IDLE, 4); return 0; } From 1dbda16970bda6602449c123c2668c9120cd0de2 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 19 Jun 2025 01:55:06 -0700 Subject: [PATCH 07/16] nvnet: Simplify nvnet_dma_packet_to_guest --- hw/xbox/mcpx/nvnet/nvnet.c | 46 ++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/hw/xbox/mcpx/nvnet/nvnet.c b/hw/xbox/mcpx/nvnet/nvnet.c index 2fc4303b41..52ca4157e4 100644 --- a/hw/xbox/mcpx/nvnet/nvnet.c +++ b/hw/xbox/mcpx/nvnet/nvnet.c @@ -223,33 +223,26 @@ static ssize_t nvnet_dma_packet_to_guest(NvNetState *s, const uint8_t *buf, size_t size) { PCIDevice *d = PCI_DEVICE(s); - bool did_receive = false; + ssize_t rval; uint32_t ctrl = nvnet_get_reg(s, NVNET_TX_RX_CONTROL, 4); nvnet_set_reg(s, NVNET_TX_RX_CONTROL, ctrl & ~NVNET_TX_RX_CONTROL_IDLE, 4); - for (int i = 0; i < s->rx_ring_size; i++) { - struct RingDesc desc; - s->rx_ring_index %= s->rx_ring_size; - dma_addr_t rx_ring_addr = nvnet_get_reg(s, NVNET_RX_RING_PHYS_ADDR, 4); - rx_ring_addr += s->rx_ring_index * sizeof(desc); - pci_dma_read(d, rx_ring_addr, &desc, sizeof(desc)); + struct RingDesc desc; + s->rx_ring_index %= s->rx_ring_size; + dma_addr_t rx_ring_addr = nvnet_get_reg(s, NVNET_RX_RING_PHYS_ADDR, 4); + rx_ring_addr += s->rx_ring_index * sizeof(desc); + pci_dma_read(d, rx_ring_addr, &desc, sizeof(desc)); - NVNET_DPRINTF("RX: Looking at ring descriptor %d (0x%" HWADDR_PRIx - "): ", - s->rx_ring_index, rx_ring_addr); - NVNET_DPRINTF("Buffer: 0x%x, ", desc.packet_buffer); - NVNET_DPRINTF("Length: 0x%x, ", desc.length); - NVNET_DPRINTF("Flags: 0x%x\n", desc.flags); - - if (!(desc.flags & NV_RX_AVAIL)) { - break; - } + NVNET_DPRINTF("RX: Looking at ring descriptor %d (0x%" HWADDR_PRIx "): ", + s->rx_ring_index, rx_ring_addr); + NVNET_DPRINTF("Buffer: 0x%x, ", desc.packet_buffer); + NVNET_DPRINTF("Length: 0x%x, ", desc.length); + NVNET_DPRINTF("Flags: 0x%x\n", desc.flags); + if (desc.flags & NV_RX_AVAIL) { assert((desc.length + 1) >= size); // FIXME - s->rx_ring_index += 1; - NVNET_DPRINTF("Transferring packet, size 0x%zx, to memory at 0x%x\n", size, desc.packet_buffer); pci_dma_write(d, desc.packet_buffer, buf, size); @@ -266,19 +259,18 @@ static ssize_t nvnet_dma_packet_to_guest(NvNetState *s, const uint8_t *buf, uint32_t irq_status = nvnet_get_reg(s, NVNET_IRQ_STATUS, 4); nvnet_set_reg(s, NVNET_IRQ_STATUS, irq_status | NVNET_IRQ_STATUS_RX, 4); nvnet_update_irq(s); - did_receive = true; - break; + + s->rx_ring_index += 1; + rval = size; + } else { + NVNET_DPRINTF("Could not find free buffer!\n"); + rval = -1; } ctrl = nvnet_get_reg(s, NVNET_TX_RX_CONTROL, 4); nvnet_set_reg(s, NVNET_TX_RX_CONTROL, ctrl | NVNET_TX_RX_CONTROL_IDLE, 4); - if (did_receive) { - return size; - } else { - NVNET_DPRINTF("Could not find free buffer!\n"); - return -1; - } + return rval; } static ssize_t nvnet_dma_packet_from_guest(NvNetState *s) From 3fd776d98e17ead3e34bdd8053fbac10f71e8813 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 19 Jun 2025 01:55:06 -0700 Subject: [PATCH 08/16] nvnet: Convert descriptor fields to host byte order and back --- hw/xbox/mcpx/nvnet/nvnet.c | 74 ++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/hw/xbox/mcpx/nvnet/nvnet.c b/hw/xbox/mcpx/nvnet/nvnet.c index 52ca4157e4..922956941b 100644 --- a/hw/xbox/mcpx/nvnet/nvnet.c +++ b/hw/xbox/mcpx/nvnet/nvnet.c @@ -234,26 +234,33 @@ static ssize_t nvnet_dma_packet_to_guest(NvNetState *s, const uint8_t *buf, rx_ring_addr += s->rx_ring_index * sizeof(desc); pci_dma_read(d, rx_ring_addr, &desc, sizeof(desc)); + uint32_t packet_buffer = le32_to_cpu(desc.packet_buffer); + uint16_t length = le16_to_cpu(desc.length); + uint16_t flags = le16_to_cpu(desc.flags); + NVNET_DPRINTF("RX: Looking at ring descriptor %d (0x%" HWADDR_PRIx "): ", s->rx_ring_index, rx_ring_addr); - NVNET_DPRINTF("Buffer: 0x%x, ", desc.packet_buffer); - NVNET_DPRINTF("Length: 0x%x, ", desc.length); - NVNET_DPRINTF("Flags: 0x%x\n", desc.flags); + NVNET_DPRINTF("Buffer: 0x%x, ", packet_buffer); + NVNET_DPRINTF("Length: 0x%x, ", length); + NVNET_DPRINTF("Flags: 0x%x\n", flags); - if (desc.flags & NV_RX_AVAIL) { - assert((desc.length + 1) >= size); // FIXME + if (flags & NV_RX_AVAIL) { + assert((length + 1) >= size); // FIXME NVNET_DPRINTF("Transferring packet, size 0x%zx, to memory at 0x%x\n", - size, desc.packet_buffer); - pci_dma_write(d, desc.packet_buffer, buf, size); + size, packet_buffer); + pci_dma_write(d, packet_buffer, buf, size); - desc.length = size; - desc.flags = NV_RX_BIT4 | NV_RX_DESCRIPTORVALID; + length = size; + flags = NV_RX_BIT4 | NV_RX_DESCRIPTORVALID; + + desc.length = cpu_to_le16(length); + desc.flags = cpu_to_le16(flags); pci_dma_write(d, rx_ring_addr, &desc, sizeof(desc)); NVNET_DPRINTF("Updated ring descriptor: "); - NVNET_DPRINTF("Length: 0x%x, ", desc.length); - NVNET_DPRINTF("Flags: 0x%x\n", desc.flags); + NVNET_DPRINTF("Length: 0x%x, ", length); + NVNET_DPRINTF("Flags: 0x%x\n", flags); NVNET_DPRINTF("Triggering interrupt\n"); uint32_t irq_status = nvnet_get_reg(s, NVNET_IRQ_STATUS, 4); @@ -288,25 +295,29 @@ static ssize_t nvnet_dma_packet_from_guest(NvNetState *s) tx_ring_addr += s->tx_ring_index * sizeof(desc); pci_dma_read(d, tx_ring_addr, &desc, sizeof(desc)); + uint32_t packet_buffer = le32_to_cpu(desc.packet_buffer); + uint16_t length = le16_to_cpu(desc.length); + uint16_t flags = le16_to_cpu(desc.flags); + NVNET_DPRINTF("TX: Looking at ring desc %d (%" HWADDR_PRIx "): ", s->tx_ring_index, tx_ring_addr); - NVNET_DPRINTF("Buffer: 0x%x, ", desc.packet_buffer); - NVNET_DPRINTF("Length: 0x%x, ", desc.length); - NVNET_DPRINTF("Flags: 0x%x\n", desc.flags); + NVNET_DPRINTF("Buffer: 0x%x, ", packet_buffer); + NVNET_DPRINTF("Length: 0x%x, ", length); + NVNET_DPRINTF("Flags: 0x%x\n", flags); - if (!(desc.flags & NV_TX_VALID)) { + if (!(flags & NV_TX_VALID)) { break; } s->tx_ring_index += 1; - assert((s->tx_dma_buf_offset + desc.length + 1) <= + assert((s->tx_dma_buf_offset + length + 1) <= sizeof(s->tx_dma_buf)); - pci_dma_read(d, desc.packet_buffer, - &s->tx_dma_buf[s->tx_dma_buf_offset], desc.length + 1); - s->tx_dma_buf_offset += desc.length + 1; + pci_dma_read(d, packet_buffer, &s->tx_dma_buf[s->tx_dma_buf_offset], + length + 1); + s->tx_dma_buf_offset += length + 1; - bool is_last_packet = desc.flags & NV_TX_LASTPACKET; + bool is_last_packet = flags & NV_TX_LASTPACKET; if (is_last_packet) { NVNET_DPRINTF("Sending packet...\n"); nvnet_send_packet(s, s->tx_dma_buf, s->tx_dma_buf_offset); @@ -314,10 +325,13 @@ static ssize_t nvnet_dma_packet_from_guest(NvNetState *s) packet_sent = true; } - desc.flags &= ~(NV_TX_VALID | NV_TX_RETRYERROR | NV_TX_DEFERRED | - NV_TX_CARRIERLOST | NV_TX_LATECOLLISION | - NV_TX_UNDERFLOW | NV_TX_ERROR); - desc.length = desc.length + 5; + flags &= ~(NV_TX_VALID | NV_TX_RETRYERROR | NV_TX_DEFERRED | + NV_TX_CARRIERLOST | NV_TX_LATECOLLISION | NV_TX_UNDERFLOW | + NV_TX_ERROR); + length += 5; // FIXME + + desc.flags = cpu_to_le16(flags); + desc.length = cpu_to_le16(length); pci_dma_write(d, tx_ring_addr, &desc, sizeof(desc)); if (is_last_packet) { @@ -559,9 +573,9 @@ static void nvnet_dump_ring_descriptors(NvNetState *s) pci_dma_read(d, tx_ring_addr, &desc, sizeof(desc)); NVNET_DPRINTF("TX: Dumping ring desc %d (%" HWADDR_PRIx "): ", i, tx_ring_addr); - NVNET_DPRINTF("Buffer: 0x%x, ", desc.packet_buffer); - NVNET_DPRINTF("Length: 0x%x, ", desc.length); - NVNET_DPRINTF("Flags: 0x%x\n", desc.flags); + NVNET_DPRINTF("Buffer: 0x%x, ", le32_to_cpu(desc.packet_buffer)); + NVNET_DPRINTF("Length: 0x%x, ", le16_to_cpu(desc.length)); + NVNET_DPRINTF("Flags: 0x%x\n", le16_to_cpu(desc.flags)); } NVNET_DPRINTF("------------------------------------------------\n"); @@ -571,9 +585,9 @@ static void nvnet_dump_ring_descriptors(NvNetState *s) pci_dma_read(d, rx_ring_addr, &desc, sizeof(desc)); NVNET_DPRINTF("RX: Dumping ring desc %d (%" HWADDR_PRIx "): ", i, rx_ring_addr); - NVNET_DPRINTF("Buffer: 0x%x, ", desc.packet_buffer); - NVNET_DPRINTF("Length: 0x%x, ", desc.length); - NVNET_DPRINTF("Flags: 0x%x\n", desc.flags); + NVNET_DPRINTF("Buffer: 0x%x, ", le32_to_cpu(desc.packet_buffer)); + NVNET_DPRINTF("Length: 0x%x, ", le16_to_cpu(desc.length)); + NVNET_DPRINTF("Flags: 0x%x\n", le16_to_cpu(desc.flags)); } NVNET_DPRINTF("------------------------------------------------\n"); #endif From bfe9f659d26fdfd9507ea6759e512546e472b37a Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 19 Jun 2025 01:55:06 -0700 Subject: [PATCH 09/16] nvnet: Shrink some debug printfs --- hw/xbox/mcpx/nvnet/nvnet.c | 48 ++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/hw/xbox/mcpx/nvnet/nvnet.c b/hw/xbox/mcpx/nvnet/nvnet.c index 922956941b..3b32acb46c 100644 --- a/hw/xbox/mcpx/nvnet/nvnet.c +++ b/hw/xbox/mcpx/nvnet/nvnet.c @@ -238,11 +238,9 @@ static ssize_t nvnet_dma_packet_to_guest(NvNetState *s, const uint8_t *buf, uint16_t length = le16_to_cpu(desc.length); uint16_t flags = le16_to_cpu(desc.flags); - NVNET_DPRINTF("RX: Looking at ring descriptor %d (0x%" HWADDR_PRIx "): ", - s->rx_ring_index, rx_ring_addr); - NVNET_DPRINTF("Buffer: 0x%x, ", packet_buffer); - NVNET_DPRINTF("Length: 0x%x, ", length); - NVNET_DPRINTF("Flags: 0x%x\n", flags); + NVNET_DPRINTF("RX: Looking at ring descriptor %d (0x%" HWADDR_PRIx "): " + "Buffer: 0x%x, Length: 0x%x, Flags: 0x%x\n", + s->rx_ring_index, rx_ring_addr, packet_buffer, length, flags); if (flags & NV_RX_AVAIL) { assert((length + 1) >= size); // FIXME @@ -258,9 +256,8 @@ static ssize_t nvnet_dma_packet_to_guest(NvNetState *s, const uint8_t *buf, desc.flags = cpu_to_le16(flags); pci_dma_write(d, rx_ring_addr, &desc, sizeof(desc)); - NVNET_DPRINTF("Updated ring descriptor: "); - NVNET_DPRINTF("Length: 0x%x, ", length); - NVNET_DPRINTF("Flags: 0x%x\n", flags); + NVNET_DPRINTF("Updated ring descriptor: Length: 0x%x, Flags: 0x%x\n", + length, flags); NVNET_DPRINTF("Triggering interrupt\n"); uint32_t irq_status = nvnet_get_reg(s, NVNET_IRQ_STATUS, 4); @@ -299,11 +296,10 @@ static ssize_t nvnet_dma_packet_from_guest(NvNetState *s) uint16_t length = le16_to_cpu(desc.length); uint16_t flags = le16_to_cpu(desc.flags); - NVNET_DPRINTF("TX: Looking at ring desc %d (%" HWADDR_PRIx "): ", - s->tx_ring_index, tx_ring_addr); - NVNET_DPRINTF("Buffer: 0x%x, ", packet_buffer); - NVNET_DPRINTF("Length: 0x%x, ", length); - NVNET_DPRINTF("Flags: 0x%x\n", flags); + NVNET_DPRINTF("TX: Looking at ring desc %d (%" HWADDR_PRIx "): " + "Buffer: 0x%x, Length: 0x%x, Flags: 0x%x\n", + s->tx_ring_index, tx_ring_addr, packet_buffer, length, + flags); if (!(flags & NV_TX_VALID)) { break; @@ -562,33 +558,35 @@ static uint64_t nvnet_mmio_read(void *opaque, hwaddr addr, unsigned int size) static void nvnet_dump_ring_descriptors(NvNetState *s) { -#if NVNET_DEBUG - struct RingDesc desc; +#if DEBUG_NVNET PCIDevice *d = PCI_DEVICE(s); NVNET_DPRINTF("------------------------------------------------\n"); + for (int i = 0; i < s->tx_ring_size; i++) { + struct RingDesc desc; dma_addr_t tx_ring_addr = nvnet_get_reg(s, NVNET_TX_RING_PHYS_ADDR, 4); tx_ring_addr += i * sizeof(desc); pci_dma_read(d, tx_ring_addr, &desc, sizeof(desc)); - NVNET_DPRINTF("TX: Dumping ring desc %d (%" HWADDR_PRIx "): ", i, - tx_ring_addr); - NVNET_DPRINTF("Buffer: 0x%x, ", le32_to_cpu(desc.packet_buffer)); - NVNET_DPRINTF("Length: 0x%x, ", le16_to_cpu(desc.length)); - NVNET_DPRINTF("Flags: 0x%x\n", le16_to_cpu(desc.flags)); + NVNET_DPRINTF("TX desc %d (%" HWADDR_PRIx "): " + "Buffer: 0x%x, Length: 0x%x, Flags: 0x%x\n", + i, tx_ring_addr, le32_to_cpu(desc.packet_buffer), + le16_to_cpu(desc.length), le16_to_cpu(desc.flags)); } + NVNET_DPRINTF("------------------------------------------------\n"); for (int i = 0; i < s->rx_ring_size; i++) { + struct RingDesc desc; dma_addr_t rx_ring_addr = nvnet_get_reg(s, NVNET_RX_RING_PHYS_ADDR, 4); rx_ring_addr += i * sizeof(desc); pci_dma_read(d, rx_ring_addr, &desc, sizeof(desc)); - NVNET_DPRINTF("RX: Dumping ring desc %d (%" HWADDR_PRIx "): ", i, - rx_ring_addr); - NVNET_DPRINTF("Buffer: 0x%x, ", le32_to_cpu(desc.packet_buffer)); - NVNET_DPRINTF("Length: 0x%x, ", le16_to_cpu(desc.length)); - NVNET_DPRINTF("Flags: 0x%x\n", le16_to_cpu(desc.flags)); + NVNET_DPRINTF("RX desc %d (%" HWADDR_PRIx "): " + "Buffer: 0x%x, Length: 0x%x, Flags: 0x%x\n", + i, rx_ring_addr, le32_to_cpu(desc.packet_buffer), + le16_to_cpu(desc.length), le16_to_cpu(desc.flags)); } + NVNET_DPRINTF("------------------------------------------------\n"); #endif } From 9e00beaffabf9a527a31fbda4637f15475d87c13 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 19 Jun 2025 01:55:06 -0700 Subject: [PATCH 10/16] nvnet: Migrate ring size tracking to registers --- hw/xbox/mcpx/nvnet/nvnet.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/hw/xbox/mcpx/nvnet/nvnet.c b/hw/xbox/mcpx/nvnet/nvnet.c index 3b32acb46c..bcbb766d2e 100644 --- a/hw/xbox/mcpx/nvnet/nvnet.c +++ b/hw/xbox/mcpx/nvnet/nvnet.c @@ -66,9 +66,7 @@ typedef struct NvNetState { uint32_t phy_regs[6]; uint8_t tx_ring_index; - uint8_t tx_ring_size; uint8_t rx_ring_index; - uint8_t rx_ring_size; uint8_t tx_dma_buf[TX_ALLOC_BUFSIZE]; uint32_t tx_dma_buf_offset; uint8_t rx_dma_buf[RX_ALLOC_BUFSIZE]; @@ -219,6 +217,18 @@ static void nvnet_send_packet(NvNetState *s, const uint8_t *buf, int size) qemu_send_packet(nc, buf, size); } +static uint16_t get_tx_ring_size(NvNetState *s) +{ + uint32_t ring_size = nvnet_get_reg(s, NVNET_RING_SIZE, 4); + return GET_MASK(ring_size, NVNET_RING_SIZE_TX) + 1; +} + +static uint16_t get_rx_ring_size(NvNetState *s) +{ + uint32_t ring_size = nvnet_get_reg(s, NVNET_RING_SIZE, 4); + return GET_MASK(ring_size, NVNET_RING_SIZE_RX) + 1; +} + static ssize_t nvnet_dma_packet_to_guest(NvNetState *s, const uint8_t *buf, size_t size) { @@ -229,7 +239,7 @@ static ssize_t nvnet_dma_packet_to_guest(NvNetState *s, const uint8_t *buf, nvnet_set_reg(s, NVNET_TX_RX_CONTROL, ctrl & ~NVNET_TX_RX_CONTROL_IDLE, 4); struct RingDesc desc; - s->rx_ring_index %= s->rx_ring_size; + s->rx_ring_index %= get_rx_ring_size(s); dma_addr_t rx_ring_addr = nvnet_get_reg(s, NVNET_RX_RING_PHYS_ADDR, 4); rx_ring_addr += s->rx_ring_index * sizeof(desc); pci_dma_read(d, rx_ring_addr, &desc, sizeof(desc)); @@ -285,9 +295,9 @@ static ssize_t nvnet_dma_packet_from_guest(NvNetState *s) uint32_t ctrl = nvnet_get_reg(s, NVNET_TX_RX_CONTROL, 4); nvnet_set_reg(s, NVNET_TX_RX_CONTROL, ctrl & ~NVNET_TX_RX_CONTROL_IDLE, 4); - for (int i = 0; i < s->tx_ring_size; i++) { + for (int i = 0; i < get_tx_ring_size(s); i++) { struct RingDesc desc; - s->tx_ring_index %= s->tx_ring_size; + s->tx_ring_index %= get_tx_ring_size(s); dma_addr_t tx_ring_addr = nvnet_get_reg(s, NVNET_TX_RING_PHYS_ADDR, 4); tx_ring_addr += s->tx_ring_index * sizeof(desc); pci_dma_read(d, tx_ring_addr, &desc, sizeof(desc)); @@ -563,7 +573,7 @@ static void nvnet_dump_ring_descriptors(NvNetState *s) NVNET_DPRINTF("------------------------------------------------\n"); - for (int i = 0; i < s->tx_ring_size; i++) { + for (int i = 0; i < get_tx_ring_size(s); i++) { struct RingDesc desc; dma_addr_t tx_ring_addr = nvnet_get_reg(s, NVNET_TX_RING_PHYS_ADDR, 4); tx_ring_addr += i * sizeof(desc); @@ -576,7 +586,7 @@ static void nvnet_dump_ring_descriptors(NvNetState *s) NVNET_DPRINTF("------------------------------------------------\n"); - for (int i = 0; i < s->rx_ring_size; i++) { + for (int i = 0; i < get_rx_ring_size(s); i++) { struct RingDesc desc; dma_addr_t rx_ring_addr = nvnet_get_reg(s, NVNET_RX_RING_PHYS_ADDR, 4); rx_ring_addr += i * sizeof(desc); @@ -600,11 +610,6 @@ static void nvnet_mmio_write(void *opaque, hwaddr addr, uint64_t val, trace_nvnet_reg_write(addr, nvnet_get_reg_name(addr & ~3), size, val); switch (addr) { - case NVNET_RING_SIZE: - s->rx_ring_size = GET_MASK(val, NVNET_RING_SIZE_RX) + 1; - s->tx_ring_size = GET_MASK(val, NVNET_RING_SIZE_TX) + 1; - break; - case NVNET_MDIO_ADDR: assert(size == 4); if (val & NVNET_MDIO_ADDR_WRITE) { @@ -695,9 +700,7 @@ static void nvnet_realize(PCIDevice *pci_dev, Error **errp) memset(s->regs, 0, sizeof(s->regs)); s->rx_ring_index = 0; - s->rx_ring_size = 0; s->tx_ring_index = 0; - s->tx_ring_size = 0; memory_region_init_io(&s->mmio, OBJECT(dev), &nvnet_mmio_ops, s, "nvnet-mmio", MMIO_SIZE); @@ -731,9 +734,7 @@ static void nvnet_reset(void *opaque) memset(&s->regs, 0, sizeof(s->regs)); memset(&s->phy_regs, 0, sizeof(s->phy_regs)); s->tx_ring_index = 0; - s->tx_ring_size = 0; s->rx_ring_index = 0; - s->rx_ring_size = 0; memset(&s->tx_dma_buf, 0, sizeof(s->tx_dma_buf)); s->tx_dma_buf_offset = 0; memset(&s->rx_dma_buf, 0, sizeof(s->rx_dma_buf)); @@ -754,9 +755,9 @@ static const VMStateDescription vmstate_nvnet = { VMSTATE_UINT8_ARRAY(regs, NvNetState, MMIO_SIZE), VMSTATE_UINT32_ARRAY(phy_regs, NvNetState, 6), VMSTATE_UINT8(tx_ring_index, NvNetState), - VMSTATE_UINT8(tx_ring_size, NvNetState), + VMSTATE_UNUSED(1), VMSTATE_UINT8(rx_ring_index, NvNetState), - VMSTATE_UINT8(rx_ring_size, NvNetState), + VMSTATE_UNUSED(1), VMSTATE_END_OF_LIST() }, }; From 389f7ad577b2a32b94375f7831562be7401374f8 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 19 Jun 2025 01:55:06 -0700 Subject: [PATCH 11/16] nvnet: Rename RingDesc::packet_buffer -> buffer_addr --- hw/xbox/mcpx/nvnet/nvnet.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/hw/xbox/mcpx/nvnet/nvnet.c b/hw/xbox/mcpx/nvnet/nvnet.c index bcbb766d2e..f00fafb64b 100644 --- a/hw/xbox/mcpx/nvnet/nvnet.c +++ b/hw/xbox/mcpx/nvnet/nvnet.c @@ -73,7 +73,7 @@ typedef struct NvNetState { } NvNetState; struct RingDesc { - uint32_t packet_buffer; + uint32_t buffer_addr; uint16_t length; uint16_t flags; } QEMU_PACKED; @@ -244,20 +244,20 @@ static ssize_t nvnet_dma_packet_to_guest(NvNetState *s, const uint8_t *buf, rx_ring_addr += s->rx_ring_index * sizeof(desc); pci_dma_read(d, rx_ring_addr, &desc, sizeof(desc)); - uint32_t packet_buffer = le32_to_cpu(desc.packet_buffer); + uint32_t buffer_addr = le32_to_cpu(desc.buffer_addr); uint16_t length = le16_to_cpu(desc.length); uint16_t flags = le16_to_cpu(desc.flags); NVNET_DPRINTF("RX: Looking at ring descriptor %d (0x%" HWADDR_PRIx "): " "Buffer: 0x%x, Length: 0x%x, Flags: 0x%x\n", - s->rx_ring_index, rx_ring_addr, packet_buffer, length, flags); + s->rx_ring_index, rx_ring_addr, buffer_addr, length, flags); if (flags & NV_RX_AVAIL) { assert((length + 1) >= size); // FIXME NVNET_DPRINTF("Transferring packet, size 0x%zx, to memory at 0x%x\n", - size, packet_buffer); - pci_dma_write(d, packet_buffer, buf, size); + size, buffer_addr); + pci_dma_write(d, buffer_addr, buf, size); length = size; flags = NV_RX_BIT4 | NV_RX_DESCRIPTORVALID; @@ -302,13 +302,13 @@ static ssize_t nvnet_dma_packet_from_guest(NvNetState *s) tx_ring_addr += s->tx_ring_index * sizeof(desc); pci_dma_read(d, tx_ring_addr, &desc, sizeof(desc)); - uint32_t packet_buffer = le32_to_cpu(desc.packet_buffer); + uint32_t buffer_addr = le32_to_cpu(desc.buffer_addr); uint16_t length = le16_to_cpu(desc.length); uint16_t flags = le16_to_cpu(desc.flags); NVNET_DPRINTF("TX: Looking at ring desc %d (%" HWADDR_PRIx "): " "Buffer: 0x%x, Length: 0x%x, Flags: 0x%x\n", - s->tx_ring_index, tx_ring_addr, packet_buffer, length, + s->tx_ring_index, tx_ring_addr, buffer_addr, length, flags); if (!(flags & NV_TX_VALID)) { @@ -319,7 +319,7 @@ static ssize_t nvnet_dma_packet_from_guest(NvNetState *s) assert((s->tx_dma_buf_offset + length + 1) <= sizeof(s->tx_dma_buf)); - pci_dma_read(d, packet_buffer, &s->tx_dma_buf[s->tx_dma_buf_offset], + pci_dma_read(d, buffer_addr, &s->tx_dma_buf[s->tx_dma_buf_offset], length + 1); s->tx_dma_buf_offset += length + 1; @@ -580,7 +580,7 @@ static void nvnet_dump_ring_descriptors(NvNetState *s) pci_dma_read(d, tx_ring_addr, &desc, sizeof(desc)); NVNET_DPRINTF("TX desc %d (%" HWADDR_PRIx "): " "Buffer: 0x%x, Length: 0x%x, Flags: 0x%x\n", - i, tx_ring_addr, le32_to_cpu(desc.packet_buffer), + i, tx_ring_addr, le32_to_cpu(desc.buffer_addr), le16_to_cpu(desc.length), le16_to_cpu(desc.flags)); } @@ -593,7 +593,7 @@ static void nvnet_dump_ring_descriptors(NvNetState *s) pci_dma_read(d, rx_ring_addr, &desc, sizeof(desc)); NVNET_DPRINTF("RX desc %d (%" HWADDR_PRIx "): " "Buffer: 0x%x, Length: 0x%x, Flags: 0x%x\n", - i, rx_ring_addr, le32_to_cpu(desc.packet_buffer), + i, rx_ring_addr, le32_to_cpu(desc.buffer_addr), le16_to_cpu(desc.length), le16_to_cpu(desc.flags)); } From 59d98ed3be5b7093b7199c4a7870a38b67b92880 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 19 Jun 2025 01:55:06 -0700 Subject: [PATCH 12/16] nvnet: Drop some useless debug prints --- hw/xbox/mcpx/nvnet/nvnet.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/xbox/mcpx/nvnet/nvnet.c b/hw/xbox/mcpx/nvnet/nvnet.c index f00fafb64b..254b7faa0a 100644 --- a/hw/xbox/mcpx/nvnet/nvnet.c +++ b/hw/xbox/mcpx/nvnet/nvnet.c @@ -325,7 +325,6 @@ static ssize_t nvnet_dma_packet_from_guest(NvNetState *s) bool is_last_packet = flags & NV_TX_LASTPACKET; if (is_last_packet) { - NVNET_DPRINTF("Sending packet...\n"); nvnet_send_packet(s, s->tx_dma_buf, s->tx_dma_buf_offset); s->tx_dma_buf_offset = 0; packet_sent = true; @@ -347,7 +346,6 @@ static ssize_t nvnet_dma_packet_from_guest(NvNetState *s) } if (packet_sent) { - NVNET_DPRINTF("Triggering interrupt\n"); uint32_t irq_status = nvnet_get_reg(s, NVNET_IRQ_STATUS, 4); nvnet_set_reg(s, NVNET_IRQ_STATUS, irq_status | NVNET_IRQ_STATUS_TX, 4); nvnet_update_irq(s); From d4a5e78ba77dc817aca4e62d20f1dad796f00e0a Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 19 Jun 2025 01:55:06 -0700 Subject: [PATCH 13/16] nvnet: Drop post-tx descriptor length increase --- hw/xbox/mcpx/nvnet/nvnet.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/xbox/mcpx/nvnet/nvnet.c b/hw/xbox/mcpx/nvnet/nvnet.c index 254b7faa0a..99127c7ce5 100644 --- a/hw/xbox/mcpx/nvnet/nvnet.c +++ b/hw/xbox/mcpx/nvnet/nvnet.c @@ -333,10 +333,8 @@ static ssize_t nvnet_dma_packet_from_guest(NvNetState *s) flags &= ~(NV_TX_VALID | NV_TX_RETRYERROR | NV_TX_DEFERRED | NV_TX_CARRIERLOST | NV_TX_LATECOLLISION | NV_TX_UNDERFLOW | NV_TX_ERROR); - length += 5; // FIXME desc.flags = cpu_to_le16(flags); - desc.length = cpu_to_le16(length); pci_dma_write(d, tx_ring_addr, &desc, sizeof(desc)); if (is_last_packet) { From e75c5f3e8fbc326459397d4d19143b484cf95241 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 19 Jun 2025 01:55:06 -0700 Subject: [PATCH 14/16] nvnet: Simplify length adjustment in nvnet_dma_packet_from_guest --- hw/xbox/mcpx/nvnet/nvnet.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/xbox/mcpx/nvnet/nvnet.c b/hw/xbox/mcpx/nvnet/nvnet.c index 99127c7ce5..1a4d50ad83 100644 --- a/hw/xbox/mcpx/nvnet/nvnet.c +++ b/hw/xbox/mcpx/nvnet/nvnet.c @@ -303,7 +303,7 @@ static ssize_t nvnet_dma_packet_from_guest(NvNetState *s) pci_dma_read(d, tx_ring_addr, &desc, sizeof(desc)); uint32_t buffer_addr = le32_to_cpu(desc.buffer_addr); - uint16_t length = le16_to_cpu(desc.length); + uint16_t length = le16_to_cpu(desc.length) + 1; uint16_t flags = le16_to_cpu(desc.flags); NVNET_DPRINTF("TX: Looking at ring desc %d (%" HWADDR_PRIx "): " @@ -317,11 +317,11 @@ static ssize_t nvnet_dma_packet_from_guest(NvNetState *s) s->tx_ring_index += 1; - assert((s->tx_dma_buf_offset + length + 1) <= + assert((s->tx_dma_buf_offset + length) <= sizeof(s->tx_dma_buf)); pci_dma_read(d, buffer_addr, &s->tx_dma_buf[s->tx_dma_buf_offset], - length + 1); - s->tx_dma_buf_offset += length + 1; + length); + s->tx_dma_buf_offset += length; bool is_last_packet = flags & NV_TX_LASTPACKET; if (is_last_packet) { From 0eb0a315b8840ab4b124affa5124736037783033 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 19 Jun 2025 01:55:06 -0700 Subject: [PATCH 15/16] nvnet: Migrate ring index tracking to device registers --- hw/xbox/mcpx/nvnet/nvnet.c | 143 +++++++++++++++++++++++--------- hw/xbox/mcpx/nvnet/nvnet_regs.h | 8 +- 2 files changed, 112 insertions(+), 39 deletions(-) diff --git a/hw/xbox/mcpx/nvnet/nvnet.c b/hw/xbox/mcpx/nvnet/nvnet.c index 1a4d50ad83..0590601dc8 100644 --- a/hw/xbox/mcpx/nvnet/nvnet.c +++ b/hw/xbox/mcpx/nvnet/nvnet.c @@ -65,11 +65,13 @@ typedef struct NvNetState { uint8_t regs[MMIO_SIZE]; uint32_t phy_regs[6]; - uint8_t tx_ring_index; - uint8_t rx_ring_index; uint8_t tx_dma_buf[TX_ALLOC_BUFSIZE]; uint32_t tx_dma_buf_offset; uint8_t rx_dma_buf[RX_ALLOC_BUFSIZE]; + + /* Deprecated */ + uint8_t tx_ring_index; + uint8_t rx_ring_index; } NvNetState; struct RingDesc { @@ -110,8 +112,13 @@ static const char *nvnet_get_reg_name(hwaddr addr) R(NVNET_RING_SIZE) R(NVNET_UNKNOWN_TRANSMITTER_REG) R(NVNET_LINKSPEED) + R(NVNET_TX_RING_CURRENT_DESC_PHYS_ADDR) + R(NVNET_RX_RING_CURRENT_DESC_PHYS_ADDR) + R(NVNET_TX_CURRENT_BUFFER_PHYS_ADDR) + R(NVNET_RX_CURRENT_BUFFER_PHYS_ADDR) R(NVNET_UNKNOWN_SETUP_REG5) - R(NVNET_UNKNOWN_SETUP_REG3) + R(NVNET_TX_RING_NEXT_DESC_PHYS_ADDR) + R(NVNET_RX_RING_NEXT_DESC_PHYS_ADDR) R(NVNET_UNKNOWN_SETUP_REG8) R(NVNET_UNKNOWN_SETUP_REG7) R(NVNET_TX_RX_CONTROL) @@ -229,6 +236,19 @@ static uint16_t get_rx_ring_size(NvNetState *s) return GET_MASK(ring_size, NVNET_RING_SIZE_RX) + 1; } +static void reset_descriptor_ring_pointers(NvNetState *s) +{ + uint32_t base_desc_addr; + + base_desc_addr = nvnet_get_reg(s, NVNET_TX_RING_PHYS_ADDR, 4); + nvnet_set_reg(s, NVNET_TX_RING_CURRENT_DESC_PHYS_ADDR, base_desc_addr, 4); + nvnet_set_reg(s, NVNET_TX_RING_NEXT_DESC_PHYS_ADDR, base_desc_addr, 4); + + base_desc_addr = nvnet_get_reg(s, NVNET_RX_RING_PHYS_ADDR, 4); + nvnet_set_reg(s, NVNET_RX_RING_CURRENT_DESC_PHYS_ADDR, base_desc_addr, 4); + nvnet_set_reg(s, NVNET_RX_RING_NEXT_DESC_PHYS_ADDR, base_desc_addr, 4); +} + static ssize_t nvnet_dma_packet_to_guest(NvNetState *s, const uint8_t *buf, size_t size) { @@ -238,19 +258,28 @@ static ssize_t nvnet_dma_packet_to_guest(NvNetState *s, const uint8_t *buf, uint32_t ctrl = nvnet_get_reg(s, NVNET_TX_RX_CONTROL, 4); nvnet_set_reg(s, NVNET_TX_RX_CONTROL, ctrl & ~NVNET_TX_RX_CONTROL_IDLE, 4); + uint32_t base_desc_addr = nvnet_get_reg(s, NVNET_RX_RING_PHYS_ADDR, 4); + uint32_t max_desc_addr = + base_desc_addr + get_rx_ring_size(s) * sizeof(struct RingDesc); + uint32_t cur_desc_addr = + nvnet_get_reg(s, NVNET_RX_RING_NEXT_DESC_PHYS_ADDR, 4); + if ((cur_desc_addr < base_desc_addr) || + ((cur_desc_addr + sizeof(struct RingDesc)) > max_desc_addr)) { + cur_desc_addr = base_desc_addr; + } + nvnet_set_reg(s, NVNET_RX_RING_CURRENT_DESC_PHYS_ADDR, cur_desc_addr, 4); + struct RingDesc desc; - s->rx_ring_index %= get_rx_ring_size(s); - dma_addr_t rx_ring_addr = nvnet_get_reg(s, NVNET_RX_RING_PHYS_ADDR, 4); - rx_ring_addr += s->rx_ring_index * sizeof(desc); - pci_dma_read(d, rx_ring_addr, &desc, sizeof(desc)); + pci_dma_read(d, cur_desc_addr, &desc, sizeof(desc)); uint32_t buffer_addr = le32_to_cpu(desc.buffer_addr); uint16_t length = le16_to_cpu(desc.length); uint16_t flags = le16_to_cpu(desc.flags); - NVNET_DPRINTF("RX: Looking at ring descriptor %d (0x%" HWADDR_PRIx "): " + NVNET_DPRINTF("RX: Looking at ring descriptor %zd (0x%x): " "Buffer: 0x%x, Length: 0x%x, Flags: 0x%x\n", - s->rx_ring_index, rx_ring_addr, buffer_addr, length, flags); + (cur_desc_addr - base_desc_addr) / sizeof(struct RingDesc), + cur_desc_addr, buffer_addr, length, flags); if (flags & NV_RX_AVAIL) { assert((length + 1) >= size); // FIXME @@ -264,7 +293,7 @@ static ssize_t nvnet_dma_packet_to_guest(NvNetState *s, const uint8_t *buf, desc.length = cpu_to_le16(length); desc.flags = cpu_to_le16(flags); - pci_dma_write(d, rx_ring_addr, &desc, sizeof(desc)); + pci_dma_write(d, cur_desc_addr, &desc, sizeof(desc)); NVNET_DPRINTF("Updated ring descriptor: Length: 0x%x, Flags: 0x%x\n", length, flags); @@ -274,7 +303,12 @@ static ssize_t nvnet_dma_packet_to_guest(NvNetState *s, const uint8_t *buf, nvnet_set_reg(s, NVNET_IRQ_STATUS, irq_status | NVNET_IRQ_STATUS_RX, 4); nvnet_update_irq(s); - s->rx_ring_index += 1; + uint32_t next_desc_addr = cur_desc_addr + sizeof(struct RingDesc); + if (next_desc_addr >= max_desc_addr) { + next_desc_addr = base_desc_addr; + } + nvnet_set_reg(s, NVNET_RX_RING_NEXT_DESC_PHYS_ADDR, next_desc_addr, 4); + rval = size; } else { NVNET_DPRINTF("Could not find free buffer!\n"); @@ -295,28 +329,37 @@ static ssize_t nvnet_dma_packet_from_guest(NvNetState *s) uint32_t ctrl = nvnet_get_reg(s, NVNET_TX_RX_CONTROL, 4); nvnet_set_reg(s, NVNET_TX_RX_CONTROL, ctrl & ~NVNET_TX_RX_CONTROL_IDLE, 4); + uint32_t base_desc_addr = nvnet_get_reg(s, NVNET_TX_RING_PHYS_ADDR, 4); + uint32_t max_desc_addr = + base_desc_addr + get_tx_ring_size(s) * sizeof(struct RingDesc); + for (int i = 0; i < get_tx_ring_size(s); i++) { + uint32_t cur_desc_addr = + nvnet_get_reg(s, NVNET_TX_RING_NEXT_DESC_PHYS_ADDR, 4); + if ((cur_desc_addr < base_desc_addr) || + ((cur_desc_addr + sizeof(struct RingDesc)) > max_desc_addr)) { + cur_desc_addr = base_desc_addr; + } + nvnet_set_reg(s, NVNET_TX_RING_CURRENT_DESC_PHYS_ADDR, cur_desc_addr, + 4); + struct RingDesc desc; - s->tx_ring_index %= get_tx_ring_size(s); - dma_addr_t tx_ring_addr = nvnet_get_reg(s, NVNET_TX_RING_PHYS_ADDR, 4); - tx_ring_addr += s->tx_ring_index * sizeof(desc); - pci_dma_read(d, tx_ring_addr, &desc, sizeof(desc)); + pci_dma_read(d, cur_desc_addr, &desc, sizeof(desc)); uint32_t buffer_addr = le32_to_cpu(desc.buffer_addr); uint16_t length = le16_to_cpu(desc.length) + 1; uint16_t flags = le16_to_cpu(desc.flags); - NVNET_DPRINTF("TX: Looking at ring desc %d (%" HWADDR_PRIx "): " + NVNET_DPRINTF("TX: Looking at ring desc %zd (%x): " "Buffer: 0x%x, Length: 0x%x, Flags: 0x%x\n", - s->tx_ring_index, tx_ring_addr, buffer_addr, length, - flags); + (cur_desc_addr - base_desc_addr) / + sizeof(struct RingDesc), + cur_desc_addr, buffer_addr, length, flags); if (!(flags & NV_TX_VALID)) { break; } - s->tx_ring_index += 1; - assert((s->tx_dma_buf_offset + length) <= sizeof(s->tx_dma_buf)); pci_dma_read(d, buffer_addr, &s->tx_dma_buf[s->tx_dma_buf_offset], @@ -335,7 +378,13 @@ static ssize_t nvnet_dma_packet_from_guest(NvNetState *s) NV_TX_ERROR); desc.flags = cpu_to_le16(flags); - pci_dma_write(d, tx_ring_addr, &desc, sizeof(desc)); + pci_dma_write(d, cur_desc_addr, &desc, sizeof(desc)); + + uint32_t next_desc_addr = cur_desc_addr + sizeof(struct RingDesc); + if (next_desc_addr >= max_desc_addr) { + next_desc_addr = base_desc_addr; + } + nvnet_set_reg(s, NVNET_TX_RING_NEXT_DESC_PHYS_ADDR, next_desc_addr, 4); if (is_last_packet) { // FIXME @@ -628,8 +677,7 @@ static void nvnet_mmio_write(void *opaque, hwaddr addr, uint64_t val, } if (val & NVNET_TX_RX_CONTROL_RESET) { - s->tx_ring_index = 0; - s->rx_ring_index = 0; + reset_descriptor_ring_pointers(s); s->tx_dma_buf_offset = 0; } @@ -638,13 +686,9 @@ static void nvnet_mmio_write(void *opaque, hwaddr addr, uint64_t val, nvnet_set_reg(s, NVNET_IRQ_STATUS, 0, 4); break; } else if (val == 0) { - uint32_t temp = nvnet_get_reg(s, NVNET_UNKNOWN_SETUP_REG3, 4); - if (temp == NVNET_UNKNOWN_SETUP_REG3_VAL1) { - /* forcedeth waits for this bit to be set... */ - nvnet_set_reg(s, NVNET_UNKNOWN_SETUP_REG5, - NVNET_UNKNOWN_SETUP_REG5_BIT31, 4); - break; - } + /* forcedeth waits for this bit to be set... */ + nvnet_set_reg(s, NVNET_UNKNOWN_SETUP_REG5, + NVNET_UNKNOWN_SETUP_REG5_BIT31, 4); } break; @@ -695,9 +739,6 @@ static void nvnet_realize(PCIDevice *pci_dev, Error **errp) memset(s->regs, 0, sizeof(s->regs)); - s->rx_ring_index = 0; - s->tx_ring_index = 0; - memory_region_init_io(&s->mmio, OBJECT(dev), &nvnet_mmio_ops, s, "nvnet-mmio", MMIO_SIZE); pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio); @@ -729,11 +770,15 @@ static void nvnet_reset(void *opaque) memset(&s->regs, 0, sizeof(s->regs)); memset(&s->phy_regs, 0, sizeof(s->phy_regs)); + memset(&s->tx_dma_buf, 0, sizeof(s->tx_dma_buf)); + memset(&s->rx_dma_buf, 0, sizeof(s->rx_dma_buf)); + s->tx_dma_buf_offset = 0; + + reset_descriptor_ring_pointers(s); + + /* Deprecated */ s->tx_ring_index = 0; s->rx_ring_index = 0; - memset(&s->tx_dma_buf, 0, sizeof(s->tx_dma_buf)); - s->tx_dma_buf_offset = 0; - memset(&s->rx_dma_buf, 0, sizeof(s->rx_dma_buf)); } static void nvnet_reset_hold(Object *obj, ResetType type) @@ -742,10 +787,34 @@ static void nvnet_reset_hold(Object *obj, ResetType type) nvnet_reset(s); } +static int nvnet_post_load(void *opaque, int version_id) +{ + NvNetState *s = NVNET(opaque); + + if (version_id < 2) { + /* Migrate old snapshot tx descriptor index */ + uint32_t next_desc_addr = + nvnet_get_reg(s, NVNET_TX_RING_PHYS_ADDR, 4) + + (s->tx_ring_index % get_tx_ring_size(s)) * sizeof(struct RingDesc); + nvnet_set_reg(s, NVNET_TX_RING_NEXT_DESC_PHYS_ADDR, next_desc_addr, 4); + s->tx_ring_index = 0; + + /* Migrate old snapshot rx descriptor index */ + next_desc_addr = + nvnet_get_reg(s, NVNET_RX_RING_PHYS_ADDR, 4) + + (s->rx_ring_index % get_rx_ring_size(s)) * sizeof(struct RingDesc); + nvnet_set_reg(s, NVNET_RX_RING_NEXT_DESC_PHYS_ADDR, next_desc_addr, 4); + s->rx_ring_index = 0; + } + + return 0; +} + static const VMStateDescription vmstate_nvnet = { .name = "nvnet", - .version_id = 1, + .version_id = 2, .minimum_version_id = 1, + .post_load = nvnet_post_load, .fields = (VMStateField[]){ VMSTATE_PCI_DEVICE(parent_obj, NvNetState), VMSTATE_UINT8_ARRAY(regs, NvNetState, MMIO_SIZE), diff --git a/hw/xbox/mcpx/nvnet/nvnet_regs.h b/hw/xbox/mcpx/nvnet/nvnet_regs.h index d521c97cca..8f6d41eb6a 100644 --- a/hw/xbox/mcpx/nvnet/nvnet_regs.h +++ b/hw/xbox/mcpx/nvnet/nvnet_regs.h @@ -129,10 +129,14 @@ # define NVNET_LINKSPEED_10 10 # define NVNET_LINKSPEED_100 100 # define NVNET_LINKSPEED_1000 1000 +#define NVNET_TX_RING_CURRENT_DESC_PHYS_ADDR 0x11C +#define NVNET_RX_RING_CURRENT_DESC_PHYS_ADDR 0x120 +#define NVNET_TX_CURRENT_BUFFER_PHYS_ADDR 0x124 +#define NVNET_RX_CURRENT_BUFFER_PHYS_ADDR 0x12C #define NVNET_UNKNOWN_SETUP_REG5 0x130 # define NVNET_UNKNOWN_SETUP_REG5_BIT31 (1 << 31) -#define NVNET_UNKNOWN_SETUP_REG3 0x134 -# define NVNET_UNKNOWN_SETUP_REG3_VAL1 0x00200010 +#define NVNET_TX_RING_NEXT_DESC_PHYS_ADDR 0x134 +#define NVNET_RX_RING_NEXT_DESC_PHYS_ADDR 0x138 #define NVNET_UNKNOWN_SETUP_REG8 0x13C # define NVNET_UNKNOWN_SETUP_REG8_VAL1 0x00300010 #define NVNET_UNKNOWN_SETUP_REG7 0x140 From b22f42ff95968f63ad7f2967726d5db13feb6ff4 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 19 Jun 2025 01:55:06 -0700 Subject: [PATCH 16/16] nvnet: Move tx_dma_buf_offset field up --- hw/xbox/mcpx/nvnet/nvnet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/xbox/mcpx/nvnet/nvnet.c b/hw/xbox/mcpx/nvnet/nvnet.c index 0590601dc8..fa27b7ce33 100644 --- a/hw/xbox/mcpx/nvnet/nvnet.c +++ b/hw/xbox/mcpx/nvnet/nvnet.c @@ -65,8 +65,8 @@ typedef struct NvNetState { uint8_t regs[MMIO_SIZE]; uint32_t phy_regs[6]; - uint8_t tx_dma_buf[TX_ALLOC_BUFSIZE]; uint32_t tx_dma_buf_offset; + uint8_t tx_dma_buf[TX_ALLOC_BUFSIZE]; uint8_t rx_dma_buf[RX_ALLOC_BUFSIZE]; /* Deprecated */