diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7b57efd6be..118f850806 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -420,7 +420,7 @@ jobs: run: | cp dist/xemu-win-x86_64-release-pdb/xemu-win-x86_64-release.zip dist/xemu-win-x86_64-release-pdb/xemu-win-release.zip - name: Publish release - uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2 + uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8 # v2.3.2 with: tag_name: v${{ env.XEMU_VERSION }} name: v${{ env.XEMU_VERSION }} diff --git a/hw/xbox/mcpx/nvnet/nvnet.c b/hw/xbox/mcpx/nvnet/nvnet.c index fef42f0360..fa27b7ce33 100644 --- a/hw/xbox/mcpx/nvnet/nvnet.c +++ b/hw/xbox/mcpx/nvnet/nvnet.c @@ -21,144 +21,192 @@ #include "qemu/osdep.h" #include "trace.h" #include "hw/hw.h" +#include "hw/net/mii.h" #include "hw/pci/pci.h" #include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" #include "net/net.h" +#include "net/eth.h" #include "qemu/bswap.h" #include "qemu/iov.h" #include "migration/vmstate.h" #include "nvnet_regs.h" #define IOPORT_SIZE 0x8 -#define MMIO_SIZE 0x400 +#define MMIO_SIZE 0x400 +#define PHY_ADDR 1 -static const uint8_t bcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +#define GET_MASK(v, mask) (((v) & (mask)) >> ctz32(mask)) -// #define DEBUG -#ifdef DEBUG -# define NVNET_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) -# define NVNET_DUMP_PACKETS_TO_SCREEN -#else -# define NVNET_DPRINTF(format, ...) do { } while (0) +#ifndef DEBUG_NVNET +#define DEBUG_NVNET 0 #endif -static NetClientInfo net_nvnet_info; -static Property nvnet_properties[]; +#define NVNET_DPRINTF(fmt, ...) \ + do { \ + if (DEBUG_NVNET) { \ + fprintf(stderr, fmt, ##__VA_ARGS__); \ + } \ + } while (0); -/******************************************************************************* - * Primary State Structure - ******************************************************************************/ +#define TYPE_NVNET "nvnet" +OBJECT_DECLARE_SIMPLE_TYPE(NvNetState, NVNET) typedef struct NvNetState { /*< private >*/ PCIDevice parent_obj; /*< public >*/ - NICState *nic; - NICConf conf; + NICState *nic; + NICConf conf; + MemoryRegion mmio, io; - uint8_t regs[MMIO_SIZE]; - 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]; + uint8_t regs[MMIO_SIZE]; + uint32_t phy_regs[6]; - FILE *packet_dump_file; - char *packet_dump_path; + uint32_t tx_dma_buf_offset; + uint8_t tx_dma_buf[TX_ALLOC_BUFSIZE]; + uint8_t rx_dma_buf[RX_ALLOC_BUFSIZE]; + + /* Deprecated */ + uint8_t tx_ring_index; + uint8_t rx_ring_index; } NvNetState; -#pragma pack(1) struct RingDesc { - uint32_t packet_buffer; + uint32_t buffer_addr; uint16_t length; uint16_t flags; -}; -#pragma pack() +} QEMU_PACKED; -/******************************************************************************* - * Helper Macros - ******************************************************************************/ +#define R(r) \ + case r: \ + return #r; -#define NVNET_DEVICE(obj) \ - OBJECT_CHECK(NvNetState, (obj), "nvnet") +static const char *nvnet_get_reg_name(hwaddr addr) +{ + switch (addr) { + R(NVNET_IRQ_STATUS) + R(NVNET_IRQ_MASK) + R(NVNET_UNKNOWN_SETUP_REG6) + R(NVNET_POLLING_INTERVAL) + R(NVNET_MISC1) + R(NVNET_TRANSMITTER_CONTROL) + R(NVNET_TRANSMITTER_STATUS) + R(NVNET_PACKET_FILTER) + R(NVNET_OFFLOAD) + R(NVNET_RECEIVER_CONTROL) + R(NVNET_RECEIVER_STATUS) + R(NVNET_RANDOM_SEED) + R(NVNET_UNKNOWN_SETUP_REG1) + R(NVNET_UNKNOWN_SETUP_REG2) + R(NVNET_MAC_ADDR_A) + R(NVNET_MAC_ADDR_B) + R(NVNET_MULTICAST_ADDR_A) + R(NVNET_MULTICAST_ADDR_B) + R(NVNET_MULTICAST_MASK_A) + R(NVNET_MULTICAST_MASK_B) + R(NVNET_TX_RING_PHYS_ADDR) + R(NVNET_RX_RING_PHYS_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_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) + R(NVNET_MII_STATUS) + R(NVNET_UNKNOWN_SETUP_REG4) + R(NVNET_ADAPTER_CONTROL) + R(NVNET_MII_SPEED) + R(NVNET_MDIO_ADDR) + R(NVNET_MDIO_DATA) + R(NVNET_WAKEUPFLAGS) + R(NVNET_PATTERN_CRC) + R(NVNET_PATTERN_MASK) + R(NVNET_POWERCAP) + R(NVNET_POWERSTATE) + default: + return "Unknown"; + } +} -/******************************************************************************* - * Prototypes - ******************************************************************************/ +static const char *nvnet_get_phy_reg_name(uint8_t reg) +{ + switch (reg) { + R(MII_PHYID1) + R(MII_PHYID2) + R(MII_BMCR) + R(MII_BMSR) + R(MII_ANAR) + R(MII_ANLPAR) + default: + return "Unknown"; + } +} -/* Init */ -static void nvnet_realize(PCIDevice *dev, Error **errp); -static void nvnet_uninit(PCIDevice *dev); -static void nvnet_class_init(ObjectClass *klass, void *data); -static void nvnet_cleanup(NetClientState *nc); -static void nvnet_reset(void *opaque); -static void nvnet_reset_hold(Object *obj, ResetType type); -static void nvnet_register(void); +#undef R -/* MMIO / IO / Phy / Device Register Access */ -static uint64_t nvnet_mmio_read(void *opaque, - hwaddr addr, unsigned int size); -static void nvnet_mmio_write(void *opaque, - hwaddr addr, uint64_t val, unsigned int size); -static uint32_t nvnet_get_reg(NvNetState *s, - hwaddr addr, unsigned int size); -static void nvnet_set_reg(NvNetState *s, - hwaddr addr, uint32_t val, unsigned int size); -static uint64_t nvnet_io_read(void *opaque, - hwaddr addr, unsigned int size); -static void nvnet_io_write(void *opaque, - hwaddr addr, uint64_t val, unsigned int size); -static int nvnet_mii_rw(NvNetState *s, - uint64_t val); +static uint32_t nvnet_get_reg(NvNetState *s, hwaddr addr, unsigned int size) +{ + assert(addr < MMIO_SIZE); -/* Link State */ -static void nvnet_link_down(NvNetState *s); -static void nvnet_link_up(NvNetState *s); -static void nvnet_set_link_status(NetClientState *nc); + switch (size) { + case 4: + assert((addr & 3) == 0); + return ((uint32_t *)s->regs)[addr >> 2]; -/* Interrupts */ -static void nvnet_update_irq(NvNetState *s); + case 2: + assert((addr & 1) == 0); + return ((uint16_t *)s->regs)[addr >> 1]; -/* Packet Tx / Rx */ -static void nvnet_send_packet(NvNetState *s, - const uint8_t *buf, int size); -static ssize_t nvnet_dma_packet_to_guest(NvNetState *s, - const uint8_t *buf, size_t size); -static ssize_t nvnet_dma_packet_from_guest(NvNetState *s); -static bool nvnet_can_receive(NetClientState *nc); -static ssize_t nvnet_receive(NetClientState *nc, - const uint8_t *buf, size_t size); -static ssize_t nvnet_receive_iov(NetClientState *nc, - const struct iovec *iov, int iovcnt); + case 1: + return s->regs[addr]; -/* Utility Functions */ -static void nvnet_hex_dump(NvNetState *s, const uint8_t *buf, int size); + default: + assert(!"Unsupported register access"); + return 0; + } +} -static const char *nvnet_get_reg_name(hwaddr addr); -static const char *nvnet_get_mii_reg_name(uint8_t reg); -#ifdef DEBUG -static void nvnet_dump_ring_descriptors(NvNetState *s); -#endif +static void nvnet_set_reg(NvNetState *s, hwaddr addr, uint32_t val, + unsigned int size) +{ + assert(addr < MMIO_SIZE); -/******************************************************************************* - * IRQ - ******************************************************************************/ + switch (size) { + case 4: + assert((addr & 3) == 0); + ((uint32_t *)s->regs)[addr >> 2] = val; + break; + + case 2: + assert((addr & 1) == 0); + ((uint16_t *)s->regs)[addr >> 1] = (uint16_t)val; + break; + + case 1: + s->regs[addr] = (uint8_t)val; + break; + + default: + assert(!"Unsupported register access"); + } +} -/* - * Update IRQ status - */ static void nvnet_update_irq(NvNetState *s) { PCIDevice *d = PCI_DEVICE(s); - uint32_t irq_mask = nvnet_get_reg(s, NvRegIrqMask, 4); - uint32_t irq_status = nvnet_get_reg(s, NvRegIrqStatus, 4); + uint32_t irq_mask = nvnet_get_reg(s, NVNET_IRQ_MASK, 4); + uint32_t irq_status = nvnet_get_reg(s, NVNET_IRQ_STATUS, 4); if (irq_mask & irq_status) { NVNET_DPRINTF("Asserting IRQ\n"); @@ -168,266 +216,200 @@ static void nvnet_update_irq(NvNetState *s) } } -/******************************************************************************* - * Register Control - ******************************************************************************/ - -/* - * Read backing store for a device register. - */ -static uint32_t nvnet_get_reg(NvNetState *s, hwaddr addr, unsigned int size) -{ - assert(addr < MMIO_SIZE); - - switch (size) { - case 4: - assert((addr & 3) == 0); /* Unaligned register access. */ - return ((uint32_t *)s->regs)[addr >> 2]; - - case 2: - assert((addr & 1) == 0); /* Unaligned register access. */ - return ((uint16_t *)s->regs)[addr >> 1]; - - case 1: - return s->regs[addr]; - - default: - assert(0); /* Unsupported register access. */ - return 0; - } -} - -/* - * Write backing store for a device register. - */ -static void nvnet_set_reg(NvNetState *s, - hwaddr addr, uint32_t val, unsigned int size) -{ - assert(addr < MMIO_SIZE); - - switch (size) { - case 4: - assert((addr & 3) == 0); /* Unaligned register access. */ - ((uint32_t *)s->regs)[addr >> 2] = val; - break; - - case 2: - assert((addr & 1) == 0); /* Unaligned register access. */ - ((uint16_t *)s->regs)[addr >> 1] = (uint16_t)val; - break; - - case 1: - s->regs[addr] = (uint8_t)val; - break; - - default: - assert(0); /* Unsupported register access. */ - } -} - -/******************************************************************************* - * PHY Control - ******************************************************************************/ - -/* - * Read from PHY. - */ -static int nvnet_mii_rw(NvNetState *s, uint64_t val) -{ - uint32_t mii_ctl; - int write, retval, phy_addr, reg; - - retval = 0; - mii_ctl = nvnet_get_reg(s, NvRegMIIControl, 4); - phy_addr = (mii_ctl >> NVREG_MIICTL_ADDRSHIFT) & 0x1f; - reg = mii_ctl & ((1 << NVREG_MIICTL_ADDRSHIFT) - 1); - write = mii_ctl & NVREG_MIICTL_WRITE; - - if (phy_addr != 1) { - retval = -1; - goto out; - } - - if (write) { - goto out; - } - - switch (reg) { - case MII_BMSR: - /* Phy initialization code waits for BIT2 to be set.. If not set, - * software may report controller as not running */ - retval = BMSR_ANEGCOMPLETE | BMSR_BIT2; - break; - - case MII_ADVERTISE: - /* Fall through... */ - - case MII_LPA: - retval = LPA_10HALF | LPA_10FULL; - retval |= LPA_100HALF | LPA_100FULL | LPA_100BASE4; - break; - - default: - break; - } - -out: - if (write) { - trace_nvnet_mii_write(phy_addr, reg, nvnet_get_mii_reg_name(reg), val); - } else { - trace_nvnet_mii_read(phy_addr, reg, nvnet_get_mii_reg_name(reg), - retval); - } - return retval; -} - -/******************************************************************************* - * MMIO Read / Write - ******************************************************************************/ - -/* - * Handler for guest reads from MMIO ranges owned by this device. - */ -static uint64_t nvnet_mmio_read(void *opaque, hwaddr addr, unsigned int size) -{ - NvNetState *s = NVNET_DEVICE(opaque); - uint64_t retval; - - switch (addr) { - case NvRegMIIData: - assert(size == 4); - retval = nvnet_mii_rw(s, MII_READ); - break; - - case NvRegMIIControl: - retval = nvnet_get_reg(s, addr, size); - retval &= ~NVREG_MIICTL_INUSE; - break; - - case NvRegMIIStatus: - retval = 0; - break; - - default: - retval = nvnet_get_reg(s, addr, size); - break; - } - - trace_nvnet_reg_read(addr, nvnet_get_reg_name(addr & ~3), size, retval); - return retval; -} - -/* - * Handler for guest writes to MMIO ranges owned by this device. - */ -static void nvnet_mmio_write(void *opaque, hwaddr addr, - uint64_t val, unsigned int size) -{ - NvNetState *s = NVNET_DEVICE(opaque); - uint32_t temp; - - trace_nvnet_reg_write(addr, nvnet_get_reg_name(addr & ~3), size, val); - - switch (addr) { - case NvRegRingSizes: - nvnet_set_reg(s, addr, val, size); - s->rx_ring_size = ((val >> NVREG_RINGSZ_RXSHIFT) & 0xffff) + 1; - s->tx_ring_size = ((val >> NVREG_RINGSZ_TXSHIFT) & 0xffff) + 1; - break; - - case NvRegMIIData: - nvnet_mii_rw(s, val); - break; - - case NvRegTxRxControl: - if (val == NVREG_TXRXCTL_KICK) { - NVNET_DPRINTF("NvRegTxRxControl = NVREG_TXRXCTL_KICK!\n"); -#ifdef DEBUG - nvnet_dump_ring_descriptors(s); -#endif - nvnet_dma_packet_from_guest(s); - } - - if (val & NVREG_TXRXCTL_BIT2) { - nvnet_set_reg(s, NvRegTxRxControl, NVREG_TXRXCTL_IDLE, 4); - break; - } - - if (val & NVREG_TXRXCTL_RESET) { - s->tx_ring_index = 0; - s->rx_ring_index = 0; - s->tx_dma_buf_offset = 0; - } - - if (val & NVREG_TXRXCTL_BIT1) { - // FIXME - nvnet_set_reg(s, NvRegIrqStatus, 0, 4); - break; - } else if (val == 0) { - temp = nvnet_get_reg(s, NvRegUnknownSetupReg3, 4); - if (temp == NVREG_UNKSETUP3_VAL1) { - /* forcedeth waits for this bit to be set... */ - nvnet_set_reg(s, NvRegUnknownSetupReg5, - NVREG_UNKSETUP5_BIT31, 4); - break; - } - } - - nvnet_set_reg(s, NvRegTxRxControl, val, size); - break; - - case NvRegIrqMask: - nvnet_set_reg(s, addr, val, size); - nvnet_update_irq(s); - break; - - case NvRegIrqStatus: - nvnet_set_reg(s, addr, nvnet_get_reg(s, addr, size) & ~val, size); - nvnet_update_irq(s); - break; - - default: - nvnet_set_reg(s, addr, val, size); - break; - } -} - -static const MemoryRegionOps nvnet_mmio_ops = { - .read = nvnet_mmio_read, - .write = nvnet_mmio_write, -}; - -/******************************************************************************* - * Packet TX / RX - ******************************************************************************/ - static void nvnet_send_packet(NvNetState *s, const uint8_t *buf, int size) { NetClientState *nc = qemu_get_queue(s->nic); NVNET_DPRINTF("nvnet: Sending packet!\n"); - nvnet_hex_dump(s, buf, 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 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) +{ + PCIDevice *d = PCI_DEVICE(s); + 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); + + 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; + 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 %zd (0x%x): " + "Buffer: 0x%x, Length: 0x%x, Flags: 0x%x\n", + (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 + + NVNET_DPRINTF("Transferring packet, size 0x%zx, to memory at 0x%x\n", + size, buffer_addr); + pci_dma_write(d, buffer_addr, buf, size); + + 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, cur_desc_addr, &desc, sizeof(desc)); + + 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); + nvnet_set_reg(s, NVNET_IRQ_STATUS, irq_status | NVNET_IRQ_STATUS_RX, 4); + nvnet_update_irq(s); + + 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"); + 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); + + return rval; +} + +static ssize_t nvnet_dma_packet_from_guest(NvNetState *s) +{ + PCIDevice *d = PCI_DEVICE(s); + bool packet_sent = false; + + 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; + 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 %zd (%x): " + "Buffer: 0x%x, Length: 0x%x, Flags: 0x%x\n", + (cur_desc_addr - base_desc_addr) / + sizeof(struct RingDesc), + cur_desc_addr, buffer_addr, length, flags); + + if (!(flags & NV_TX_VALID)) { + break; + } + + 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); + s->tx_dma_buf_offset += length; + + bool is_last_packet = flags & NV_TX_LASTPACKET; + if (is_last_packet) { + nvnet_send_packet(s, s->tx_dma_buf, s->tx_dma_buf_offset); + s->tx_dma_buf_offset = 0; + packet_sent = true; + } + + flags &= ~(NV_TX_VALID | NV_TX_RETRYERROR | NV_TX_DEFERRED | + NV_TX_CARRIERLOST | NV_TX_LATECOLLISION | NV_TX_UNDERFLOW | + NV_TX_ERROR); + + desc.flags = cpu_to_le16(flags); + 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 + break; + } + } + + if (packet_sent) { + 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); + } + + 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; +} + static bool nvnet_can_receive(NetClientState *nc) { NVNET_DPRINTF("nvnet_can_receive called\n"); return true; } -static ssize_t nvnet_receive(NetClientState *nc, - const uint8_t *buf, size_t size) -{ - const struct iovec iov = { - .iov_base = (uint8_t *)buf, - .iov_len = size - }; - - NVNET_DPRINTF("nvnet_receive called\n"); - return nvnet_receive_iov(nc, &iov, 1); -} - static bool nvnet_is_packet_oversized(size_t size) { return size > RX_ALLOC_BUFSIZE; @@ -439,30 +421,31 @@ static bool receive_filter(NvNetState *s, const uint8_t *buf, int size) return false; } - uint32_t rctl = nvnet_get_reg(s, NvRegPacketFilterFlags, 4); - int isbcast = !memcmp(buf, bcast, sizeof bcast); + uint32_t rctl = nvnet_get_reg(s, NVNET_PACKET_FILTER, 4); /* Broadcast */ - if (isbcast) { + if (is_broadcast_ether_addr(buf)) { /* FIXME: bcast filtering */ trace_nvnet_rx_filter_bcast_match(); return true; } - if (!(rctl & NVREG_PFF_MYADDR)) { + if (!(rctl & NVNET_PACKET_FILTER_MYADDR)) { /* FIXME: Confirm PFF_MYADDR filters mcast */ return true; } /* Multicast */ uint32_t addr[2]; - addr[0] = cpu_to_le32(nvnet_get_reg(s, NvRegMulticastAddrA, 4)); - addr[1] = cpu_to_le32(nvnet_get_reg(s, NvRegMulticastAddrB, 4)); - if (memcmp(addr, bcast, sizeof bcast)) { + addr[0] = cpu_to_le32(nvnet_get_reg(s, NVNET_MULTICAST_ADDR_A, 4)); + addr[1] = cpu_to_le32(nvnet_get_reg(s, NVNET_MULTICAST_ADDR_B, 4)); + if (!is_broadcast_ether_addr((uint8_t *)addr)) { uint32_t dest_addr[2]; memcpy(dest_addr, buf, 6); - dest_addr[0] &= cpu_to_le32(nvnet_get_reg(s, NvRegMulticastMaskA, 4)); - dest_addr[1] &= cpu_to_le32(nvnet_get_reg(s, NvRegMulticastMaskB, 4)); + dest_addr[0] &= + cpu_to_le32(nvnet_get_reg(s, NVNET_MULTICAST_MASK_A, 4)); + dest_addr[1] &= + cpu_to_le32(nvnet_get_reg(s, NVNET_MULTICAST_MASK_B, 4)); if (!memcmp(dest_addr, addr, 6)) { trace_nvnet_rx_filter_mcast_match(MAC_ARG(dest_addr)); @@ -473,8 +456,8 @@ static bool receive_filter(NvNetState *s, const uint8_t *buf, int size) } /* Unicast */ - addr[0] = cpu_to_le32(nvnet_get_reg(s, NvRegMacAddrA, 4)); - addr[1] = cpu_to_le32(nvnet_get_reg(s, NvRegMacAddrB, 4)); + addr[0] = cpu_to_le32(nvnet_get_reg(s, NVNET_MAC_ADDR_A, 4)); + addr[1] = cpu_to_le32(nvnet_get_reg(s, NVNET_MAC_ADDR_B, 4)); if (!memcmp(buf, addr, 6)) { trace_nvnet_rx_filter_ucast_match(MAC_ARG(buf)); return true; @@ -485,8 +468,8 @@ static bool receive_filter(NvNetState *s, const uint8_t *buf, int size) return false; } -static ssize_t nvnet_receive_iov(NetClientState *nc, - const struct iovec *iov, int iovcnt) +static ssize_t nvnet_receive_iov(NetClientState *nc, const struct iovec *iov, + int iovcnt) { NvNetState *s = qemu_get_nic_opaque(nc); size_t size = iov_size(iov, iovcnt); @@ -494,7 +477,6 @@ static ssize_t nvnet_receive_iov(NetClientState *nc, NVNET_DPRINTF("nvnet: Packet received!\n"); if (nvnet_is_packet_oversized(size)) { - /* Drop */ NVNET_DPRINTF("%s packet too large!\n", __func__); trace_nvnet_rx_oversized(size); return size; @@ -507,154 +489,18 @@ static ssize_t nvnet_receive_iov(NetClientState *nc, return size; } -#ifdef DEBUG - nvnet_hex_dump(s, s->rx_dma_buf, size); -#endif return nvnet_dma_packet_to_guest(s, s->rx_dma_buf, size); } - -static ssize_t nvnet_dma_packet_to_guest(NvNetState *s, - const uint8_t *buf, size_t size) +static ssize_t nvnet_receive(NetClientState *nc, const uint8_t *buf, + size_t size) { - PCIDevice *d = PCI_DEVICE(s); - bool did_receive = false; + const struct iovec iov = { .iov_base = (uint8_t *)buf, .iov_len = size }; - nvnet_set_reg(s, NvRegTxRxControl, - nvnet_get_reg(s, NvRegTxRxControl, 4) & ~NVREG_TXRXCTL_IDLE, - 4); - - for (int i = 0; i < s->rx_ring_size; i++) { - /* Read current ring descriptor */ - struct RingDesc desc; - s->rx_ring_index %= s->rx_ring_size; - dma_addr_t rx_ring_addr = nvnet_get_reg(s, NvRegRxRingPhysAddr, 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; - } - - assert((desc.length+1) >= size); // FIXME - - s->rx_ring_index += 1; - - /* Transfer packet from device to memory */ - 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); - - /* Update descriptor indicating the packet is waiting */ - desc.length = size; - desc.flags = NV_RX_BIT4 | NV_RX_DESCRIPTORVALID; - 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); - - /* Trigger interrupt */ - NVNET_DPRINTF("Triggering interrupt\n"); - uint32_t irq_status = nvnet_get_reg(s, NvRegIrqStatus, 4); - nvnet_set_reg(s, NvRegIrqStatus, irq_status | NVREG_IRQSTAT_BIT1, 4); - nvnet_update_irq(s); - did_receive = true; - break; - } - - nvnet_set_reg(s, NvRegTxRxControl, - nvnet_get_reg(s, NvRegTxRxControl, 4) | NVREG_TXRXCTL_IDLE, - 4); - - if (did_receive) { - return size; - } else { - /* Could not find free buffer, or packet too large. */ - NVNET_DPRINTF("Could not find free buffer!\n"); - return -1; - } + NVNET_DPRINTF("nvnet_receive called\n"); + return nvnet_receive_iov(nc, &iov, 1); } -static ssize_t nvnet_dma_packet_from_guest(NvNetState *s) -{ - PCIDevice *d = PCI_DEVICE(s); - bool packet_sent = false; - - nvnet_set_reg(s, NvRegTxRxControl, - nvnet_get_reg(s, NvRegTxRxControl, 4) & ~NVREG_TXRXCTL_IDLE, - 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, NvRegTxRingPhysAddr, 4); - tx_ring_addr += s->tx_ring_index * sizeof(desc); - pci_dma_read(d, tx_ring_addr, &desc, sizeof(desc)); - 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); - - if (!(desc.flags & NV_TX_VALID)) { - break; - } - - s->tx_ring_index += 1; - - /* Transfer packet from guest memory */ - assert((s->tx_dma_buf_offset + desc.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; - - /* Update descriptor */ - bool is_last_packet = desc.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; - } - - 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; - pci_dma_write(d, tx_ring_addr, &desc, sizeof(desc)); - - if (is_last_packet) { - // FIXME - break; - } - } - - /* Trigger interrupt */ - if (packet_sent) { - NVNET_DPRINTF("Triggering interrupt\n"); - uint32_t irq_status = nvnet_get_reg(s, NvRegIrqStatus, 4); - nvnet_set_reg(s, NvRegIrqStatus, irq_status | NVREG_IRQSTAT_BIT4, 4); - nvnet_update_irq(s); - } - - nvnet_set_reg(s, NvRegTxRxControl, - nvnet_get_reg(s, NvRegTxRxControl, 4) | NVREG_TXRXCTL_IDLE, - 4); - - return 0; -} - -/******************************************************************************* - * Link Status Control - ******************************************************************************/ - static void nvnet_link_down(NvNetState *s) { NVNET_DPRINTF("nvnet_link_down called\n"); @@ -675,9 +521,195 @@ static void nvnet_set_link_status(NetClientState *nc) } } -/******************************************************************************* - * IO Read / Write - ******************************************************************************/ +static NetClientInfo net_nvnet_info = { + .type = NET_CLIENT_DRIVER_NIC, + .size = sizeof(NICState), + .can_receive = nvnet_can_receive, + .receive = nvnet_receive, + .receive_iov = nvnet_receive_iov, + .link_status_changed = nvnet_set_link_status, +}; + +static uint16_t nvnet_phy_reg_read(NvNetState *s, uint8_t reg) +{ + uint16_t value; + + switch (reg) { + case MII_BMSR: + value = MII_BMSR_AN_COMP | MII_BMSR_LINK_ST; + break; + + case MII_ANAR: + /* Fall through... */ + + case MII_ANLPAR: + value = MII_ANLPAR_10 | MII_ANLPAR_10FD | MII_ANLPAR_TX | + MII_ANLPAR_TXFD | MII_ANLPAR_T4; + break; + + default: + value = 0; + break; + } + + trace_nvnet_phy_reg_read(PHY_ADDR, reg, nvnet_get_phy_reg_name(reg), value); + return value; +} + +static void nvnet_phy_reg_write(NvNetState *s, uint8_t reg, uint16_t value) +{ + trace_nvnet_phy_reg_write(PHY_ADDR, reg, nvnet_get_phy_reg_name(reg), value); +} + +static void nvnet_mdio_read(NvNetState *s) +{ + uint32_t mdio_addr = nvnet_get_reg(s, NVNET_MDIO_ADDR, 4); + uint32_t mdio_data = -1; + 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); + } + + mdio_addr &= ~NVNET_MDIO_ADDR_INUSE; + nvnet_set_reg(s, NVNET_MDIO_ADDR, mdio_addr, 4); + nvnet_set_reg(s, NVNET_MDIO_DATA, mdio_data, 4); +} + +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); + 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); + } + + mdio_addr &= ~NVNET_MDIO_ADDR_INUSE; + nvnet_set_reg(s, NVNET_MDIO_ADDR, mdio_addr, 4); +} + +static uint64_t nvnet_mmio_read(void *opaque, hwaddr addr, unsigned int size) +{ + NvNetState *s = NVNET(opaque); + uint64_t retval; + + switch (addr) { + case NVNET_MII_STATUS: + retval = 0; + break; + + default: + retval = nvnet_get_reg(s, addr, size); + break; + } + + trace_nvnet_reg_read(addr, nvnet_get_reg_name(addr & ~3), size, retval); + return retval; +} + +static void nvnet_dump_ring_descriptors(NvNetState *s) +{ +#if DEBUG_NVNET + PCIDevice *d = PCI_DEVICE(s); + + NVNET_DPRINTF("------------------------------------------------\n"); + + 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); + 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.buffer_addr), + le16_to_cpu(desc.length), le16_to_cpu(desc.flags)); + } + + NVNET_DPRINTF("------------------------------------------------\n"); + + 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); + 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.buffer_addr), + le16_to_cpu(desc.length), le16_to_cpu(desc.flags)); + } + + NVNET_DPRINTF("------------------------------------------------\n"); +#endif +} + +static void nvnet_mmio_write(void *opaque, hwaddr addr, uint64_t val, + unsigned int size) +{ + NvNetState *s = NVNET(opaque); + + nvnet_set_reg(s, addr, val, size); + trace_nvnet_reg_write(addr, nvnet_get_reg_name(addr & ~3), size, val); + + switch (addr) { + case NVNET_MDIO_ADDR: + assert(size == 4); + if (val & NVNET_MDIO_ADDR_WRITE) { + nvnet_mdio_write(s); + } else { + nvnet_mdio_read(s); + } + break; + + case NVNET_TX_RX_CONTROL: + if (val == NVNET_TX_RX_CONTROL_KICK) { + NVNET_DPRINTF("NVNET_TX_RX_CONTROL = NVNET_TX_RX_CONTROL_KICK!\n"); + nvnet_dump_ring_descriptors(s); + nvnet_dma_packet_from_guest(s); + } + + if (val & NVNET_TX_RX_CONTROL_BIT2) { + nvnet_set_reg(s, NVNET_TX_RX_CONTROL, NVNET_TX_RX_CONTROL_IDLE, 4); + break; + } + + if (val & NVNET_TX_RX_CONTROL_RESET) { + reset_descriptor_ring_pointers(s); + s->tx_dma_buf_offset = 0; + } + + if (val & NVNET_TX_RX_CONTROL_BIT1) { + // FIXME + nvnet_set_reg(s, NVNET_IRQ_STATUS, 0, 4); + break; + } else if (val == 0) { + /* forcedeth waits for this bit to be set... */ + nvnet_set_reg(s, NVNET_UNKNOWN_SETUP_REG5, + NVNET_UNKNOWN_SETUP_REG5_BIT31, 4); + } + break; + + case NVNET_IRQ_MASK: + nvnet_update_irq(s); + break; + + case NVNET_IRQ_STATUS: + nvnet_set_reg(s, addr, nvnet_get_reg(s, addr, size) & ~val, size); + nvnet_update_irq(s); + break; + + default: + break; + } +} + +static const MemoryRegionOps nvnet_mmio_ops = { + .read = nvnet_mmio_read, + .write = nvnet_mmio_write, +}; static uint64_t nvnet_io_read(void *opaque, hwaddr addr, unsigned int size) { @@ -686,77 +718,48 @@ static uint64_t nvnet_io_read(void *opaque, hwaddr addr, unsigned int size) return r; } -static void nvnet_io_write(void *opaque, - hwaddr addr, uint64_t val, unsigned int size) +static void nvnet_io_write(void *opaque, hwaddr addr, uint64_t val, + unsigned int size) { trace_nvnet_io_write(addr, size, val); } static const MemoryRegionOps nvnet_io_ops = { - .read = nvnet_io_read, + .read = nvnet_io_read, .write = nvnet_io_write, }; -/******************************************************************************* - * Init - ******************************************************************************/ - static void nvnet_realize(PCIDevice *pci_dev, Error **errp) { DeviceState *dev = DEVICE(pci_dev); - NvNetState *s = NVNET_DEVICE(pci_dev); + NvNetState *s = NVNET(pci_dev); PCIDevice *d = PCI_DEVICE(s); pci_dev->config[PCI_INTERRUPT_PIN] = 0x01; - s->packet_dump_file = NULL; - if (s->packet_dump_path && *s->packet_dump_path != '\x00') { - s->packet_dump_file = fopen(s->packet_dump_path, "wb"); - if (!s->packet_dump_file) { - fprintf(stderr, "Failed to open %s for writing!\n", - s->packet_dump_path); - exit(1); - } - } - 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); + "nvnet-mmio", MMIO_SIZE); pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio); - memory_region_init_io(&s->io, OBJECT(dev), &nvnet_io_ops, s, - "nvnet-io", IOPORT_SIZE); + memory_region_init_io(&s->io, OBJECT(dev), &nvnet_io_ops, s, "nvnet-io", + IOPORT_SIZE); pci_register_bar(d, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io); qemu_macaddr_default_if_unset(&s->conf.macaddr); - s->nic = qemu_new_nic(&net_nvnet_info, &s->conf, - object_get_typename(OBJECT(s)), dev->id, &dev->mem_reentrancy_guard, s); + s->nic = + qemu_new_nic(&net_nvnet_info, &s->conf, object_get_typename(OBJECT(s)), + dev->id, &dev->mem_reentrancy_guard, s); assert(s->nic); } static void nvnet_uninit(PCIDevice *dev) { - NvNetState *s = NVNET_DEVICE(dev); - - if (s->packet_dump_file) { - fclose(s->packet_dump_file); - } - - // memory_region_destroy(&s->mmio); - // memory_region_destroy(&s->io); + NvNetState *s = NVNET(dev); qemu_del_nic(s->nic); } -void nvnet_cleanup(NetClientState *nc) -{ -} - static void nvnet_reset(void *opaque) { NvNetState *s = opaque; @@ -767,184 +770,65 @@ 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)); + s->tx_dma_buf_offset = 0; + + reset_descriptor_ring_pointers(s); + + /* Deprecated */ + s->tx_ring_index = 0; + s->rx_ring_index = 0; } static void nvnet_reset_hold(Object *obj, ResetType type) { - NvNetState *s = NVNET_DEVICE(obj); + NvNetState *s = NVNET(obj); nvnet_reset(s); } -/******************************************************************************* - * Utility Functions - ******************************************************************************/ - -static void hex_dump(FILE *f, const uint8_t *buf, int size) +static int nvnet_post_load(void *opaque, int version_id) { - int len, i, j, c; + NvNetState *s = NVNET(opaque); - for (i = 0; i < size; i += 16) { - len = size - i; - if (len > 16) { - len = 16; - } - fprintf(f, "%08x ", i); - for (j = 0; j < 16; j++) { - if (j < len) { - fprintf(f, " %02x", buf[i + j]); - } else { - fprintf(f, " "); - } - } - fprintf(f, " "); - for (j = 0; j < len; j++) { - c = buf[i + j]; - if (c < ' ' || c > '~') { - c = '.'; - } - fprintf(f, "%c", c); - } - fprintf(f, "\n"); + 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 void nvnet_hex_dump(NvNetState *s, const uint8_t *buf, int size) -{ -#ifdef NVNET_DUMP_PACKETS_TO_SCREEN - hex_dump(stdout, buf, size); -#endif - if (s->packet_dump_file) { - hex_dump(s->packet_dump_file, buf, size); - } -} - -/* - * Return register name given the offset of the device register. - */ -static const char *nvnet_get_reg_name(hwaddr addr) -{ - switch (addr) { - case NvRegIrqStatus: return "NvRegIrqStatus"; - case NvRegIrqMask: return "NvRegIrqMask"; - case NvRegUnknownSetupReg6: return "NvRegUnknownSetupReg6"; - case NvRegPollingInterval: return "NvRegPollingInterval"; - case NvRegMisc1: return "NvRegMisc1"; - case NvRegTransmitterControl: return "NvRegTransmitterControl"; - case NvRegTransmitterStatus: return "NvRegTransmitterStatus"; - case NvRegPacketFilterFlags: return "NvRegPacketFilterFlags"; - case NvRegOffloadConfig: return "NvRegOffloadConfig"; - case NvRegReceiverControl: return "NvRegReceiverControl"; - case NvRegReceiverStatus: return "NvRegReceiverStatus"; - case NvRegRandomSeed: return "NvRegRandomSeed"; - case NvRegUnknownSetupReg1: return "NvRegUnknownSetupReg1"; - case NvRegUnknownSetupReg2: return "NvRegUnknownSetupReg2"; - case NvRegMacAddrA: return "NvRegMacAddrA"; - case NvRegMacAddrB: return "NvRegMacAddrB"; - case NvRegMulticastAddrA: return "NvRegMulticastAddrA"; - case NvRegMulticastAddrB: return "NvRegMulticastAddrB"; - case NvRegMulticastMaskA: return "NvRegMulticastMaskA"; - case NvRegMulticastMaskB: return "NvRegMulticastMaskB"; - case NvRegTxRingPhysAddr: return "NvRegTxRingPhysAddr"; - case NvRegRxRingPhysAddr: return "NvRegRxRingPhysAddr"; - case NvRegRingSizes: return "NvRegRingSizes"; - case NvRegUnknownTransmitterReg: return "NvRegUnknownTransmitterReg"; - case NvRegLinkSpeed: return "NvRegLinkSpeed"; - case NvRegUnknownSetupReg5: return "NvRegUnknownSetupReg5"; - case NvRegUnknownSetupReg3: return "NvRegUnknownSetupReg3"; - case NvRegUnknownSetupReg8: return "NvRegUnknownSetupReg8"; - case NvRegUnknownSetupReg7: return "NvRegUnknownSetupReg7"; - case NvRegTxRxControl: return "NvRegTxRxControl"; - case NvRegMIIStatus: return "NvRegMIIStatus"; - case NvRegUnknownSetupReg4: return "NvRegUnknownSetupReg4"; - case NvRegAdapterControl: return "NvRegAdapterControl"; - case NvRegMIISpeed: return "NvRegMIISpeed"; - case NvRegMIIControl: return "NvRegMIIControl"; - case NvRegMIIData: return "NvRegMIIData"; - case NvRegWakeUpFlags: return "NvRegWakeUpFlags"; - case NvRegPatternCRC: return "NvRegPatternCRC"; - case NvRegPatternMask: return "NvRegPatternMask"; - case NvRegPowerCap: return "NvRegPowerCap"; - case NvRegPowerState: return "NvRegPowerState"; - default: return "Unknown"; - } -} - -/* - * Get PHY register name. - */ -static const char *nvnet_get_mii_reg_name(uint8_t reg) -{ - switch (reg) { - case MII_PHYSID1: return "MII_PHYSID1"; - case MII_PHYSID2: return "MII_PHYSID2"; - case MII_BMCR: return "MII_BMCR"; - case MII_BMSR: return "MII_BMSR"; - case MII_ADVERTISE: return "MII_ADVERTISE"; - case MII_LPA: return "MII_LPA"; - default: return "Unknown"; - } -} - -#ifdef DEBUG -static void nvnet_dump_ring_descriptors(NvNetState *s) -{ - struct RingDesc desc; - PCIDevice *d = PCI_DEVICE(s); - - NVNET_DPRINTF("------------------------------------------------\n"); - for (int i = 0; i < s->tx_ring_size; i++) { - /* Read ring descriptor */ - dma_addr_t tx_ring_addr = nvnet_get_reg(s, NvRegTxRingPhysAddr, 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++) { - /* Read ring descriptor */ - dma_addr_t rx_ring_addr = nvnet_get_reg(s, NvRegRxRingPhysAddr, 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 - -/******************************************************************************* - * Properties - ******************************************************************************/ - static const VMStateDescription vmstate_nvnet = { .name = "nvnet", - .version_id = 1, + .version_id = 2, .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(parent_obj, NvNetState), - 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_UINT8(rx_ring_index, NvNetState), - VMSTATE_UINT8(rx_ring_size, NvNetState), - VMSTATE_END_OF_LIST() - }, + .post_load = nvnet_post_load, + .fields = + (VMStateField[]){ VMSTATE_PCI_DEVICE(parent_obj, NvNetState), + VMSTATE_UINT8_ARRAY(regs, NvNetState, MMIO_SIZE), + VMSTATE_UINT32_ARRAY(phy_regs, NvNetState, 6), + VMSTATE_UINT8(tx_ring_index, NvNetState), + VMSTATE_UNUSED(1), + VMSTATE_UINT8(rx_ring_index, NvNetState), + VMSTATE_UNUSED(1), + VMSTATE_END_OF_LIST() }, +}; + +static Property nvnet_properties[] = { + DEFINE_NIC_PROPERTIES(NvNetState, conf), + DEFINE_PROP_END_OF_LIST(), }; static void nvnet_class_init(ObjectClass *klass, void *data) @@ -968,35 +852,21 @@ static void nvnet_class_init(ObjectClass *klass, void *data) device_class_set_props(dc, nvnet_properties); } -static Property nvnet_properties[] = { - DEFINE_NIC_PROPERTIES(NvNetState, conf), - DEFINE_PROP_STRING("dump", NvNetState, packet_dump_path), - DEFINE_PROP_END_OF_LIST(), -}; - -static NetClientInfo net_nvnet_info = { - .type = NET_CLIENT_DRIVER_NIC, - .size = sizeof(NICState), - .can_receive = nvnet_can_receive, - .receive = nvnet_receive, - .receive_iov = nvnet_receive_iov, - .cleanup = nvnet_cleanup, - .link_status_changed = nvnet_set_link_status, -}; - static const TypeInfo nvnet_info = { - .name = "nvnet", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(NvNetState), - .class_init = nvnet_class_init, - .interfaces = (InterfaceInfo[]) { - { INTERFACE_CONVENTIONAL_PCI_DEVICE }, - { }, - }, + .name = "nvnet", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(NvNetState), + .class_init = nvnet_class_init, + .interfaces = + (InterfaceInfo[]){ + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + {}, + }, }; static void nvnet_register(void) { type_register_static(&nvnet_info); } -type_init(nvnet_register); + +type_init(nvnet_register) diff --git a/hw/xbox/mcpx/nvnet/nvnet_regs.h b/hw/xbox/mcpx/nvnet/nvnet_regs.h index 7a1744f7bc..8f6d41eb6a 100644 --- a/hw/xbox/mcpx/nvnet/nvnet_regs.h +++ b/hw/xbox/mcpx/nvnet/nvnet_regs.h @@ -2,7 +2,7 @@ * QEMU nForce Ethernet Controller register definitions * * Copyright (c) 2013 espes - * Copyright (c) 2015-2021 Matt Borgerson + * Copyright (c) 2015-2025 Matt Borgerson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,8 +22,8 @@ * Most definitions are based on forcedeth.c, taken from cromwell project. * Original forcedeth.c license follows: * - * -- - * forcedeth.c -- Etherboot device driver for the NVIDIA nForce + * -- + * forcedeth.c -- Etherboot device driver for the NVIDIA nForce * media access controllers. * * Note: This driver is based on the Linux driver that was based on @@ -53,159 +53,145 @@ * * (C) 2003 Manfred Spraul * See Linux Driver for full information - * + * * Linux Driver Version 0.22, 19 Jan 2004 - * - * + * + * * REVISION HISTORY: * ================ * v1.0 01-31-2004 timlegge Initial port of Linux driver - * v1.1 02-03-2004 timlegge Large Clean up, first release - * + * v1.1 02-03-2004 timlegge Large Clean up, first release + * * Indent Options: indent -kr -i8 ***************************************************************************/ #ifndef HW_NVNET_REGS_H #define HW_NVNET_REGS_H -// clang-format on +// clang-format off -#define DEV_NEED_LASTPACKET1 0x0001 -#define DEV_IRQMASK_1 0x0002 -#define DEV_IRQMASK_2 0x0004 -#define DEV_NEED_TIMERIRQ 0x0008 - -enum { - NvRegIrqStatus = 0x000, -# define NVREG_IRQSTAT_BIT1 0x002 -# define NVREG_IRQSTAT_BIT4 0x010 -# define NVREG_IRQSTAT_MIIEVENT 0x040 -# define NVREG_IRQSTAT_MASK 0x1ff - NvRegIrqMask = 0x004, -# define NVREG_IRQ_RX 0x0002 -# define NVREG_IRQ_RX_NOBUF 0x0004 -# define NVREG_IRQ_TX_ERR 0x0008 -# define NVREG_IRQ_TX2 0x0010 -# define NVREG_IRQ_TIMER 0x0020 -# define NVREG_IRQ_LINK 0x0040 -# define NVREG_IRQ_TX1 0x0100 -# define NVREG_IRQMASK_WANTED_1 0x005f -# define NVREG_IRQMASK_WANTED_2 0x0147 -# define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX | NVREG_IRQ_RX_NOBUF | \ - NVREG_IRQ_TX_ERR | NVREG_IRQ_TX2 | NVREG_IRQ_TIMER | NVREG_IRQ_LINK | \ - NVREG_IRQ_TX1)) - NvRegUnknownSetupReg6 = 0x008, -# define NVREG_UNKSETUP6_VAL 3 +#define NVNET_IRQ_STATUS 0x000 +# define NVNET_IRQ_STATUS_RX 0x00000002 +# define NVNET_IRQ_STATUS_RX_NOBUF 0x00000004 +# define NVNET_IRQ_STATUS_TX_ERR 0x00000008 +# define NVNET_IRQ_STATUS_TX 0x00000010 +# define NVNET_IRQ_STATUS_TIMER 0x00000020 +# define NVNET_IRQ_STATUS_MIIEVENT 0x00000040 +#define NVNET_IRQ_MASK 0x004 +#define NVNET_UNKNOWN_SETUP_REG6 0x008 +# define NVNET_UNKNOWN_SETUP_REG6_VAL 3 /* - * NVREG_POLL_DEFAULT is the interval length of the timer source on the nic - * NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms + * NVNET_POLLING_INTERVAL_DEFAULT is the interval length of the timer source on the nic + * NVNET_POLLING_INTERVAL_DEFAULT=97 would result in an interval length of 1 ms */ - NvRegPollingInterval = 0x00c, -# define NVREG_POLL_DEFAULT 970 - NvRegMisc1 = 0x080, -# define NVREG_MISC1_HD 0x02 -# define NVREG_MISC1_FORCE 0x3b0f3c - NvRegTransmitterControl = 0x084, -# define NVREG_XMITCTL_START 0x01 - NvRegTransmitterStatus = 0x088, -# define NVREG_XMITSTAT_BUSY 0x01 - NvRegPacketFilterFlags = 0x8c, -# define NVREG_PFF_ALWAYS 0x7F0008 -# define NVREG_PFF_PROMISC 0x80 -# define NVREG_PFF_MYADDR 0x20 - NvRegOffloadConfig = 0x90, -# define NVREG_OFFLOAD_HOMEPHY 0x601 -# define NVREG_OFFLOAD_NORMAL 0x5ee - NvRegReceiverControl = 0x094, -# define NVREG_RCVCTL_START 0x01 - NvRegReceiverStatus = 0x98, -# define NVREG_RCVSTAT_BUSY 0x01 - NvRegRandomSeed = 0x9c, -# define NVREG_RNDSEED_MASK 0x00ff -# define NVREG_RNDSEED_FORCE 0x7f00 - NvRegUnknownSetupReg1 = 0xA0, -# define NVREG_UNKSETUP1_VAL 0x16070f - NvRegUnknownSetupReg2 = 0xA4, -# define NVREG_UNKSETUP2_VAL 0x16 - NvRegMacAddrA = 0xA8, - NvRegMacAddrB = 0xAC, - NvRegMulticastAddrA = 0xB0, -# define NVREG_MCASTADDRA_FORCE 0x01 - NvRegMulticastAddrB = 0xB4, - NvRegMulticastMaskA = 0xB8, - NvRegMulticastMaskB = 0xBC, - NvRegTxRingPhysAddr = 0x100, - NvRegRxRingPhysAddr = 0x104, - NvRegRingSizes = 0x108, -# define NVREG_RINGSZ_TXSHIFT 0 -# define NVREG_RINGSZ_RXSHIFT 16 - NvRegUnknownTransmitterReg = 0x10c, - NvRegLinkSpeed = 0x110, -# define NVREG_LINKSPEED_FORCE 0x10000 -# define NVREG_LINKSPEED_10 10 -# define NVREG_LINKSPEED_100 100 -# define NVREG_LINKSPEED_1000 1000 - NvRegUnknownSetupReg5 = 0x130, -# define NVREG_UNKSETUP5_BIT31 (1 << 31) - NvRegUnknownSetupReg3 = 0x134, -# define NVREG_UNKSETUP3_VAL1 0x200010 - NvRegUnknownSetupReg8 = 0x13C, -# define NVREG_UNKSETUP8_VAL1 0x300010 - NvRegUnknownSetupReg7 = 0x140, -# define NVREG_UNKSETUP7_VAL 0x300010 - NvRegTxRxControl = 0x144, -# define NVREG_TXRXCTL_KICK 0x0001 -# define NVREG_TXRXCTL_BIT1 0x0002 -# define NVREG_TXRXCTL_BIT2 0x0004 -# define NVREG_TXRXCTL_IDLE 0x0008 -# define NVREG_TXRXCTL_RESET 0x0010 - NvRegMIIStatus = 0x180, -# define NVREG_MIISTAT_ERROR 0x0001 -# define NVREG_MIISTAT_LINKCHANGE 0x0008 -# define NVREG_MIISTAT_MASK 0x000f -# define NVREG_MIISTAT_MASK2 0x000f - NvRegUnknownSetupReg4 = 0x184, -# define NVREG_UNKSETUP4_VAL 8 - NvRegAdapterControl = 0x188, -# define NVREG_ADAPTCTL_START 0x02 -# define NVREG_ADAPTCTL_LINKUP 0x04 -# define NVREG_ADAPTCTL_PHYVALID 0x4000 -# define NVREG_ADAPTCTL_RUNNING 0x100000 -# define NVREG_ADAPTCTL_PHYSHIFT 24 - NvRegMIISpeed = 0x18c, -# define NVREG_MIISPEED_BIT8 (1 << 8) -# define NVREG_MIIDELAY 5 - NvRegMIIControl = 0x190, -# define NVREG_MIICTL_INUSE 0x10000 -# define NVREG_MIICTL_WRITE 0x08000 -# define NVREG_MIICTL_ADDRSHIFT 5 - NvRegMIIData = 0x194, - NvRegWakeUpFlags = 0x200, -# define NVREG_WAKEUPFLAGS_VAL 0x7770 -# define NVREG_WAKEUPFLAGS_BUSYSHIFT 24 -# define NVREG_WAKEUPFLAGS_ENABLESHIFT 16 -# define NVREG_WAKEUPFLAGS_D3SHIFT 12 -# define NVREG_WAKEUPFLAGS_D2SHIFT 8 -# define NVREG_WAKEUPFLAGS_D1SHIFT 4 -# define NVREG_WAKEUPFLAGS_D0SHIFT 0 -# define NVREG_WAKEUPFLAGS_ACCEPT_MAGPAT 0x01 -# define NVREG_WAKEUPFLAGS_ACCEPT_WAKEUPPAT 0x02 -# define NVREG_WAKEUPFLAGS_ACCEPT_LINKCHANGE 0x04 - NvRegPatternCRC = 0x204, - NvRegPatternMask = 0x208, - NvRegPowerCap = 0x268, -# define NVREG_POWERCAP_D3SUPP (1 << 30) -# define NVREG_POWERCAP_D2SUPP (1 << 26) -# define NVREG_POWERCAP_D1SUPP (1 << 25) - NvRegPowerState = 0x26c, -# define NVREG_POWERSTATE_POWEREDUP 0x8000 -# define NVREG_POWERSTATE_VALID 0x0100 -# define NVREG_POWERSTATE_MASK 0x0003 -# define NVREG_POWERSTATE_D0 0x0000 -# define NVREG_POWERSTATE_D1 0x0001 -# define NVREG_POWERSTATE_D2 0x0002 -# define NVREG_POWERSTATE_D3 0x0003 -}; +#define NVNET_POLLING_INTERVAL 0x00C +# define NVNET_POLLING_INTERVAL_DEFAULT 970 +#define NVNET_MISC1 0x080 +# define NVNET_MISC1_HD 0x00000002 +# define NVNET_MISC1_FORCE 0x003B0F3C +#define NVNET_TRANSMITTER_CONTROL 0x084 +# define NVNET_TRANSMITTER_CONTROL_START 0x00000001 +#define NVNET_TRANSMITTER_STATUS 0x088 +# define NVNET_TRANSMITTER_STATUS_BUSY 0x00000001 +#define NVNET_PACKET_FILTER 0x08C +# define NVNET_PACKET_FILTER_ALWAYS 0x007F0008 +# define NVNET_PACKET_FILTER_PROMISC 0x00000080 +# define NVNET_PACKET_FILTER_MYADDR 0x00000020 +#define NVNET_OFFLOAD 0x090 +# define NVNET_OFFLOAD_HOMEPHY 0x00000601 +# define NVNET_OFFLOAD_NORMAL 0x000005EE +#define NVNET_RECEIVER_CONTROL 0x094 +# define NVNET_RECEIVER_CONTROL_START 0x00000001 +#define NVNET_RECEIVER_STATUS 0x098 +# define NVNET_RECEIVER_STATUS_BUSY 0x00000001 +#define NVNET_RANDOM_SEED 0x09C +# define NVNET_RANDOM_SEED_MASK 0x000000FF +# define NVNET_RANDOM_SEED_FORCE 0x00007F00 +#define NVNET_UNKNOWN_SETUP_REG1 0x0A0 +# define NVNET_UNKNOWN_SETUP_REG1_VAL 0x0016070F +#define NVNET_UNKNOWN_SETUP_REG2 0x0A4 +# define NVNET_UNKNOWN_SETUP_REG2_VAL 0x00000016 +#define NVNET_MAC_ADDR_A 0x0A8 +#define NVNET_MAC_ADDR_B 0x0AC +#define NVNET_MULTICAST_ADDR_A 0x0B0 +# define NVNET_MULTICAST_ADDR_A_FORCE 0x00000001 +#define NVNET_MULTICAST_ADDR_B 0x0B4 +#define NVNET_MULTICAST_MASK_A 0x0B8 +#define NVNET_MULTICAST_MASK_B 0x0BC +#define NVNET_TX_RING_PHYS_ADDR 0x100 +#define NVNET_RX_RING_PHYS_ADDR 0x104 +#define NVNET_RING_SIZE 0x108 +# define NVNET_RING_SIZE_TX 0x0000FFFF +# define NVNET_RING_SIZE_RX 0xFFFF0000 +#define NVNET_UNKNOWN_TRANSMITTER_REG 0x10C +#define NVNET_LINKSPEED 0x110 +# define NVNET_LINKSPEED_FORCE 0x00010000 +# 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_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 +# define NVNET_UNKNOWN_SETUP_REG7_VAL 0x00300010 +#define NVNET_TX_RX_CONTROL 0x144 +# define NVNET_TX_RX_CONTROL_KICK 0x00000001 +# define NVNET_TX_RX_CONTROL_BIT1 0x00000002 +# define NVNET_TX_RX_CONTROL_BIT2 0x00000004 +# define NVNET_TX_RX_CONTROL_IDLE 0x00000008 +# define NVNET_TX_RX_CONTROL_RESET 0x00000010 +#define NVNET_MII_STATUS 0x180 +# define NVNET_MII_STATUS_ERROR 0x00000001 +# define NVNET_MII_STATUS_LINKCHANGE 0x00000008 +#define NVNET_UNKNOWN_SETUP_REG4 0x184 +# define NVNET_UNKNOWN_SETUP_REG4_VAL 8 +#define NVNET_ADAPTER_CONTROL 0x188 +# define NVNET_ADAPTER_CONTROL_START 0x00000002 +# define NVNET_ADAPTER_CONTROL_LINKUP 0x00000004 +# define NVNET_ADAPTER_CONTROL_PHYVALID 0x00004000 +# define NVNET_ADAPTER_CONTROL_RUNNING 0x00100000 +# define NVNET_ADAPTER_CONTROL_PHYSHIFT 24 +#define NVNET_MII_SPEED 0x18C +# define NVNET_MII_SPEED_BIT8 (1 << 8) +# define NVNET_MII_SPEED_DELAY 5 +#define NVNET_MDIO_ADDR 0x190 +# define NVNET_MDIO_ADDR_INUSE 0x00008000 +# define NVNET_MDIO_ADDR_WRITE 0x00000400 +# define NVNET_MDIO_ADDR_PHYADDR 0x000003E0 +# define NVNET_MDIO_ADDR_PHYREG 0x0000001F +#define NVNET_MDIO_DATA 0x194 +#define NVNET_WAKEUPFLAGS 0x200 +# define NVNET_WAKEUPFLAGS_VAL 0x00007770 +# define NVNET_WAKEUPFLAGS_BUSYSHIFT 24 +# define NVNET_WAKEUPFLAGS_ENABLESHIFT 16 +# define NVNET_WAKEUPFLAGS_D3SHIFT 12 +# define NVNET_WAKEUPFLAGS_D2SHIFT 8 +# define NVNET_WAKEUPFLAGS_D1SHIFT 4 +# define NVNET_WAKEUPFLAGS_D0SHIFT 0 +# define NVNET_WAKEUPFLAGS_ACCEPT_MAGPAT 0x00000001 +# define NVNET_WAKEUPFLAGS_ACCEPT_WAKEUPPAT 0x00000002 +# define NVNET_WAKEUPFLAGS_ACCEPT_LINKCHANGE 0x00000004 +#define NVNET_PATTERN_CRC 0x204 +#define NVNET_PATTERN_MASK 0x208 +#define NVNET_POWERCAP 0x268 +# define NVNET_POWERCAP_D3SUPP (1 << 30) +# define NVNET_POWERCAP_D2SUPP (1 << 26) +# define NVNET_POWERCAP_D1SUPP (1 << 25) +#define NVNET_POWERSTATE 0x26C +# define NVNET_POWERSTATE_POWEREDUP 0x00008000 +# define NVNET_POWERSTATE_VALID 0x00000100 +# define NVNET_POWERSTATE_MASK 0x00000003 +# define NVNET_POWERSTATE_D0 0x00000000 +# define NVNET_POWERSTATE_D1 0x00000001 +# define NVNET_POWERSTATE_D2 0x00000002 +# define NVNET_POWERSTATE_D3 0x00000003 #define NV_TX_LASTPACKET (1 << 0) #define NV_TX_RETRYERROR (1 << 3) @@ -270,29 +256,12 @@ enum { #define OOM_REFILL (1 + HZ / 20) #define POLL_WAIT (1 + HZ / 100) -#define MII_READ (-1) -#define MII_PHYSID1 0x02 /* PHYS ID 1 */ -#define MII_PHYSID2 0x03 /* PHYS ID 2 */ -#define MII_BMCR 0x00 /* Basic mode control register */ -#define MII_BMSR 0x01 /* Basic mode status register */ -#define MII_ADVERTISE 0x04 /* Advertisement control reg */ -#define MII_LPA 0x05 /* Link partner ability reg */ - -#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */ -#define BMSR_BIT2 0x0004 /* Unknown... */ - /* Link partner ability register. */ -#define LPA_SLCT 0x001f /* Same as advertise selector */ -#define LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */ -#define LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */ -#define LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */ -#define LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */ -#define LPA_100BASE4 0x0200 /* Can do 100mbps 4k packets */ -#define LPA_RESV 0x1c00 /* Unused... */ +#define LPA_SLCT 0x001F /* Same as advertise selector */ +#define LPA_RESV 0x1C00 /* Unused... */ #define LPA_RFAULT 0x2000 /* Link partner faulted */ -#define LPA_LPACK 0x4000 /* Link partner acked us */ #define LPA_NPAGE 0x8000 /* Next page bit */ -// clang-format off +// clang-format on #endif /* HW_NVNET_REGS_H */ diff --git a/hw/xbox/mcpx/nvnet/trace-events b/hw/xbox/mcpx/nvnet/trace-events index fbda278fe7..027058f909 100644 --- a/hw/xbox/mcpx/nvnet/trace-events +++ b/hw/xbox/mcpx/nvnet/trace-events @@ -1,8 +1,8 @@ # See docs/devel/tracing.rst for syntax documentation. # nvnet.c -nvnet_mii_read(unsigned int phy_addr, uint32_t addr, const char *name, uint64_t val) "phy %d addr 0x%"PRIx32" %s val 0x%"PRIx64 -nvnet_mii_write(unsigned int phy_addr, uint32_t addr, const char *name, uint64_t val) "phy %d addr 0x%"PRIx32" %s val 0x%"PRIx64 +nvnet_phy_reg_read(unsigned int phy_addr, uint8_t addr, const char *name, uint16_t val) "phy %d addr 0x%"PRIx8" %s val 0x%"PRIx16 +nvnet_phy_reg_write(unsigned int phy_addr, uint8_t addr, const char *name, uint16_t val) "phy %d addr 0x%"PRIx8" %s val 0x%"PRIx16 nvnet_reg_read(uint32_t addr, const char *name, unsigned int size, uint64_t val) "addr 0x%"PRIx32" %s size %d val 0x%"PRIx64 nvnet_reg_write(uint32_t addr, const char *name, unsigned int size, uint64_t val) "addr 0x%"PRIx32" %s size %d val 0x%"PRIx64 nvnet_io_read(uint32_t addr, unsigned int size, uint64_t val) "addr 0x%"PRIx32" size %d val 0x%"PRIx64 diff --git a/system/vl.c b/system/vl.c index 580d0cfd28..d32b6e2d0a 100644 --- a/system/vl.c +++ b/system/vl.c @@ -651,8 +651,20 @@ static int cleanup_add_fd(void *opaque, QemuOpts *opts, Error **errp) static int drive_init_func(void *opaque, QemuOpts *opts, Error **errp) { BlockInterfaceType *block_default_type = opaque; + const char *file_path = qemu_opt_get(opts, "file"); + bool is_cdrom_with_file = !strcmp(qemu_opt_get(opts, "media"), "cdrom") && strlen(file_path) > 0; - return drive_new(opts, *block_default_type, errp) == NULL; + bool failed = drive_new(opts, *block_default_type, is_cdrom_with_file ? &error_warn : errp) == NULL; + + if (failed && is_cdrom_with_file) { + char *msg = g_strdup_printf("Failed to open DVD image file '%s'. Please check machine settings.", file_path); + xemu_queue_error_message(msg); + g_free(msg); + qemu_opt_set(opts, "file", "", errp); + failed = drive_new(opts, *block_default_type, errp) == NULL; + } + + return failed; } static int drive_enable_snapshot(void *opaque, QemuOpts *opts, Error **errp) @@ -2972,15 +2984,6 @@ void qemu_init(int argc, char **argv) } } - if (strlen(dvd_path) > 0) { - if (xemu_check_file(dvd_path) || strcmp(dvd_path, hdd_path) == 0) { - char *msg = g_strdup_printf("Failed to open DVD image file '%s'. Please check machine settings.", dvd_path); - xemu_queue_error_message(msg); - g_free(msg); - dvd_path = ""; - } - } - // Always populate DVD drive. If disc path is the empty string, drive is // connected but no media present. fake_argv[fake_argc++] = strdup("-drive"); diff --git a/ui/xui/actions.cc b/ui/xui/actions.cc index dc2c830c50..1d42d78643 100644 --- a/ui/xui/actions.cc +++ b/ui/xui/actions.cc @@ -38,7 +38,8 @@ void ActionLoadDisc(void) { Error *err = NULL; - const char *iso_file_filters = ".iso Files\0*.iso\0All Files\0*.*\0"; + const char *iso_file_filters = + "Disc Image Files (*.iso, *.xiso)\0*.iso;*.xiso\0All Files\0*.*\0"; const char *new_disc_path = PausedFileOpen(NOC_FILE_DIALOG_OPEN, iso_file_filters, g_config.sys.files.dvd_path, NULL);