]> git.proxmox.com Git - qemu.git/blobdiff - hw/pcnet.c
pcnet: Restart poll timer on pcnet_start
[qemu.git] / hw / pcnet.c
index 99703480fd4bdcbe6a71b1ffa1e189cb4ee87ae5..008b71a53b2b533bd85aad76af4d795e02efe2e9 100644 (file)
  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
  */
 
-#include <netinet/in.h>
-
-#include "hw.h"
+#include "sysbus.h"
 #include "pci.h"
 #include "net.h"
 #include "qemu-timer.h"
+#include "qemu_socket.h"
 
 //#define PCNET_DEBUG
 //#define PCNET_DEBUG_IO
 typedef struct PCNetState_st PCNetState;
 
 struct PCNetState_st {
-    PCIDevice dev;
     PCIDevice *pci_dev;
     VLANClientState *vc;
-    NICInfo *nd;
+    uint8_t macaddr[6];
     QEMUTimer *poll_timer;
-    int mmio_index, rap, isr, lnkst;
+    int rap, isr, lnkst;
     uint32_t rdra, tdra;
     uint8_t prom[16];
     uint16_t csr[128];
     uint16_t bcr[32];
     uint64_t timer;
-    int xmit_pos, recv_pos;
+    int mmio_index, xmit_pos, recv_pos;
     uint8_t buffer[4096];
     int tx_busy;
     qemu_irq irq;
@@ -84,6 +82,16 @@ struct PCNetState_st {
     int looptest;
 };
 
+typedef struct {
+    PCIDevice pci_dev;
+    PCNetState state;
+} PCIPCNetState;
+
+typedef struct {
+    SysBusDevice busdev;
+    PCNetState state;
+} SysBusPCNetState;
+
 struct qemu_ether_header {
     uint8_t ether_dhost[6];
     uint8_t ether_shost[6];
@@ -928,6 +936,7 @@ static void pcnet_start(PCNetState *s)
 
     s->csr[0] &= ~0x0004;       /* clear STOP bit */
     s->csr[0] |= 0x0002;
+    pcnet_poll_timer(s);
 }
 
 static void pcnet_stop(PCNetState *s)
@@ -965,11 +974,11 @@ static void pcnet_rdte_poll(PCNetState *s)
             (BCR_SWSTYLE(s) ? 16 : 8 );
 #endif
 
-        CHECK_RMD(PHYSADDR(s,crda), bad);
+        CHECK_RMD(crda, bad);
         if (!bad) {
-            CHECK_RMD(PHYSADDR(s,nrda), bad);
+            CHECK_RMD(nrda, bad);
             if (bad || (nrda == crda)) nrda = 0;
-            CHECK_RMD(PHYSADDR(s,nnrd), bad);
+            CHECK_RMD(nnrd, bad);
             if (bad || (nnrd == crda)) nnrd = 0;
 
             s->csr[28] = crda & 0xffff;
@@ -981,11 +990,11 @@ static void pcnet_rdte_poll(PCNetState *s)
 #ifdef PCNET_DEBUG
             if (bad) {
                 printf("pcnet: BAD RMD RECORDS AFTER 0x" TARGET_FMT_plx "\n",
-                       PHYSADDR(s,crda));
+                       crda);
             }
         } else {
             printf("pcnet: BAD RMD RDA=0x" TARGET_FMT_plx "\n",
-                   PHYSADDR(s,crda));
+                   crda);
 #endif
         }
     }
@@ -1024,7 +1033,7 @@ static int pcnet_tdte_poll(PCNetState *s)
             (CSR_XMTRL(s) - CSR_XMTRC(s)) *
             (BCR_SWSTYLE(s) ? 16 : 8);
         int bad = 0;
-        CHECK_TMD(PHYSADDR(s, cxda),bad);
+        CHECK_TMD(cxda, bad);
         if (!bad) {
             if (CSR_CXDA(s) != cxda) {
                 s->csr[60] = s->csr[34];
@@ -1035,7 +1044,7 @@ static int pcnet_tdte_poll(PCNetState *s)
             s->csr[34] = cxda & 0xffff;
             s->csr[35] = cxda >> 16;
 #ifdef PCNET_DEBUG_X
-            printf("pcnet: BAD TMD XDA=0x%08x\n", PHYSADDR(s,cxda));
+            printf("pcnet: BAD TMD XDA=0x%08x\n", cxda);
 #endif
         }
     }
@@ -1054,9 +1063,9 @@ static int pcnet_tdte_poll(PCNetState *s)
     return !!(CSR_CXST(s) & 0x8000);
 }
 
-static int pcnet_can_receive(void *opaque)
+static int pcnet_can_receive(VLANClientState *vc)
 {
-    PCNetState *s = opaque;
+    PCNetState *s = vc->opaque;
     if (CSR_STOP(s) || CSR_SPND(s))
         return 0;
 
@@ -1068,16 +1077,17 @@ static int pcnet_can_receive(void *opaque)
 
 #define MIN_BUF_SIZE 60
 
-static void pcnet_receive(void *opaque, const uint8_t *buf, int size)
+static ssize_t pcnet_receive(VLANClientState *vc, const uint8_t *buf, size_t size_)
 {
-    PCNetState *s = opaque;
+    PCNetState *s = vc->opaque;
     int is_padr = 0, is_bcast = 0, is_ladr = 0;
     uint8_t buf1[60];
     int remaining;
     int crc_err = 0;
+    int size = size_;
 
     if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size)
-        return;
+        return -1;
 
 #ifdef PCNET_DEBUG
     printf("pcnet_receive size=%d\n", size);
@@ -1108,7 +1118,7 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size)
                 nrda = s->rdra +
                     (CSR_RCVRL(s) - rcvrc) *
                     (BCR_SWSTYLE(s) ? 16 : 8 );
-                RMDLOAD(&rmd, PHYSADDR(s,nrda));
+                RMDLOAD(&rmd, nrda);
                 if (GET_FIELD(rmd.status, RMDS, OWN)) {
 #ifdef PCNET_DEBUG_RMD
                     printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n",
@@ -1244,6 +1254,8 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size)
 
     pcnet_poll(s);
     pcnet_update_irq(s);
+
+    return size_;
 }
 
 static void pcnet_transmit(PCNetState *s)
@@ -1294,7 +1306,7 @@ static void pcnet_transmit(PCNetState *s)
                 if (BCR_SWSTYLE(s) == 1)
                     add_crc = !GET_FIELD(tmd.status, TMDS, NOFCS);
                 s->looptest = add_crc ? PCNET_LOOPTEST_CRC : PCNET_LOOPTEST_NOCRC;
-                pcnet_receive(s, s->buffer, s->xmit_pos);
+                pcnet_receive(s->vc, s->buffer, s->xmit_pos);
                 s->looptest = 0;
             } else
                 if (s->vc)
@@ -1320,12 +1332,12 @@ static void pcnet_transmit(PCNetState *s)
     } else
     if (s->xmit_pos >= 0) {
         struct pcnet_TMD tmd;
-        TMDLOAD(&tmd, PHYSADDR(s,xmit_cxda));
+        TMDLOAD(&tmd, xmit_cxda);
         SET_FIELD(&tmd.misc, TMDM, BUFF, 1);
         SET_FIELD(&tmd.misc, TMDM, UFLO, 1);
         SET_FIELD(&tmd.status, TMDS, ERR, 1);
         SET_FIELD(&tmd.status, TMDS, OWN, 0);
-        TMDSTORE(&tmd, PHYSADDR(s,xmit_cxda));
+        TMDSTORE(&tmd, xmit_cxda);
         s->csr[0] |= 0x0200;    /* set TINT */
         if (!CSR_DXSUFLO(s)) {
             s->csr[0] &= ~0x0010;
@@ -1593,8 +1605,7 @@ static void pcnet_h_reset(void *opaque)
 
     /* Initialize the PROM */
 
-    if (s->nd)
-        memcpy(s->prom, s->nd->macaddr, 6);
+    memcpy(s->prom, s->macaddr, 6);
     s->prom[12] = s->prom[13] = 0x00;
     s->prom[14] = s->prom[15] = 0x57;
 
@@ -1754,7 +1765,7 @@ static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
 static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num,
                              uint32_t addr, uint32_t size, int type)
 {
-    PCNetState *d = (PCNetState *)pci_dev;
+    PCNetState *d = &((PCIPCNetState *)pci_dev)->state;
 
 #ifdef PCNET_DEBUG_IO
     printf("pcnet_ioport_map addr=0x%04x size=0x%04x\n", addr, size);
@@ -1878,9 +1889,9 @@ static void pcnet_save(QEMUFile *f, void *opaque)
     if (s->pci_dev)
         pci_device_save(s->pci_dev, f);
 
-    qemu_put_be32(f, s->rap);
-    qemu_put_be32(f, s->isr);
-    qemu_put_be32(f, s->lnkst);
+    qemu_put_sbe32(f, s->rap);
+    qemu_put_sbe32(f, s->isr);
+    qemu_put_sbe32(f, s->lnkst);
     qemu_put_be32s(f, &s->rdra);
     qemu_put_be32s(f, &s->tdra);
     qemu_put_buffer(f, s->prom, 16);
@@ -1889,10 +1900,10 @@ static void pcnet_save(QEMUFile *f, void *opaque)
     for (i = 0; i < 32; i++)
         qemu_put_be16s(f, &s->bcr[i]);
     qemu_put_be64s(f, &s->timer);
-    qemu_put_be32(f, s->xmit_pos);
-    qemu_put_be32(f, s->recv_pos);
+    qemu_put_sbe32(f, s->xmit_pos);
+    qemu_put_sbe32(f, s->recv_pos);
     qemu_put_buffer(f, s->buffer, 4096);
-    qemu_put_be32(f, s->tx_busy);
+    qemu_put_sbe32(f, s->tx_busy);
     qemu_put_timer(f, s->poll_timer);
 }
 
@@ -1910,9 +1921,9 @@ static int pcnet_load(QEMUFile *f, void *opaque, int version_id)
             return ret;
     }
 
