initial APIC support
[qemu] / hw / ne2000.c
index 9a04c92..79d3026 100644 (file)
@@ -401,10 +401,10 @@ static inline void ne2000_mem_writew(NE2000State *s, uint32_t addr,
 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);
     }
 }
 
@@ -431,15 +431,33 @@ static inline uint32_t ne2000_mem_readw(NE2000State *s, uint32_t addr)
 
 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;
@@ -448,25 +466,15 @@ static void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
     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);
     }
 }
 
@@ -478,21 +486,11 @@ static uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr)
     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);
@@ -508,19 +506,10 @@ static void ne2000_asic_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
     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)
@@ -530,17 +519,7 @@ 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
@@ -559,6 +538,59 @@ static uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr)
     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;
@@ -583,6 +615,9 @@ void isa_ne2000_init(int base, int irq, NetDriverState *nd)
     ne2000_reset(s);
 
     qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s);
+
+    register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s);
+
 }
 
 /***********************************************************/
@@ -613,14 +648,15 @@ static void ne2000_map(PCIDevice *pci_dev, int region_num,
     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
@@ -632,7 +668,7 @@ void pci_ne2000_init(NetDriverState *nd)
     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
@@ -640,4 +676,9 @@ void pci_ne2000_init(NetDriverState *nd)
     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);
 }