[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: [Xen-devel] [PATCH] qemu pcnet emulation fixes


  • To: "Don Fry" <brazilnut@xxxxxxxxxx>, <xen-devel@xxxxxxxxxxxxxxxxxxx>
  • From: "Li, Xin B" <xin.b.li@xxxxxxxxx>
  • Date: Sat, 25 Mar 2006 11:35:46 +0800
  • Delivery-date: Sat, 25 Mar 2006 03:37:18 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xensource.com>
  • Thread-index: AcZPgVMQ0iSe8vF7TmqbMe6t5NrUBgAO89kw
  • Thread-topic: [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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.