-    qemu_get_be32s(f, (uint32_t*)&s->rap);
-    qemu_get_be32s(f, (uint32_t*)&s->isr);
-    qemu_get_be32s(f, (uint32_t*)&s->lnkst);
+    qemu_get_sbe32s(f, &s->rap);
+    qemu_get_sbe32s(f, &s->isr);
+    qemu_get_sbe32s(f, &s->lnkst);
     qemu_get_be32s(f, &s->rdra);
     qemu_get_be32s(f, &s->tdra);
     qemu_get_buffer(f, s->prom, 16);
@@ -1921,38 +1932,34 @@ static int pcnet_load(QEMUFile *f, void *opaque, int version_id)
     for (i = 0; i < 32; i++)
         qemu_get_be16s(f, &s->bcr[i]);
     qemu_get_be64s(f, &s->timer);
-    qemu_get_be32s(f, (uint32_t*)&s->xmit_pos);
-    qemu_get_be32s(f, (uint32_t*)&s->recv_pos);
+    qemu_get_sbe32s(f, &s->xmit_pos);
+    qemu_get_sbe32s(f, &s->recv_pos);
     qemu_get_buffer(f, s->buffer, 4096);
-    qemu_get_be32s(f, (uint32_t*)&s->tx_busy);
+    qemu_get_sbe32s(f, &s->tx_busy);
     qemu_get_timer(f, s->poll_timer);
 
     return 0;
 }
 
-static void pcnet_common_init(PCNetState *d, NICInfo *nd, const char *info_str)
+static void pcnet_common_cleanup(PCNetState *d)
 {
-    d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d);
-
-    d->nd = nd;
-
-    if (nd && nd->vlan) {
-        d->vc = qemu_new_vlan_client(nd->vlan, pcnet_receive,
-                                     pcnet_can_receive, d);
-
-        snprintf(d->vc->info_str, sizeof(d->vc->info_str),
-                 "pcnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
-                 d->nd->macaddr[0],
-                 d->nd->macaddr[1],
-                 d->nd->macaddr[2],
-                 d->nd->macaddr[3],
-                 d->nd->macaddr[4],
-                 d->nd->macaddr[5]);
-    } else {
-        d->vc = NULL;
-    }
-    pcnet_h_reset(d);
-    register_savevm("pcnet", -1, 2, pcnet_save, pcnet_load, d);
+    unregister_savevm("pcnet", d);
+
+    qemu_del_timer(d->poll_timer);
+    qemu_free_timer(d->poll_timer);
+}
+
+static void pcnet_common_init(DeviceState *dev, PCNetState *s,
+                              NetCleanup *cleanup)
+{
+    s->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, s);
+
+    qdev_get_macaddr(dev, s->macaddr);
+    s->vc = qdev_get_vlan_client(dev,
+                                 pcnet_can_receive, pcnet_receive, NULL,
+                                 cleanup, s);
+    pcnet_h_reset(s);
+    register_savevm("pcnet", -1, 2, pcnet_save, pcnet_load, s);
 }
 
 /* PCI interface */
