diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2015-06-12 12:49:40 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2015-06-12 12:49:40 +0100 |
commit | 4cb618abc1818586c08011ff0a84a015787b1672 (patch) | |
tree | e10d9c848bfe284a7687976310c4fafa1974e43b /hw | |
parent | a4ef02fd9b3d12b105b56942166c8364ade9be0f (diff) | |
parent | 6773f9b687e0a8ab4b638ef88d075fb233fb7669 (diff) |
Merge remote-tracking branch 'remotes/lalrae/tags/mips-20150612' into staging
MIPS patches 2015-06-12
Changes:
* improve dp8393x network card and rc4030 chipset emulation
* support misaligned R6 and MSA memory accesses
* support MIPS eXtended and Large Physical Addressing
* add Config5.FRE bit and ERETNC instruction (Config5.LLB)
* support ememsize on MALTA
# gpg: Signature made Fri Jun 12 09:38:11 2015 BST using RSA key ID 0B29DA6B
# gpg: Good signature from "Leon Alrae <leon.alrae@imgtec.com>"
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 8DD3 2F98 5495 9D66 35D4 4FC0 5211 8E3C 0B29 DA6B
* remotes/lalrae/tags/mips-20150612: (29 commits)
target-mips: enable XPA and LPA features
target-mips: remove misleading comments in translate_init.c
target-mips: add MTHC0 and MFHC0 instructions
target-mips: add CP0.PageGrain.ELPA support
target-mips: support Page Frame Number Extension field
target-mips: extend selected CP0 registers to 64-bits in MIPS32
target-mips: correct MFC0 for CP0.EntryLo in MIPS64
net/dp8393x: fix hardware reset
net/dp8393x: correctly reset in_use field
net/dp8393x: add load/save support
net/dp8393x: add PROM to store MAC address
net/dp8393x: QOM'ify
net/dp8393x: use dp8393x_ prefix for all functions
net/dp8393x: do not use old_mmio accesses
net/dp8393x: always calculate proper checksums
dma/rc4030: convert to QOM
dma/rc4030: use trace events instead of custom logging
dma/rc4030: document register at offset 0x210
dma/rc4030: do not use old_mmio accesses
dma/rc4030: use AddressSpace and address_space_rw in users
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/dma/rc4030.c | 462 | ||||
-rw-r--r-- | hw/mips/Makefile.objs | 3 | ||||
-rw-r--r-- | hw/mips/mips_jazz.c | 53 | ||||
-rw-r--r-- | hw/mips/mips_malta.c | 15 | ||||
-rw-r--r-- | hw/net/dp8393x.c | 369 |
5 files changed, 467 insertions, 435 deletions
diff --git a/hw/dma/rc4030.c b/hw/dma/rc4030.c index af2663256e..3efa6de352 100644 --- a/hw/dma/rc4030.c +++ b/hw/dma/rc4030.c @@ -1,7 +1,7 @@ /* * QEMU JAZZ RC4030 chipset * - * Copyright (c) 2007-2009 Herve Poussineau + * Copyright (c) 2007-2013 Hervé Poussineau * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,29 +24,16 @@ #include "hw/hw.h" #include "hw/mips/mips.h" +#include "hw/sysbus.h" #include "qemu/timer.h" - -/********************************************************/ -/* debug rc4030 */ - -//#define DEBUG_RC4030 -//#define DEBUG_RC4030_DMA - -#ifdef DEBUG_RC4030 -#define DPRINTF(fmt, ...) \ -do { printf("rc4030: " fmt , ## __VA_ARGS__); } while (0) -static const char* irq_names[] = { "parallel", "floppy", "sound", "video", - "network", "scsi", "keyboard", "mouse", "serial0", "serial1" }; -#else -#define DPRINTF(fmt, ...) -#endif - -#define RC4030_ERROR(fmt, ...) \ -do { fprintf(stderr, "rc4030 ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0) +#include "exec/address-spaces.h" +#include "trace.h" /********************************************************/ /* rc4030 emulation */ +#define MAX_TL_ENTRIES 512 + typedef struct dma_pagetable_entry { int32_t frame; int32_t owner; @@ -63,8 +50,14 @@ typedef struct dma_pagetable_entry { #define DMA_FLAG_MEM_INTR 0x0200 #define DMA_FLAG_ADDR_INTR 0x0400 +#define TYPE_RC4030 "rc4030" +#define RC4030(obj) \ + OBJECT_CHECK(rc4030State, (obj), TYPE_RC4030) + typedef struct rc4030State { + SysBusDevice parent; + uint32_t config; /* 0x0000: RC4030 config register */ uint32_t revision; /* 0x0008: RC4030 Revision register */ uint32_t invalid_address_register; /* 0x0010: Invalid Address register */ @@ -83,7 +76,7 @@ typedef struct rc4030State uint32_t cache_bmask; /* 0x0058: I/O Cache Byte Mask */ uint32_t nmi_interrupt; /* 0x0200: interrupt source */ - uint32_t offset210; + uint32_t memory_refresh_rate; /* 0x0210: memory refresh rate */ uint32_t nvram_protect; /* 0x0220: NV ram protect register */ uint32_t rem_speed[16]; uint32_t imr_jazz; /* Local bus int enable mask */ @@ -96,6 +89,16 @@ typedef struct rc4030State qemu_irq timer_irq; qemu_irq jazz_bus_irq; + /* biggest translation table */ + MemoryRegion dma_tt; + /* translation table memory region alias, added to system RAM */ + MemoryRegion dma_tt_alias; + /* whole DMA memory region, root of DMA address space */ + MemoryRegion dma_mr; + /* translation table entry aliases, added to DMA memory region */ + MemoryRegion dma_mrs[MAX_TL_ENTRIES]; + AddressSpace dma_as; + MemoryRegion iomem_chipset; MemoryRegion iomem_jazzio; } rc4030State; @@ -112,7 +115,7 @@ static void set_next_tick(rc4030State *s) } /* called for accesses to rc4030 */ -static uint32_t rc4030_readl(void *opaque, hwaddr addr) +static uint64_t rc4030_read(void *opaque, hwaddr addr, unsigned int size) { rc4030State *s = opaque; uint32_t val; @@ -220,9 +223,9 @@ static uint32_t rc4030_readl(void *opaque, hwaddr addr) case 0x0208: val = 0; break; - /* Offset 0x0210 */ + /* Memory refresh rate */ case 0x0210: - val = s->offset210; + val = s->memory_refresh_rate; break; /* NV ram protect register */ case 0x0220: @@ -238,39 +241,117 @@ static uint32_t rc4030_readl(void *opaque, hwaddr addr) val = 7; /* FIXME: should be read from EISA controller */ break; default: - RC4030_ERROR("invalid read [" TARGET_FMT_plx "]\n", addr); + qemu_log_mask(LOG_GUEST_ERROR, + "rc4030: invalid read at 0x%x", (int)addr); val = 0; break; } if ((addr & ~3) != 0x230) { - DPRINTF("read 0x%02x at " TARGET_FMT_plx "\n", val, addr); + trace_rc4030_read(addr, val); } return val; } -static uint32_t rc4030_readw(void *opaque, hwaddr addr) +static void rc4030_dma_as_update_one(rc4030State *s, int index, uint32_t frame) { - uint32_t v = rc4030_readl(opaque, addr & ~0x3); - if (addr & 0x2) - return v >> 16; - else - return v & 0xffff; + if (index < MAX_TL_ENTRIES) { + memory_region_set_enabled(&s->dma_mrs[index], false); + } + + if (!frame) { + return; + } + + if (index >= MAX_TL_ENTRIES) { + qemu_log_mask(LOG_UNIMP, + "rc4030: trying to use too high " + "translation table entry %d (max allowed=%d)", + index, MAX_TL_ENTRIES); + return; + } + memory_region_set_alias_offset(&s->dma_mrs[index], frame); + memory_region_set_enabled(&s->dma_mrs[index], true); } -static uint32_t rc4030_readb(void *opaque, hwaddr addr) +static void rc4030_dma_tt_write(void *opaque, hwaddr addr, uint64_t data, + unsigned int size) { - uint32_t v = rc4030_readl(opaque, addr & ~0x3); - return (v >> (8 * (addr & 0x3))) & 0xff; + rc4030State *s = opaque; + + /* write memory */ + memcpy(memory_region_get_ram_ptr(&s->dma_tt) + addr, &data, size); + + /* update dma address space (only if frame field has been written) */ + if (addr % sizeof(dma_pagetable_entry) == 0) { + int index = addr / sizeof(dma_pagetable_entry); + memory_region_transaction_begin(); + rc4030_dma_as_update_one(s, index, (uint32_t)data); + memory_region_transaction_commit(); + } } -static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val) +static const MemoryRegionOps rc4030_dma_tt_ops = { + .write = rc4030_dma_tt_write, + .impl.min_access_size = 4, + .impl.max_access_size = 4, +}; + +static void rc4030_dma_tt_update(rc4030State *s, uint32_t new_tl_base, + uint32_t new_tl_limit) +{ + int entries, i; + dma_pagetable_entry *dma_tl_contents; + + if (s->dma_tl_limit) { + /* write old dma tl table to physical memory */ + memory_region_del_subregion(get_system_memory(), &s->dma_tt_alias); + cpu_physical_memory_write(s->dma_tl_limit & 0x7fffffff, + memory_region_get_ram_ptr(&s->dma_tt), + memory_region_size(&s->dma_tt_alias)); + } + object_unparent(OBJECT(&s->dma_tt_alias)); + + s->dma_tl_base = new_tl_base; + s->dma_tl_limit = new_tl_limit; + new_tl_base &= 0x7fffffff; + + if (s->dma_tl_limit) { + uint64_t dma_tt_size; + if (s->dma_tl_limit <= memory_region_size(&s->dma_tt)) { + dma_tt_size = s->dma_tl_limit; + } else { + dma_tt_size = memory_region_size(&s->dma_tt); + } + memory_region_init_alias(&s->dma_tt_alias, OBJECT(s), + "dma-table-alias", + &s->dma_tt, 0, dma_tt_size); + dma_tl_contents = memory_region_get_ram_ptr(&s->dma_tt); + cpu_physical_memory_read(new_tl_base, dma_tl_contents, dma_tt_size); + + memory_region_transaction_begin(); + entries = dma_tt_size / sizeof(dma_pagetable_entry); + for (i = 0; i < entries; i++) { + rc4030_dma_as_update_one(s, i, dma_tl_contents[i].frame); + } + memory_region_add_subregion(get_system_memory(), new_tl_base, + &s->dma_tt_alias); + memory_region_transaction_commit(); + } else { + memory_region_init(&s->dma_tt_alias, OBJECT(s), + "dma-table-alias", 0); + } +} + +static void rc4030_write(void *opaque, hwaddr addr, uint64_t data, + unsigned int size) { rc4030State *s = opaque; + uint32_t val = data; addr &= 0x3fff; - DPRINTF("write 0x%02x at " TARGET_FMT_plx "\n", val, addr); + trace_rc4030_write(addr, val); switch (addr & ~0x3) { /* Global config register */ @@ -279,11 +360,11 @@ static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val) break; /* DMA transl. table base */ case 0x0018: - s->dma_tl_base = val; + rc4030_dma_tt_update(s, val, s->dma_tl_limit); break; /* DMA transl. table limit */ case 0x0020: - s->dma_tl_limit = val; + rc4030_dma_tt_update(s, s->dma_tl_base, val); break; /* DMA transl. table invalidated */ case 0x0028: @@ -371,9 +452,9 @@ static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val) s->dma_regs[entry][idx] = val; } break; - /* Offset 0x0210 */ + /* Memory refresh rate */ case 0x0210: - s->offset210 = val; + s->memory_refresh_rate = val; break; /* Interval timer reload */ case 0x0228: @@ -385,48 +466,18 @@ static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val) case 0x0238: break; default: - RC4030_ERROR("invalid write of 0x%02x at [" TARGET_FMT_plx "]\n", val, addr); - break; - } -} - -static void rc4030_writew(void *opaque, hwaddr addr, uint32_t val) -{ - uint32_t old_val = rc4030_readl(opaque, addr & ~0x3); - - if (addr & 0x2) - val = (val << 16) | (old_val & 0x0000ffff); - else - val = val | (old_val & 0xffff0000); - rc4030_writel(opaque, addr & ~0x3, val); -} - -static void rc4030_writeb(void *opaque, hwaddr addr, uint32_t val) -{ - uint32_t old_val = rc4030_readl(opaque, addr & ~0x3); - - switch (addr & 3) { - case 0: - val = val | (old_val & 0xffffff00); - break; - case 1: - val = (val << 8) | (old_val & 0xffff00ff); - break; - case 2: - val = (val << 16) | (old_val & 0xff00ffff); - break; - case 3: - val = (val << 24) | (old_val & 0x00ffffff); + qemu_log_mask(LOG_GUEST_ERROR, + "rc4030: invalid write of 0x%02x at 0x%x", + val, (int)addr); break; } - rc4030_writel(opaque, addr & ~0x3, val); } static const MemoryRegionOps rc4030_ops = { - .old_mmio = { - .read = { rc4030_readb, rc4030_readw, rc4030_readl, }, - .write = { rc4030_writeb, rc4030_writew, rc4030_writel, }, - }, + .read = rc4030_read, + .write = rc4030_write, + .impl.min_access_size = 4, + .impl.max_access_size = 4, .endianness = DEVICE_NATIVE_ENDIAN, }; @@ -436,22 +487,6 @@ static void update_jazz_irq(rc4030State *s) pending = s->isr_jazz & s->imr_jazz; -#ifdef DEBUG_RC4030 - if (s->isr_jazz != 0) { - uint32_t irq = 0; - DPRINTF("pending irqs:"); - for (irq = 0; irq < ARRAY_SIZE(irq_names); irq++) { - if (s->isr_jazz & (1 << irq)) { - printf(" %s", irq_names[irq]); - if (!(s->imr_jazz & (1 << irq))) { - printf("(ignored)"); - } - } - } - printf("\n"); - } -#endif - if (pending != 0) qemu_irq_raise(s->jazz_bus_irq); else @@ -479,7 +514,7 @@ static void rc4030_periodic_timer(void *opaque) qemu_irq_raise(s->timer_irq); } -static uint32_t jazzio_readw(void *opaque, hwaddr addr) +static uint64_t jazzio_read(void *opaque, hwaddr addr, unsigned int size) { rc4030State *s = opaque; uint32_t val; @@ -494,7 +529,6 @@ static uint32_t jazzio_readw(void *opaque, hwaddr addr) irq = 0; while (pending) { if (pending & 1) { - DPRINTF("returning irq %s\n", irq_names[irq]); val = (irq + 1) << 2; break; } @@ -508,36 +542,25 @@ static uint32_t jazzio_readw(void *opaque, hwaddr addr) val = s->imr_jazz; break; default: - RC4030_ERROR("(jazz io controller) invalid read [" TARGET_FMT_plx "]\n", addr); + qemu_log_mask(LOG_GUEST_ERROR, + "rc4030/jazzio: invalid read at 0x%x", (int)addr); val = 0; + break; } - DPRINTF("(jazz io controller) read 0x%04x at " TARGET_FMT_plx "\n", val, addr); + trace_jazzio_read(addr, val); return val; } -static uint32_t jazzio_readb(void *opaque, hwaddr addr) -{ - uint32_t v; - v = jazzio_readw(opaque, addr & ~0x1); - return (v >> (8 * (addr & 0x1))) & 0xff; -} - -static uint32_t jazzio_readl(void *opaque, hwaddr addr) -{ - uint32_t v; - v = jazzio_readw(opaque, addr); - v |= jazzio_readw(opaque, addr + 2) << 16; - return v; -} - -static void jazzio_writew(void *opaque, hwaddr addr, uint32_t val) +static void jazzio_write(void *opaque, hwaddr addr, uint64_t data, + unsigned int size) { rc4030State *s = opaque; + uint32_t val = data; addr &= 0xfff; - DPRINTF("(jazz io controller) write 0x%04x at " TARGET_FMT_plx "\n", val, addr); + trace_jazzio_write(addr, val); switch (addr) { /* Local bus int enable mask */ @@ -546,43 +569,24 @@ static void jazzio_writew(void *opaque, hwaddr addr, uint32_t val) update_jazz_irq(s); break; default: - RC4030_ERROR("(jazz io controller) invalid write of 0x%04x at [" TARGET_FMT_plx "]\n", val, addr); + qemu_log_mask(LOG_GUEST_ERROR, + "rc4030/jazzio: invalid write of 0x%02x at 0x%x", + val, (int)addr); break; } } -static void jazzio_writeb(void *opaque, hwaddr addr, uint32_t val) -{ - uint32_t old_val = jazzio_readw(opaque, addr & ~0x1); - - switch (addr & 1) { - case 0: - val = val | (old_val & 0xff00); - break; - case 1: - val = (val << 8) | (old_val & 0x00ff); - break; - } - jazzio_writew(opaque, addr & ~0x1, val); -} - -static void jazzio_writel(void *opaque, hwaddr addr, uint32_t val) -{ - jazzio_writew(opaque, addr, val & 0xffff); - jazzio_writew(opaque, addr + 2, (val >> 16) & 0xffff); -} - static const MemoryRegionOps jazzio_ops = { - .old_mmio = { - .read = { jazzio_readb, jazzio_readw, jazzio_readl, }, - .write = { jazzio_writeb, jazzio_writew, jazzio_writel, }, - }, + .read = jazzio_read, + .write = jazzio_write, + .impl.min_access_size = 2, + .impl.max_access_size = 2, .endianness = DEVICE_NATIVE_ENDIAN, }; -static void rc4030_reset(void *opaque) +static void rc4030_reset(DeviceState *dev) { - rc4030State *s = opaque; + rc4030State *s = RC4030(dev); int i; s->config = 0x410; /* some boards seem to accept 0x104 too */ @@ -590,14 +594,14 @@ static void rc4030_reset(void *opaque) s->invalid_address_register = 0; memset(s->dma_regs, 0, sizeof(s->dma_regs)); - s->dma_tl_base = s->dma_tl_limit = 0; + rc4030_dma_tt_update(s, 0, 0); s->remote_failed_address = s->memory_failed_address = 0; s->cache_maint = 0; s->cache_ptag = s->cache_ltag = 0; s->cache_bmask = 0; - s->offset210 = 0x18186; + s->memory_refresh_rate = 0x18186; s->nvram_protect = 7; for (i = 0; i < 15; i++) s->rem_speed[i] = 7; @@ -631,7 +635,7 @@ static int rc4030_load(QEMUFile *f, void *opaque, int version_id) s->cache_ptag = qemu_get_be32(f); s->cache_ltag = qemu_get_be32(f); s->cache_bmask = qemu_get_be32(f); - s->offset210 = qemu_get_be32(f); + s->memory_refresh_rate = qemu_get_be32(f); s->nvram_protect = qemu_get_be32(f); for (i = 0; i < 15; i++) s->rem_speed[i] = qemu_get_be32(f); @@ -663,7 +667,7 @@ static void rc4030_save(QEMUFile *f, void *opaque) qemu_put_be32(f, s->cache_ptag); qemu_put_be32(f, s->cache_ltag); qemu_put_be32(f, s->cache_bmask); - qemu_put_be32(f, s->offset210); + qemu_put_be32(f, s->memory_refresh_rate); qemu_put_be32(f, s->nvram_protect); for (i = 0; i < 15; i++) qemu_put_be32(f, s->rem_speed[i]); @@ -672,44 +676,6 @@ static void rc4030_save(QEMUFile *f, void *opaque) qemu_put_be32(f, s->itr); } -void rc4030_dma_memory_rw(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write) -{ - rc4030State *s = opaque; - hwaddr entry_addr; - hwaddr phys_addr; - dma_pagetable_entry entry; - int index; - int ncpy, i; - - i = 0; - for (;;) { - if (i == len) { - break; - } - - ncpy = DMA_PAGESIZE - (addr & (DMA_PAGESIZE - 1)); - if (ncpy > len - i) - ncpy = len - i; - - /* Get DMA translation table entry */ - index = addr / DMA_PAGESIZE; - if (index >= s->dma_tl_limit / sizeof(dma_pagetable_entry)) { - break; - } - entry_addr = s->dma_tl_base + index * sizeof(dma_pagetable_entry); - /* XXX: not sure. should we really use only lowest bits? */ - entry_addr &= 0x7fffffff; - cpu_physical_memory_read(entry_addr, &entry, sizeof(entry)); - - /* Read/write data at right place */ - phys_addr = entry.frame + (addr & (DMA_PAGESIZE - 1)); - cpu_physical_memory_rw(phys_addr, &buf[i], ncpy, is_write); - - i += ncpy; - addr += ncpy; - } -} - static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_write) { rc4030State *s = opaque; @@ -733,32 +699,11 @@ static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_wri dma_addr = s->dma_regs[n][DMA_REG_ADDRESS]; /* Read/write data at right place */ - rc4030_dma_memory_rw(opaque, dma_addr, buf, len, is_write); + address_space_rw(&s->dma_as, dma_addr, MEMTXATTRS_UNSPECIFIED, + buf, len, is_write); s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_TC_INTR; s->dma_regs[n][DMA_REG_COUNT] -= len; - -#ifdef DEBUG_RC4030_DMA - { - int i, j; - printf("rc4030 dma: Copying %d bytes %s host %p\n", - len, is_write ? "from" : "to", buf); - for (i = 0; i < len; i += 16) { - int n = 16; - if (n > len - i) { - n = len - i; - } - for (j = 0; j < n; j++) - printf("%02x ", buf[i + j]); - while (j++ < 16) - printf(" "); - printf("| "); - for (j = 0; j < n; j++) - printf("%c", isprint(buf[i + j]) ? buf[i + j] : '.'); - printf("\n"); - } - } -#endif } struct rc4030DMAState { @@ -795,31 +740,102 @@ static rc4030_dma *rc4030_allocate_dmas(void *opaque, int n) return s; } -void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus, - qemu_irq **irqs, rc4030_dma **dmas, - MemoryRegion *sysmem) +static void rc4030_initfn(Object *obj) { - rc4030State *s; + DeviceState *dev = DEVICE(obj); + rc4030State *s = RC4030(obj); + SysBusDevice *sysbus = SYS_BUS_DEVICE(obj); - s = g_malloc0(sizeof(rc4030State)); + qdev_init_gpio_in(dev, rc4030_irq_jazz_request, 16); - *irqs = qemu_allocate_irqs(rc4030_irq_jazz_request, s, 16); - *dmas = rc4030_allocate_dmas(s, 4); + sysbus_init_irq(sysbus, &s->timer_irq); + sysbus_init_irq(sysbus, &s->jazz_bus_irq); - s->periodic_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, rc4030_periodic_timer, s); - s->timer_irq = timer; - s->jazz_bus_irq = jazz_bus; - - qemu_register_reset(rc4030_reset, s); register_savevm(NULL, "rc4030", 0, 2, rc4030_save, rc4030_load, s); - rc4030_reset(s); + + sysbus_init_mmio(sysbus, &s->iomem_chipset); + sysbus_init_mmio(sysbus, &s->iomem_jazzio); +} + +static void rc4030_realize(DeviceState *dev, Error **errp) +{ + rc4030State *s = RC4030(dev); + Object *o = OBJECT(dev); + int i; + + s->periodic_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + rc4030_periodic_timer, s); memory_region_init_io(&s->iomem_chipset, NULL, &rc4030_ops, s, "rc4030.chipset", 0x300); - memory_region_add_subregion(sysmem, 0x80000000, &s->iomem_chipset); memory_region_init_io(&s->iomem_jazzio, NULL, &jazzio_ops, s, "rc4030.jazzio", 0x00001000); - memory_region_add_subregion(sysmem, 0xf0000000, &s->iomem_jazzio); - return s; + memory_region_init_rom_device(&s->dma_tt, o, + &rc4030_dma_tt_ops, s, "dma-table", + MAX_TL_ENTRIES * sizeof(dma_pagetable_entry), + NULL); + memory_region_init(&s->dma_tt_alias, o, "dma-table-alias", 0); + memory_region_init(&s->dma_mr, o, "dma", INT32_MAX); + for (i = 0; i < MAX_TL_ENTRIES; ++i) { + memory_region_init_alias(&s->dma_mrs[i], o, "dma-alias", + get_system_memory(), 0, DMA_PAGESIZE); + memory_region_set_enabled(&s->dma_mrs[i], false); + memory_region_add_subregion(&s->dma_mr, i * DMA_PAGESIZE, + &s->dma_mrs[i]); + } + address_space_init(&s->dma_as, &s->dma_mr, "rc4030-dma"); +} + +static void rc4030_unrealize(DeviceState *dev, Error **errp) +{ + rc4030State *s = RC4030(dev); + int i; + + timer_free(s->periodic_timer); + + address_space_destroy(&s->dma_as); + object_unparent(OBJECT(&s->dma_tt)); + object_unparent(OBJECT(&s->dma_tt_alias)); + object_unparent(OBJECT(&s->dma_mr)); + for (i = 0; i < MAX_TL_ENTRIES; ++i) { + memory_region_del_subregion(&s->dma_mr, &s->dma_mrs[i]); + object_unparent(OBJECT(&s->dma_mrs[i])); + } +} + +static void rc4030_class_init(ObjectClass *klass, void *class_data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = rc4030_realize; + dc->unrealize = rc4030_unrealize; + dc->reset = rc4030_reset; +} + +static const TypeInfo rc4030_info = { + .name = TYPE_RC4030, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(rc4030State), + .instance_init = rc4030_initfn, + .class_init = rc4030_class_init, +}; + +static void rc4030_register_types(void) +{ + type_register_static(&rc4030_info); +} + +type_init(rc4030_register_types) + +DeviceState *rc4030_init(rc4030_dma **dmas, MemoryRegion **dma_mr) +{ + DeviceState *dev; + + dev = qdev_create(NULL, TYPE_RC4030); + qdev_init_nofail(dev); + + *dmas = rc4030_allocate_dmas(dev, 4); + *dma_mr = &RC4030(dev)->dma_mr; + return dev; } diff --git a/hw/mips/Makefile.objs b/hw/mips/Makefile.objs index 0a652f8521..9633f3a57d 100644 --- a/hw/mips/Makefile.objs +++ b/hw/mips/Makefile.objs @@ -1,4 +1,5 @@ -obj-y += mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o +obj-y += mips_r4k.o mips_malta.o mips_mipssim.o obj-y += addr.o cputimer.o mips_int.o +obj-$(CONFIG_JAZZ) += mips_jazz.o obj-$(CONFIG_FULONG) += mips_fulong2e.o obj-y += gt64xxx_pci.o diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c index 2c153e092f..9d60633efb 100644 --- a/hw/mips/mips_jazz.c +++ b/hw/mips/mips_jazz.c @@ -135,16 +135,16 @@ static void mips_jazz_init(MachineState *machine, MIPSCPU *cpu; CPUClass *cc; CPUMIPSState *env; - qemu_irq *rc4030, *i8259; + qemu_irq *i8259; rc4030_dma *dmas; - void* rc4030_opaque; + MemoryRegion *rc4030_dma_mr; MemoryRegion *isa_mem = g_new(MemoryRegion, 1); MemoryRegion *isa_io = g_new(MemoryRegion, 1); MemoryRegion *rtc = g_new(MemoryRegion, 1); MemoryRegion *i8042 = g_new(MemoryRegion, 1); MemoryRegion *dma_dummy = g_new(MemoryRegion, 1); NICInfo *nd; - DeviceState *dev; + DeviceState *dev, *rc4030; SysBusDevice *sysbus; ISABus *isa_bus; ISADevice *pit; @@ -157,12 +157,7 @@ static void mips_jazz_init(MachineState *machine, /* init CPUs */ if (cpu_model == NULL) { -#ifdef TARGET_MIPS64 cpu_model = "R4000"; -#else - /* FIXME: All wrong, this maybe should be R3000 for the older JAZZs. */ - cpu_model = "24Kf"; -#endif } cpu = cpu_mips_init(cpu_model); if (cpu == NULL) { @@ -218,8 +213,14 @@ static void mips_jazz_init(MachineState *machine, cpu_mips_clock_init(env); /* Chipset */ - rc4030_opaque = rc4030_init(env->irq[6], env->irq[3], &rc4030, &dmas, - address_space); + rc4030 = rc4030_init(&dmas, &rc4030_dma_mr); + sysbus = SYS_BUS_DEVICE(rc4030); + sysbus_connect_irq(sysbus, 0, env->irq[6]); + sysbus_connect_irq(sysbus, 1, env->irq[3]); + memory_region_add_subregion(address_space, 0x80000000, + sysbus_mmio_get_region(sysbus, 0)); + memory_region_add_subregion(address_space, 0xf0000000, + sysbus_mmio_get_region(sysbus, 1)); memory_region_init_io(dma_dummy, NULL, &dma_dummy_ops, NULL, "dummy_dma", 0x1000); memory_region_add_subregion(address_space, 0x8000d000, dma_dummy); @@ -246,7 +247,7 @@ static void mips_jazz_init(MachineState *machine, sysbus = SYS_BUS_DEVICE(dev); sysbus_mmio_map(sysbus, 0, 0x60080000); sysbus_mmio_map(sysbus, 1, 0x40000000); - sysbus_connect_irq(sysbus, 0, rc4030[3]); + sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(rc4030, 3)); { /* Simple ROM, so user doesn't have to provide one */ MemoryRegion *rom_mr = g_new(MemoryRegion, 1); @@ -272,8 +273,17 @@ static void mips_jazz_init(MachineState *machine, if (!nd->model) nd->model = g_strdup("dp83932"); if (strcmp(nd->model, "dp83932") == 0) { - dp83932_init(nd, 0x80001000, 2, get_system_memory(), rc4030[4], - rc4030_opaque, rc4030_dma_memory_rw); + qemu_check_nic_model(nd, "dp83932"); + + dev = qdev_create(NULL, "dp8393x"); + qdev_set_nic_properties(dev, nd); + qdev_prop_set_uint8(dev, "it_shift", 2); + qdev_prop_set_ptr(dev, "dma_mr", rc4030_dma_mr); + qdev_init_nofail(dev); + sysbus = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(sysbus, 0, 0x80001000); + sysbus_mmio_map(sysbus, 1, 0x8000b000); + sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(rc4030, 4)); break; } else if (is_help_option(nd->model)) { fprintf(stderr, "qemu: Supported NICs: dp83932\n"); @@ -287,7 +297,7 @@ static void mips_jazz_init(MachineState *machine, /* SCSI adapter */ esp_init(0x80002000, 0, rc4030_dma_read, rc4030_dma_write, dmas[0], - rc4030[5], &esp_reset, &dma_enable); + qdev_get_gpio_in(rc4030, 5), &esp_reset, &dma_enable); /* Floppy */ if (drive_get_max_bus(IF_FLOPPY) >= MAX_FD) { @@ -297,7 +307,7 @@ static void mips_jazz_init(MachineState *machine, for (n = 0; n < MAX_FD; n++) { fds[n] = drive_get(IF_FLOPPY, 0, n); } - fdctrl_init_sysbus(rc4030[1], 0, 0x80003000, fds); + fdctrl_init_sysbus(qdev_get_gpio_in(rc4030, 1), 0, 0x80003000, fds); /* Real time clock */ rtc_init(isa_bus, 1980, NULL); @@ -305,23 +315,26 @@ static void mips_jazz_init(MachineState *machine, memory_region_add_subregion(address_space, 0x80004000, rtc); /* Keyboard (i8042) */ - i8042_mm_init(rc4030[6], rc4030[7], i8042, 0x1000, 0x1); + i8042_mm_init(qdev_get_gpio_in(rc4030, 6), qdev_get_gpio_in(rc4030, 7), + i8042, 0x1000, 0x1); memory_region_add_subregion(address_space, 0x80005000, i8042); /* Serial ports */ if (serial_hds[0]) { - serial_mm_init(address_space, 0x80006000, 0, rc4030[8], 8000000/16, + serial_mm_init(address_space, 0x80006000, 0, + qdev_get_gpio_in(rc4030, 8), 8000000/16, serial_hds[0], DEVICE_NATIVE_ENDIAN); } if (serial_hds[1]) { - serial_mm_init(address_space, 0x80007000, 0, rc4030[9], 8000000/16, + serial_mm_init(address_space, 0x80007000, 0, + qdev_get_gpio_in(rc4030, 9), 8000000/16, serial_hds[1], DEVICE_NATIVE_ENDIAN); } /* Parallel port */ if (parallel_hds[0]) - parallel_mm_init(address_space, 0x80008000, 0, rc4030[0], - parallel_hds[0]); + parallel_mm_init(address_space, 0x80008000, 0, + qdev_get_gpio_in(rc4030, 0), parallel_hds[0]); /* FIXME: missing Jazz sound at 0x8000c000, rc4030[2] */ diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index 5140882c00..786a8f0638 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -97,7 +97,7 @@ typedef struct { static ISADevice *pit; static struct _loaderparams { - int ram_size; + int ram_size, ram_low_size; const char *kernel_filename; const char *kernel_cmdline; const char *initrd_filename; @@ -641,8 +641,8 @@ static void write_bootloader (CPUMIPSState *env, uint8_t *base, stl_p(p++, 0x34a50000 | (ENVP_ADDR & 0xffff)); /* ori a1, a1, low(ENVP_ADDR) */ stl_p(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */ stl_p(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */ - stl_p(p++, 0x3c070000 | (loaderparams.ram_size >> 16)); /* lui a3, high(ram_size) */ - stl_p(p++, 0x34e70000 | (loaderparams.ram_size & 0xffff)); /* ori a3, a3, low(ram_size) */ + stl_p(p++, 0x3c070000 | (loaderparams.ram_low_size >> 16)); /* lui a3, high(ram_low_size) */ + stl_p(p++, 0x34e70000 | (loaderparams.ram_low_size & 0xffff)); /* ori a3, a3, low(ram_low_size) */ /* Load BAR registers as done by YAMON */ stl_p(p++, 0x3c09b400); /* lui t1, 0xb400 */ @@ -851,8 +851,10 @@ static int64_t load_kernel (void) } prom_set(prom_buf, prom_index++, "memsize"); - prom_set(prom_buf, prom_index++, "%i", - MIN(loaderparams.ram_size, 256 << 20)); + prom_set(prom_buf, prom_index++, "%u", loaderparams.ram_low_size); + + prom_set(prom_buf, prom_index++, "ememsize"); + prom_set(prom_buf, prom_index++, "%u", loaderparams.ram_size); prom_set(prom_buf, prom_index++, "modetty0"); prom_set(prom_buf, prom_index++, "38400n8r"); @@ -1054,7 +1056,8 @@ void mips_malta_init(MachineState *machine) } /* Write a small bootloader to the flash location. */ - loaderparams.ram_size = ram_low_size; + loaderparams.ram_size = ram_size; + loaderparams.ram_low_size = ram_low_size; loaderparams.kernel_filename = kernel_filename; loaderparams.kernel_cmdline = kernel_cmdline; loaderparams.initrd_filename = initrd_filename; diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c index 7ce13d2b46..cd889bce86 100644 --- a/hw/net/dp8393x.c +++ b/hw/net/dp8393x.c @@ -17,20 +17,15 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "hw/hw.h" -#include "qemu/timer.h" +#include "hw/sysbus.h" +#include "hw/devices.h" #include "net/net.h" -#include "hw/mips/mips.h" +#include "qemu/timer.h" +#include <zlib.h> //#define DEBUG_SONIC -/* Calculate CRCs properly on Rx packets */ -#define SONIC_CALCULATE_RXCRC - -#if defined(SONIC_CALCULATE_RXCRC) -/* For crc32 */ -#include <zlib.h> -#endif +#define SONIC_PROM_SIZE 0x1000 #ifdef DEBUG_SONIC #define DPRINTF(fmt, ...) \ @@ -145,9 +140,14 @@ do { printf("sonic ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0) #define SONIC_ISR_PINT 0x0800 #define SONIC_ISR_LCD 0x1000 +#define TYPE_DP8393X "dp8393x" +#define DP8393X(obj) OBJECT_CHECK(dp8393xState, (obj), TYPE_DP8393X) + typedef struct dp8393xState { + SysBusDevice parent_obj; + /* Hardware */ - int it_shift; + uint8_t it_shift; qemu_irq irq; #ifdef DEBUG_SONIC int irq_level; @@ -156,8 +156,8 @@ typedef struct dp8393xState { int64_t wt_last_update; NICConf conf; NICState *nic; - MemoryRegion *address_space; MemoryRegion mmio; + MemoryRegion prom; /* Registers */ uint8_t cam[16][6]; @@ -168,8 +168,8 @@ typedef struct dp8393xState { int loopback_packet; /* Memory access */ - void (*memory_rw)(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write); - void* mem_opaque; + void *dma_mr; + AddressSpace as; } dp8393xState; static void dp8393x_update_irq(dp8393xState *s) @@ -190,7 +190,7 @@ static void dp8393x_update_irq(dp8393xState *s) qemu_set_irq(s->irq, level); } -static void do_load_cam(dp8393xState *s) +static void dp8393x_do_load_cam(dp8393xState *s) { uint16_t data[8]; int width, size; @@ -201,9 +201,9 @@ static void do_load_cam(dp8393xState *s) while (s->regs[SONIC_CDC] & 0x1f) { /* Fill current entry */ - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP], - (uint8_t *)data, size, 0); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->cam[index][0] = data[1 * width] & 0xff; s->cam[index][1] = data[1 * width] >> 8; s->cam[index][2] = data[2 * width] & 0xff; @@ -220,9 +220,9 @@ static void do_load_cam(dp8393xState *s) } /* Read CAM enable */ - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP], - (uint8_t *)data, size, 0); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->regs[SONIC_CE] = data[0 * width]; DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]); @@ -232,7 +232,7 @@ static void do_load_cam(dp8393xState *s) dp8393x_update_irq(s); } -static void do_read_rra(dp8393xState *s) +static void dp8393x_do_read_rra(dp8393xState *s) { uint16_t data[8]; int width, size; @@ -240,9 +240,9 @@ static void do_read_rra(dp8393xState *s) /* Read memory */ width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1; size = sizeof(uint16_t) * 4 * width; - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_RRP], - (uint8_t *)data, size, 0); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); /* Update SONIC registers */ s->regs[SONIC_CRBA0] = data[0 * width]; @@ -272,7 +272,7 @@ static void do_read_rra(dp8393xState *s) s->regs[SONIC_CR] &= ~SONIC_CR_RRRA; } -static void do_software_reset(dp8393xState *s) +static void dp8393x_do_software_reset(dp8393xState *s) { timer_del(s->watchdog); @@ -280,7 +280,7 @@ static void do_software_reset(dp8393xState *s) s->regs[SONIC_CR] |= SONIC_CR_RST | SONIC_CR_RXDIS; } -static void set_next_tick(dp8393xState *s) +static void dp8393x_set_next_tick(dp8393xState *s) { uint32_t ticks; int64_t delay; @@ -296,7 +296,7 @@ static void set_next_tick(dp8393xState *s) timer_mod(s->watchdog, s->wt_last_update + delay); } -static void update_wt_regs(dp8393xState *s) +static void dp8393x_update_wt_regs(dp8393xState *s) { int64_t elapsed; uint32_t val; @@ -311,33 +311,33 @@ static void update_wt_regs(dp8393xState *s) val -= elapsed / 5000000; s->regs[SONIC_WT1] = (val >> 16) & 0xffff; s->regs[SONIC_WT0] = (val >> 0) & 0xffff; - set_next_tick(s); + dp8393x_set_next_tick(s); } -static void do_start_timer(dp8393xState *s) +static void dp8393x_do_start_timer(dp8393xState *s) { s->regs[SONIC_CR] &= ~SONIC_CR_STP; - set_next_tick(s); + dp8393x_set_next_tick(s); } -static void do_stop_timer(dp8393xState *s) +static void dp8393x_do_stop_timer(dp8393xState *s) { s->regs[SONIC_CR] &= ~SONIC_CR_ST; - update_wt_regs(s); + dp8393x_update_wt_regs(s); } -static void do_receiver_enable(dp8393xState *s) +static void dp8393x_do_receiver_enable(dp8393xState *s) { s->regs[SONIC_CR] &= ~SONIC_CR_RXDIS; } -static void do_receiver_disable(dp8393xState *s) +static void dp8393x_do_receiver_disable(dp8393xState *s) { s->regs[SONIC_CR] &= ~SONIC_CR_RXEN; } -static void do_transmit_packets(dp8393xState *s) +static void dp8393x_do_transmit_packets(dp8393xState *s) { NetClientState *nc = qemu_get_queue(s->nic); uint16_t data[12]; @@ -353,9 +353,9 @@ static void do_transmit_packets(dp8393xState *s) (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_CTDA]); size = sizeof(uint16_t) * 6 * width; s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA]; - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * width, - (uint8_t *)data, size, 0); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); tx_len = 0; /* Update registers */ @@ -379,18 +379,18 @@ static void do_transmit_packets(dp8393xState *s) if (tx_len + len > sizeof(s->tx_buffer)) { len = sizeof(s->tx_buffer) - tx_len; } - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, (s->regs[SONIC_TSA1] << 16) | s->regs[SONIC_TSA0], - &s->tx_buffer[tx_len], len, 0); + MEMTXATTRS_UNSPECIFIED, &s->tx_buffer[tx_len], len, 0); tx_len += len; i++; if (i != s->regs[SONIC_TFC]) { /* Read next fragment details */ size = sizeof(uint16_t) * 3 * width; - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * i) * width, - (uint8_t *)data, size, 0); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->regs[SONIC_TSA0] = data[0 * width]; s->regs[SONIC_TSA1] = data[1 * width]; s->regs[SONIC_TFS] = data[2 * width]; @@ -422,16 +422,16 @@ static void do_transmit_packets(dp8393xState *s) /* Write status */ data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */ size = sizeof(uint16_t) * width; - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA], - (uint8_t *)data, size, 1); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1); if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) { /* Read footer of packet */ size = sizeof(uint16_t) * width; - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * s->regs[SONIC_TFC]) * width, - (uint8_t *)data, size, 0); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->regs[SONIC_CTDA] = data[0 * width] & ~0x1; if (data[0 * width] & 0x1) { /* EOL detected */ @@ -446,12 +446,12 @@ static void do_transmit_packets(dp8393xState *s) dp8393x_update_irq(s); } -static void do_halt_transmission(dp8393xState *s) +static void dp8393x_do_halt_transmission(dp8393xState *s) { /* Nothing to do */ } -static void do_command(dp8393xState *s, uint16_t command) +static void dp8393x_do_command(dp8393xState *s, uint16_t command) { if ((s->regs[SONIC_CR] & SONIC_CR_RST) && !(command & SONIC_CR_RST)) { s->regs[SONIC_CR] &= ~SONIC_CR_RST; @@ -461,34 +461,36 @@ static void do_command(dp8393xState *s, uint16_t command) s->regs[SONIC_CR] |= (command & SONIC_CR_MASK); if (command & SONIC_CR_HTX) - do_halt_transmission(s); + dp8393x_do_halt_transmission(s); if (command & SONIC_CR_TXP) - do_transmit_packets(s); + dp8393x_do_transmit_packets(s); if (command & SONIC_CR_RXDIS) - do_receiver_disable(s); + dp8393x_do_receiver_disable(s); if (command & SONIC_CR_RXEN) - do_receiver_enable(s); + dp8393x_do_receiver_enable(s); if (command & SONIC_CR_STP) - do_stop_timer(s); + dp8393x_do_stop_timer(s); if (command & SONIC_CR_ST) - do_start_timer(s); + dp8393x_do_start_timer(s); if (command & SONIC_CR_RST) - do_software_reset(s); + dp8393x_do_software_reset(s); if (command & SONIC_CR_RRRA) - do_read_rra(s); + dp8393x_do_read_rra(s); if (command & SONIC_CR_LCAM) - do_load_cam(s); + dp8393x_do_load_cam(s); } -static uint16_t read_register(dp8393xState *s, int reg) +static uint64_t dp8393x_read(void *opaque, hwaddr addr, unsigned int size) { + dp8393xState *s = opaque; + int reg = addr >> s->it_shift; uint16_t val = 0; switch (reg) { /* Update data before reading it */ case SONIC_WT0: case SONIC_WT1: - update_wt_regs(s); + dp8393x_update_wt_regs(s); val = s->regs[reg]; break; /* Accept read to some registers only when in reset mode */ @@ -510,14 +512,18 @@ static uint16_t read_register(dp8393xState *s, int reg) return val; } -static void write_register(dp8393xState *s, int reg, uint16_t val) +static void dp8393x_write(void *opaque, hwaddr addr, uint64_t data, + unsigned int size) { - DPRINTF("write 0x%04x to reg %s\n", val, reg_names[reg]); + dp8393xState *s = opaque; + int reg = addr >> s->it_shift; + + DPRINTF("write 0x%04x to reg %s\n", (uint16_t)data, reg_names[reg]); switch (reg) { /* Command register */ case SONIC_CR: - do_command(s, val); + dp8393x_do_command(s, data); break; /* Prevent write to read-only registers */ case SONIC_CAP2: @@ -530,37 +536,37 @@ static void write_register(dp8393xState *s, int reg, uint16_t val) /* Accept write to some registers only when in reset mode */ case SONIC_DCR: if (s->regs[SONIC_CR] & SONIC_CR_RST) { - s->regs[reg] = val & 0xbfff; + s->regs[reg] = data & 0xbfff; } else { DPRINTF("writing to DCR invalid\n"); } break; case SONIC_DCR2: if (s->regs[SONIC_CR] & SONIC_CR_RST) { - s->regs[reg] = val & 0xf017; + s->regs[reg] = data & 0xf017; } else { DPRINTF("writing to DCR2 invalid\n"); } break; /* 12 lower bytes are Read Only */ case SONIC_TCR: - s->regs[reg] = val & 0xf000; + s->regs[reg] = data & 0xf000; break; /* 9 lower bytes are Read Only */ case SONIC_RCR: - s->regs[reg] = val & 0xffe0; + s->regs[reg] = data & 0xffe0; break; /* Ignore most significant bit */ case SONIC_IMR: - s->regs[reg] = val & 0x7fff; + s->regs[reg] = data & 0x7fff; dp8393x_update_irq(s); break; /* Clear bits by writing 1 to them */ case SONIC_ISR: - val &= s->regs[reg]; - s->regs[reg] &= ~val; - if (val & SONIC_ISR_RBE) { - do_read_rra(s); + data &= s->regs[reg]; + s->regs[reg] &= ~data; + if (data & SONIC_ISR_RBE) { + dp8393x_do_read_rra(s); } dp8393x_update_irq(s); break; @@ -569,24 +575,32 @@ static void write_register(dp8393xState *s, int reg, uint16_t val) case SONIC_REA: case SONIC_RRP: case SONIC_RWP: - s->regs[reg] = val & 0xfffe; + s->regs[reg] = data & 0xfffe; break; /* Invert written value for some registers */ case SONIC_CRCT: case SONIC_FAET: case SONIC_MPT: - s->regs[reg] = val ^ 0xffff; + s->regs[reg] = data ^ 0xffff; break; /* All other registers have no special contrainst */ default: - s->regs[reg] = val; + s->regs[reg] = data; } if (reg == SONIC_WT0 || reg == SONIC_WT1) { - set_next_tick(s); + dp8393x_set_next_tick(s); } } +static const MemoryRegionOps dp8393x_ops = { + .read = dp8393x_read, + .write = dp8393x_write, + .impl.min_access_size = 2, + .impl.max_access_size = 2, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + static void dp8393x_watchdog(void *opaque) { dp8393xState *s = opaque; @@ -597,84 +611,14 @@ static void dp8393x_watchdog(void *opaque) s->regs[SONIC_WT1] = 0xffff; s->regs[SONIC_WT0] = 0xffff; - set_next_tick(s); + dp8393x_set_next_tick(s); /* Signal underflow */ s->regs[SONIC_ISR] |= SONIC_ISR_TC; dp8393x_update_irq(s); } -static uint32_t dp8393x_readw(void *opaque, hwaddr addr) -{ - dp8393xState *s = opaque; - int reg; - - if ((addr & ((1 << s->it_shift) - 1)) != 0) { - return 0; - } - - reg = addr >> s->it_shift; - return read_register(s, reg); -} - -static uint32_t dp8393x_readb(void *opaque, hwaddr addr) -{ - uint16_t v = dp8393x_readw(opaque, addr & ~0x1); - return (v >> (8 * (addr & 0x1))) & 0xff; -} - -static uint32_t dp8393x_readl(void *opaque, hwaddr addr) -{ - uint32_t v; - v = dp8393x_readw(opaque, addr); - v |= dp8393x_readw(opaque, addr + 2) << 16; - return v; -} - -static void dp8393x_writew(void *opaque, hwaddr addr, uint32_t val) -{ - dp8393xState *s = opaque; - int reg; - - if ((addr & ((1 << s->it_shift) - 1)) != 0) { - return; - } - - reg = addr >> s->it_shift; - - write_register(s, reg, (uint16_t)val); -} - -static void dp8393x_writeb(void *opaque, hwaddr addr, uint32_t val) -{ - uint16_t old_val = dp8393x_readw(opaque, addr & ~0x1); - - switch (addr & 3) { - case 0: - val = val | (old_val & 0xff00); - break; - case 1: - val = (val << 8) | (old_val & 0x00ff); - break; - } - dp8393x_writew(opaque, addr & ~0x1, val); -} - -static void dp8393x_writel(void *opaque, hwaddr addr, uint32_t val) -{ - dp8393x_writew(opaque, addr, val & 0xffff); - dp8393x_writew(opaque, addr + 2, (val >> 16) & 0xffff); -} - -static const MemoryRegionOps dp8393x_ops = { - .old_mmio = { - .read = { dp8393x_readb, dp8393x_readw, dp8393x_readl, }, - .write = { dp8393x_writeb, dp8393x_writew, dp8393x_writel, }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int nic_can_receive(NetClientState *nc) +static int dp8393x_can_receive(NetClientState *nc) { dp8393xState *s = qemu_get_nic_opaque(nc); @@ -685,7 +629,8 @@ static int nic_can_receive(NetClientState *nc) return 1; } -static int receive_filter(dp8393xState *s, const uint8_t * buf, int size) +static int dp8393x_receive_filter(dp8393xState *s, const uint8_t * buf, + int size) { static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; int i; @@ -723,7 +668,8 @@ static int receive_filter(dp8393xState *s, const uint8_t * buf, int size) return -1; } -static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) +static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf, + size_t size) { dp8393xState *s = qemu_get_nic_opaque(nc); uint16_t data[10]; @@ -737,7 +683,7 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) s->regs[SONIC_RCR] &= ~(SONIC_RCR_PRX | SONIC_RCR_LBK | SONIC_RCR_FAER | SONIC_RCR_CRCR | SONIC_RCR_LPKT | SONIC_RCR_BC | SONIC_RCR_MC); - packet_type = receive_filter(s, buf, size); + packet_type = dp8393x_receive_filter(s, buf, size); if (packet_type < 0) { DPRINTF("packet not for netcard\n"); return -1; @@ -750,7 +696,8 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) /* Are we still in resource exhaustion? */ size = sizeof(uint16_t) * 1 * width; address = ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width; - s->memory_rw(s->mem_opaque, address, (uint8_t*)data, size, 0); + address_space_rw(&s->as, address, MEMTXATTRS_UNSPECIFIED, + (uint8_t *)data, size, 0); if (data[0 * width] & 0x1) { /* Still EOL ; stop reception */ return -1; @@ -764,18 +711,16 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) s->regs[SONIC_TRBA0] = s->regs[SONIC_CRBA0]; /* Calculate the ethernet checksum */ -#ifdef SONIC_CALCULATE_RXCRC checksum = cpu_to_le32(crc32(0, buf, rx_len)); -#else - checksum = 0; -#endif /* Put packet into RBA */ DPRINTF("Receive packet at %08x\n", (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]); address = (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]; - s->memory_rw(s->mem_opaque, address, (uint8_t*)buf, rx_len, 1); + address_space_rw(&s->as, address, + MEMTXATTRS_UNSPECIFIED, (uint8_t *)buf, rx_len, 1); address += rx_len; - s->memory_rw(s->mem_opaque, address, (uint8_t*)&checksum, 4, 1); + address_space_rw(&s->as, address, + MEMTXATTRS_UNSPECIFIED, (uint8_t *)&checksum, 4, 1); rx_len += 4; s->regs[SONIC_CRBA1] = address >> 16; s->regs[SONIC_CRBA0] = address & 0xffff; @@ -803,29 +748,30 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) data[3 * width] = s->regs[SONIC_TRBA1]; /* pkt_ptr1 */ data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */ size = sizeof(uint16_t) * 5 * width; - s->memory_rw(s->mem_opaque, (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA], (uint8_t *)data, size, 1); + address_space_rw(&s->as, (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA], + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1); /* Move to next descriptor */ size = sizeof(uint16_t) * width; - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width, - (uint8_t *)data, size, 0); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->regs[SONIC_LLFA] = data[0 * width]; if (s->regs[SONIC_LLFA] & 0x1) { /* EOL detected */ s->regs[SONIC_ISR] |= SONIC_ISR_RDE; } else { data[0 * width] = 0; /* in_use */ - s->memory_rw(s->mem_opaque, + address_space_rw(&s->as, ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 6 * width, - (uint8_t *)data, size, 1); + MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, sizeof(uint16_t), 1); s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA]; s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX; s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff); if (s->regs[SONIC_RCR] & SONIC_RCR_LPKT) { /* Read next RRA */ - do_read_rra(s); + dp8393x_do_read_rra(s); } } @@ -835,11 +781,12 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) return size; } -static void nic_reset(void *opaque) +static void dp8393x_reset(DeviceState *dev) { - dp8393xState *s = opaque; + dp8393xState *s = DP8393X(dev); timer_del(s->watchdog); + memset(s->regs, 0, sizeof(s->regs)); s->regs[SONIC_CR] = SONIC_CR_RST | SONIC_CR_STP | SONIC_CR_RXDIS; s->regs[SONIC_DCR] &= ~(SONIC_DCR_EXBUS | SONIC_DCR_LBR); s->regs[SONIC_RCR] &= ~(SONIC_RCR_LB0 | SONIC_RCR_LB1 | SONIC_RCR_BRD | SONIC_RCR_RNT); @@ -862,39 +809,91 @@ static void nic_reset(void *opaque) static NetClientInfo net_dp83932_info = { .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), - .can_receive = nic_can_receive, - .receive = nic_receive, + .can_receive = dp8393x_can_receive, + .receive = dp8393x_receive, }; -void dp83932_init(NICInfo *nd, hwaddr base, int it_shift, - MemoryRegion *address_space, - qemu_irq irq, void* mem_opaque, - void (*memory_rw)(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write)) +static void dp8393x_instance_init(Object *obj) { - dp8393xState *s; + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + dp8393xState *s = DP8393X(obj); + + sysbus_init_mmio(sbd, &s->mmio); + sysbus_init_mmio(sbd, &s->prom); + sysbus_init_irq(sbd, &s->irq); +} - qemu_check_nic_model(nd, "dp83932"); +static void dp8393x_realize(DeviceState *dev, Error **errp) +{ + dp8393xState *s = DP8393X(dev); + int i, checksum; + uint8_t *prom; - s = g_malloc0(sizeof(dp8393xState)); + address_space_init(&s->as, s->dma_mr, "dp8393x"); + memory_region_init_io(&s->mmio, OBJECT(dev), &dp8393x_ops, s, + "dp8393x-regs", 0x40 << s->it_shift); + + s->nic = qemu_new_nic(&net_dp83932_info, &s->conf, + object_get_typename(OBJECT(dev)), dev->id, s); + qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); - s->address_space = address_space; - s->mem_opaque = mem_opaque; - s->memory_rw = memory_rw; - s->it_shift = it_shift; - s->irq = irq; s->watchdog = timer_new_ns(QEMU_CLOCK_VIRTUAL, dp8393x_watchdog, s); s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */ - s->conf.macaddr = nd->macaddr; - s->conf.peers.ncs[0] = nd->netdev; + memory_region_init_rom_device(&s->prom, OBJECT(dev), NULL, NULL, + "dp8393x-prom", SONIC_PROM_SIZE, NULL); + prom = memory_region_get_ram_ptr(&s->prom); + checksum = 0; + for (i = 0; i < 6; i++) { + prom[i] = s->conf.macaddr.a[i]; + checksum += prom[i]; + if (checksum > 0xff) { + checksum = (checksum + 1) & 0xff; + } + } + prom[7] = 0xff - checksum; +} - s->nic = qemu_new_nic(&net_dp83932_info, &s->conf, nd->model, nd->name, s); +static const VMStateDescription vmstate_dp8393x = { + .name = "dp8393x", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField []) { + VMSTATE_BUFFER_UNSAFE(cam, dp8393xState, 0, 16 * 6), + VMSTATE_UINT16_ARRAY(regs, dp8393xState, 0x40), + VMSTATE_END_OF_LIST() + } +}; - qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); - qemu_register_reset(nic_reset, s); - nic_reset(s); +static Property dp8393x_properties[] = { + DEFINE_NIC_PROPERTIES(dp8393xState, conf), + DEFINE_PROP_PTR("dma_mr", dp8393xState, dma_mr), + DEFINE_PROP_UINT8("it_shift", dp8393xState, it_shift, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void dp8393x_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); - memory_region_init_io(&s->mmio, NULL, &dp8393x_ops, s, - "dp8393x", 0x40 << it_shift); - memory_region_add_subregion(address_space, base, &s->mmio); + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); + dc->realize = dp8393x_realize; + dc->reset = dp8393x_reset; + dc->vmsd = &vmstate_dp8393x; + dc->props = dp8393x_properties; } + +static const TypeInfo dp8393x_info = { + .name = TYPE_DP8393X, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(dp8393xState), + .instance_init = dp8393x_instance_init, + .class_init = dp8393x_class_init, +}; + +static void dp8393x_register_types(void) +{ + type_register_static(&dp8393x_info); +} + +type_init(dp8393x_register_types) |