]> git.proxmox.com Git - qemu.git/blobdiff - hw/pcnet.c
Unexport ticks_per_sec variable. Create get_ticks_per_sec() function
[qemu.git] / hw / pcnet.c
index 188e5ffd3b6386d459f97bc46eb0d9b2679262b6..ae98a201dc85cab3e72d985d10fbf59c7494d141 100644 (file)
@@ -35,7 +35,7 @@
  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
  */
 
-#include "hw.h"
+#include "sysbus.h"
 #include "pci.h"
 #include "net.h"
 #include "qemu-timer.h"
 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;
@@ -83,6 +81,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];
@@ -718,7 +726,7 @@ static inline int64_t pcnet_get_next_poll_time(PCNetState *s, int64_t current_ti
 {
     int64_t next_time = current_time +
         muldiv64(65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s)),
-                 ticks_per_sec, 33000000L);
+                 get_ticks_per_sec(), 33000000L);
     if (next_time <= current_time)
         next_time = current_time + 1;
     return next_time;
@@ -964,11 +972,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;
@@ -980,11 +988,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
         }
     }
@@ -1023,7 +1031,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];
@@ -1034,7 +1042,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
         }
     }
@@ -1053,9 +1061,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;
 
@@ -1067,16 +1075,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);
@@ -1107,7 +1116,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",
@@ -1243,6 +1252,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)
@@ -1293,7 +1304,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)
@@ -1319,12 +1330,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;
@@ -1592,8 +1603,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;
 
@@ -1753,7 +1763,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 = &DO_UPCAST(PCIPCNetState, pci_dev, pci_dev)->state;
 
 #ifdef PCNET_DEBUG_IO
     printf("pcnet_ioport_map addr=0x%04x size=0x%04x\n", addr, size);
@@ -1874,9 +1884,6 @@ static void pcnet_save(QEMUFile *f, void *opaque)
     PCNetState *s = opaque;
     unsigned int i;
 
-    if (s->pci_dev)
-        pci_device_save(s->pci_dev, f);
-
     qemu_put_sbe32(f, s->rap);
     qemu_put_sbe32(f, s->isr);
     qemu_put_sbe32(f, s->lnkst);
@@ -1898,17 +1905,11 @@ static void pcnet_save(QEMUFile *f, void *opaque)
 static int pcnet_load(QEMUFile *f, void *opaque, int version_id)
 {
     PCNetState *s = opaque;
-    int i, ret;
+    int i;
 
     if (version_id != 2)
         return -EINVAL;
 
-    if (s->pci_dev) {
-        ret = pci_device_load(s->pci_dev, f);
-        if (ret < 0)
-            return ret;
-    }
-
     qemu_get_sbe32s(f, &s->rap);
     qemu_get_sbe32s(f, &s->isr);
     qemu_get_sbe32s(f, &s->lnkst);
@@ -1929,55 +1930,74 @@ static int pcnet_load(QEMUFile *f, void *opaque, int version_id)
     return 0;
 }
 
-static void pcnet_common_init(PCNetState *d, NICInfo *nd, const char *info_str)
+static void pci_pcnet_save(QEMUFile *f, void *opaque)
 {
-    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);
+    PCIPCNetState *s = opaque;
+
+    pci_device_save(&s->pci_dev, f);
+    pcnet_save(f, &s->state);
+}
+
+static int pci_pcnet_load(QEMUFile *f, void *opaque, int version_id)
+{
+    PCIPCNetState *s = opaque;
+    int ret;
+
+    if (version_id != 2)
+        return -EINVAL;
+
+    ret = pci_device_load(&s->pci_dev, f);
+    if (ret < 0)
+        return ret;
+
+    return pcnet_load(f, &s->state, version_id);
+}
+
+static void pcnet_common_cleanup(PCNetState *d)
+{
+    unregister_savevm("pcnet", d);
+
+    qemu_del_timer(d->poll_timer);
+    qemu_free_timer(d->poll_timer);
+}
+
+static int 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);
+    return 0;
 }
 
 /* PCI interface */
 