@@ -1972,13 +1979,13 @@ static CPUReadMemoryFunc *pcnet_mmio_read[] = {
 static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num,
                             uint32_t addr, uint32_t size, int type)
 {
-    PCNetState *d = (PCNetState *)pci_dev;
+    PCIPCNetState *d = (PCIPCNetState *)pci_dev;
 
 #ifdef PCNET_DEBUG_IO
     printf("pcnet_mmio_map addr=0x%08x 0x%08x\n", addr, size);
 #endif
 
-    cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->mmio_index);
+    cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->state.mmio_index);
 }
 
 static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr,
@@ -1993,9 +2000,26 @@ static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr,
     cpu_physical_memory_read(addr, buf, len);
 }
 
-void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn)
+static void pci_pcnet_cleanup(VLANClientState *vc)
+{
+    PCNetState *d = vc->opaque;
+
+    pcnet_common_cleanup(d);
+}
+
+static int pci_pcnet_uninit(PCIDevice *dev)
+{
+    PCIPCNetState *d = (PCIPCNetState *)dev;
+
+    cpu_unregister_io_memory(d->state.mmio_index);
+
+    return 0;
+}
+
+static void pci_pcnet_init(PCIDevice *pci_dev)
 {
-    PCNetState *d;
+    PCIPCNetState *d = (PCIPCNetState *)pci_dev;
+    PCNetState *s = &d->state;
     uint8_t *pci_conf;
 
 #if 0
@@ -2003,20 +2027,18 @@ void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn)
         sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD));
 #endif
 
-    d = (PCNetState *)pci_register_device(bus, "PCNet", sizeof(PCNetState),
-                                          devfn, NULL, NULL);
+    pci_dev->unregister = pci_pcnet_uninit;
 
-    pci_conf = d->dev.config;
+    pci_conf = pci_dev->config;
 
-    *(uint16_t *)&pci_conf[0x00] = cpu_to_le16(0x1022);
-    *(uint16_t *)&pci_conf[0x02] = cpu_to_le16(0x2000);
+    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_AMD);
+    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_AMD_LANCE);
     *(uint16_t *)&pci_conf[0x04] = cpu_to_le16(0x0007);
     *(uint16_t *)&pci_conf[0x06] = cpu_to_le16(0x0280);
     pci_conf[0x08] = 0x10;
     pci_conf[0x09] = 0x00;
-    pci_conf[0x0a] = 0x00; // ethernet network controller
-    pci_conf[0x0b] = 0x02;
-    pci_conf[0x0e] = 0x00; // header_type
+    pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
+    pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
 
     *(uint32_t *)&pci_conf[0x10] = cpu_to_le32(0x00000001);
     *(uint32_t *)&pci_conf[0x14] = cpu_to_le32(0x00000000);
@@ -2026,21 +2048,21 @@ void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn)
     pci_conf[0x3f] = 0xff;
 
     /* Handler for memory-mapped I/O */
-    d->mmio_index =
-      cpu_register_io_memory(0, pcnet_mmio_read, pcnet_mmio_write, d);
+    s->mmio_index =
+      cpu_register_io_memory(pcnet_mmio_read, pcnet_mmio_write, &d->state);
 
