Hi,

I got PCNet working in Sun4m architecture by fixing endianness problems and adding IOMMU hooks. There are still some endianness issues, that's why I disabled the address matching code.

The original code could benefit from some touchup and performance tuning.

Any comments?

_________________________________________________________________
Express yourself instantly with MSN Messenger! Download today it's FREE! http://messenger.msn.click-url.com/go/onm00200471ave/direct/01/
Merge Lance and PCNet drivers.

Index: qemu/hw/pcnet.c
===================================================================
--- qemu.orig/hw/pcnet.c        2006-08-20 13:46:51.000000000 +0000
+++ qemu/hw/pcnet.c     2006-08-24 17:22:19.000000000 +0000
@@ -36,10 +36,27 @@
//#define PCNET_DEBUG_RMD
//#define PCNET_DEBUG_TMD
//#define PCNET_DEBUG_MATCH
+//#define PCNET_DEBUG_SPARC_IOMMU
+//#define PCNET_DEBUG_SPARC_LEDMA

+#ifdef PCNET_DEBUG_SPARC_LEDMA
+#define DPRINTF(fmt, args...) \
+do { printf("PCNET: " fmt , ##args); } while (0)
+#define pic_set_irq(irq, level)                                       \
+do { printf("PCNET: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level));} while (0)
+#else
+#define DPRINTF(fmt, args...)
+#endif
+#if defined(PCNET_DEBUG_SPARC_IOMMU)
+#define iommu_translate(addr)                                           \
+    (printf("PCNET: iommu_translate(0x%x) -> 0x%x\n", (addr),           \
+            iommu_translate(addr)), iommu_translate(addr))
+#endif

#define PCNET_IOPORT_SIZE       0x20
#define PCNET_PNPMMIO_SIZE      0x20
+#define LEDMA_REGS 4
+#define LEDMA_MAXADDR (LEDMA_REGS * 4 - 1)


typedef struct PCNetState_st PCNetState;
@@ -49,7 +66,8 @@
    VLANClientState *vc;
    NICInfo *nd;
    QEMUTimer *poll_timer;
-    int mmio_io_addr, rap, isr, lnkst;
+    target_phys_addr_t mmio_io_addr;
+    int rap, isr, lnkst;
    target_phys_addr_t rdra, tdra;
    uint8_t prom[16];
    uint16_t csr[128];
@@ -58,6 +76,11 @@
    int xmit_pos, recv_pos;
    uint8_t buffer[4096];
    int tx_busy;
+#if defined(TARGET_SPARC) && !defined (TARGET_SPARC64)
+    // Lance-specific
+    int irq;
+    uint32_t ledmaregs[LEDMA_REGS];
+#endif
};

/* XXX: using bitfields for target memory structures is almost surely
@@ -90,7 +113,11 @@

#define BCR_DWIO(S)      !!((S)->bcr[BCR_BSBC] & 0x0080)
#define BCR_SSIZE32(S)   !!((S)->bcr[BCR_SWS ] & 0x0100)
+#if defined(TARGET_SPARC) && !defined (TARGET_SPARC64)
+#define BCR_SWSTYLE(S)     (0)
+#else
#define BCR_SWSTYLE(S)     ((S)->bcr[BCR_SWS ] & 0x00FF)
+#endif

#define CSR_INIT(S)      !!(((S)->csr[0])&0x0001)
#define CSR_STRT(S)      !!(((S)->csr[0])&0x0002)
@@ -142,14 +169,28 @@
#define CSR_PXDA(S)      ((S)->csr[60] | ((S)->csr[61] << 16))
#define CSR_NXBA(S)      ((S)->csr[64] | ((S)->csr[65] << 16))

+#if defined(TARGET_SPARC) && !defined (TARGET_SPARC64)
+#define PHYSADDR(S,A) ((A) | (S)->ledmaregs[3])
+#define SPARC_IOMMU_TRANSLATE(addr) iommu_translate(addr)
+#define SPARC_FIX_INITBLK(initblk) do{ bswap16s((uint16_t *)&initblk.ladrf4 + 1); \
+        bswap16s((uint16_t *)&initblk.ladrf4 + 2);                      \
+        bswap16s((uint16_t *)&initblk.ladrf4 + 3);                      \
+        bswap16s((uint16_t *)&initblk.ladrf4 + 4);} while(0)
+#define SPARC_FIX_DESC(desc) do{ bswap16s((uint16_t *)&desc);     \
+        bswap16s((uint16_t *)&desc + 1);                          \
+        bswap16s((uint16_t *)&desc + 2);                          \
+        bswap16s((uint16_t *)&desc + 3); } while(0)
+#else
#define PHYSADDR(S,A) \
  (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(s)->csr[2])<<16))
+#define SPARC_IOMMU_TRANSLATE(addr) (addr)
+#define SPARC_FIX_INITBLK(initblk) do{}while(0)
+#define SPARC_FIX_DESC(desc) do{}while(0)
+#endif

struct pcnet_initblk16 {
    uint16_t mode;
-    uint16_t padr1;
-    uint16_t padr2;
-    uint16_t padr3;
+    uint8_t padr[6];
    uint16_t ladrf1;
    uint16_t ladrf2;
    uint16_t ladrf3;
@@ -168,9 +209,7 @@
    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 padr[6];
    uint16_t _res;
    uint16_t ladrf1;
    uint16_t ladrf2;
@@ -255,8 +294,10 @@
{
    if (!BCR_SWSTYLE(s)) {
        uint16_t xda[4];
+        addr = SPARC_IOMMU_TRANSLATE(addr);
        cpu_physical_memory_read(addr,
                (void *)&xda[0], sizeof(xda));
+        SPARC_FIX_DESC(xda);
        ((uint32_t *)tmd)[0] = (xda[0]&0xffff) |
                ((xda[1]&0x00ff) << 16);
        ((uint32_t *)tmd)[1] = (xda[2]&0xffff)|
@@ -288,6 +329,8 @@
            ((((uint32_t *)tmd)[1]>>16)&0xff00);
        xda[2] = ((uint32_t *)tmd)[1] & 0xffff;
        xda[3] = ((uint32_t *)tmd)[2] >> 16;
+        SPARC_FIX_DESC(xda);
+        addr = SPARC_IOMMU_TRANSLATE(addr);
        cpu_physical_memory_write(addr,
                (void *)&xda[0], sizeof(xda));
    }
@@ -310,8 +353,10 @@
{
    if (!BCR_SWSTYLE(s)) {
        uint16_t rda[4];
+        addr = SPARC_IOMMU_TRANSLATE(addr);
        cpu_physical_memory_read(addr,
                (void *)&rda[0], sizeof(rda));
+        SPARC_FIX_DESC(rda);
        ((uint32_t *)rmd)[0] = (rda[0]&0xffff)|
                ((rda[1] & 0x00ff) << 16);
        ((uint32_t *)rmd)[1] = (rda[2]&0xffff)|
@@ -342,6 +387,8 @@
            ((((uint32_t *)rmd)[1]>>16)&0xff00);\
        rda[2] = ((uint32_t *)rmd)[1] & 0xffff; \
        rda[3] = ((uint32_t *)rmd)[2] & 0xffff; \
+        SPARC_FIX_DESC(rda);
+        addr = SPARC_IOMMU_TRANSLATE(addr);
        cpu_physical_memory_write(addr,         \
                (void *)&rda[0], sizeof(rda));  \
    }
@@ -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

@@ -564,6 +610,7 @@
           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]);
+ printf("csr[12]=%x, lo %x hi %x\n", s->csr[12], s->csr[12] & 0xff, s->csr[12]>>8);
    printf("padr_match result=%d\n", result);
#endif
    return result;
@@ -643,9 +690,9 @@
    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);
    s->csr[15] &= 0x21c4;
    s->csr[72]  = 1;
    s->csr[74]  = 1;
@@ -721,8 +768,12 @@
        printf("pcnet: INTA=%d\n", isr);
#endif
    }
-        pci_set_irq(&s->dev, 0, isr);
-        s->isr = isr;
+#if defined(TARGET_SPARC) && !defined (TARGET_SPARC64)
+    pic_set_irq(s->irq, isr);
+#else
+    pci_set_irq(&s->dev, 0, isr);
+#endif
+    s->isr = isr;
}

static void pcnet_init(PCNetState *s)
@@ -732,19 +783,20 @@
#endif

#define PCNET_INIT() do { \
-        cpu_physical_memory_read(PHYSADDR(s,CSR_IADR(s)),       \
+ cpu_physical_memory_read(SPARC_IOMMU_TRANSLATE(PHYSADDR(s,CSR_IADR(s))), \
                (uint8_t *)&initblk, sizeof(initblk));          \
+        SPARC_FIX_INITBLK(initblk);                             \
        s->csr[15] = le16_to_cpu(initblk.mode);                 \
        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->csr[ 8] = initblk.ladrf1;                                    \
+        s->csr[ 9] = initblk.ladrf2;                                    \
+        s->csr[10] = initblk.ladrf3;                                    \
+        s->csr[11] = initblk.ladrf4;                                    \
+        s->csr[12] = initblk.padr[0] | (initblk.padr[1] << 8);          \
+        s->csr[13] = initblk.padr[2] | (initblk.padr[3] << 8);          \
+        s->csr[14] = initblk.padr[4] | (initblk.padr[5] << 8);          \
        s->rdra = PHYSADDR(s,initblk.rdra);                             \
        s->tdra = PHYSADDR(s,initblk.tdra);                             \
} while (0)
@@ -954,11 +1006,13 @@
        buf = buf1;
        size = MIN_BUF_SIZE;
    }
-
+#if 0
    if (CSR_PROM(s)
        || (is_padr=padr_match(s, buf, size))
        || (is_bcast=padr_bcast(s, buf, size))
-        || (is_ladr=ladr_match(s, buf, size))) {
+        || (is_ladr=ladr_match(s, buf, size)))
+#endif
+        {

        pcnet_rdte_poll(s);

@@ -1035,6 +1089,7 @@
#define PCNET_RECV_STORE() do {                                 \
    int count = MIN(4096 - rmd.rmd1.bcnt,size);                 \
    target_phys_addr_t rbadr = PHYSADDR(s, rmd.rmd0.rbadr);     \
+    rbadr = SPARC_IOMMU_TRANSLATE(rbadr);                       \
    cpu_physical_memory_write(rbadr, src, count);               \
    src += count; size -= count;                                \
    rmd.rmd2.mcnt = count; rmd.rmd1.own = 0;                    \
@@ -1125,14 +1180,14 @@
        if (tmd.tmd1.stp) {
            s->xmit_pos = 0;
            if (!tmd.tmd1.enp) {
-                cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr),
+ cpu_physical_memory_read(SPARC_IOMMU_TRANSLATE(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),
+ cpu_physical_memory_read(SPARC_IOMMU_TRANSLATE(PHYSADDR(s, tmd.tmd0.tbadr)),
                    s->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt);
            s->xmit_pos += 4096 - tmd.tmd1.bcnt;
#ifdef PCNET_DEBUG
@@ -1727,6 +1782,28 @@
cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->mmio_io_addr);
}

+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);
+}
+
void pci_pcnet_init(PCIBus *bus, NICInfo *nd)
{
    PCNetState *d;
@@ -1768,22 +1845,65 @@

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

-    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]);
+#if defined(TARGET_SPARC) && !defined (TARGET_SPARC64)
+// Due to Qemu limitations, Lance DMA registers are accessed via ESP
+// DMA registers
+static PCNetState *global_pcnet;

-    pcnet_h_reset(d);
+uint32_t ledma_mem_readl(target_phys_addr_t addr)
+{
+    uint32_t saddr;
+
+    saddr = (addr & LEDMA_MAXADDR) >> 2;
+    DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr,
+            global_pcnet->ledmaregs[saddr]);
+
+    return global_pcnet->ledmaregs[saddr];
+}
+
+void ledma_mem_writel(target_phys_addr_t addr, uint32_t val)
+{
+    uint32_t saddr;
+
+    saddr = (addr & LEDMA_MAXADDR) >> 2;
+    DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr,
+            global_pcnet->ledmaregs[saddr], val);
+    global_pcnet->ledmaregs[saddr] = val;
}
+
+static CPUWriteMemoryFunc *lance_mem_write[3] = {
+    pcnet_ioport_writew,
+    pcnet_ioport_writew,
+    pcnet_ioport_writew,
+};
+
+static CPUReadMemoryFunc *lance_mem_read[3] = {
+    pcnet_ioport_readw,
+    pcnet_ioport_readw,
+    pcnet_ioport_readw,
+};
+
+void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr)
+{
+    PCNetState *d;
+    int lance_io_memory;
+
+    d = qemu_mallocz(sizeof(PCNetState));
+    if (!d)
+        return;
+
+    global_pcnet = d;
+    d->irq = irq;
+
+    lance_io_memory =
+        cpu_register_io_memory(0, lance_mem_read, lance_mem_write, d);
+
+    cpu_register_physical_memory(leaddr, 4, lance_io_memory);
+
+    pcnet_common_init(d, nd, "lance");
+}
+#endif
Index: qemu/Makefile.target
===================================================================
--- qemu.orig/Makefile.target   2006-08-20 13:46:51.000000000 +0000
+++ qemu/Makefile.target        2006-08-22 17:36:23.000000000 +0000
@@ -359,7 +359,7 @@
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+= 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
endif
endif
Index: qemu/hw/esp.c
===================================================================
--- qemu.orig/hw/esp.c  2006-08-20 13:46:51.000000000 +0000
+++ qemu/hw/esp.c       2006-08-20 13:54:38.000000000 +0000
@@ -37,6 +37,7 @@

#define ESPDMA_REGS 4
#define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1)
+#define DMA_MAXADDR (ESPDMA_REGS * 4 * 2 - 1)
#define ESP_MAXREG 0x3f
#define TI_BUFSZ 32
#define DMA_VER 0xa0000000
@@ -474,12 +475,17 @@
    esp_mem_writeb,
};

+extern uint32_t ledma_mem_readl(target_phys_addr_t addr);
+extern void ledma_mem_writel(target_phys_addr_t addr, uint32_t val);
+
static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr)
{
    ESPState *s = opaque;
    uint32_t saddr;

-    saddr = (addr & ESPDMA_MAXADDR) >> 2;
+    saddr = (addr & DMA_MAXADDR) >> 2;
+    if (saddr > ESPDMA_REGS)
+        return ledma_mem_readl(addr);
    DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->espdmaregs[saddr]);

    return s->espdmaregs[saddr];
@@ -490,7 +496,11 @@
    ESPState *s = opaque;
    uint32_t saddr;

-    saddr = (addr & ESPDMA_MAXADDR) >> 2;
+    saddr = (addr & DMA_MAXADDR) >> 2;
+    if (saddr > ESPDMA_REGS) {
+        ledma_mem_writel(addr, val);
+        return;
+    }
DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->espdmaregs[saddr], val);
    switch (saddr) {
    case 0:
@@ -581,8 +591,10 @@
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);

+    // Due to Qemu limitations, Lance DMA registers are accessed via ESP
+    // DMA registers
espdma_io_memory = cpu_register_io_memory(0, espdma_mem_read, espdma_mem_write, s);
-    cpu_register_physical_memory(espdaddr, 16, espdma_io_memory);
+    cpu_register_physical_memory(espdaddr, 16 * 2, espdma_io_memory);

    esp_reset(s);


_______________________________________________
Qemu-devel mailing list
Qemu-devel@nongnu.org
http://lists.nongnu.org/mailman/listinfo/qemu-devel

Reply via email to