The attached patch to the qemu emulation of the pcnet hardware fixes several problems. It will now only read and write a transmit or receive descriptor once. It will correctly handle transmitting frames with more than two fragments. It will discard oversize frames instead of corrupting memory. I have tested all the changes I have made and even seen an improvement in receive performance from 1.7MB/s to 3.3MB/s. Your mileage will vary. The code could be simplified if multi-fragment frames were deleted. It appears that both Linux and Windows XP don''t use fragmented frames. The mac crc computation code was deleted, since it has never been used. The code was checking the wrong bit in the control register. I tested type 3 descriptors by modifying the linux pcnet32 driver, but did not see any difference in performance over type 2 currently used. I have not made any change to type 0 (16-bit) transmit/receive descriptors as I have no way to test the changes. Please test this as soon as possible, as I will be on vacation next week and in a class the following week. I will check email from time to time, but my ability to make changes to code will be greatly dimished. One other thing I noticed in my testing, is that if I tell a linux domU to reboot, it will reboot but not have any pcnet32 device after rebooting. By doing a shutdown, xm destroy and xm create, I was able to get around that problem. Signed-off-by: Don Fry <brazilnut@us.ibm.com> --- tools/ioemu/hw/orig.pcnet.h 2006-03-24 12:08:37.000000000 -0800 +++ tools/ioemu/hw/pcnet.h 2006-03-24 12:16:02.000000000 -0800 @@ -177,6 +177,26 @@ struct pcnet_RMD { } rmd3; }; +typedef struct PCNetState_st PCNetState; + +struct PCNetState_st { + PCIDevice dev; + NetDriverState *nd; + int mmio_io_addr, rap, isr, lnkst; + target_phys_addr_t rdra, tdra; + uint8_t prom[16]; + uint16_t csr[128]; + uint16_t bcr[32]; + uint64_t timer; + int recv_pos; + uint8_t tx_buffer[2048]; + uint8_t rx_buffer[2048]; + struct pcnet_TMD tmd; + struct pcnet_RMD crmd; + struct pcnet_RMD nrmd; + struct pcnet_RMD nnrmd; +}; + #define PRINT_TMD(T) printf( \ "TMD0 : TBADR=0x%08x\n" \ @@ -230,18 +250,17 @@ static inline void pcnet_tmd_load(PCNetS cpu_physical_memory_read(addr+4, (void *)&tmd->tmd1, 4); cpu_physical_memory_read(addr, (void *)&tmd->tmd0, 4); } else { - uint32_t xda[4]; - cpu_physical_memory_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]; - ((uint32_t *)tmd)[3] = xda[3]; + uint32_t xda[2]; + cpu_physical_memory_read(addr+4, (void *)&xda[0], sizeof(xda)); + ((uint32_t *)tmd)[0] = xda[1]; + ((uint32_t *)tmd)[1] = xda[0]; + ((uint32_t *)tmd)[2] = 0; } } static inline void pcnet_tmd_store(PCNetState *s, struct pcnet_TMD *tmd, target_phys_addr_t addr) { + tmd->tmd1.own = 0; cpu_physical_memory_set_dirty(addr); if (!BCR_SWSTYLE(s)) { uint16_t xda[4]; @@ -259,13 +278,10 @@ static inline void pcnet_tmd_store(PCNet cpu_physical_memory_write(addr+8, (void *)&tmd->tmd2, 4); cpu_physical_memory_write(addr+4, (void *)&tmd->tmd1, 4); } else { - uint32_t xda[4]; + uint32_t xda[2]; 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)); + cpu_physical_memory_write(addr, (void *)&xda[0], sizeof(xda)); } cpu_physical_memory_set_dirty(addr+15); } @@ -286,22 +302,21 @@ static inline void pcnet_rmd_load(PCNetS } else if (BCR_SWSTYLE(s) != 3) { - rmd->rmd2.zeros = 0; + ((uint32_t *)rmd)[2] = 0; cpu_physical_memory_read(addr+4, (void *)&rmd->rmd1, 4); cpu_physical_memory_read(addr, (void *)&rmd->rmd0, 4); } else { - uint32_t rda[4]; - cpu_physical_memory_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]; - ((uint32_t *)rmd)[3] = rda[3]; + uint32_t rda[2]; + cpu_physical_memory_read(addr+4, (void *)&rda[0], sizeof(rda)); + ((uint32_t *)rmd)[0] = rda[1]; + ((uint32_t *)rmd)[1] = rda[0]; + ((uint32_t *)rmd)[2] = 0; } } static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr) { + rmd->rmd1.own = 0; cpu_physical_memory_set_dirty(addr); if (!BCR_SWSTYLE(s)) { uint16_t rda[4]; \ @@ -319,13 +334,10 @@ static inline void pcnet_rmd_store(PCNet cpu_physical_memory_write(addr+8, (void *)&rmd->rmd2, 4); cpu_physical_memory_write(addr+4, (void *)&rmd->rmd1, 4); } else { - uint32_t rda[4]; + uint32_t rda[2]; 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)); + cpu_physical_memory_write(addr, (void *)&rda[0], sizeof(rda)); } cpu_physical_memory_set_dirty(addr+15); } @@ -340,79 +352,16 @@ static inline void pcnet_rmd_store(PCNet #define RMDSTORE(RMD,ADDR) pcnet_rmd_store(s,RMD,ADDR) -#if 1 - -#define CHECK_RMD(ADDR,RES) do { \ - struct pcnet_RMD rmd; \ - RMDLOAD(&rmd,(ADDR)); \ - (RES) |= (rmd.rmd1.ones != 15); \ -} while (0) - -#define CHECK_TMD(ADDR,RES) do { \ - struct pcnet_TMD tmd; \ - TMDLOAD(&tmd,(ADDR)); \ - (RES) |= (tmd.tmd1.ones != 15); \ -} while (0) - -#else - -#define CHECK_RMD(ADDR,RES) do { \ - switch (BCR_SWSTYLE(s)) { \ - case 0x00: \ - do { \ - uint16_t rda[4]; \ - cpu_physical_memory_read((ADDR), \ - (void *)&rda[0], sizeof(rda)); \ - (RES) |= (rda[2] & 0xf000)!=0xf000; \ - (RES) |= (rda[3] & 0xf000)!=0x0000; \ - } while (0); \ - break; \ - case 0x01: \ - case 0x02: \ - do { \ - uint32_t rda[4]; \ - cpu_physical_memory_read((ADDR), \ - (void *)&rda[0], sizeof(rda)); \ - (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \ - (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \ - } while (0); \ - break; \ - case 0x03: \ - do { \ - uint32_t rda[4]; \ - cpu_physical_memory_read((ADDR), \ - (void *)&rda[0], sizeof(rda)); \ - (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \ - (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \ - } while (0); \ - break; \ - } \ +#define CHECK_RMD(RMD,ADDR,RES) do { \ + RMDLOAD((RMD),(ADDR)); \ + (RES) |= ((RMD)->rmd1.ones != 15); \ } while (0) -#define CHECK_TMD(ADDR,RES) do { \ - switch (BCR_SWSTYLE(s)) { \ - case 0x00: \ - do { \ - uint16_t xda[4]; \ - cpu_physical_memory_read((ADDR), \ - (void *)&xda[0], sizeof(xda)); \ - (RES) |= (xda[2] & 0xf000)!=0xf000;\ - } while (0); \ - break; \ - case 0x01: \ - case 0x02: \ - case 0x03: \ - do { \ - uint32_t xda[4]; \ - cpu_physical_memory_read((ADDR), \ - (void *)&xda[0], sizeof(xda)); \ - (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \ - } while (0); \ - break; \ - } \ +#define CHECK_TMD(ADDR,RES) do { \ + TMDLOAD(&(s->tmd),(ADDR)); \ + (RES) |= (s->tmd.tmd1.ones != 15); \ } while (0) -#endif #define PRINT_PKTHDR(BUF) do { \ struct ether_header *hdr = (void *)(BUF); \ --- tools/ioemu/hw/orig.pcnet.c 2006-03-24 12:08:37.000000000 -0800 +++ tools/ioemu/hw/pcnet.c 2006-03-24 12:21:49.000000000 -0800 @@ -45,21 +45,6 @@ #define PCNET_PNPMMIO_SIZE 0x20 -typedef struct PCNetState_st PCNetState; - -struct PCNetState_st { - PCIDevice dev; - NetDriverState *nd; - int mmio_io_addr, rap, isr, lnkst; - target_phys_addr_t rdra, tdra; - uint8_t prom[16]; - uint16_t csr[128]; - uint16_t bcr[32]; - uint64_t timer; - int xmit_pos, recv_pos; - uint8_t buffer[4096]; -}; - #include "pcnet.h" static void pcnet_poll(PCNetState *s); @@ -217,6 +202,11 @@ static void pcnet_init(PCNetState *s) CSR_RCVRC(s) = CSR_RCVRL(s); CSR_XMTRC(s) = CSR_XMTRL(s); + /* flush any cached receive descriptors */ + s->crmd.rmd1.own = 0; + s->nrmd.rmd1.own = 0; + s->nnrmd.rmd1.own = 0; + #ifdef PCNET_DEBUG printf("pcnet ss32=%d rdra=0x%08x[%d] tdra=0x%08x[%d]\n", BCR_SSIZE32(s), @@ -239,6 +229,11 @@ static void pcnet_start(PCNetState *s) if (!CSR_DRX(s)) s->csr[0] |= 0x0020; /* set RXON */ + /* flush any cached receive descriptors */ + s->crmd.rmd1.own = 0; + s->nrmd.rmd1.own = 0; + s->nnrmd.rmd1.own = 0; + s->csr[0] &= ~0x0004; /* clear STOP bit */ s->csr[0] |= 0x0002; } @@ -260,29 +255,21 @@ static void pcnet_rdte_poll(PCNetState * s->csr[28] = s->csr[29] = 0; if (s->rdra) { int bad = 0; -#if 1 target_phys_addr_t crda = pcnet_rdra_addr(s, CSR_RCVRC(s)); target_phys_addr_t nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s)); target_phys_addr_t nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s)); -#else - target_phys_addr_t crda = s->rdra + - (CSR_RCVRL(s) - CSR_RCVRC(s)) * - (BCR_SWSTYLE(s) ? 16 : 8 ); - int nrdc = CSR_RCVRC(s)<=1 ? CSR_RCVRL(s) : CSR_RCVRC(s)-1; - target_phys_addr_t nrda = s->rdra + - (CSR_RCVRL(s) - nrdc) * - (BCR_SWSTYLE(s) ? 16 : 8 ); - int nnrc = nrdc<=1 ? CSR_RCVRL(s) : nrdc-1; - target_phys_addr_t nnrd = s->rdra + - (CSR_RCVRL(s) - nnrc) * - (BCR_SWSTYLE(s) ? 16 : 8 ); -#endif - CHECK_RMD(PHYSADDR(s,crda), bad); + if (!s->crmd.rmd1.own) { + CHECK_RMD(&(s->crmd),PHYSADDR(s,crda), bad); + } if (!bad) { - CHECK_RMD(PHYSADDR(s,nrda), bad); + if (s->crmd.rmd1.own && !s->nrmd.rmd1.own) { + CHECK_RMD(&(s->nrmd),PHYSADDR(s,nrda), bad); + } if (bad || (nrda == crda)) nrda = 0; - CHECK_RMD(PHYSADDR(s,nnrd), bad); + if (s->crmd.rmd1.own && s->nrmd.rmd1.own && !s->nnrmd.rmd1.own) { + CHECK_RMD(&(s->nnrmd),PHYSADDR(s,nnrd), bad); + } if (bad || (nnrd == crda)) nnrd = 0; s->csr[28] = crda & 0xffff; @@ -303,14 +290,12 @@ static void pcnet_rdte_poll(PCNetState * } if (CSR_CRDA(s)) { - struct pcnet_RMD rmd; - RMDLOAD(&rmd, PHYSADDR(s,CSR_CRDA(s))); - CSR_CRBC(s) = rmd.rmd1.bcnt; - CSR_CRST(s) = ((uint32_t *)&rmd)[1] >> 16; + CSR_CRBC(s) = s->crmd.rmd1.bcnt; + CSR_CRST(s) = ((uint32_t *)&(s->crmd))[1] >> 16; #ifdef PCNET_DEBUG_RMD_X printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMD1=0x%08x RMD2=0x%08x\n", PHYSADDR(s,CSR_CRDA(s)), CSR_CRST(s), CSR_RCVRC(s), - ((uint32_t *)&rmd)[1], ((uint32_t *)&rmd)[2]); + ((uint32_t *)&(s->crmd))[1], ((uint32_t *)&(s->crmd))[2]); PRINT_RMD(&rmd); #endif } else { @@ -318,10 +303,8 @@ static void pcnet_rdte_poll(PCNetState * } if (CSR_NRDA(s)) { - struct pcnet_RMD rmd; - RMDLOAD(&rmd, PHYSADDR(s,CSR_NRDA(s))); - CSR_NRBC(s) = rmd.rmd1.bcnt; - CSR_NRST(s) = ((uint32_t *)&rmd)[1] >> 16; + CSR_NRBC(s) = s->nrmd.rmd1.bcnt; + CSR_NRST(s) = ((uint32_t *)&(s->nrmd))[1] >> 16; } else { CSR_NRBC(s) = CSR_NRST(s) = 0; } @@ -336,6 +319,7 @@ static int pcnet_tdte_poll(PCNetState *s (CSR_XMTRL(s) - CSR_XMTRC(s)) * (BCR_SWSTYLE(s) ? 16 : 8 ); int bad = 0; + s->csr[0] &= ~0x0008; /* clear TDMD */ CHECK_TMD(PHYSADDR(s, cxda),bad); if (!bad) { if (CSR_CXDA(s) != cxda) { @@ -354,12 +338,8 @@ static int pcnet_tdte_poll(PCNetState *s } if (CSR_CXDA(s)) { - struct pcnet_TMD tmd; - - TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s))); - - CSR_CXBC(s) = tmd.tmd1.bcnt; - CSR_CXST(s) = ((uint32_t *)&tmd)[1] >> 16; + CSR_CXBC(s) = s->tmd.tmd1.bcnt; + CSR_CXST(s) = ((uint32_t *)&(s->tmd))[1] >> 16; } else { CSR_CXBC(s) = CSR_CXST(s) = 0; } @@ -373,14 +353,11 @@ static int pcnet_can_receive(void *opaqu if (CSR_STOP(s) || CSR_SPND(s)) return 0; - if (s->recv_pos > 0) - return 0; - pcnet_rdte_poll(s); if (!(CSR_CRST(s) & 0x8000)) { return 0; } - return sizeof(s->buffer)-16; + return sizeof(s->rx_buffer)-16; } #define MIN_BUF_SIZE 60 @@ -389,7 +366,7 @@ static void pcnet_receive(void *opaque, { PCNetState *s = opaque; int is_padr = 0, is_bcast = 0, is_ladr = 0; - uint8_t buf1[60]; + int pad; if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size) return; @@ -399,12 +376,10 @@ static void pcnet_receive(void *opaque, #endif /* if too small buffer, then expand it */ - if (size < MIN_BUF_SIZE) { - memcpy(buf1, buf, size); - memset(buf1 + size, 0, MIN_BUF_SIZE - size); - buf = buf1; - size = MIN_BUF_SIZE; - } + if (size < MIN_BUF_SIZE) + pad = MIN_BUF_SIZE - size + 4; + else + pad = 4; if (CSR_PROM(s) || (is_padr=padr_match(s, buf, size)) @@ -413,124 +388,74 @@ static void pcnet_receive(void *opaque, pcnet_rdte_poll(s); - if (!(CSR_CRST(s) & 0x8000) && s->rdra) { - struct pcnet_RMD rmd; - int rcvrc = CSR_RCVRC(s)-1,i; - target_phys_addr_t nrda; - for (i = CSR_RCVRL(s)-1; i > 0; i--, rcvrc--) { - if (rcvrc <= 1) - rcvrc = CSR_RCVRL(s); - nrda = s->rdra + - (CSR_RCVRL(s) - rcvrc) * - (BCR_SWSTYLE(s) ? 16 : 8 ); - RMDLOAD(&rmd, PHYSADDR(s,nrda)); - if (rmd.rmd1.own) { + if (size > 2000) { #ifdef PCNET_DEBUG_RMD - printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n", - rcvrc, CSR_RCVRC(s)); + printf("pcnet - oversize packet discarded.\n"); #endif - CSR_RCVRC(s) = rcvrc; - pcnet_rdte_poll(s); - break; - } - } - } - - if (!(CSR_CRST(s) & 0x8000)) { + } else if (!(CSR_CRST(s) & 0x8000)) { #ifdef PCNET_DEBUG_RMD printf("pcnet - no buffer: RCVRC=%d\n", CSR_RCVRC(s)); #endif s->csr[0] |= 0x1000; /* Set MISS flag */ CSR_MISSC(s)++; } else { - uint8_t *src = &s->buffer[8]; + uint8_t *src = &s->rx_buffer[8]; target_phys_addr_t crda = CSR_CRDA(s); - struct pcnet_RMD rmd; + target_phys_addr_t nrda = CSR_NRDA(s); + target_phys_addr_t nnrda = CSR_NNRD(s); int pktcount = 0; + int packet_size = size + pad; memcpy(src, buf, size); - - if (!CSR_ASTRP_RCV(s)) { - uint32_t fcs = ~0; -#if 0 - uint8_t *p = s->buffer; - - ((uint32_t *)p)[0] = ((uint32_t *)p)[1] = 0xaaaaaaaa; - p[7] = 0xab; -#else - uint8_t *p = src; -#endif - - while (size < 46) { - src[size++] = 0; - } - - while (p != &src[size]) { - CRC(fcs, *p++); - } - ((uint32_t *)&src[size])[0] = htonl(fcs); - size += 4; /* FCS at end of packet */ - } else size += 4; + memset(src + size, 0, pad); + size += pad; #ifdef PCNET_DEBUG_MATCH PRINT_PKTHDR(buf); #endif - RMDLOAD(&rmd, PHYSADDR(s,crda)); - /*if (!CSR_LAPPEN(s))*/ - rmd.rmd1.stp = 1; - -#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); \ - cpu_physical_memory_set_dirty(rbadr); \ - cpu_physical_memory_set_dirty(rbadr+count); \ - src += count; size -= count; \ - rmd.rmd2.mcnt = count; rmd.rmd1.own = 0; \ - RMDSTORE(&rmd, PHYSADDR(s,crda)); \ - pktcount++; \ -} while (0) - - PCNET_RECV_STORE(); - if ((size > 0) && CSR_NRDA(s)) { - target_phys_addr_t nrda = CSR_NRDA(s); - RMDLOAD(&rmd, PHYSADDR(s,nrda)); - if (rmd.rmd1.own) { - crda = nrda; - PCNET_RECV_STORE(); - if ((size > 0) && (nrda=CSR_NNRD(s))) { - RMDLOAD(&rmd, PHYSADDR(s,nrda)); - if (rmd.rmd1.own) { - crda = nrda; - PCNET_RECV_STORE(); - } - } - } - } - -#undef PCNET_RECV_STORE + s->crmd.rmd1.stp = 1; + do { + int count = MIN(4096 - s->crmd.rmd1.bcnt,size); + target_phys_addr_t rbadr = PHYSADDR(s, s->crmd.rmd0.rbadr); + cpu_physical_memory_write(rbadr, src, count); + cpu_physical_memory_set_dirty(rbadr); + cpu_physical_memory_set_dirty(rbadr+count); + src += count; size -= count; + if (size > 0 && s->nrmd.rmd1.own) { + RMDSTORE(&(s->crmd), PHYSADDR(s,crda)); + crda = nrda; + nrda = nnrda; + s->crmd = s->nrmd; + s->nrmd = s->nnrmd; + s->nnrmd.rmd1.own = 0; + } + pktcount++; + } while (size > 0 && s->crmd.rmd1.own); - RMDLOAD(&rmd, PHYSADDR(s,crda)); if (size == 0) { - rmd.rmd1.enp = 1; - rmd.rmd1.pam = !CSR_PROM(s) && is_padr; - rmd.rmd1.lafm = !CSR_PROM(s) && is_ladr; - rmd.rmd1.bam = !CSR_PROM(s) && is_bcast; + s->crmd.rmd1.enp = 1; + s->crmd.rmd2.mcnt = packet_size; + s->crmd.rmd1.pam = !CSR_PROM(s) && is_padr; + s->crmd.rmd1.lafm = !CSR_PROM(s) && is_ladr; + s->crmd.rmd1.bam = !CSR_PROM(s) && is_bcast; } else { - rmd.rmd1.oflo = 1; - rmd.rmd1.buff = 1; - rmd.rmd1.err = 1; + s->crmd.rmd1.oflo = 1; + s->crmd.rmd1.buff = 1; + s->crmd.rmd1.err = 1; } - RMDSTORE(&rmd, PHYSADDR(s,crda)); + RMDSTORE(&(s->crmd), PHYSADDR(s,crda)); s->csr[0] |= 0x0400; + s->crmd = s->nrmd; + s->nrmd = s->nnrmd; + s->nnrmd.rmd1.own = 0; #ifdef PCNET_DEBUG printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n", CSR_RCVRC(s), PHYSADDR(s,CSR_CRDA(s)), pktcount); #endif #ifdef PCNET_DEBUG_RMD - PRINT_RMD(&rmd); + PRINT_RMD(&s->crmd); #endif while (pktcount--) { @@ -551,80 +476,88 @@ static void pcnet_receive(void *opaque, static void pcnet_transmit(PCNetState *s) { - target_phys_addr_t xmit_cxda = 0; + target_phys_addr_t start_addr = 0; + struct pcnet_TMD start_tmd; int count = CSR_XMTRL(s)-1; - s->xmit_pos = -1; + int xmit_pos = 0; + int len; + if (!CSR_TXON(s)) { s->csr[0] &= ~0x0008; return; } - txagain: - if (pcnet_tdte_poll(s)) { - struct pcnet_TMD tmd; - - TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s))); + while (pcnet_tdte_poll(s)) { #ifdef PCNET_DEBUG_TMD printf(" TMDLOAD 0x%08x\n", PHYSADDR(s,CSR_CXDA(s))); - PRINT_TMD(&tmd); + PRINT_TMD(&(s->tmd)); #endif - 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->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->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt); - s->xmit_pos += 4096 - tmd.tmd1.bcnt; + len = 4096 - s->tmd.tmd1.bcnt; + if (CSR_XMTRC(s) <= 1) + CSR_XMTRC(s) = CSR_XMTRL(s); + else + CSR_XMTRC(s)--; - tmd.tmd1.own = 0; - TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s))); + /* handle start followed by start */ + if (s->tmd.tmd1.stp && start_addr) { + TMDSTORE(&start_tmd, start_addr); + start_addr = 0; + xmit_pos = 0; + } + if ((xmit_pos + len) < sizeof(s->tx_buffer)) { + cpu_physical_memory_read(PHYSADDR(s, s->tmd.tmd0.tbadr), + s->tx_buffer + xmit_pos, len); + xmit_pos += len; + } else { + s->tmd.tmd2.buff = s->tmd.tmd2.uflo = s->tmd.tmd1.err = 1; + TMDSTORE(&(s->tmd), PHYSADDR(s,CSR_CXDA(s))); + if (start_addr == PHYSADDR(s,CSR_CXDA(s))) + start_addr = 0; /* don''t clear own bit twice */ + continue; + } + if (s->tmd.tmd1.stp) { + if (s->tmd.tmd1.enp) { + if (CSR_LOOP(s)) + pcnet_receive(s, s->tx_buffer, xmit_pos); + else + qemu_send_packet(s->nd, s->tx_buffer, xmit_pos); + + s->csr[4] |= 0x0008; /* set TXSTRT */ + TMDSTORE(&(s->tmd), PHYSADDR(s,CSR_CXDA(s))); + xmit_pos = 0; + count--; + } else { + start_tmd = s->tmd; + start_addr = PHYSADDR(s,CSR_CXDA(s)); + } + } else if (s->tmd.tmd1.enp) { + TMDSTORE(&(s->tmd), PHYSADDR(s,CSR_CXDA(s))); + if (start_addr) { + TMDSTORE(&start_tmd, start_addr); + } + start_addr = 0; + xmit_pos = 0; + count--; -#ifdef PCNET_DEBUG - printf("pcnet_transmit size=%d\n", s->xmit_pos); -#endif - if (CSR_LOOP(s)) - pcnet_receive(s, s->buffer, s->xmit_pos); - else - qemu_send_packet(s->nd, s->buffer, s->xmit_pos); - - s->csr[0] &= ~0x0008; /* clear TDMD */ - s->csr[4] |= 0x0004; /* set TXSTRT */ - s->xmit_pos = -1; } else { - tmd.tmd1.own = 0; - TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s))); + TMDSTORE(&(s->tmd), PHYSADDR(s,CSR_CXDA(s))); } - if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && tmd.tmd1.ltint)) + if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && s->tmd.tmd1.ltint)) s->csr[0] |= 0x0200; /* set TINT */ - if (CSR_XMTRC(s)<=1) - CSR_XMTRC(s) = CSR_XMTRL(s); - else - CSR_XMTRC(s)--; - if (count--) - goto txagain; + if (count <= 0) + break; - } else - if (s->xmit_pos >= 0) { - struct pcnet_TMD tmd; - TMDLOAD(&tmd, PHYSADDR(s,xmit_cxda)); - tmd.tmd2.buff = tmd.tmd2.uflo = tmd.tmd1.err = 1; - tmd.tmd1.own = 0; - TMDSTORE(&tmd, PHYSADDR(s,xmit_cxda)); + } + if (start_addr) { + start_tmd.tmd2.buff = start_tmd.tmd2.uflo = start_tmd.tmd1.err = 1; + TMDSTORE(&start_tmd, PHYSADDR(s,start_addr)); s->csr[0] |= 0x0200; /* set TINT */ if (!CSR_DXSUFLO(s)) { s->csr[0] &= ~0x0010; - } else - if (count--) - goto txagain; + } } } -- Don Fry brazilnut@us.ibm.com _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Don Fry wrote:> The attached patch to the qemu emulation of the pcnet hardware fixes > several problems. It will now only read and write a transmit or receive > descriptor once. It will correctly handle transmitting frames with more > than two fragments. It will discard oversize frames instead of > corrupting memory. I have tested all the changes I have made and even > seen an improvement in receive performance from 1.7MB/s to 3.3MB/s. > Your mileage will vary.Don, the better performance due to the fact that we aren''t reading some descriptors multiple times for no good reason any more, correct?> The code could be simplified if multi-fragment frames were deleted. It > appears that both Linux and Windows XP don''t use fragmented frames.I''d suggest we keep this for at least long enough to validate that the other OSs we want to support don''t use them either. Thanks very much! thanks, Nivedita _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
This patch can *not* apply cleanly to the current tip. -Xin>-----Original Message----- >From: xen-devel-bounces@lists.xensource.com >[mailto:xen-devel-bounces@lists.xensource.com] On Behalf Of Don Fry >Sent: 2006年3月25日 4:27 >To: xen-devel@lists.xensource.com >Subject: [Xen-devel] [PATCH] qemu pcnet emulation fixes > >The attached patch to the qemu emulation of the pcnet hardware fixes >several problems. It will now only read and write a transmit >or receive >descriptor once. It will correctly handle transmitting frames >with more >than two fragments. It will discard oversize frames instead of >corrupting memory. I have tested all the changes I have made and even >seen an improvement in receive performance from 1.7MB/s to 3.3MB/s. >Your mileage will vary. > >The code could be simplified if multi-fragment frames were deleted. It >appears that both Linux and Windows XP don''t use fragmented frames. > >The mac crc computation code was deleted, since it has never been used. >The code was checking the wrong bit in the control register. > >I tested type 3 descriptors by modifying the linux pcnet32 driver, but >did not see any difference in performance over type 2 currently used. > >I have not made any change to type 0 (16-bit) transmit/receive >descriptors as I have no way to test the changes. > >Please test this as soon as possible, as I will be on vacation >next week >and in a class the following week. I will check email from time to >time, but my ability to make changes to code will be greatly dimished. > >One other thing I noticed in my testing, is that if I tell a linux domU >to reboot, it will reboot but not have any pcnet32 device after >rebooting. By doing a shutdown, xm destroy and xm create, I >was able to >get around that problem. > >Signed-off-by: Don Fry <brazilnut@us.ibm.com> > >--- tools/ioemu/hw/orig.pcnet.h 2006-03-24 >12:08:37.000000000 -0800 >+++ tools/ioemu/hw/pcnet.h 2006-03-24 12:16:02.000000000 -0800 >@@ -177,6 +177,26 @@ struct pcnet_RMD { > } rmd3; > }; > >+typedef struct PCNetState_st PCNetState; >+ >+struct PCNetState_st { >+ PCIDevice dev; >+ NetDriverState *nd; >+ int mmio_io_addr, rap, isr, lnkst; >+ target_phys_addr_t rdra, tdra; >+ uint8_t prom[16]; >+ uint16_t csr[128]; >+ uint16_t bcr[32]; >+ uint64_t timer; >+ int recv_pos; >+ uint8_t tx_buffer[2048]; >+ uint8_t rx_buffer[2048]; >+ struct pcnet_TMD tmd; >+ struct pcnet_RMD crmd; >+ struct pcnet_RMD nrmd; >+ struct pcnet_RMD nnrmd; >+}; >+ > > #define PRINT_TMD(T) printf( \ > "TMD0 : TBADR=0x%08x\n" \ >@@ -230,18 +250,17 @@ static inline void pcnet_tmd_load(PCNetS > cpu_physical_memory_read(addr+4, (void *)&tmd->tmd1, 4); > cpu_physical_memory_read(addr, (void *)&tmd->tmd0, 4); > } else { >- uint32_t xda[4]; >- cpu_physical_memory_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]; >- ((uint32_t *)tmd)[3] = xda[3]; >+ uint32_t xda[2]; >+ cpu_physical_memory_read(addr+4, (void *)&xda[0], >sizeof(xda)); >+ ((uint32_t *)tmd)[0] = xda[1]; >+ ((uint32_t *)tmd)[1] = xda[0]; >+ ((uint32_t *)tmd)[2] = 0; > } > } > > static inline void pcnet_tmd_store(PCNetState *s, struct >pcnet_TMD *tmd, target_phys_addr_t addr) > { >+ tmd->tmd1.own = 0; > cpu_physical_memory_set_dirty(addr); > if (!BCR_SWSTYLE(s)) { > uint16_t xda[4]; >@@ -259,13 +278,10 @@ static inline void pcnet_tmd_store(PCNet > cpu_physical_memory_write(addr+8, (void *)&tmd->tmd2, 4); > cpu_physical_memory_write(addr+4, (void *)&tmd->tmd1, 4); > } else { >- uint32_t xda[4]; >+ uint32_t xda[2]; > 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)); >+ cpu_physical_memory_write(addr, (void *)&xda[0], >sizeof(xda)); > } > cpu_physical_memory_set_dirty(addr+15); > } >@@ -286,22 +302,21 @@ static inline void pcnet_rmd_load(PCNetS > } > else > if (BCR_SWSTYLE(s) != 3) { >- rmd->rmd2.zeros = 0; >+ ((uint32_t *)rmd)[2] = 0; > cpu_physical_memory_read(addr+4, (void *)&rmd->rmd1, 4); > cpu_physical_memory_read(addr, (void *)&rmd->rmd0, 4); > } else { >- uint32_t rda[4]; >- cpu_physical_memory_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]; >- ((uint32_t *)rmd)[3] = rda[3]; >+ uint32_t rda[2]; >+ cpu_physical_memory_read(addr+4, (void *)&rda[0], >sizeof(rda)); >+ ((uint32_t *)rmd)[0] = rda[1]; >+ ((uint32_t *)rmd)[1] = rda[0]; >+ ((uint32_t *)rmd)[2] = 0; > } > } > > static inline void pcnet_rmd_store(PCNetState *s, struct >pcnet_RMD *rmd, target_phys_addr_t addr) > { >+ rmd->rmd1.own = 0; > cpu_physical_memory_set_dirty(addr); > if (!BCR_SWSTYLE(s)) { > uint16_t rda[4]; \ >@@ -319,13 +334,10 @@ static inline void pcnet_rmd_store(PCNet > cpu_physical_memory_write(addr+8, (void *)&rmd->rmd2, 4); > cpu_physical_memory_write(addr+4, (void *)&rmd->rmd1, 4); > } else { >- uint32_t rda[4]; >+ uint32_t rda[2]; > 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)); >+ cpu_physical_memory_write(addr, (void *)&rda[0], >sizeof(rda)); > } > cpu_physical_memory_set_dirty(addr+15); > } >@@ -340,79 +352,16 @@ static inline void pcnet_rmd_store(PCNet > > #define RMDSTORE(RMD,ADDR) pcnet_rmd_store(s,RMD,ADDR) > >-#if 1 >- >-#define CHECK_RMD(ADDR,RES) do { \ >- struct pcnet_RMD rmd; \ >- RMDLOAD(&rmd,(ADDR)); \ >- (RES) |= (rmd.rmd1.ones != 15); \ >-} while (0) >- >-#define CHECK_TMD(ADDR,RES) do { \ >- struct pcnet_TMD tmd; \ >- TMDLOAD(&tmd,(ADDR)); \ >- (RES) |= (tmd.tmd1.ones != 15); \ >-} while (0) >- >-#else >- >-#define CHECK_RMD(ADDR,RES) do { \ >- switch (BCR_SWSTYLE(s)) { \ >- case 0x00: \ >- do { \ >- uint16_t rda[4]; \ >- cpu_physical_memory_read((ADDR), \ >- (void *)&rda[0], sizeof(rda)); \ >- (RES) |= (rda[2] & 0xf000)!=0xf000; \ >- (RES) |= (rda[3] & 0xf000)!=0x0000; \ >- } while (0); \ >- break; \ >- case 0x01: \ >- case 0x02: \ >- do { \ >- uint32_t rda[4]; \ >- cpu_physical_memory_read((ADDR), \ >- (void *)&rda[0], sizeof(rda)); \ >- (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \ >- (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \ >- } while (0); \ >- break; \ >- case 0x03: \ >- do { \ >- uint32_t rda[4]; \ >- cpu_physical_memory_read((ADDR), \ >- (void *)&rda[0], sizeof(rda)); \ >- (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \ >- (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \ >- } while (0); \ >- break; \ >- } \ >+#define CHECK_RMD(RMD,ADDR,RES) do { \ >+ RMDLOAD((RMD),(ADDR)); \ >+ (RES) |= ((RMD)->rmd1.ones != 15); \ > } while (0) > >-#define CHECK_TMD(ADDR,RES) do { \ >- switch (BCR_SWSTYLE(s)) { \ >- case 0x00: \ >- do { \ >- uint16_t xda[4]; \ >- cpu_physical_memory_read((ADDR), \ >- (void *)&xda[0], sizeof(xda)); \ >- (RES) |= (xda[2] & 0xf000)!=0xf000;\ >- } while (0); \ >- break; \ >- case 0x01: \ >- case 0x02: \ >- case 0x03: \ >- do { \ >- uint32_t xda[4]; \ >- cpu_physical_memory_read((ADDR), \ >- (void *)&xda[0], sizeof(xda)); \ >- (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \ >- } while (0); \ >- break; \ >- } \ >+#define CHECK_TMD(ADDR,RES) do { \ >+ TMDLOAD(&(s->tmd),(ADDR)); \ >+ (RES) |= (s->tmd.tmd1.ones != 15); \ > } while (0) > >-#endif > > #define PRINT_PKTHDR(BUF) do { \ > struct ether_header *hdr = (void *)(BUF); \ > >--- tools/ioemu/hw/orig.pcnet.c 2006-03-24 >12:08:37.000000000 -0800 >+++ tools/ioemu/hw/pcnet.c 2006-03-24 12:21:49.000000000 -0800 >@@ -45,21 +45,6 @@ > #define PCNET_PNPMMIO_SIZE 0x20 > > >-typedef struct PCNetState_st PCNetState; >- >-struct PCNetState_st { >- PCIDevice dev; >- NetDriverState *nd; >- int mmio_io_addr, rap, isr, lnkst; >- target_phys_addr_t rdra, tdra; >- uint8_t prom[16]; >- uint16_t csr[128]; >- uint16_t bcr[32]; >- uint64_t timer; >- int xmit_pos, recv_pos; >- uint8_t buffer[4096]; >-}; >- > #include "pcnet.h" > > static void pcnet_poll(PCNetState *s); >@@ -217,6 +202,11 @@ static void pcnet_init(PCNetState *s) > CSR_RCVRC(s) = CSR_RCVRL(s); > CSR_XMTRC(s) = CSR_XMTRL(s); > >+ /* flush any cached receive descriptors */ >+ s->crmd.rmd1.own = 0; >+ s->nrmd.rmd1.own = 0; >+ s->nnrmd.rmd1.own = 0; >+ > #ifdef PCNET_DEBUG > printf("pcnet ss32=%d rdra=0x%08x[%d] tdra=0x%08x[%d]\n", > BCR_SSIZE32(s), >@@ -239,6 +229,11 @@ static void pcnet_start(PCNetState *s) > if (!CSR_DRX(s)) > s->csr[0] |= 0x0020; /* set RXON */ > >+ /* flush any cached receive descriptors */ >+ s->crmd.rmd1.own = 0; >+ s->nrmd.rmd1.own = 0; >+ s->nnrmd.rmd1.own = 0; >+ > s->csr[0] &= ~0x0004; /* clear STOP bit */ > s->csr[0] |= 0x0002; > } >@@ -260,29 +255,21 @@ static void pcnet_rdte_poll(PCNetState * > s->csr[28] = s->csr[29] = 0; > if (s->rdra) { > int bad = 0; >-#if 1 > target_phys_addr_t crda = pcnet_rdra_addr(s, CSR_RCVRC(s)); > target_phys_addr_t nrda = pcnet_rdra_addr(s, -1 + >CSR_RCVRC(s)); > target_phys_addr_t nnrd = pcnet_rdra_addr(s, -2 + >CSR_RCVRC(s)); >-#else >- target_phys_addr_t crda = s->rdra + >- (CSR_RCVRL(s) - CSR_RCVRC(s)) * >- (BCR_SWSTYLE(s) ? 16 : 8 ); >- int nrdc = CSR_RCVRC(s)<=1 ? CSR_RCVRL(s) : CSR_RCVRC(s)-1; >- target_phys_addr_t nrda = s->rdra + >- (CSR_RCVRL(s) - nrdc) * >- (BCR_SWSTYLE(s) ? 16 : 8 ); >- int nnrc = nrdc<=1 ? CSR_RCVRL(s) : nrdc-1; >- target_phys_addr_t nnrd = s->rdra + >- (CSR_RCVRL(s) - nnrc) * >- (BCR_SWSTYLE(s) ? 16 : 8 ); >-#endif > >- CHECK_RMD(PHYSADDR(s,crda), bad); >+ if (!s->crmd.rmd1.own) { >+ CHECK_RMD(&(s->crmd),PHYSADDR(s,crda), bad); >+ } > if (!bad) { >- CHECK_RMD(PHYSADDR(s,nrda), bad); >+ if (s->crmd.rmd1.own && !s->nrmd.rmd1.own) { >+ CHECK_RMD(&(s->nrmd),PHYSADDR(s,nrda), bad); >+ } > if (bad || (nrda == crda)) nrda = 0; >- CHECK_RMD(PHYSADDR(s,nnrd), bad); >+ if (s->crmd.rmd1.own && s->nrmd.rmd1.own && >!s->nnrmd.rmd1.own) { >+ CHECK_RMD(&(s->nnrmd),PHYSADDR(s,nnrd), bad); >+ } > if (bad || (nnrd == crda)) nnrd = 0; > > s->csr[28] = crda & 0xffff; >@@ -303,14 +290,12 @@ static void pcnet_rdte_poll(PCNetState * > } > > if (CSR_CRDA(s)) { >- struct pcnet_RMD rmd; >- RMDLOAD(&rmd, PHYSADDR(s,CSR_CRDA(s))); >- CSR_CRBC(s) = rmd.rmd1.bcnt; >- CSR_CRST(s) = ((uint32_t *)&rmd)[1] >> 16; >+ CSR_CRBC(s) = s->crmd.rmd1.bcnt; >+ CSR_CRST(s) = ((uint32_t *)&(s->crmd))[1] >> 16; > #ifdef PCNET_DEBUG_RMD_X > printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMD1=0x%08x >RMD2=0x%08x\n", > PHYSADDR(s,CSR_CRDA(s)), CSR_CRST(s), CSR_RCVRC(s), >- ((uint32_t *)&rmd)[1], ((uint32_t *)&rmd)[2]); >+ ((uint32_t *)&(s->crmd))[1], ((uint32_t >*)&(s->crmd))[2]); > PRINT_RMD(&rmd); > #endif > } else { >@@ -318,10 +303,8 @@ static void pcnet_rdte_poll(PCNetState * > } > > if (CSR_NRDA(s)) { >- struct pcnet_RMD rmd; >- RMDLOAD(&rmd, PHYSADDR(s,CSR_NRDA(s))); >- CSR_NRBC(s) = rmd.rmd1.bcnt; >- CSR_NRST(s) = ((uint32_t *)&rmd)[1] >> 16; >+ CSR_NRBC(s) = s->nrmd.rmd1.bcnt; >+ CSR_NRST(s) = ((uint32_t *)&(s->nrmd))[1] >> 16; > } else { > CSR_NRBC(s) = CSR_NRST(s) = 0; > } >@@ -336,6 +319,7 @@ static int pcnet_tdte_poll(PCNetState *s > (CSR_XMTRL(s) - CSR_XMTRC(s)) * > (BCR_SWSTYLE(s) ? 16 : 8 ); > int bad = 0; >+ s->csr[0] &= ~0x0008; /* clear TDMD */ > CHECK_TMD(PHYSADDR(s, cxda),bad); > if (!bad) { > if (CSR_CXDA(s) != cxda) { >@@ -354,12 +338,8 @@ static int pcnet_tdte_poll(PCNetState *s > } > > if (CSR_CXDA(s)) { >- struct pcnet_TMD tmd; >- >- TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s))); >- >- CSR_CXBC(s) = tmd.tmd1.bcnt; >- CSR_CXST(s) = ((uint32_t *)&tmd)[1] >> 16; >+ CSR_CXBC(s) = s->tmd.tmd1.bcnt; >+ CSR_CXST(s) = ((uint32_t *)&(s->tmd))[1] >> 16; > } else { > CSR_CXBC(s) = CSR_CXST(s) = 0; > } >@@ -373,14 +353,11 @@ static int pcnet_can_receive(void *opaqu > if (CSR_STOP(s) || CSR_SPND(s)) > return 0; > >- if (s->recv_pos > 0) >- return 0; >- > pcnet_rdte_poll(s); > if (!(CSR_CRST(s) & 0x8000)) { > return 0; > } >- return sizeof(s->buffer)-16; >+ return sizeof(s->rx_buffer)-16; > } > > #define MIN_BUF_SIZE 60 >@@ -389,7 +366,7 @@ static void pcnet_receive(void *opaque, > { > PCNetState *s = opaque; > int is_padr = 0, is_bcast = 0, is_ladr = 0; >- uint8_t buf1[60]; >+ int pad; > > if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size) > return; >@@ -399,12 +376,10 @@ static void pcnet_receive(void *opaque, > #endif > > /* if too small buffer, then expand it */ >- if (size < MIN_BUF_SIZE) { >- memcpy(buf1, buf, size); >- memset(buf1 + size, 0, MIN_BUF_SIZE - size); >- buf = buf1; >- size = MIN_BUF_SIZE; >- } >+ if (size < MIN_BUF_SIZE) >+ pad = MIN_BUF_SIZE - size + 4; >+ else >+ pad = 4; > > if (CSR_PROM(s) > || (is_padr=padr_match(s, buf, size)) >@@ -413,124 +388,74 @@ static void pcnet_receive(void *opaque, > > pcnet_rdte_poll(s); > >- if (!(CSR_CRST(s) & 0x8000) && s->rdra) { >- struct pcnet_RMD rmd; >- int rcvrc = CSR_RCVRC(s)-1,i; >- target_phys_addr_t nrda; >- for (i = CSR_RCVRL(s)-1; i > 0; i--, rcvrc--) { >- if (rcvrc <= 1) >- rcvrc = CSR_RCVRL(s); >- nrda = s->rdra + >- (CSR_RCVRL(s) - rcvrc) * >- (BCR_SWSTYLE(s) ? 16 : 8 ); >- RMDLOAD(&rmd, PHYSADDR(s,nrda)); >- if (rmd.rmd1.own) { >+ if (size > 2000) { > #ifdef PCNET_DEBUG_RMD >- printf("pcnet - scan buffer: RCVRC=%d >PREV_RCVRC=%d\n", >- rcvrc, CSR_RCVRC(s)); >+ printf("pcnet - oversize packet discarded.\n"); > #endif >- CSR_RCVRC(s) = rcvrc; >- pcnet_rdte_poll(s); >- break; >- } >- } >- } >- >- if (!(CSR_CRST(s) & 0x8000)) { >+ } else if (!(CSR_CRST(s) & 0x8000)) { > #ifdef PCNET_DEBUG_RMD > printf("pcnet - no buffer: RCVRC=%d\n", CSR_RCVRC(s)); > #endif > s->csr[0] |= 0x1000; /* Set MISS flag */ > CSR_MISSC(s)++; > } else { >- uint8_t *src = &s->buffer[8]; >+ uint8_t *src = &s->rx_buffer[8]; > target_phys_addr_t crda = CSR_CRDA(s); >- struct pcnet_RMD rmd; >+ target_phys_addr_t nrda = CSR_NRDA(s); >+ target_phys_addr_t nnrda = CSR_NNRD(s); > int pktcount = 0; >+ int packet_size = size + pad; > > memcpy(src, buf, size); >- >- if (!CSR_ASTRP_RCV(s)) { >- uint32_t fcs = ~0; >-#if 0 >- uint8_t *p = s->buffer; >- >- ((uint32_t *)p)[0] = ((uint32_t *)p)[1] = 0xaaaaaaaa; >- p[7] = 0xab; >-#else >- uint8_t *p = src; >-#endif >- >- while (size < 46) { >- src[size++] = 0; >- } >- >- while (p != &src[size]) { >- CRC(fcs, *p++); >- } >- ((uint32_t *)&src[size])[0] = htonl(fcs); >- size += 4; /* FCS at end of packet */ >- } else size += 4; >+ memset(src + size, 0, pad); >+ size += pad; > > #ifdef PCNET_DEBUG_MATCH > PRINT_PKTHDR(buf); > #endif > >- RMDLOAD(&rmd, PHYSADDR(s,crda)); >- /*if (!CSR_LAPPEN(s))*/ >- rmd.rmd1.stp = 1; >- >-#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); \ >- cpu_physical_memory_set_dirty(rbadr); \ >- cpu_physical_memory_set_dirty(rbadr+count); \ >- src += count; size -= count; \ >- rmd.rmd2.mcnt = count; rmd.rmd1.own = 0; \ >- RMDSTORE(&rmd, PHYSADDR(s,crda)); \ >- pktcount++; \ >-} while (0) >- >- PCNET_RECV_STORE(); >- if ((size > 0) && CSR_NRDA(s)) { >- target_phys_addr_t nrda = CSR_NRDA(s); >- RMDLOAD(&rmd, PHYSADDR(s,nrda)); >- if (rmd.rmd1.own) { >- crda = nrda; >- PCNET_RECV_STORE(); >- if ((size > 0) && (nrda=CSR_NNRD(s))) { >- RMDLOAD(&rmd, PHYSADDR(s,nrda)); >- if (rmd.rmd1.own) { >- crda = nrda; >- PCNET_RECV_STORE(); >- } >- } >- } >- } >- >-#undef PCNET_RECV_STORE >+ s->crmd.rmd1.stp = 1; >+ do { >+ int count = MIN(4096 - s->crmd.rmd1.bcnt,size); >+ target_phys_addr_t rbadr = PHYSADDR(s, >s->crmd.rmd0.rbadr); >+ cpu_physical_memory_write(rbadr, src, count); >+ cpu_physical_memory_set_dirty(rbadr); >+ cpu_physical_memory_set_dirty(rbadr+count); >+ src += count; size -= count; >+ if (size > 0 && s->nrmd.rmd1.own) { >+ RMDSTORE(&(s->crmd), PHYSADDR(s,crda)); >+ crda = nrda; >+ nrda = nnrda; >+ s->crmd = s->nrmd; >+ s->nrmd = s->nnrmd; >+ s->nnrmd.rmd1.own = 0; >+ } >+ pktcount++; >+ } while (size > 0 && s->crmd.rmd1.own); > >- RMDLOAD(&rmd, PHYSADDR(s,crda)); > if (size == 0) { >- rmd.rmd1.enp = 1; >- rmd.rmd1.pam = !CSR_PROM(s) && is_padr; >- rmd.rmd1.lafm = !CSR_PROM(s) && is_ladr; >- rmd.rmd1.bam = !CSR_PROM(s) && is_bcast; >+ s->crmd.rmd1.enp = 1; >+ s->crmd.rmd2.mcnt = packet_size; >+ s->crmd.rmd1.pam = !CSR_PROM(s) && is_padr; >+ s->crmd.rmd1.lafm = !CSR_PROM(s) && is_ladr; >+ s->crmd.rmd1.bam = !CSR_PROM(s) && is_bcast; > } else { >- rmd.rmd1.oflo = 1; >- rmd.rmd1.buff = 1; >- rmd.rmd1.err = 1; >+ s->crmd.rmd1.oflo = 1; >+ s->crmd.rmd1.buff = 1; >+ s->crmd.rmd1.err = 1; > } >- RMDSTORE(&rmd, PHYSADDR(s,crda)); >+ RMDSTORE(&(s->crmd), PHYSADDR(s,crda)); > s->csr[0] |= 0x0400; >+ s->crmd = s->nrmd; >+ s->nrmd = s->nnrmd; >+ s->nnrmd.rmd1.own = 0; > > #ifdef PCNET_DEBUG > printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n", > CSR_RCVRC(s), PHYSADDR(s,CSR_CRDA(s)), pktcount); > #endif > #ifdef PCNET_DEBUG_RMD >- PRINT_RMD(&rmd); >+ PRINT_RMD(&s->crmd); > #endif > > while (pktcount--) { >@@ -551,80 +476,88 @@ static void pcnet_receive(void *opaque, > > static void pcnet_transmit(PCNetState *s) > { >- target_phys_addr_t xmit_cxda = 0; >+ target_phys_addr_t start_addr = 0; >+ struct pcnet_TMD start_tmd; > int count = CSR_XMTRL(s)-1; >- s->xmit_pos = -1; >+ int xmit_pos = 0; >+ int len; >+ > > if (!CSR_TXON(s)) { > s->csr[0] &= ~0x0008; > return; > } > >- txagain: >- if (pcnet_tdte_poll(s)) { >- struct pcnet_TMD tmd; >- >- TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s))); >+ while (pcnet_tdte_poll(s)) { > > #ifdef PCNET_DEBUG_TMD > printf(" TMDLOAD 0x%08x\n", PHYSADDR(s,CSR_CXDA(s))); >- PRINT_TMD(&tmd); >+ PRINT_TMD(&(s->tmd)); > #endif >- 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->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->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt); >- s->xmit_pos += 4096 - tmd.tmd1.bcnt; >+ len = 4096 - s->tmd.tmd1.bcnt; >+ if (CSR_XMTRC(s) <= 1) >+ CSR_XMTRC(s) = CSR_XMTRL(s); >+ else >+ CSR_XMTRC(s)--; > >- tmd.tmd1.own = 0; >- TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s))); >+ /* handle start followed by start */ >+ if (s->tmd.tmd1.stp && start_addr) { >+ TMDSTORE(&start_tmd, start_addr); >+ start_addr = 0; >+ xmit_pos = 0; >+ } >+ if ((xmit_pos + len) < sizeof(s->tx_buffer)) { >+ cpu_physical_memory_read(PHYSADDR(s, s->tmd.tmd0.tbadr), >+ s->tx_buffer + xmit_pos, len); >+ xmit_pos += len; >+ } else { >+ s->tmd.tmd2.buff = s->tmd.tmd2.uflo = s->tmd.tmd1.err = 1; >+ TMDSTORE(&(s->tmd), PHYSADDR(s,CSR_CXDA(s))); >+ if (start_addr == PHYSADDR(s,CSR_CXDA(s))) >+ start_addr = 0; /* don''t clear own bit twice */ >+ continue; >+ } >+ if (s->tmd.tmd1.stp) { >+ if (s->tmd.tmd1.enp) { >+ if (CSR_LOOP(s)) >+ pcnet_receive(s, s->tx_buffer, xmit_pos); >+ else >+ qemu_send_packet(s->nd, s->tx_buffer, xmit_pos); >+ >+ s->csr[4] |= 0x0008; /* set TXSTRT */ >+ TMDSTORE(&(s->tmd), PHYSADDR(s,CSR_CXDA(s))); >+ xmit_pos = 0; >+ count--; >+ } else { >+ start_tmd = s->tmd; >+ start_addr = PHYSADDR(s,CSR_CXDA(s)); >+ } >+ } else if (s->tmd.tmd1.enp) { >+ TMDSTORE(&(s->tmd), PHYSADDR(s,CSR_CXDA(s))); >+ if (start_addr) { >+ TMDSTORE(&start_tmd, start_addr); >+ } >+ start_addr = 0; >+ xmit_pos = 0; >+ count--; > >-#ifdef PCNET_DEBUG >- printf("pcnet_transmit size=%d\n", s->xmit_pos); >-#endif >- if (CSR_LOOP(s)) >- pcnet_receive(s, s->buffer, s->xmit_pos); >- else >- qemu_send_packet(s->nd, s->buffer, s->xmit_pos); >- >- s->csr[0] &= ~0x0008; /* clear TDMD */ >- s->csr[4] |= 0x0004; /* set TXSTRT */ >- s->xmit_pos = -1; > } else { >- tmd.tmd1.own = 0; >- TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s))); >+ TMDSTORE(&(s->tmd), PHYSADDR(s,CSR_CXDA(s))); > } >- if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && tmd.tmd1.ltint)) >+ if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && s->tmd.tmd1.ltint)) > s->csr[0] |= 0x0200; /* set TINT */ > >- if (CSR_XMTRC(s)<=1) >- CSR_XMTRC(s) = CSR_XMTRL(s); >- else >- CSR_XMTRC(s)--; >- if (count--) >- goto txagain; >+ if (count <= 0) >+ break; > >- } else >- if (s->xmit_pos >= 0) { >- struct pcnet_TMD tmd; >- TMDLOAD(&tmd, PHYSADDR(s,xmit_cxda)); >- tmd.tmd2.buff = tmd.tmd2.uflo = tmd.tmd1.err = 1; >- tmd.tmd1.own = 0; >- TMDSTORE(&tmd, PHYSADDR(s,xmit_cxda)); >+ } >+ if (start_addr) { >+ start_tmd.tmd2.buff = start_tmd.tmd2.uflo = >start_tmd.tmd1.err = 1; >+ TMDSTORE(&start_tmd, PHYSADDR(s,start_addr)); > s->csr[0] |= 0x0200; /* set TINT */ > if (!CSR_DXSUFLO(s)) { > s->csr[0] &= ~0x0010; >- } else >- if (count--) >- goto txagain; >+ } > } > } > > >-- >Don Fry >brazilnut@us.ibm.com > >_______________________________________________ >Xen-devel mailing list >Xen-devel@lists.xensource.com >http://lists.xensource.com/xen-devel >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel