static inline void ne2000_mem_writel(NE2000State *s, uint32_t addr,
uint32_t val)
{
- addr &= ~3; /* XXX: check exact behaviour if not even */
+ addr &= ~1; /* XXX: check exact behaviour if not even */
if (addr < 32 ||
(addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
- *(uint32_t *)(s->mem + addr) = cpu_to_le32(val);
+ cpu_to_le32wu((uint32_t *)(s->mem + addr), val);
}
}
static inline uint32_t ne2000_mem_readl(NE2000State *s, uint32_t addr)
{
- addr &= ~3; /* XXX: check exact behaviour if not even */
+ addr &= ~1; /* XXX: check exact behaviour if not even */
if (addr < 32 ||
(addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
- return le32_to_cpu(*(uint32_t *)(s->mem + addr));
+ return le32_to_cpupu((uint32_t *)(s->mem + addr));
} else {
return 0xffffffff;
}
}
+static inline void ne2000_dma_update(NE2000State *s, int len)
+{
+ s->rsar += len;
+ /* wrap */
+ /* XXX: check what to do if rsar > stop */
+ if (s->rsar == s->stop)
+ s->rsar = s->start;
+
+ if (s->rcnt <= len) {
+ s->rcnt = 0;
+ /* signal end of transfert */
+ s->isr |= ENISR_RDC;
+ ne2000_update_irq(s);
+ } else {
+ s->rcnt -= len;
+ }
+}
+
static void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
NE2000State *s = opaque;
printf("NE2000: asic write val=0x%04x\n", val);
#endif
if (s->rcnt == 0)
- return;
+ return;
if (s->dcfg & 0x01) {
/* 16 bit access */
ne2000_mem_writew(s, s->rsar, val);
- s->rsar += 2;
- s->rcnt -= 2;
+ ne2000_dma_update(s, 2);
} else {
/* 8 bit access */
ne2000_mem_writeb(s, s->rsar, val);
- s->rsar++;
- s->rcnt--;
- }
- /* wrap */
- if (s->rsar == s->stop)
- s->rsar = s->start;
- if (s->rcnt == 0) {
- /* signal end of transfert */
- s->isr |= ENISR_RDC;
- ne2000_update_irq(s);
+ ne2000_dma_update(s, 1);
}
}
if (s->dcfg & 0x01) {
/* 16 bit access */
ret = ne2000_mem_readw(s, s->rsar);
- s->rsar += 2;
- s->rcnt -= 2;
+ ne2000_dma_update(s, 2);
} else {
/* 8 bit access */
ret = ne2000_mem_readb(s, s->rsar);
- s->rsar++;
- s->rcnt--;
- }
- /* wrap */
- if (s->rsar == s->stop)
- s->rsar = s->start;
- if (s->rcnt == 0) {
- /* signal end of transfert */
- s->isr |= ENISR_RDC;
- ne2000_update_irq(s);
+ ne2000_dma_update(s, 1);
}
#ifdef DEBUG_NE2000
printf("NE2000: asic read val=0x%04x\n", ret);
printf("NE2000: asic writel val=0x%04x\n", val);
#endif
if (s->rcnt == 0)
- return;
+ return;
/* 32 bit access */
ne2000_mem_writel(s, s->rsar, val);
- s->rsar += 4;
- s->rcnt -= 4;
- /* wrap */
- if (s->rsar == s->stop)
- s->rsar = s->start;
- if (s->rcnt == 0) {
- /* signal end of transfert */
- s->isr |= ENISR_RDC;
- ne2000_update_irq(s);
- }
+ ne2000_dma_update(s, 4);
}
static uint32_t ne2000_asic_ioport_readl(void *opaque, uint32_t addr)
/* 32 bit access */
ret = ne2000_mem_readl(s, s->rsar);
- s->rsar += 4;
- s->rcnt -= 4;
-
- /* wrap */
- if (s->rsar == s->stop)
- s->rsar = s->start;
- if (s->rcnt == 0) {
- /* signal end of transfert */
- s->isr |= ENISR_RDC;
- ne2000_update_irq(s);
- }
+ ne2000_dma_update(s, 4);
#ifdef DEBUG_NE2000
printf("NE2000: asic readl val=0x%04x\n", ret);
#endif
return 0;
}
+static void ne2000_save(QEMUFile* f,void* opaque)
+{
+ NE2000State* s=(NE2000State*)opaque;
+
+ qemu_put_8s(f, &s->cmd);
+ qemu_put_be32s(f, &s->start);
+ qemu_put_be32s(f, &s->stop);
+ qemu_put_8s(f, &s->boundary);
+ qemu_put_8s(f, &s->tsr);
+ qemu_put_8s(f, &s->tpsr);
+ qemu_put_be16s(f, &s->tcnt);
+ qemu_put_be16s(f, &s->rcnt);
+ qemu_put_be32s(f, &s->rsar);
+ qemu_put_8s(f, &s->rsr);
+ qemu_put_8s(f, &s->isr);
+ qemu_put_8s(f, &s->dcfg);
+ qemu_put_8s(f, &s->imr);
+ qemu_put_buffer(f, s->phys, 6);
+ qemu_put_8s(f, &s->curpag);
+ qemu_put_buffer(f, s->mult, 8);
+ qemu_put_be32s(f, &s->irq);
+ qemu_put_buffer(f, s->mem, NE2000_MEM_SIZE);
+}
+
+static int ne2000_load(QEMUFile* f,void* opaque,int version_id)
+{
+ NE2000State* s=(NE2000State*)opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ qemu_get_8s(f, &s->cmd);
+ qemu_get_be32s(f, &s->start);
+ qemu_get_be32s(f, &s->stop);
+ qemu_get_8s(f, &s->boundary);
+ qemu_get_8s(f, &s->tsr);
+ qemu_get_8s(f, &s->tpsr);
+ qemu_get_be16s(f, &s->tcnt);
+ qemu_get_be16s(f, &s->rcnt);
+ qemu_get_be32s(f, &s->rsar);
+ qemu_get_8s(f, &s->rsr);
+ qemu_get_8s(f, &s->isr);
+ qemu_get_8s(f, &s->dcfg);
+ qemu_get_8s(f, &s->imr);
+ qemu_get_buffer(f, s->phys, 6);
+ qemu_get_8s(f, &s->curpag);
+ qemu_get_buffer(f, s->mult, 8);
+ qemu_get_be32s(f, &s->irq);
+ qemu_get_buffer(f, s->mem, NE2000_MEM_SIZE);
+
+ return 0;
+}
+
void isa_ne2000_init(int base, int irq, NetDriverState *nd)
{
NE2000State *s;
ne2000_reset(s);
qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s);
+
+ register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s);
+
}
/***********************************************************/
register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
}
-void pci_ne2000_init(NetDriverState *nd)
+void pci_ne2000_init(PCIBus *bus, NetDriverState *nd)
{
PCINE2000State *d;
NE2000State *s;
uint8_t *pci_conf;
- d = (PCINE2000State *)pci_register_device("NE2000", sizeof(PCINE2000State),
- 0, -1,
+ d = (PCINE2000State *)pci_register_device(bus,
+ "NE2000", sizeof(PCINE2000State),
+ -1,
NULL, NULL);
pci_conf = d->dev.config;
pci_conf[0x00] = 0xec; // Realtek 8029
pci_conf[0x0e] = 0x00; // header_type
pci_conf[0x3d] = 1; // interrupt pin 0
- pci_register_io_region((PCIDevice *)d, 0, 0x100,
+ pci_register_io_region(&d->dev, 0, 0x100,
PCI_ADDRESS_SPACE_IO, ne2000_map);
s = &d->ne2000;
s->irq = 16; // PCI interrupt
s->nd = nd;
ne2000_reset(s);
qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s);
+
+ /* XXX: instance number ? */
+ register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s);
+ register_savevm("ne2000_pci", 0, 1, generic_pci_save, generic_pci_load,
+ &d->dev);
}