-    pci_register_io_region((PCIDevice *)d, 0, PCNET_IOPORT_SIZE,
+    pci_register_bar((PCIDevice *)d, 0, PCNET_IOPORT_SIZE,
                            PCI_ADDRESS_SPACE_IO, pcnet_ioport_map);
 
-    pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE,
+    pci_register_bar((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE,
                            PCI_ADDRESS_SPACE_MEM, pcnet_mmio_map);
 
-    d->irq = d->dev.irq[0];
-    d->phys_mem_read = pci_physical_memory_read;
-    d->phys_mem_write = pci_physical_memory_write;
-    d->pci_dev = &d->dev;
+    s->irq = pci_dev->irq[0];
+    s->phys_mem_read = pci_physical_memory_read;
+    s->phys_mem_write = pci_physical_memory_write;
+    s->pci_dev = pci_dev;
 
-    pcnet_common_init(d, nd, "pcnet");
+    pcnet_common_init(&pci_dev->qdev, s, pci_pcnet_cleanup);
 }
 
 /* SPARC32 interface */
@@ -2050,25 +2072,28 @@ void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn)
 
 static void parent_lance_reset(void *opaque, int irq, int level)
 {
+    SysBusPCNetState *d = opaque;
     if (level)
-        pcnet_h_reset(opaque);
+        pcnet_h_reset(&d->state);
 }
 
 static void lance_mem_writew(void *opaque, target_phys_addr_t addr,
                              uint32_t val)
 {
+    SysBusPCNetState *d = opaque;
 #ifdef PCNET_DEBUG_IO
     printf("lance_mem_writew addr=" TARGET_FMT_plx " val=0x%04x\n", addr,
            val & 0xffff);
 #endif
-    pcnet_ioport_writew(opaque, addr & 7, val & 0xffff);
+    pcnet_ioport_writew(&d->state, addr, val & 0xffff);
 }
 
 static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr)
 {
+    SysBusPCNetState *d = opaque;
     uint32_t val;
 
-    val = pcnet_ioport_readw(opaque, addr & 7);
+    val = pcnet_ioport_readw(&d->state, addr);
 #ifdef PCNET_DEBUG_IO
     printf("lance_mem_readw addr=" TARGET_FMT_plx " val = 0x%04x\n", addr,
            val & 0xffff);
@@ -2089,29 +2114,61 @@ static CPUWriteMemoryFunc *lance_mem_write[3] = {
     NULL,
 };
 
-void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque,
-                qemu_irq irq, qemu_irq *reset)
+static void lance_cleanup(VLANClientState *vc)
 {
-    PCNetState *d;
-    int lance_io_memory;
+    PCNetState *d = vc->opaque;
 
-    d = qemu_mallocz(sizeof(PCNetState));
-    if (!d)
-        return;
+    pcnet_common_cleanup(d);
+}
 
-    lance_io_memory =
-        cpu_register_io_memory(0, lance_mem_read, lance_mem_write, d);
+static void lance_init(SysBusDevice *dev)
+{
+    SysBusPCNetState *d = FROM_SYSBUS(SysBusPCNetState, dev);
+    PCNetState *s = &d->state;
 
-    d->dma_opaque = dma_opaque;
+    s->mmio_index =
+        cpu_register_io_memory(lance_mem_read, lance_mem_write, d);
 
-    *reset = *qemu_allocate_irqs(parent_lance_reset, d, 1);
+    qdev_init_gpio_in(&dev->qdev, parent_lance_reset, 1);
 
-    cpu_register_physical_memory(leaddr, 4, lance_io_memory);
+    sysbus_init_mmio(dev, 4, s->mmio_index);
 
-    d->irq = irq;
-    d->phys_mem_read = ledma_memory_read;
-    d->phys_mem_write = ledma_memory_write;
+    sysbus_init_irq(dev, &s->irq);
 
-    pcnet_common_init(d, nd, "lance");
+    s->phys_mem_read = ledma_memory_read;
+    s->phys_mem_write = ledma_memory_write;
+
+    pcnet_common_init(&dev->qdev, s, lance_cleanup);
 }
+
+static SysBusDeviceInfo lance_info = {
+    .init = lance_init,
+    .qdev.name  = "lance",
+    .qdev.size  = sizeof(SysBusPCNetState),
+    .qdev.props = (Property[]) {
+        {
+            .name   = "dma",
+            .info   = &qdev_prop_ptr,
+            .offset = offsetof(SysBusPCNetState, state.dma_opaque),
+        },
+        {/* end of list */}
+    }
+};
+
 #endif /* TARGET_SPARC */
+
+static PCIDeviceInfo pcnet_info = {
+    .qdev.name = "pcnet",
+    .qdev.size = sizeof(PCIPCNetState),
+    .init      = pci_pcnet_init,
+};
+
+static void pcnet_register_devices(void)
+{
+    pci_qdev_register(&pcnet_info);
+#if defined (TARGET_SPARC) && !defined(TARGET_SPARC64)
+    sysbus_register_withprop(&lance_info);
+#endif
+}
+
+device_init(pcnet_register_devices)