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-29 20:40:38.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,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 +1903,47 @@ 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); + + 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); -}