All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] Updated PCnet/Lance/DMA/ESP patch
@ 2006-08-30 19:45 Blue Swirl
  2006-08-30 20:45 ` [Qemu-devel] " Fabrice Bellard
  0 siblings, 1 reply; 3+ messages in thread
From: Blue Swirl @ 2006-08-30 19:45 UTC (permalink / raw)
  To: fabrice, paul; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 306 bytes --]

Hi,

I added save, load and reset methods to pcnet.c. Can this be merged, or is 
there something that needs fixing?

_________________________________________________________________
FREE pop-up blocking with the new MSN Toolbar - get it now! 
http://toolbar.msn.click-url.com/go/onm00200415ave/direct/01/

[-- Attachment #2: pcnet-lance-merge.diff --]
[-- Type: text/plain, Size: 67422 bytes --]

Merge Lance and PCNet drivers.  Separate the DMA controllers.
Convert ESP to new DMA methods.

Index: qemu/hw/pcnet.c
===================================================================
--- qemu.orig/hw/pcnet.c	2006-08-29 16:48:51.000000000 +0000
+++ qemu/hw/pcnet.c	2006-08-30 19:19:51.000000000 +0000
@@ -26,6 +26,14 @@
  * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
  * AMD Publication# 19436  Rev:E  Amendment/0  Issue Date: June 2000
  */
+
+/*
+ * On Sparc32, this is the Lance (Am7990) part of chip STP2000 (Master 
I/O), also
+ * produced as NCR89C100. See
+ * 
http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
+ * and
+ * 
http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
+ */

#include "vl.h"

@@ -50,7 +58,7 @@
     NICInfo *nd;
     QEMUTimer *poll_timer;
     int mmio_io_addr, rap, isr, lnkst;
-    target_phys_addr_t rdra, tdra;
+    uint32_t rdra, tdra;
     uint8_t prom[16];
     uint16_t csr[128];
     uint16_t bcr[32];
@@ -58,6 +66,14 @@
     int xmit_pos, recv_pos;
     uint8_t buffer[4096];
     int tx_busy;
+    uint8_t macaddr[8];
+    uint8_t logical_address_filter[8];
+    int big_endian;
+    void (*set_irq_cb)(void *s, int isr);
+    void (*phys_mem_read)(target_phys_addr_t addr,
+                         uint8_t *buf, int len);
+    void (*phys_mem_write)(target_phys_addr_t addr,
+                          uint8_t *buf, int len);
};

/* XXX: using bitfields for target memory structures is almost surely
@@ -147,35 +163,21 @@

struct pcnet_initblk16 {
     uint16_t mode;
-    uint16_t padr1;
-    uint16_t padr2;
-    uint16_t padr3;
-    uint16_t ladrf1;
-    uint16_t ladrf2;
-    uint16_t ladrf3;
-    uint16_t ladrf4;
-    unsigned PACKED_FIELD(rdra:24);
-    unsigned PACKED_FIELD(res1:5);
-    unsigned PACKED_FIELD(rlen:3);
-    unsigned PACKED_FIELD(tdra:24);
-    unsigned PACKED_FIELD(res2:5);
-    unsigned PACKED_FIELD(tlen:3);
+    uint8_t padr[6];
+    uint8_t ladrf[8];
+    uint8_t rdra[3];
+    uint8_t rlen;
+    uint8_t tdra[3];
+    uint8_t tlen;
};

struct pcnet_initblk32 {
     uint16_t mode;
-    unsigned PACKED_FIELD(res1:4);
-    unsigned PACKED_FIELD(rlen:4);
-    unsigned PACKED_FIELD(res2:4);
-    unsigned PACKED_FIELD(tlen:4);
-    uint16_t padr1;
-    uint16_t padr2;
-    uint16_t padr3;
+    uint8_t rlen;
+    uint8_t tlen;
+    uint8_t padr[6];
     uint16_t _res;
-    uint16_t ladrf1;
-    uint16_t ladrf2;
-    uint16_t ladrf3;
-    uint16_t ladrf4;
+    uint8_t ladrf[8];
     uint32_t rdra;
     uint32_t tdra;
};
@@ -251,27 +253,49 @@
         (R)->rmd2.rcc, (R)->rmd2.rpc, (R)->rmd2.mcnt,   \
         (R)->rmd2.zeros)

+static void pci_physical_memory_write(target_phys_addr_t addr,
+                           uint8_t *buf, int len)
+{
+    cpu_physical_memory_write(addr, buf, len);
+}
+
+static void pci_physical_memory_read(target_phys_addr_t addr,
+                           uint8_t *buf, int len)
+{
+    cpu_physical_memory_read(addr, buf, len);
+}
+
static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd, 
target_phys_addr_t addr)
{
     if (!BCR_SWSTYLE(s)) {
         uint16_t xda[4];
-        cpu_physical_memory_read(addr,
-                (void *)&xda[0], sizeof(xda));
-        ((uint32_t *)tmd)[0] = (xda[0]&0xffff) |
-                ((xda[1]&0x00ff) << 16);
-        ((uint32_t *)tmd)[1] = (xda[2]&0xffff)|
-                ((xda[1] & 0xff00) << 16);
-        ((uint32_t *)tmd)[2] =
-                (xda[3] & 0xffff) << 16;
-        ((uint32_t *)tmd)[3] = 0;
+
+        s->phys_mem_read(addr, (void *)&xda[0], sizeof(xda));
+        if (s->big_endian) {
+            ((uint32_t *)tmd)[0] = be16_to_cpu(xda[0]) |
+                ((be16_to_cpu(xda[1]) & 0x00ff) << 16);
+            ((uint32_t *)tmd)[1] = be16_to_cpu(xda[2]) |
+                ((be16_to_cpu(xda[1]) & 0xff00) << 16);
+            ((uint32_t *)tmd)[2] =
+                (be16_to_cpu(xda[3]) & 0xffff) << 16;
+            ((uint32_t *)tmd)[3] = 0;
+        } else {
+            ((uint32_t *)tmd)[0] = le16_to_cpu(xda[0]) |
+                ((le16_to_cpu(xda[1]) & 0x00ff) << 16);
+            ((uint32_t *)tmd)[1] = le16_to_cpu(xda[2]) |
+                ((le16_to_cpu(xda[1]) & 0xff00) << 16);
+            ((uint32_t *)tmd)[2] =
+                (le16_to_cpu(xda[3]) & 0xffff) << 16;
+            ((uint32_t *)tmd)[3] = 0;
+        }
     }
     else
     if (BCR_SWSTYLE(s) != 3)
-        cpu_physical_memory_read(addr, (void *)tmd, 16);
+        s->phys_mem_read(addr, (void *)tmd, 16);
     else {
         uint32_t xda[4];
-        cpu_physical_memory_read(addr,
-                (void *)&xda[0], sizeof(xda));
+
+        s->phys_mem_read(addr, (void *)&xda[0], sizeof(xda));
         ((uint32_t *)tmd)[0] = xda[2];
         ((uint32_t *)tmd)[1] = xda[1];
         ((uint32_t *)tmd)[2] = xda[0];
@@ -283,25 +307,32 @@
{
     if (!BCR_SWSTYLE(s)) {
         uint16_t xda[4];
-        xda[0] = ((uint32_t *)tmd)[0] & 0xffff;
-        xda[1] = ((((uint32_t *)tmd)[0]>>16)&0x00ff) |
-            ((((uint32_t *)tmd)[1]>>16)&0xff00);
-        xda[2] = ((uint32_t *)tmd)[1] & 0xffff;
-        xda[3] = ((uint32_t *)tmd)[2] >> 16;
-        cpu_physical_memory_write(addr,
-                (void *)&xda[0], sizeof(xda));
+
+        if (s->big_endian) {
+            xda[0] = cpu_to_be16(((uint32_t *)tmd)[0] & 0xffff);
+            xda[1] = cpu_to_be16(((((uint32_t *)tmd)[0] >> 16) & 0x00ff) |
+                                 ((((uint32_t *)tmd)[1] >> 16) & 0xff00));
+            xda[2] = cpu_to_be16(((uint32_t *)tmd)[1] & 0xffff);
+            xda[3] = cpu_to_be16(((uint32_t *)tmd)[2] >> 16);
+        } else {
+            xda[0] = cpu_to_le16(((uint32_t *)tmd)[0] & 0xffff);
+            xda[1] = cpu_to_le16(((((uint32_t *)tmd)[0] >> 16) & 0x00ff) |
+                                 ((((uint32_t *)tmd)[1] >> 16) & 0xff00));
+            xda[2] = cpu_to_le16(((uint32_t *)tmd)[1] & 0xffff);
+            xda[3] = cpu_to_le16(((uint32_t *)tmd)[2] >> 16);
+        }
+        s->phys_mem_write(addr, (void *)&xda[0], sizeof(xda));
     }
     else {
         if (BCR_SWSTYLE(s) != 3)
-            cpu_physical_memory_write(addr, (void *)tmd, 16);
+            s->phys_mem_write(addr, (void *)tmd, 16);
         else {
             uint32_t xda[4];
             xda[0] = ((uint32_t *)tmd)[2];
             xda[1] = ((uint32_t *)tmd)[1];
             xda[2] = ((uint32_t *)tmd)[0];
             xda[3] = ((uint32_t *)tmd)[3];
-            cpu_physical_memory_write(addr,
-                    (void *)&xda[0], sizeof(xda));
+            s->phys_mem_write(addr, (void *)&xda[0], sizeof(xda));
         }
     }
}
@@ -310,22 +341,31 @@
{
     if (!BCR_SWSTYLE(s)) {
         uint16_t rda[4];
-        cpu_physical_memory_read(addr,
-                (void *)&rda[0], sizeof(rda));
-        ((uint32_t *)rmd)[0] = (rda[0]&0xffff)|
-                ((rda[1] & 0x00ff) << 16);
-        ((uint32_t *)rmd)[1] = (rda[2]&0xffff)|
-                ((rda[1] & 0xff00) << 16);
-        ((uint32_t *)rmd)[2] = rda[3] & 0xffff;
-        ((uint32_t *)rmd)[3] = 0;
+
+        s->phys_mem_read(addr, (void *)&rda[0], sizeof(rda));
+        if (s->big_endian) {
+            ((uint32_t *)rmd)[0] = (be16_to_cpu(rda[0]) & 0xffff) |
+                ((be16_to_cpu(rda[1]) & 0x00ff) << 16);
+            ((uint32_t *)rmd)[1] = (be16_to_cpu(rda[2]) & 0xffff) |
+                ((be16_to_cpu(rda[1]) & 0xff00) << 16);
+            ((uint32_t *)rmd)[2] = be16_to_cpu(rda[3]) & 0xffff;
+            ((uint32_t *)rmd)[3] = 0;
+        } else {
+            ((uint32_t *)rmd)[0] = (le16_to_cpu(rda[0]) & 0xffff) |
+                ((le16_to_cpu(rda[1]) & 0x00ff) << 16);
+            ((uint32_t *)rmd)[1] = (le16_to_cpu(rda[2]) & 0xffff) |
+                ((le16_to_cpu(rda[1]) & 0xff00) << 16);
+            ((uint32_t *)rmd)[2] = le16_to_cpu(rda[3]) & 0xffff;
+            ((uint32_t *)rmd)[3] = 0;
+        }
     }
     else
     if (BCR_SWSTYLE(s) != 3)
-        cpu_physical_memory_read(addr, (void *)rmd, 16);
+        s->phys_mem_read(addr, (void *)rmd, 16);
     else {
         uint32_t rda[4];
-        cpu_physical_memory_read(addr,
-                (void *)&rda[0], sizeof(rda));
+
+        s->phys_mem_read(addr, (void *)&rda[0], sizeof(rda));
         ((uint32_t *)rmd)[0] = rda[2];
         ((uint32_t *)rmd)[1] = rda[1];
         ((uint32_t *)rmd)[2] = rda[0];
@@ -336,26 +376,33 @@
static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, 
target_phys_addr_t addr)
{
     if (!BCR_SWSTYLE(s)) {
-        uint16_t rda[4];                        \
-        rda[0] = ((uint32_t *)rmd)[0] & 0xffff; \
-        rda[1] = ((((uint32_t *)rmd)[0]>>16)&0xff)|\
-            ((((uint32_t *)rmd)[1]>>16)&0xff00);\
-        rda[2] = ((uint32_t *)rmd)[1] & 0xffff; \
-        rda[3] = ((uint32_t *)rmd)[2] & 0xffff; \
-        cpu_physical_memory_write(addr,         \
-                (void *)&rda[0], sizeof(rda));  \
+        uint16_t rda[4];
+
+        if (s->big_endian) {
+            rda[0] = cpu_to_be16(((uint32_t *)rmd)[0] & 0xffff);
+            rda[1] = cpu_to_be16(((((uint32_t *)rmd)[0] >> 16) & 0xff) |
+                                 ((((uint32_t *)rmd)[1] >> 16) & 0xff00));
+            rda[2] = cpu_to_be16(((uint32_t *)rmd)[1] & 0xffff);
+            rda[3] = cpu_to_be16(((uint32_t *)rmd)[2] & 0xffff);
+        } else {
+            rda[0] = cpu_to_le16(((uint32_t *)rmd)[0] & 0xffff);
+            rda[1] = cpu_to_le16(((((uint32_t *)rmd)[0] >> 16) & 0xff) |
+                                 ((((uint32_t *)rmd)[1] >> 16) & 0xff00));
+            rda[2] = cpu_to_le16(((uint32_t *)rmd)[1] & 0xffff);
+            rda[3] = cpu_to_le16(((uint32_t *)rmd)[2] & 0xffff);
+        }
+        s->phys_mem_write(addr, (void *)&rda[0], sizeof(rda));
     }
     else {
         if (BCR_SWSTYLE(s) != 3)
-            cpu_physical_memory_write(addr, (void *)rmd, 16);
+            s->phys_mem_write(addr, (void *)rmd, 16);
         else {
             uint32_t rda[4];
             rda[0] = ((uint32_t *)rmd)[2];
             rda[1] = ((uint32_t *)rmd)[1];
             rda[2] = ((uint32_t *)rmd)[0];
             rda[3] = ((uint32_t *)rmd)[3];
-            cpu_physical_memory_write(addr,
-                    (void *)&rda[0], sizeof(rda));
+            s->phys_mem_write(addr, (void *)&rda[0], sizeof(rda));
         }
     }
}
@@ -391,7 +438,7 @@
     case 0x00:                                  \
         do {                                    \
             uint16_t rda[4];                    \
-            cpu_physical_memory_read((ADDR),    \
+            s->phys_mem_read((ADDR),            \
                 (void *)&rda[0], sizeof(rda));  \
             (RES) |= (rda[2] & 0xf000)!=0xf000; \
             (RES) |= (rda[3] & 0xf000)!=0x0000; \
@@ -401,7 +448,7 @@
     case 0x02:                                  \
         do {                                    \
             uint32_t rda[4];                    \
-            cpu_physical_memory_read((ADDR),    \
+            s->phys_mem_read((ADDR),            \
                 (void *)&rda[0], sizeof(rda)); \
             (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
             (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \
@@ -410,7 +457,7 @@
     case 0x03:                                  \
         do {                                    \
             uint32_t rda[4];                    \
-            cpu_physical_memory_read((ADDR),    \
+            s->phys_mem_read((ADDR),            \
                 (void *)&rda[0], sizeof(rda)); \
             (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \
             (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
@@ -424,7 +471,7 @@
     case 0x00:                                  \
         do {                                    \
             uint16_t xda[4];                    \
-            cpu_physical_memory_read((ADDR),    \
+            s->phys_mem_read((ADDR),            \
                 (void *)&xda[0], sizeof(xda));  \
             (RES) |= (xda[2] & 0xf000)!=0xf000;\
         } while (0);                            \
@@ -434,7 +481,7 @@
     case 0x03:                                  \
         do {                                    \
             uint32_t xda[4];                    \
-            cpu_physical_memory_read((ADDR),    \
+            s->phys_mem_read((ADDR),            \
                 (void *)&xda[0], sizeof(xda));  \
             (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \
         } while (0);                            \
@@ -448,14 +495,13 @@
     struct qemu_ether_header *hdr = (void *)(BUF);   \
     printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, "       \
            "shost=%02x:%02x:%02x:%02x:%02x:%02x, "              \
-           "type=0x%04x (bcast=%d)\n",                          \
+           "type=0x%04x\n",                                             \
            hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \
            hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \
            hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \
            hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \
-           be16_to_cpu(hdr->ether_type),                                \
-           !!ETHER_IS_MULTICAST(hdr->ether_dhost));                     \
-} while (0)
+           be16_to_cpu(hdr->ether_type));                               \
+    } while (0)

#define MULTICAST_FILTER_LEN 8

@@ -552,18 +598,13 @@
static inline int padr_match(PCNetState *s, const uint8_t *buf, int size)
{
     struct qemu_ether_header *hdr = (void *)buf;
-    uint8_t padr[6] = {
-        s->csr[12] & 0xff, s->csr[12] >> 8,
-        s->csr[13] & 0xff, s->csr[13] >> 8,
-        s->csr[14] & 0xff, s->csr[14] >> 8
-    };
-    int result = (!CSR_DRCVPA(s)) && !memcmp(hdr->ether_dhost, padr, 6);
+    int result = (!CSR_DRCVPA(s)) && !memcmp(hdr->ether_dhost, s->macaddr, 
6);
#ifdef PCNET_DEBUG_MATCH
     printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, "
            "padr=%02x:%02x:%02x:%02x:%02x:%02x\n",
            hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2],
            hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5],
-           padr[0],padr[1],padr[2],padr[3],padr[4],padr[5]);
+           
s->macaddr[0],s->macaddr[1],s->macaddr[2],s->macaddr[3],s->macaddr[4],s->macaddr[5]);
     printf("padr_match result=%d\n", result);
#endif
     return result;
@@ -571,8 +612,9 @@

static inline int padr_bcast(PCNetState *s, const uint8_t *buf, int size)
{
-    static uint8_t BCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+    static const uint8_t BCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
     struct qemu_ether_header *hdr = (void *)buf;
+
     int result = !CSR_DRCVBC(s) && !memcmp(hdr->ether_dhost, BCAST, 6);
#ifdef PCNET_DEBUG_MATCH
     printf("padr_bcast result=%d\n", result);
@@ -583,16 +625,11 @@
static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size)
{
     struct qemu_ether_header *hdr = (void *)buf;
-    if ((*(hdr->ether_dhost)&0x01) &&
-        ((uint64_t *)&s->csr[8])[0] != 0LL) {
-        uint8_t ladr[8] = {
-            s->csr[8] & 0xff, s->csr[8] >> 8,
-            s->csr[9] & 0xff, s->csr[9] >> 8,
-            s->csr[10] & 0xff, s->csr[10] >> 8,
-            s->csr[11] & 0xff, s->csr[11] >> 8
-        };
+
+    if ((*(hdr->ether_dhost) & 0x01) &&
+        (*(uint64_t *)&s->logical_address_filter[0]) != 0LL) {
         int index = lnc_mchash(hdr->ether_dhost) >> 26;
-        return !!(ladr[index >> 3] & (1 << (index & 7)));
+        return !!(s->logical_address_filter[index >> 3] & (1 << (index & 
7)));
     }
     return 0;
}
@@ -643,9 +680,10 @@
     s->csr[9]   = 0;
     s->csr[10]  = 0;
     s->csr[11]  = 0;
-    s->csr[12]  = le16_to_cpu(((uint16_t *)&s->prom[0])[0]);
-    s->csr[13]  = le16_to_cpu(((uint16_t *)&s->prom[0])[1]);
-    s->csr[14]  = le16_to_cpu(((uint16_t *)&s->prom[0])[2]);
+    s->csr[12]  = s->prom[0] | (s->prom[1] << 8);
+    s->csr[13]  = s->prom[2] | (s->prom[3] << 8);
+    s->csr[14]  = s->prom[4] | (s->prom[5] << 8);
+    memcpy(s->macaddr, s->prom, 6);
     s->csr[15] &= 0x21c4;
     s->csr[72]  = 1;
     s->csr[74]  = 1;
@@ -666,6 +704,13 @@
     s->tx_busy = 0;
}

+static void pcnet_pci_set_irq_cb(void *opaque, int isr)
+{
+    PCNetState *s = opaque;
+
+    pci_set_irq(&s->dev, 0, isr);
+}
+
static void pcnet_update_irq(PCNetState *s)
{
     int isr = 0;
@@ -721,8 +766,8 @@
         printf("pcnet: INTA=%d\n", isr);
#endif
     }
-        pci_set_irq(&s->dev, 0, isr);
-        s->isr = isr;
+    s->set_irq_cb(s, isr);
+    s->isr = isr;
}

static void pcnet_init(PCNetState *s)
@@ -732,33 +777,56 @@
#endif

#define PCNET_INIT() do { \
-        cpu_physical_memory_read(PHYSADDR(s,CSR_IADR(s)),       \
-                (uint8_t *)&initblk, sizeof(initblk));          \
-        s->csr[15] = le16_to_cpu(initblk.mode);                 \
+        s->phys_mem_read(PHYSADDR(s,CSR_IADR(s)),                       \
+                                 (uint8_t *)&initblk, sizeof(initblk)); \
+        if (s->big_endian) {                                            \
+            s->csr[15] = be16_to_cpu(initblk.mode);                     \
+            s->logical_address_filter[0] = initblk.ladrf[1];            \
+            s->logical_address_filter[1] = initblk.ladrf[0];            \
+            s->logical_address_filter[2] = initblk.ladrf[3];            \
+            s->logical_address_filter[3] = initblk.ladrf[2];            \
+            s->logical_address_filter[4] = initblk.ladrf[5];            \
+            s->logical_address_filter[5] = initblk.ladrf[4];            \
+            s->logical_address_filter[6] = initblk.ladrf[7];            \
+            s->logical_address_filter[7] = initblk.ladrf[6];            \
+                                                                        \
+            s->macaddr[0] = initblk.padr[1];                            \
+            s->macaddr[1] = initblk.padr[0];                            \
+            s->macaddr[2] = initblk.padr[3];                            \
+            s->macaddr[3] = initblk.padr[2];                            \
+            s->macaddr[4] = initblk.padr[5];                            \
+            s->macaddr[5] = initblk.padr[4];                            \
+        } else {                                                        \
+            s->csr[15] = le16_to_cpu(initblk.mode);                     \
+            memcpy(s->logical_address_filter, &initblk.ladrf[0], 8);    \
+            memcpy(s->macaddr, &initblk.padr[0], 6);                    \
+        }                                                               \
         CSR_RCVRL(s) = (initblk.rlen < 9) ? (1 << initblk.rlen) : 512;  \
         CSR_XMTRL(s) = (initblk.tlen < 9) ? (1 << initblk.tlen) : 512;  \
         s->csr[ 6] = (initblk.tlen << 12) | (initblk.rlen << 8);        \
-        s->csr[ 8] = le16_to_cpu(initblk.ladrf1);                       \
-        s->csr[ 9] = le16_to_cpu(initblk.ladrf2);                       \
-        s->csr[10] = le16_to_cpu(initblk.ladrf3);                       \
-        s->csr[11] = le16_to_cpu(initblk.ladrf4);                       \
-        s->csr[12] = le16_to_cpu(initblk.padr1);                        \
-        s->csr[13] = le16_to_cpu(initblk.padr2);                        \
-        s->csr[14] = le16_to_cpu(initblk.padr3);                        \
-        s->rdra = PHYSADDR(s,initblk.rdra);                             \
-        s->tdra = PHYSADDR(s,initblk.tdra);                             \
} while (0)

     if (BCR_SSIZE32(s)) {
         struct pcnet_initblk32 initblk;
+
         PCNET_INIT();
+        s->rdra = PHYSADDR(s,initblk.rdra);
+        s->tdra = PHYSADDR(s,initblk.tdra);
#ifdef PCNET_DEBUG
         printf("initblk.rlen=0x%02x, initblk.tlen=0x%02x\n",
                 initblk.rlen, initblk.tlen);
#endif
     } else {
         struct pcnet_initblk16 initblk;
+
         PCNET_INIT();
+        if (s->big_endian) {
+            s->rdra = PHYSADDR(s,initblk.rdra[1] | (initblk.rdra[0] << 8) | 
(initblk.rdra[3] << 16));
+            s->tdra = PHYSADDR(s,initblk.tdra[1] | (initblk.tdra[0] << 8) | 
(initblk.tdra[3] << 16));
+        } else {
+            s->rdra = PHYSADDR(s,initblk.rdra[0] | (initblk.rdra[1] << 8) | 
(initblk.rdra[2] << 16));
+            s->tdra = PHYSADDR(s,initblk.tdra[0] | (initblk.tdra[1] << 8) | 
(initblk.tdra[2] << 16));
+        }
#ifdef PCNET_DEBUG
         printf("initblk.rlen=0x%02x, initblk.tlen=0x%02x\n",
                 initblk.rlen, initblk.tlen);
@@ -1035,7 +1103,7 @@
#define PCNET_RECV_STORE() do {                                 \
     int count = MIN(4096 - rmd.rmd1.bcnt,size);                 \
     target_phys_addr_t rbadr = PHYSADDR(s, rmd.rmd0.rbadr);     \
-    cpu_physical_memory_write(rbadr, src, count);               \
+    s->phys_mem_write(rbadr, src, count);                       \
     src += count; size -= count;                                \
     rmd.rmd2.mcnt = count; rmd.rmd1.own = 0;                    \
     RMDSTORE(&rmd, PHYSADDR(s,crda));                           \
@@ -1125,14 +1193,14 @@
         if (tmd.tmd1.stp) {
             s->xmit_pos = 0;
             if (!tmd.tmd1.enp) {
-                cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr),
-                        s->buffer, 4096 - tmd.tmd1.bcnt);
+                s->phys_mem_read((PHYSADDR(s, tmd.tmd0.tbadr)),
+                                 s->buffer, 4096 - tmd.tmd1.bcnt);
                 s->xmit_pos += 4096 - tmd.tmd1.bcnt;
             }
             xmit_cxda = PHYSADDR(s,CSR_CXDA(s));
         }
         if (tmd.tmd1.enp && (s->xmit_pos >= 0)) {
-            cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr),
+            s->phys_mem_read((PHYSADDR(s, tmd.tmd0.tbadr)),
                     s->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt);
             s->xmit_pos += 4096 - tmd.tmd1.bcnt;
#ifdef PCNET_DEBUG
@@ -1256,15 +1324,39 @@
             pcnet_transmit(s);

         return;
-    case 1:
-    case 2:
+    case 3:
+        s->big_endian = val & 4;
+        break;
     case 8:
+        s->logical_address_filter[0] = val & 0xff;
+        s->logical_address_filter[1] = val >> 8;
+        goto check_stop;
     case 9:
+        s->logical_address_filter[2] = val & 0xff;
+        s->logical_address_filter[3] = val >> 8;
+        goto check_stop;
     case 10:
+        s->logical_address_filter[4] = val & 0xff;
+        s->logical_address_filter[5] = val >> 8;
+        goto check_stop;
     case 11:
+        s->logical_address_filter[6] = val & 0xff;
+        s->logical_address_filter[7] = val >> 8;
+        goto check_stop;
     case 12:
+        s->macaddr[0] = val & 0xff;
+        s->macaddr[1] = val >> 8;
+        goto check_stop;
     case 13:
+        s->macaddr[2] = val & 0xff;
+        s->macaddr[3] = val >> 8;
+        goto check_stop;
     case 14:
+        s->macaddr[4] = val & 0xff;
+        s->macaddr[5] = val >> 8;
+        goto check_stop;
+    case 1:
+    case 2:
     case 15:
     case 18: /* CRBAL */
     case 19: /* CRBAU */
@@ -1301,11 +1393,10 @@
     case 76: /* RCVRL */
     case 78: /* XMTRL */
     case 112:
+    check_stop:
        if (CSR_STOP(s) || CSR_SPND(s))
            break;
        return;
-    case 3:
-        break;
     case 4:
         s->csr[4] &= ~(val & 0x026a);
         val &= ~0x026a; val |= s->csr[4] & 0x026a;
@@ -1338,6 +1429,27 @@
         val = s->csr[0];
         val |= (val & 0x7800) ? 0x8000 : 0;
         break;
+    case 8:
+        val = s->logical_address_filter[0] | (s->logical_address_filter[1] 
<< 8);
+        break;
+    case 9:
+        val = s->logical_address_filter[2] | (s->logical_address_filter[3] 
<< 8);
+        break;
+    case 10:
+        val = s->logical_address_filter[4] | (s->logical_address_filter[5] 
<< 8);
+        break;
+    case 11:
+        val = s->logical_address_filter[6] | (s->logical_address_filter[7] 
<< 8);
+        break;
+    case 12:
+        val = s->macaddr[0] | (s->macaddr[1] << 8);
+        break;
+    case 13:
+        val = s->macaddr[2] | (s->macaddr[3] << 8);
+        break;
+    case 14:
+        val = s->macaddr[4] | (s->macaddr[5] << 8);
+        break;
     case 16:
         return pcnet_csr_readw(s,1);
     case 17:
@@ -1426,8 +1538,9 @@
     return val;
}

-static void pcnet_h_reset(PCNetState *s)
+void pcnet_h_reset(void *opaque)
{
+    PCNetState *s = opaque;
     int i;
     uint16_t checksum;

@@ -1727,6 +1840,86 @@
     cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, 
d->mmio_io_addr);
}

+static void pcnet_save(QEMUFile *f, void *opaque)
+{
+    PCNetState *s = opaque;
+    unsigned int i;
+
+    qemu_put_be32s(f, &s->rap);
+    qemu_put_be32s(f, &s->isr);
+    qemu_put_be32s(f, &s->lnkst);
+    qemu_put_be32s(f, &s->rdra);
+    qemu_put_be32s(f, &s->tdra);
+    qemu_put_buffer(f, s->prom, 16);
+    for (i = 0; i < 128; i++)
+        qemu_put_be16s(f, &s->csr[i]);
+    for (i = 0; i < 32; i++)
+        qemu_put_be16s(f, &s->bcr[i]);
+    qemu_put_be64s(f, &s->timer);
+    qemu_put_be32s(f, &s->xmit_pos);
+    qemu_put_be32s(f, &s->recv_pos);
+    qemu_put_buffer(f, s->buffer, 4096);
+    qemu_put_be32s(f, &s->tx_busy);
+    qemu_put_buffer(f, s->macaddr, 8);
+    qemu_put_buffer(f, s->logical_address_filter, 8);
+    qemu_put_be32s(f, &s->big_endian);
+}
+
+static int pcnet_load(QEMUFile *f, void *opaque, int version_id)
+{
+    PCNetState *s = opaque;
+    unsigned int i;
+
+    if (version_id != 2)
+        return -EINVAL;
+
+    qemu_get_be32s(f, &s->rap);
+    qemu_get_be32s(f, &s->isr);
+    qemu_get_be32s(f, &s->lnkst);
+    qemu_get_be32s(f, &s->rdra);
+    qemu_get_be32s(f, &s->tdra);
+    qemu_get_buffer(f, s->prom, 16);
+    for (i = 0; i < 128; i++)
+        qemu_get_be16s(f, &s->csr[i]);
+    for (i = 0; i < 32; i++)
+        qemu_get_be16s(f, &s->bcr[i]);
+    qemu_get_be64s(f, &s->timer);
+    qemu_get_be32s(f, &s->xmit_pos);
+    qemu_get_be32s(f, &s->recv_pos);
+    qemu_get_buffer(f, s->buffer, 4096);
+    qemu_get_be32s(f, &s->tx_busy);
+    qemu_get_buffer(f, s->macaddr, 8);
+    qemu_get_buffer(f, s->logical_address_filter, 8);
+    qemu_get_be32s(f, &s->big_endian);
+
+    return 0;
+}
+
+static void pcnet_common_init(PCNetState *d, NICInfo *nd, const char 
*info_str)
+{
+    d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d);
+
+    d->nd = nd;
+
+    d->vc = qemu_new_vlan_client(nd->vlan, pcnet_receive,
+                                 pcnet_can_receive, d);
+
+    snprintf(d->vc->info_str, sizeof(d->vc->info_str),
+             "%s macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
+             info_str,
+             d->nd->macaddr[0],
+             d->nd->macaddr[1],
+             d->nd->macaddr[2],
+             d->nd->macaddr[3],
+             d->nd->macaddr[4],
+             d->nd->macaddr[5]);
+
+    pcnet_h_reset(d);
+
+    register_savevm(info_str, d->mmio_io_addr, 2, pcnet_save, pcnet_load, 
d);
+    qemu_register_reset(pcnet_h_reset, d);
+}
+
void pci_pcnet_init(PCIBus *bus, NICInfo *nd)
{
     PCNetState *d;
@@ -1768,22 +1961,48 @@

     pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE,
                            PCI_ADDRESS_SPACE_MEM, pcnet_mmio_map);
-
-    d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d);

-    d->nd = nd;
+    d->set_irq_cb = pcnet_pci_set_irq_cb;
+    d->phys_mem_read = pci_physical_memory_read;
+    d->phys_mem_write = pci_physical_memory_write;

-    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]);
+    pcnet_common_init(d, nd, "pcnet");
+}

-    pcnet_h_reset(d);
+static CPUWriteMemoryFunc *lance_mem_write[3] = {
+    (CPUWriteMemoryFunc *)&pcnet_ioport_writew,
+    (CPUWriteMemoryFunc *)&pcnet_ioport_writew,
+    (CPUWriteMemoryFunc *)&pcnet_ioport_writew,
+};
+
+static CPUReadMemoryFunc *lance_mem_read[3] = {
+    (CPUReadMemoryFunc *)&pcnet_ioport_readw,
+    (CPUReadMemoryFunc *)&pcnet_ioport_readw,
+    (CPUReadMemoryFunc *)&pcnet_ioport_readw,
+};
+
+void *lance_init(NICInfo *nd, int irq, uint32_t leaddr)
+{
+    PCNetState *d;
+    int lance_io_memory;
+
+    d = qemu_mallocz(sizeof(PCNetState));
+    if (!d)
+        return NULL;
+
+    lance_io_memory =
+        cpu_register_io_memory(0, lance_mem_read, lance_mem_write, d);
+
+    d->mmio_io_addr = leaddr;
+    cpu_register_physical_memory(leaddr, 4, lance_io_memory);
+
+#if defined (TARGET_SPARC) && !defined(TARGET_SPARC64) // Avoid compile 
failure
+    d->set_irq_cb = ledma_set_irq;
+    d->phys_mem_read = ledma_memory_read;
+    d->phys_mem_write = ledma_memory_write;
+#endif
+
+    pcnet_common_init(d, nd, "lance");
+
+    return d;
}
Index: qemu/Makefile.target
===================================================================
--- qemu.orig/Makefile.target	2006-08-29 16:48:51.000000000 +0000
+++ qemu/Makefile.target	2006-08-29 18:09:37.000000000 +0000
@@ -359,8 +359,8 @@
VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o
VL_OBJS+= cirrus_vga.o parallel.o
else
-VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t59.o slavio_intctl.o
-VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o
+VL_OBJS+= sun4m.o tcx.o pcnet.o iommu.o m48t59.o slavio_intctl.o
+VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o 
sparc32_dma.o
endif
endif
ifeq ($(TARGET_BASE_ARCH), arm)
Index: qemu/hw/esp.c
===================================================================
--- qemu.orig/hw/esp.c	2006-08-29 16:48:51.000000000 +0000
+++ qemu/hw/esp.c	2006-08-29 20:34:38.000000000 +0000
@@ -1,5 +1,5 @@
/*
- * QEMU ESP emulation
+ * QEMU ESP/NCR53C9x emulation
  *
  * Copyright (c) 2005-2006 Fabrice Bellard
  *
@@ -26,33 +26,31 @@
/* debug ESP card */
//#define DEBUG_ESP

+/*
+ * On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master 
I/O), also
+ * produced as NCR89C100. See
+ * 
http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
+ * and
+ * 
http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt
+ */
+
#ifdef DEBUG_ESP
#define DPRINTF(fmt, args...) \
do { printf("ESP: " fmt , ##args); } while (0)
-#define pic_set_irq(irq, level) \
-do { printf("ESP: set_irq(%d): %d\n", (irq), (level)); 
pic_set_irq((irq),(level));} while (0)
#else
#define DPRINTF(fmt, args...)
#endif

-#define ESPDMA_REGS 4
-#define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1)
#define ESP_MAXREG 0x3f
#define TI_BUFSZ 32
-#define DMA_VER 0xa0000000
-#define DMA_INTR 1
-#define DMA_INTREN 0x10
-#define DMA_WRITE_MEM 0x100
-#define DMA_LOADED 0x04000000
+
typedef struct ESPState ESPState;

struct ESPState {
     BlockDriverState **bd;
     uint8_t rregs[ESP_MAXREG];
     uint8_t wregs[ESP_MAXREG];
-    int irq;
-    uint32_t espdmaregs[ESPDMA_REGS];
-    uint32_t ti_size;
+    int32_t ti_size;
     uint32_t ti_rptr, ti_wptr;
     uint8_t ti_buf[TI_BUFSZ];
     int sense;
@@ -97,9 +95,7 @@
     target = s->wregs[4] & 7;
     DPRINTF("get_cmd: len %d target %d\n", dmalen, target);
     if (s->dma) {
-	DPRINTF("DMA Direction: %c, addr 0x%8.8x\n",
-                s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', 
s->espdmaregs[1]);
-        sparc_iommu_memory_read(s->espdmaregs[1], buf, dmalen);
+        espdma_memory_read(buf, dmalen);
     } else {
	buf[0] = 0;
	memcpy(&buf[1], s->ti_buf, dmalen);
@@ -116,13 +112,12 @@
         s->async_len = 0;
     }

-    if (target >= 4 || !s->scsi_dev[target]) {
+    if (target >= MAX_DISKS || !s->scsi_dev[target]) {
         // No such drive
	s->rregs[4] = STAT_IN;
	s->rregs[5] = INTR_DC;
	s->rregs[6] = SEQ_0;
-	s->espdmaregs[0] |= DMA_INTR;
-	pic_set_irq(s->irq, 1);
+	espdma_raise_irq();
	return 0;
     }
     s->current_dev = s->scsi_dev[target];
@@ -137,25 +132,21 @@
     DPRINTF("do_cmd: busid 0x%x\n", buf[0]);
     lun = buf[0] & 7;
     datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun);
-    if (datalen == 0) {
-        s->ti_size = 0;
-    } else {
+    s->ti_size = datalen;
+    if (datalen != 0) {
         s->rregs[4] = STAT_IN | STAT_TC;
         s->dma_left = 0;
         if (datalen > 0) {
             s->rregs[4] |= STAT_DI;
-            s->ti_size = datalen;
             scsi_read_data(s->current_dev, 0);
         } else {
             s->rregs[4] |= STAT_DO;
-            s->ti_size = -datalen;
             scsi_write_data(s->current_dev, 0);
         }
     }
     s->rregs[5] = INTR_BS | INTR_FC;
     s->rregs[6] = SEQ_CD;
-    s->espdmaregs[0] |= DMA_INTR;
-    pic_set_irq(s->irq, 1);
+    espdma_raise_irq();
}

static void handle_satn(ESPState *s)
@@ -174,12 +165,10 @@
     if (s->cmdlen) {
         DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen);
         s->do_cmd = 1;
-        s->espdmaregs[1] += s->cmdlen;
         s->rregs[4] = STAT_IN | STAT_TC | STAT_CD;
         s->rregs[5] = INTR_BS | INTR_FC;
         s->rregs[6] = SEQ_CD;
-        s->espdmaregs[0] |= DMA_INTR;
-        pic_set_irq(s->irq, 1);
+        espdma_raise_irq();
     }
}

@@ -189,9 +178,7 @@
     s->ti_buf[0] = s->sense;
     s->ti_buf[1] = 0;
     if (s->dma) {
-	DPRINTF("DMA Direction: %c\n",
-                s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r');
-        sparc_iommu_memory_write(s->espdmaregs[1], s->ti_buf, 2);
+        espdma_memory_write(s->ti_buf, 2);
	s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
	s->rregs[5] = INTR_BS | INTR_FC;
	s->rregs[6] = SEQ_CD;
@@ -201,9 +188,7 @@
	s->ti_wptr = 0;
	s->rregs[7] = 2;
     }
-    s->espdmaregs[0] |= DMA_INTR;
-    pic_set_irq(s->irq, 1);
-
+    espdma_raise_irq();
}

static void esp_dma_done(ESPState *s)
@@ -212,24 +197,19 @@
     s->rregs[5] = INTR_BS;
     s->rregs[6] = 0;
     s->rregs[7] = 0;
-    s->espdmaregs[0] |= DMA_INTR;
-    pic_set_irq(s->irq, 1);
+    espdma_raise_irq();
}

static void esp_do_dma(ESPState *s)
{
-    uint32_t addr, len;
+    uint32_t len;
     int to_device;

-    to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0;
-    addr = s->espdmaregs[1];
+    to_device = (s->ti_size < 0);
     len = s->dma_left;
-    DPRINTF("DMA address %08x len %08x\n", addr, len);
     if (s->do_cmd) {
-        s->espdmaregs[1] += len;
-        s->ti_size -= len;
         DPRINTF("command len %d + %d\n", s->cmdlen, len);
-        sparc_iommu_memory_read(addr, &s->cmdbuf[s->cmdlen], len);
+        espdma_memory_read(&s->cmdbuf[s->cmdlen], len);
         s->ti_size = 0;
         s->cmdlen = 0;
         s->do_cmd = 0;
@@ -244,19 +224,20 @@
         len = s->async_len;
     }
     if (to_device) {
-        sparc_iommu_memory_read(addr, s->async_buf, len);
+        espdma_memory_read(s->async_buf, len);
     } else {
-        sparc_iommu_memory_write(addr, s->async_buf, len);
+        espdma_memory_write(s->async_buf, len);
     }
-    s->ti_size -= len;
     s->dma_left -= len;
     s->async_buf += len;
     s->async_len -= len;
-    s->espdmaregs[1] += len;
     if (s->async_len == 0) {
         if (to_device) {
+            // ti_size is negative
+            s->ti_size += len;
             scsi_write_data(s->current_dev, 0);
         } else {
+            s->ti_size -= len;
             scsi_read_data(s->current_dev, 0);
         }
     }
@@ -303,6 +284,8 @@

     if (s->do_cmd)
         minlen = (dmalen < 32) ? dmalen : 32;
+    else if (s->ti_size < 0)
+        minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size;
     else
         minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
     DPRINTF("Transfer Information len %d\n", minlen);
@@ -320,13 +303,13 @@
     }
}

-static void esp_reset(void *opaque)
+void esp_reset(void *opaque)
{
     ESPState *s = opaque;
+
     memset(s->rregs, 0, ESP_MAXREG);
     memset(s->wregs, 0, ESP_MAXREG);
     s->rregs[0x0e] = 0x4; // Indicate fas100a
-    memset(s->espdmaregs, 0, ESPDMA_REGS * 4);
     s->ti_size = 0;
     s->ti_rptr = 0;
     s->ti_wptr = 0;
@@ -353,7 +336,7 @@
             } else {
                 s->rregs[2] = s->ti_buf[s->ti_rptr++];
             }
-	    pic_set_irq(s->irq, 1);
+            espdma_raise_irq();
	}
	if (s->ti_size == 0) {
             s->ti_rptr = 0;
@@ -364,8 +347,7 @@
         // interrupt
         // Clear interrupt/error status bits
         s->rregs[4] &= ~(STAT_IN | STAT_GE | STAT_PE);
-        pic_set_irq(s->irq, 0);
-	s->espdmaregs[0] &= ~DMA_INTR;
+	espdma_clear_irq();
         break;
     default:
	break;
@@ -426,8 +408,7 @@
	    DPRINTF("Bus reset (%2.2x)\n", val);
	    s->rregs[5] = INTR_RST;
             if (!(s->wregs[8] & 0x40)) {
-                s->espdmaregs[0] |= DMA_INTR;
-                pic_set_irq(s->irq, 1);
+                espdma_raise_irq();
             }
	    break;
	case 0x10:
@@ -490,68 +471,12 @@
     esp_mem_writeb,
};

-static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr)
-{
-    ESPState *s = opaque;
-    uint32_t saddr;
-
-    saddr = (addr & ESPDMA_MAXADDR) >> 2;
-    DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->espdmaregs[saddr]);
-
-    return s->espdmaregs[saddr];
-}
-
-static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, 
uint32_t val)
-{
-    ESPState *s = opaque;
-    uint32_t saddr;
-
-    saddr = (addr & ESPDMA_MAXADDR) >> 2;
-    DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, 
s->espdmaregs[saddr], val);
-    switch (saddr) {
-    case 0:
-	if (!(val & DMA_INTREN))
-	    pic_set_irq(s->irq, 0);
-	if (val & 0x80) {
-            esp_reset(s);
-        } else if (val & 0x40) {
-            val &= ~0x40;
-        } else if (val == 0)
-            val = 0x40;
-        val &= 0x0fffffff;
-        val |= DMA_VER;
-	break;
-    case 1:
-        s->espdmaregs[0] |= DMA_LOADED;
-        break;
-    default:
-	break;
-    }
-    s->espdmaregs[saddr] = val;
-}
-
-static CPUReadMemoryFunc *espdma_mem_read[3] = {
-    espdma_mem_readl,
-    espdma_mem_readl,
-    espdma_mem_readl,
-};
-
-static CPUWriteMemoryFunc *espdma_mem_write[3] = {
-    espdma_mem_writel,
-    espdma_mem_writel,
-    espdma_mem_writel,
-};
-
static void esp_save(QEMUFile *f, void *opaque)
{
     ESPState *s = opaque;
-    unsigned int i;

     qemu_put_buffer(f, s->rregs, ESP_MAXREG);
     qemu_put_buffer(f, s->wregs, ESP_MAXREG);
-    qemu_put_be32s(f, &s->irq);
-    for (i = 0; i < ESPDMA_REGS; i++)
-	qemu_put_be32s(f, &s->espdmaregs[i]);
     qemu_put_be32s(f, &s->ti_size);
     qemu_put_be32s(f, &s->ti_rptr);
     qemu_put_be32s(f, &s->ti_wptr);
@@ -562,16 +487,12 @@
static int esp_load(QEMUFile *f, void *opaque, int version_id)
{
     ESPState *s = opaque;
-    unsigned int i;

-    if (version_id != 1)
-        return -EINVAL;
+    if (version_id != 2)
+        return -EINVAL; // Cannot emulate 1

     qemu_get_buffer(f, s->rregs, ESP_MAXREG);
     qemu_get_buffer(f, s->wregs, ESP_MAXREG);
-    qemu_get_be32s(f, &s->irq);
-    for (i = 0; i < ESPDMA_REGS; i++)
-	qemu_get_be32s(f, &s->espdmaregs[i]);
     qemu_get_be32s(f, &s->ti_size);
     qemu_get_be32s(f, &s->ti_rptr);
     qemu_get_be32s(f, &s->ti_wptr);
@@ -581,28 +502,24 @@
     return 0;
}

-void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t 
espdaddr)
+void *esp_init(BlockDriverState **bd, uint32_t espaddr)
{
     ESPState *s;
-    int esp_io_memory, espdma_io_memory;
+    int esp_io_memory;
     int i;

     s = qemu_mallocz(sizeof(ESPState));
     if (!s)
-        return;
+        return NULL;

     s->bd = bd;
-    s->irq = irq;

     esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, 
s);
     cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory);

-    espdma_io_memory = cpu_register_io_memory(0, espdma_mem_read, 
espdma_mem_write, s);
-    cpu_register_physical_memory(espdaddr, 16, espdma_io_memory);
-
     esp_reset(s);

-    register_savevm("esp", espaddr, 1, esp_save, esp_load, s);
+    register_savevm("esp", espaddr, 2, esp_save, esp_load, s);
     qemu_register_reset(esp_reset, s);
     for (i = 0; i < MAX_DISKS; i++) {
         if (bs_table[i]) {
@@ -611,5 +528,6 @@
                 scsi_disk_init(bs_table[i], 0, esp_command_complete, s);
         }
     }
-}

+    return s;
+}
Index: qemu/vl.h
===================================================================
--- qemu.orig/vl.h	2006-08-29 16:48:51.000000000 +0000
+++ qemu/vl.h	2006-08-29 19:50:30.000000000 +0000
@@ -923,6 +923,9 @@
/* pcnet.c */

void pci_pcnet_init(PCIBus *bus, NICInfo *nd);
+void pcnet_h_reset(void *opaque);
+void *lance_init(NICInfo *nd, int irq, uint32_t leaddr);
+

/* pckbd.c */

@@ -1032,6 +1035,8 @@
                              uint8_t *buf, int len);
void sparc_iommu_memory_write(target_phys_addr_t addr,
                               uint8_t *buf, int len);
+void main_esp_reset(void);
+void main_lance_reset(void);

/* iommu.c */
void *iommu_init(uint32_t addr);
@@ -1040,9 +1045,6 @@
void sparc_iommu_memory_rw_local(void *opaque, target_phys_addr_t addr,
                                  uint8_t *buf, int len, int is_write);

-/* lance.c */
-void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr);
-
/* tcx.c */
void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base,
	       unsigned long vram_offset, int vram_size, int width, int height);
@@ -1073,7 +1075,18 @@
void slavio_set_power_fail(void *opaque, int power_failing);

/* esp.c */
-void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t 
espdaddr);
+void *esp_init(BlockDriverState **bd, uint32_t espaddr);
+void esp_reset(void *opaque);
+
+/* sparc32_dma.c */
+void sparc32_dma_init(uint32_t daddr, int espirq, int leirq);
+void ledma_set_irq(void *opaque, int isr);
+void ledma_memory_read(target_phys_addr_t addr, uint8_t *buf, int len);
+void ledma_memory_write(target_phys_addr_t addr, uint8_t *buf, int len);
+void espdma_raise_irq(void);
+void espdma_clear_irq(void);
+void espdma_memory_read(uint8_t *buf, int len);
+void espdma_memory_write(uint8_t *buf, int len);

/* sun4u.c */
extern QEMUMachine sun4u_machine;
Index: qemu/hw/sun4m.c
===================================================================
--- qemu.orig/hw/sun4m.c	2006-08-29 16:48:51.000000000 +0000
+++ qemu/hw/sun4m.c	2006-08-29 19:39:31.000000000 +0000
@@ -37,10 +37,9 @@
#define PHYS_JJ_IOMMU	0x10000000	/* I/O MMU */
#define PHYS_JJ_TCX_FB	0x50000000	/* TCX frame buffer */
#define PHYS_JJ_SLAVIO	0x70000000	/* Slavio base */
-#define PHYS_JJ_ESPDMA  0x78400000      /* ESP DMA controller */
+#define PHYS_JJ_DMA     0x78400000      /* DMA controller */
#define PHYS_JJ_ESP     0x78800000      /* ESP SCSI */
#define PHYS_JJ_ESP_IRQ    18
-#define PHYS_JJ_LEDMA   0x78400010      /* Lance DMA controller */
#define PHYS_JJ_LE      0x78C00000      /* Lance ethernet */
#define PHYS_JJ_LE_IRQ     16
#define PHYS_JJ_CLOCK	0x71D00000      /* Per-CPU timer/counter, L14 */
@@ -224,6 +223,20 @@
     cpu_reset(env);
}

+static void *main_esp;
+
+void main_esp_reset()
+{
+    esp_reset(main_esp);
+}
+
+static void *main_lance;
+
+void main_lance_reset()
+{
+    pcnet_h_reset(main_lance);
+}
+
/* Sun4m hardware initialisation */
static void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
                        DisplayState *ds, const char **fd_filename, int 
snapshot,
@@ -260,7 +273,7 @@
     if (nd_table[0].vlan) {
         if (nd_table[0].model == NULL
             || strcmp(nd_table[0].model, "lance") == 0) {
-            lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, 
PHYS_JJ_LEDMA);
+            main_lance = lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, 
PHYS_JJ_LE);
         } else {
             fprintf(stderr, "qemu: Unsupported NIC: %s\n", 
nd_table[0].model);
             exit (1);
@@ -276,8 +289,9 @@
     // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device
     slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[1], 
serial_hds[0]);
     fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table);
-    esp_init(bs_table, PHYS_JJ_ESP_IRQ, PHYS_JJ_ESP, PHYS_JJ_ESPDMA);
+    main_esp = esp_init(bs_table, PHYS_JJ_ESP);
     slavio_misc = slavio_misc_init(PHYS_JJ_SLAVIO, PHYS_JJ_ME_IRQ);
+    sparc32_dma_init(PHYS_JJ_DMA, PHYS_JJ_ESP_IRQ, PHYS_JJ_LE_IRQ);

     prom_offset = ram_size + vram_size;
     cpu_register_physical_memory(PROM_ADDR,
Index: qemu/hw/sparc32_dma.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ qemu/hw/sparc32_dma.c	2006-08-29 20:17:52.000000000 +0000
@@ -0,0 +1,237 @@
+/*
+ * QEMU Sparc32 DMA controller emulation
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a 
copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the 
rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or 
sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included 
in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 
OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+
+/* debug DMA */
+//#define DEBUG_DMA
+
+/*
+ * This is the DMA controller part of chip STP2000 (Master I/O), also
+ * produced as NCR89C100. See
+ * 
http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
+ * and
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/DMA2.txt
+ */
+
+#ifdef DEBUG_DMA
+#define DPRINTF(fmt, args...) \
+do { printf("DMA: " fmt , ##args); } while (0)
+#define pic_set_irq(irq, level) \
+do { printf("DMA: set_irq(%d): %d\n", (irq), (level)); 
pic_set_irq((irq),(level));} while (0)
+#else
+#define DPRINTF(fmt, args...)
+#endif
+
+#define DMA_REGS 8
+#define DMA_MAXADDR (DMA_REGS * 4 - 1)
+
+#define DMA_VER 0xa0000000
+#define DMA_INTR 1
+#define DMA_INTREN 0x10
+#define DMA_WRITE_MEM 0x100
+#define DMA_LOADED 0x04000000
+#define DMA_RESET 0x80
+
+typedef struct DMAState DMAState;
+
+struct DMAState {
+    uint32_t dmaregs[DMA_REGS];
+    int espirq, leirq;
+};
+
+static DMAState *global_s;
+
+void ledma_set_irq(void *opaque, int isr) // Not our opaque
+{
+    DMAState *s = global_s;
+
+    pic_set_irq(s->leirq, isr);
+}
+
+void ledma_memory_read(target_phys_addr_t addr, uint8_t *buf, int len)
+{
+    DMAState *s = global_s;
+
+    DPRINTF("DMA write, direction: %c, addr 0x%8.8x\n",
+            s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]);
+    sparc_iommu_memory_read(addr | s->dmaregs[7], buf, len);
+}
+
+void ledma_memory_write(target_phys_addr_t addr, uint8_t *buf, int len)
+{
+    DMAState *s = global_s;
+
+    DPRINTF("DMA read, direction: %c, addr 0x%8.8x\n",
+            s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]);
+    sparc_iommu_memory_write(addr | s->dmaregs[7], buf, len);
+}
+
+void espdma_raise_irq(void)
+{
+    DMAState *s = global_s;
+
+    s->dmaregs[0] |= DMA_INTR;
+    pic_set_irq(s->espirq, 1);
+}
+
+void espdma_clear_irq(void)
+{
+    DMAState *s = global_s;
+
+    s->dmaregs[0] &= ~DMA_INTR;
+    pic_set_irq(s->espirq, 0);
+}
+
+void espdma_memory_read(uint8_t *buf, int len)
+{
+    DMAState *s = global_s;
+
+    DPRINTF("DMA read, direction: %c, addr 0x%8.8x\n",
+            s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]);
+    sparc_iommu_memory_read(s->dmaregs[1], buf, len);
+    s->dmaregs[0] |= DMA_INTR;
+    s->dmaregs[1] += len;
+}
+
+void espdma_memory_write(uint8_t *buf, int len)
+{
+    DMAState *s = global_s;
+
+    DPRINTF("DMA write, direction: %c, addr 0x%8.8x\n",
+            s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]);
+    sparc_iommu_memory_write(s->dmaregs[1], buf, len);
+    s->dmaregs[0] |= DMA_INTR;
+    s->dmaregs[1] += len;
+}
+
+static uint32_t dma_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    DMAState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr & DMA_MAXADDR) >> 2;
+    DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->dmaregs[saddr]);
+
+    return s->dmaregs[saddr];
+}
+
+static void dma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t 
val)
+{
+    DMAState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr & DMA_MAXADDR) >> 2;
+    DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, 
s->dmaregs[saddr], val);
+    switch (saddr) {
+    case 0:
+        if (!(val & DMA_INTREN))
+            pic_set_irq(s->espirq, 0);
+        if (val & DMA_RESET) {
+            main_esp_reset();
+        } else if (val & 0x40) {
+            val &= ~0x40;
+        } else if (val == 0)
+            val = 0x40;
+        val &= 0x0fffffff;
+        val |= DMA_VER;
+        break;
+    case 1:
+        s->dmaregs[0] |= DMA_LOADED;
+        break;
+    case 4:
+        if (!(val & DMA_INTREN))
+            pic_set_irq(s->leirq, 0);
+        if (val & DMA_RESET)
+            main_lance_reset();
+        val &= 0x0fffffff;
+        val |= DMA_VER;
+        break;
+    default:
+        break;
+    }
+    s->dmaregs[saddr] = val;
+}
+
+static CPUReadMemoryFunc *dma_mem_read[3] = {
+    dma_mem_readl,
+    dma_mem_readl,
+    dma_mem_readl,
+};
+
+static CPUWriteMemoryFunc *dma_mem_write[3] = {
+    dma_mem_writel,
+    dma_mem_writel,
+    dma_mem_writel,
+};
+
+static void dma_reset(void *opaque)
+{
+    DMAState *s = opaque;
+
+    memset(s->dmaregs, 0, DMA_REGS * 4);
+    s->dmaregs[0] = DMA_VER;
+    s->dmaregs[4] = DMA_VER;
+}
+
+static void dma_save(QEMUFile *f, void *opaque)
+{
+    DMAState *s = opaque;
+    unsigned int i;
+
+    for (i = 0; i < DMA_REGS; i++)
+        qemu_put_be32s(f, &s->dmaregs[i]);
+}
+
+static int dma_load(QEMUFile *f, void *opaque, int version_id)
+{
+    DMAState *s = opaque;
+    unsigned int i;
+
+    if (version_id != 1)
+        return -EINVAL;
+    for (i = 0; i < DMA_REGS; i++)
+        qemu_get_be32s(f, &s->dmaregs[i]);
+
+    return 0;
+}
+
+void sparc32_dma_init(uint32_t daddr, int espirq, int leirq)
+{
+    DMAState *s;
+    int dma_io_memory;
+
+    s = qemu_mallocz(sizeof(DMAState));
+    global_s = s;
+    if (!s)
+        return;
+
+    s->espirq = espirq;
+    s->leirq = leirq;
+
+    dma_io_memory = cpu_register_io_memory(0, dma_mem_read, dma_mem_write, 
s);
+    cpu_register_physical_memory(daddr, 16 * 2, dma_io_memory);
+
+    register_savevm("sparc32_dma", daddr, 1, dma_save, dma_load, s);
+    qemu_register_reset(dma_reset, s);
+}
Index: qemu/hw/lance.c
===================================================================
--- qemu.orig/hw/lance.c	2006-08-29 20:44:02.000000000 +0000
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,474 +0,0 @@
-/*
- * QEMU Lance emulation
- *
- * Copyright (c) 2003-2005 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a 
copy
- * of this software and associated documentation files (the "Software"), to 
deal
- * in the Software without restriction, including without limitation the 
rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or 
sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included 
in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 
OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
IN
- * THE SOFTWARE.
- */
-#include "vl.h"
-
-/* debug LANCE card */
-//#define DEBUG_LANCE
-
-#ifdef DEBUG_LANCE
-#define DPRINTF(fmt, args...) \
-do { printf("LANCE: " fmt , ##args); } while (0)
-#else
-#define DPRINTF(fmt, args...)
-#endif
-
-#ifndef LANCE_LOG_TX_BUFFERS
-#define LANCE_LOG_TX_BUFFERS 4
-#define LANCE_LOG_RX_BUFFERS 4
-#endif
-
-#define LE_CSR0 0
-#define LE_CSR1 1
-#define LE_CSR2 2
-#define LE_CSR3 3
-#define LE_NREGS (LE_CSR3 + 1)
-#define LE_MAXREG LE_CSR3
-
-#define LE_RDP  0
-#define LE_RAP  1
-
-#define LE_MO_PROM      0x8000  /* Enable promiscuous mode */
-
-#define	LE_C0_ERR	0x8000  /* Error: set if BAB, SQE, MISS or ME is set */
-#define	LE_C0_BABL	0x4000  /* BAB:  Babble: tx timeout. */
-#define	LE_C0_CERR	0x2000  /* SQE:  Signal quality error */
-#define	LE_C0_MISS	0x1000  /* MISS: Missed a packet */
-#define	LE_C0_MERR	0x0800  /* ME:   Memory error */
-#define	LE_C0_RINT	0x0400  /* Received interrupt */
-#define	LE_C0_TINT	0x0200  /* Transmitter Interrupt */
-#define	LE_C0_IDON	0x0100  /* IFIN: Init finished. */
-#define	LE_C0_INTR	0x0080  /* Interrupt or error */
-#define	LE_C0_INEA	0x0040  /* Interrupt enable */
-#define	LE_C0_RXON	0x0020  /* Receiver on */
-#define	LE_C0_TXON	0x0010  /* Transmitter on */
-#define	LE_C0_TDMD	0x0008  /* Transmitter demand */
-#define	LE_C0_STOP	0x0004  /* Stop the card */
-#define	LE_C0_STRT	0x0002  /* Start the card */
-#define	LE_C0_INIT	0x0001  /* Init the card */
-
-#define	LE_C3_BSWP	0x4     /* SWAP */
-#define	LE_C3_ACON	0x2     /* ALE Control */
-#define	LE_C3_BCON	0x1     /* Byte control */
-
-/* Receive message descriptor 1 */
-#define LE_R1_OWN       0x80    /* Who owns the entry */
-#define LE_R1_ERR       0x40    /* Error: if FRA, OFL, CRC or BUF is set */
-#define LE_R1_FRA       0x20    /* FRA: Frame error */
-#define LE_R1_OFL       0x10    /* OFL: Frame overflow */
-#define LE_R1_CRC       0x08    /* CRC error */
-#define LE_R1_BUF       0x04    /* BUF: Buffer error */
-#define LE_R1_SOP       0x02    /* Start of packet */
-#define LE_R1_EOP       0x01    /* End of packet */
-#define LE_R1_POK       0x03    /* Packet is complete: SOP + EOP */
-
-#define LE_T1_OWN       0x80    /* Lance owns the packet */
-#define LE_T1_ERR       0x40    /* Error summary */
-#define LE_T1_EMORE     0x10    /* Error: more than one retry needed */
-#define LE_T1_EONE      0x08    /* Error: one retry needed */
-#define LE_T1_EDEF      0x04    /* Error: deferred */
-#define LE_T1_SOP       0x02    /* Start of packet */
-#define LE_T1_EOP       0x01    /* End of packet */
-#define LE_T1_POK	0x03    /* Packet is complete: SOP + EOP */
-
-#define LE_T3_BUF       0x8000  /* Buffer error */
-#define LE_T3_UFL       0x4000  /* Error underflow */
-#define LE_T3_LCOL      0x1000  /* Error late collision */
-#define LE_T3_CLOS      0x0800  /* Error carrier loss */
-#define LE_T3_RTY       0x0400  /* Error retry */
-#define LE_T3_TDR       0x03ff  /* Time Domain Reflectometry counter */
-
-#define TX_RING_SIZE			(1 << (LANCE_LOG_TX_BUFFERS))
-#define TX_RING_MOD_MASK		(TX_RING_SIZE - 1)
-#define TX_RING_LEN_BITS		((LANCE_LOG_TX_BUFFERS) << 29)
-
-#define RX_RING_SIZE			(1 << (LANCE_LOG_RX_BUFFERS))
-#define RX_RING_MOD_MASK		(RX_RING_SIZE - 1)
-#define RX_RING_LEN_BITS		((LANCE_LOG_RX_BUFFERS) << 29)
-
-#define PKT_BUF_SZ		1544
-#define RX_BUFF_SIZE            PKT_BUF_SZ
-#define TX_BUFF_SIZE            PKT_BUF_SZ
-
-struct lance_rx_desc {
-    unsigned short rmd0;        /* low address of packet */
-    unsigned char rmd1_bits;    /* descriptor bits */
-    unsigned char rmd1_hadr;    /* high address of packet */
-    short length;               /* This length is 2s complement (negative)!
-                                 * Buffer length
-                                 */
-    unsigned short mblength;    /* This is the actual number of bytes 
received */
-};
-
-struct lance_tx_desc {
-    unsigned short tmd0;        /* low address of packet */
-    unsigned char tmd1_bits;    /* descriptor bits */
-    unsigned char tmd1_hadr;    /* high address of packet */
-    short length;               /* Length is 2s complement (negative)! */
-    unsigned short misc;
-};
-
-/* The LANCE initialization block, described in databook. */
-/* On the Sparc, this block should be on a DMA region     */
-struct lance_init_block {
-    unsigned short mode;        /* Pre-set mode (reg. 15) */
-    unsigned char phys_addr[6]; /* Physical ethernet address */
-    unsigned filter[2];         /* Multicast filter. */
-
-    /* Receive and transmit ring base, along with extra bits. */
-    unsigned short rx_ptr;      /* receive descriptor addr */
-    unsigned short rx_len;      /* receive len and high addr */
-    unsigned short tx_ptr;      /* transmit descriptor addr */
-    unsigned short tx_len;      /* transmit len and high addr */
-
-    /* The Tx and Rx ring entries must aligned on 8-byte boundaries. */
-    struct lance_rx_desc brx_ring[RX_RING_SIZE];
-    struct lance_tx_desc btx_ring[TX_RING_SIZE];
-
-    char tx_buf[TX_RING_SIZE][TX_BUFF_SIZE];
-    char pad[2];                /* align rx_buf for copy_and_sum(). */
-    char rx_buf[RX_RING_SIZE][RX_BUFF_SIZE];
-};
-
-#define LEDMA_REGS 4
-#define LEDMA_MAXADDR (LEDMA_REGS * 4 - 1)
-
-typedef struct LANCEState {
-    VLANClientState *vc;
-    uint8_t macaddr[6];         /* init mac address */
-    uint32_t leptr;
-    uint16_t addr;
-    uint16_t regs[LE_NREGS];
-    uint8_t phys[6];            /* mac address */
-    int irq;
-    unsigned int rxptr, txptr;
-    uint32_t ledmaregs[LEDMA_REGS];
-} LANCEState;
-
-static void lance_send(void *opaque);
-
-static void lance_reset(void *opaque)
-{
-    LANCEState *s = opaque;
-    memcpy(s->phys, s->macaddr, 6);
-    s->rxptr = 0;
-    s->txptr = 0;
-    memset(s->regs, 0, LE_NREGS * 2);
-    s->regs[LE_CSR0] = LE_C0_STOP;
-    memset(s->ledmaregs, 0, LEDMA_REGS * 4);
-}
-
-static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr)
-{
-    LANCEState *s = opaque;
-    uint32_t saddr;
-
-    saddr = addr & LE_MAXREG;
-    switch (saddr >> 1) {
-    case LE_RDP:
-        DPRINTF("read dreg[%d] = %4.4x\n", s->addr, s->regs[s->addr]);
-        return s->regs[s->addr];
-    case LE_RAP:
-        DPRINTF("read areg = %4.4x\n", s->addr);
-        return s->addr;
-    default:
-        DPRINTF("read unknown(%d)\n", saddr >> 1);
-        break;
-    }
-    return 0;
-}
-
-static void lance_mem_writew(void *opaque, target_phys_addr_t addr,
-                             uint32_t val)
-{
-    LANCEState *s = opaque;
-    uint32_t saddr;
-    uint16_t reg;
-
-    saddr = addr & LE_MAXREG;
-    switch (saddr >> 1) {
-    case LE_RDP:
-        DPRINTF("write dreg[%d] = %4.4x\n", s->addr, val);
-        switch (s->addr) {
-        case LE_CSR0:
-            if (val & LE_C0_STOP) {
-                s->regs[LE_CSR0] = LE_C0_STOP;
-                break;
-            }
-
-            reg = s->regs[LE_CSR0];
-
-            // 1 = clear for some bits
-            reg &= ~(val & 0x7f00);
-
-            // generated bits
-            reg &= ~(LE_C0_ERR | LE_C0_INTR);
-            if (reg & 0x7100)
-                reg |= LE_C0_ERR;
-            if (reg & 0x7f00)
-                reg |= LE_C0_INTR;
-
-            // direct bit
-            reg &= ~LE_C0_INEA;
-            reg |= val & LE_C0_INEA;
-
-            // exclusive bits
-            if (val & LE_C0_INIT) {
-                reg |= LE_C0_IDON | LE_C0_INIT;
-                reg &= ~LE_C0_STOP;
-            } else if (val & LE_C0_STRT) {
-                reg |= LE_C0_STRT | LE_C0_RXON | LE_C0_TXON;
-                reg &= ~LE_C0_STOP;
-            }
-
-            s->regs[LE_CSR0] = reg;
-            break;
-        case LE_CSR1:
-            s->leptr = (s->leptr & 0xffff0000) | (val & 0xffff);
-            s->regs[s->addr] = val;
-            break;
-        case LE_CSR2:
-            s->leptr = (s->leptr & 0xffff) | ((val & 0xffff) << 16);
-            s->regs[s->addr] = val;
-            break;
-        case LE_CSR3:
-            s->regs[s->addr] = val;
-            break;
-        }
-        break;
-    case LE_RAP:
-        DPRINTF("write areg = %4.4x\n", val);
-        if (val < LE_NREGS)
-            s->addr = val;
-        break;
-    default:
-        DPRINTF("write unknown(%d) = %4.4x\n", saddr >> 1, val);
-        break;
-    }
-    lance_send(s);
-}
-
-static CPUReadMemoryFunc *lance_mem_read[3] = {
-    lance_mem_readw,
-    lance_mem_readw,
-    lance_mem_readw,
-};
-
-static CPUWriteMemoryFunc *lance_mem_write[3] = {
-    lance_mem_writew,
-    lance_mem_writew,
-    lance_mem_writew,
-};
-
-
-#define MIN_BUF_SIZE 60
-
-static int lance_can_receive(void *opaque)
-{
-    return 1;
-}
-
-static void lance_receive(void *opaque, const uint8_t * buf, int size)
-{
-    LANCEState *s = opaque;
-    uint32_t dmaptr = s->leptr + s->ledmaregs[3];
-    struct lance_init_block *ib;
-    unsigned int i, old_rxptr;
-    uint16_t temp16;
-    uint8_t temp8;
-
-    DPRINTF("receive size %d\n", size);
-    if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
-        return;
-
-    ib = (void *) iommu_translate(dmaptr);
-
-    old_rxptr = s->rxptr;
-    for (i = s->rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK);
-         i = (i + 1) & RX_RING_MOD_MASK) {
-        cpu_physical_memory_read((uint32_t) & ib->brx_ring[i].rmd1_bits,
-                                 (void *) &temp8, 1);
-        if (temp8 == (LE_R1_OWN)) {
-            s->rxptr = (s->rxptr + 1) & RX_RING_MOD_MASK;
-            temp16 = size + 4;
-            bswap16s(&temp16);
-            cpu_physical_memory_write((uint32_t) & ib->brx_ring[i].
-                                      mblength, (void *) &temp16, 2);
-            cpu_physical_memory_write((uint32_t) & ib->rx_buf[i], buf,
-                                      size);
-            temp8 = LE_R1_POK;
-            cpu_physical_memory_write((uint32_t) & ib->brx_ring[i].
-                                      rmd1_bits, (void *) &temp8, 1);
-            s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR;
-            if (s->regs[LE_CSR0] & LE_C0_INEA)
-                pic_set_irq(s->irq, 1);
-            DPRINTF("got packet, len %d\n", size);
-            return;
-        }
-    }
-}
-
-static void lance_send(void *opaque)
-{
-    LANCEState *s = opaque;
-    uint32_t dmaptr = s->leptr + s->ledmaregs[3];
-    struct lance_init_block *ib;
-    unsigned int i, old_txptr;
-    uint16_t temp16;
-    uint8_t temp8;
-    char pkt_buf[PKT_BUF_SZ];
-
-    DPRINTF("sending packet? (csr0 %4.4x)\n", s->regs[LE_CSR0]);
-    if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
-        return;
-
-    ib = (void *) iommu_translate(dmaptr);
-
-    DPRINTF("sending packet? (dmaptr %8.8x) (ib %p) (btx_ring %p)\n",
-            dmaptr, ib, &ib->btx_ring);
-    old_txptr = s->txptr;
-    for (i = s->txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK);
-         i = (i + 1) & TX_RING_MOD_MASK) {
-        cpu_physical_memory_read((uint32_t) & ib->btx_ring[i].tmd1_bits,
-                                 (void *) &temp8, 1);
-        if (temp8 == (LE_T1_POK | LE_T1_OWN)) {
-            cpu_physical_memory_read((uint32_t) & ib->btx_ring[i].length,
-                                     (void *) &temp16, 2);
-            bswap16s(&temp16);
-            temp16 = (~temp16) + 1;
-            cpu_physical_memory_read((uint32_t) & ib->tx_buf[i], pkt_buf,
-                                     temp16);
-            DPRINTF("sending packet, len %d\n", temp16);
-            qemu_send_packet(s->vc, pkt_buf, temp16);
-            temp8 = LE_T1_POK;
-            cpu_physical_memory_write((uint32_t) & ib->btx_ring[i].
-                                      tmd1_bits, (void *) &temp8, 1);
-            s->txptr = (s->txptr + 1) & TX_RING_MOD_MASK;
-            s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR;
-        }
-    }
-    if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA))
-        pic_set_irq(s->irq, 1);
-}
-
-static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr)
-{
-    LANCEState *s = opaque;
-    uint32_t saddr;
-
-    saddr = (addr & LEDMA_MAXADDR) >> 2;
-    return s->ledmaregs[saddr];
-}
-
-static void ledma_mem_writel(void *opaque, target_phys_addr_t addr,
-                             uint32_t val)
-{
-    LANCEState *s = opaque;
-    uint32_t saddr;
-
-    saddr = (addr & LEDMA_MAXADDR) >> 2;
-    s->ledmaregs[saddr] = val;
-}
-
-static CPUReadMemoryFunc *ledma_mem_read[3] = {
-    ledma_mem_readl,
-    ledma_mem_readl,
-    ledma_mem_readl,
-};
-
-static CPUWriteMemoryFunc *ledma_mem_write[3] = {
-    ledma_mem_writel,
-    ledma_mem_writel,
-    ledma_mem_writel,
-};
-
-static void lance_save(QEMUFile * f, void *opaque)
-{
-    LANCEState *s = opaque;
-    int i;
-
-    qemu_put_be32s(f, &s->leptr);
-    qemu_put_be16s(f, &s->addr);
-    for (i = 0; i < LE_NREGS; i++)
-        qemu_put_be16s(f, &s->regs[i]);
-    qemu_put_buffer(f, s->phys, 6);
-    qemu_put_be32s(f, &s->irq);
-    for (i = 0; i < LEDMA_REGS; i++)
-        qemu_put_be32s(f, &s->ledmaregs[i]);
-}
-
-static int lance_load(QEMUFile * f, void *opaque, int version_id)
-{
-    LANCEState *s = opaque;
-    int i;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    qemu_get_be32s(f, &s->leptr);
-    qemu_get_be16s(f, &s->addr);
-    for (i = 0; i < LE_NREGS; i++)
-        qemu_get_be16s(f, &s->regs[i]);
-    qemu_get_buffer(f, s->phys, 6);
-    qemu_get_be32s(f, &s->irq);
-    for (i = 0; i < LEDMA_REGS; i++)
-        qemu_get_be32s(f, &s->ledmaregs[i]);
-    return 0;
-}
-
-void lance_init(NICInfo * nd, int irq, uint32_t leaddr, uint32_t ledaddr)
-{
-    LANCEState *s;
-    int lance_io_memory, ledma_io_memory;
-
-    s = qemu_mallocz(sizeof(LANCEState));
-    if (!s)
-        return;
-
-    s->irq = irq;
-
-    lance_io_memory =
-        cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s);
-    cpu_register_physical_memory(leaddr, 4, lance_io_memory);
-
-    ledma_io_memory =
-        cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s);
-    cpu_register_physical_memory(ledaddr, 16, ledma_io_memory);
-
-    memcpy(s->macaddr, nd->macaddr, 6);
-
-    lance_reset(s);
-
-    s->vc =
-        qemu_new_vlan_client(nd->vlan, lance_receive, lance_can_receive,
-                             s);
-
-    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
-             "lance macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
-             s->macaddr[0],
-             s->macaddr[1],
-             s->macaddr[2], s->macaddr[3], s->macaddr[4], s->macaddr[5]);
-
-    register_savevm("lance", leaddr, 1, lance_save, lance_load, s);
-    qemu_register_reset(lance_reset, s);
-}


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2006-08-31 11:54 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-08-30 19:45 [Qemu-devel] Updated PCnet/Lance/DMA/ESP patch Blue Swirl
2006-08-30 20:45 ` [Qemu-devel] " Fabrice Bellard
2006-08-31 11:54   ` malc

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.