-static CPUWriteMemoryFunc *pcnet_mmio_write[] = {
-    (CPUWriteMemoryFunc *)&pcnet_mmio_writeb,
-    (CPUWriteMemoryFunc *)&pcnet_mmio_writew,
-    (CPUWriteMemoryFunc *)&pcnet_mmio_writel
+static CPUWriteMemoryFunc * const pcnet_mmio_write[] = {
+    &pcnet_mmio_writeb,
+    &pcnet_mmio_writew,
+    &pcnet_mmio_writel
 };
 
-static CPUReadMemoryFunc *pcnet_mmio_read[] = {
-    (CPUReadMemoryFunc *)&pcnet_mmio_readb,
-    (CPUReadMemoryFunc *)&pcnet_mmio_readw,
-    (CPUReadMemoryFunc *)&pcnet_mmio_readl
+static CPUReadMemoryFunc * const pcnet_mmio_read[] = {
+    &pcnet_mmio_readb,
+    &pcnet_mmio_readw,
+    &pcnet_mmio_readl
 };
 
 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 = DO_UPCAST(PCIPCNetState, pci_dev, 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,
@@ -1992,9 +2012,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)
 {
-    PCNetState *d;
+    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, dev);
+
+    cpu_unregister_io_memory(d->state.mmio_index);
+
+    return 0;
+}
+
+static int pci_pcnet_init(PCIDevice *pci_dev)
+{
+    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
+    PCNetState *s = &d->state;
     uint8_t *pci_conf;
 
 #if 0
@@ -2002,20 +2039,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);
@@ -2025,21 +2060,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;
 
-    pcnet_common_init(d, nd, "pcnet");
+    register_savevm("pcnet", -1, 2, pci_pcnet_save, pci_pcnet_load, d);
+    return pcnet_common_init(&pci_dev->qdev, s, pci_pcnet_cleanup);
 }
 
 /* SPARC32 interface */
@@ -2049,25 +2084,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);
@@ -2076,41 +2114,70 @@ static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr)
     return val & 0xffff;
 }
 
-static CPUReadMemoryFunc *lance_mem_read[3] = {
+static CPUReadMemoryFunc * const lance_mem_read[3] = {
     NULL,
     lance_mem_readw,
     NULL,
 };
 
-static CPUWriteMemoryFunc *lance_mem_write[3] = {
+static CPUWriteMemoryFunc * const lance_mem_write[3] = {
     NULL,
     lance_mem_writew,
     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);
+}
+
+static int lance_init(SysBusDevice *dev)
+{
+    SysBusPCNetState *d = FROM_SYSBUS(SysBusPCNetState, dev);
+    PCNetState *s = &d->state;
 
-    lance_io_memory =
-        cpu_register_io_memory(0, lance_mem_read, lance_mem_write, d);
+    s->mmio_index =
+        cpu_register_io_memory(lance_mem_read, lance_mem_write, d);
 
-    d->dma_opaque = dma_opaque;
+    qdev_init_gpio_in(&dev->qdev, parent_lance_reset, 1);
 
-    *reset = *qemu_allocate_irqs(parent_lance_reset, d, 1);
+    sysbus_init_mmio(dev, 4, s->mmio_index);
 
-    cpu_register_physical_memory(leaddr, 4, lance_io_memory);
+    sysbus_init_irq(dev, &s->irq);
 
-    d->irq = irq;
-    d->phys_mem_read = ledma_memory_read;
-    d->phys_mem_write = ledma_memory_write;
+    s->phys_mem_read = ledma_memory_read;
+    s->phys_mem_write = ledma_memory_write;
 
-    pcnet_common_init(d, nd, "lance");
+    register_savevm("pcnet", -1, 2, pcnet_save, pcnet_load, s);
+    return 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[]) {
+        DEFINE_PROP_PTR("dma", SysBusPCNetState, state.dma_opaque),
+        DEFINE_PROP_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)