[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] RE: [Xen-devel] [PATCH] qemu pcnet emulation fixes
This patch can *not* apply cleanly to the current tip. -Xin >-----Original Message----- >From: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx >[mailto:xen-devel-bounces@xxxxxxxxxxxxxxxxxxx] On Behalf Of Don Fry >Sent: 2006年3月25日 4:27 >To: xen-devel@xxxxxxxxxxxxxxxxxxx >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@xxxxxxxxxx> > >--- 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@xxxxxxxxxx > >_______________________________________________ >Xen-devel mailing list >Xen-devel@xxxxxxxxxxxxxxxxxxx >http://lists.xensource.com/xen-devel > _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |