ia64/xen-unstable

changeset 9455:c848b80c0b20

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>
author kaf24@firebug.cl.cam.ac.uk
date Sun Mar 26 11:39:04 2006 +0100 (2006-03-26)
parents 38c170be0e63
children 1e5788066d1f
files tools/ioemu/hw/pcnet.c tools/ioemu/hw/pcnet.h
line diff
     1.1 --- a/tools/ioemu/hw/pcnet.c	Sun Mar 26 11:35:11 2006 +0100
     1.2 +++ b/tools/ioemu/hw/pcnet.c	Sun Mar 26 11:39:04 2006 +0100
     1.3 @@ -45,21 +45,6 @@
     1.4  #define PCNET_PNPMMIO_SIZE      0x20
     1.5  
     1.6  
     1.7 -typedef struct PCNetState_st PCNetState;
     1.8 -
     1.9 -struct PCNetState_st {
    1.10 -    PCIDevice dev;
    1.11 -    NetDriverState *nd;
    1.12 -    int mmio_io_addr, rap, isr, lnkst;
    1.13 -    target_phys_addr_t rdra, tdra;
    1.14 -    uint8_t prom[16];
    1.15 -    uint16_t csr[128];
    1.16 -    uint16_t bcr[32];
    1.17 -    uint64_t timer;
    1.18 -    int xmit_pos, recv_pos;
    1.19 -    uint8_t buffer[4096];
    1.20 -};
    1.21 -
    1.22  #include "pcnet.h"
    1.23  
    1.24  static void pcnet_poll(PCNetState *s);
    1.25 @@ -217,6 +202,11 @@ static void pcnet_init(PCNetState *s)
    1.26      CSR_RCVRC(s) = CSR_RCVRL(s);
    1.27      CSR_XMTRC(s) = CSR_XMTRL(s);
    1.28  
    1.29 +    /* flush any cached receive descriptors */
    1.30 +    s->crmd.rmd1.own = 0;
    1.31 +    s->nrmd.rmd1.own = 0;
    1.32 +    s->nnrmd.rmd1.own = 0;
    1.33 +
    1.34  #ifdef PCNET_DEBUG
    1.35      printf("pcnet ss32=%d rdra=0x%08x[%d] tdra=0x%08x[%d]\n", 
    1.36          BCR_SSIZE32(s),
    1.37 @@ -239,6 +229,11 @@ static void pcnet_start(PCNetState *s)
    1.38      if (!CSR_DRX(s))
    1.39          s->csr[0] |= 0x0020;    /* set RXON */
    1.40  
    1.41 +    /* flush any cached receive descriptors */
    1.42 +    s->crmd.rmd1.own = 0;
    1.43 +    s->nrmd.rmd1.own = 0;
    1.44 +    s->nnrmd.rmd1.own = 0;
    1.45 +
    1.46      s->csr[0] &= ~0x0004;       /* clear STOP bit */
    1.47      s->csr[0] |= 0x0002;
    1.48  }
    1.49 @@ -260,29 +255,21 @@ static void pcnet_rdte_poll(PCNetState *
    1.50      s->csr[28] = s->csr[29] = 0;
    1.51      if (s->rdra) {
    1.52          int bad = 0;
    1.53 -#if 1
    1.54          target_phys_addr_t crda = pcnet_rdra_addr(s, CSR_RCVRC(s));
    1.55          target_phys_addr_t nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s));
    1.56          target_phys_addr_t nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s));
    1.57 -#else
    1.58 -        target_phys_addr_t crda = s->rdra + 
    1.59 -            (CSR_RCVRL(s) - CSR_RCVRC(s)) *
    1.60 -            (BCR_SWSTYLE(s) ? 16 : 8 );
    1.61 -        int nrdc = CSR_RCVRC(s)<=1 ? CSR_RCVRL(s) : CSR_RCVRC(s)-1;
    1.62 -        target_phys_addr_t nrda = s->rdra + 
    1.63 -            (CSR_RCVRL(s) - nrdc) *
    1.64 -            (BCR_SWSTYLE(s) ? 16 : 8 );
    1.65 -        int nnrc = nrdc<=1 ? CSR_RCVRL(s) : nrdc-1;
    1.66 -        target_phys_addr_t nnrd = s->rdra + 
    1.67 -            (CSR_RCVRL(s) - nnrc) *
    1.68 -            (BCR_SWSTYLE(s) ? 16 : 8 );
    1.69 -#endif
    1.70  
    1.71 -        CHECK_RMD(PHYSADDR(s,crda), bad);
    1.72 +	if (!s->crmd.rmd1.own) {
    1.73 +	    CHECK_RMD(&(s->crmd),PHYSADDR(s,crda), bad);
    1.74 +	}
    1.75          if (!bad) {
    1.76 -            CHECK_RMD(PHYSADDR(s,nrda), bad);
    1.77 +	    if (s->crmd.rmd1.own && !s->nrmd.rmd1.own) {
    1.78 +		CHECK_RMD(&(s->nrmd),PHYSADDR(s,nrda), bad);
    1.79 +	    }
    1.80              if (bad || (nrda == crda)) nrda = 0;
    1.81 -            CHECK_RMD(PHYSADDR(s,nnrd), bad);
    1.82 +	    if (s->crmd.rmd1.own && s->nrmd.rmd1.own && !s->nnrmd.rmd1.own) {
    1.83 +		CHECK_RMD(&(s->nnrmd),PHYSADDR(s,nnrd), bad);
    1.84 +	    }
    1.85              if (bad || (nnrd == crda)) nnrd = 0;
    1.86  
    1.87              s->csr[28] = crda & 0xffff;
    1.88 @@ -303,14 +290,12 @@ static void pcnet_rdte_poll(PCNetState *
    1.89      }
    1.90      
    1.91      if (CSR_CRDA(s)) {
    1.92 -        struct pcnet_RMD rmd;
    1.93 -        RMDLOAD(&rmd, PHYSADDR(s,CSR_CRDA(s)));
    1.94 -        CSR_CRBC(s) = rmd.rmd1.bcnt;
    1.95 -        CSR_CRST(s) = ((uint32_t *)&rmd)[1] >> 16;
    1.96 +        CSR_CRBC(s) = s->crmd.rmd1.bcnt;
    1.97 +        CSR_CRST(s) = ((uint32_t *)&(s->crmd))[1] >> 16;
    1.98  #ifdef PCNET_DEBUG_RMD_X
    1.99          printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMD1=0x%08x RMD2=0x%08x\n",
   1.100                  PHYSADDR(s,CSR_CRDA(s)), CSR_CRST(s), CSR_RCVRC(s),
   1.101 -                ((uint32_t *)&rmd)[1], ((uint32_t *)&rmd)[2]);
   1.102 +                ((uint32_t *)&(s->crmd))[1], ((uint32_t *)&(s->crmd))[2]);
   1.103          PRINT_RMD(&rmd);
   1.104  #endif
   1.105      } else {
   1.106 @@ -318,10 +303,8 @@ static void pcnet_rdte_poll(PCNetState *
   1.107      }
   1.108      
   1.109      if (CSR_NRDA(s)) {
   1.110 -        struct pcnet_RMD rmd;
   1.111 -        RMDLOAD(&rmd, PHYSADDR(s,CSR_NRDA(s)));
   1.112 -        CSR_NRBC(s) = rmd.rmd1.bcnt;
   1.113 -        CSR_NRST(s) = ((uint32_t *)&rmd)[1] >> 16;
   1.114 +        CSR_NRBC(s) = s->nrmd.rmd1.bcnt;
   1.115 +        CSR_NRST(s) = ((uint32_t *)&(s->nrmd))[1] >> 16;
   1.116      } else {
   1.117          CSR_NRBC(s) = CSR_NRST(s) = 0;
   1.118      }
   1.119 @@ -336,6 +319,7 @@ static int pcnet_tdte_poll(PCNetState *s
   1.120              (CSR_XMTRL(s) - CSR_XMTRC(s)) *
   1.121              (BCR_SWSTYLE(s) ? 16 : 8 );
   1.122          int bad = 0;
   1.123 +	s->csr[0] &= ~0x0008;   /* clear TDMD */
   1.124          CHECK_TMD(PHYSADDR(s, cxda),bad);
   1.125          if (!bad) {
   1.126              if (CSR_CXDA(s) != cxda) {
   1.127 @@ -354,12 +338,8 @@ static int pcnet_tdte_poll(PCNetState *s
   1.128      }
   1.129  
   1.130      if (CSR_CXDA(s)) {
   1.131 -        struct pcnet_TMD tmd;
   1.132 -
   1.133 -        TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));                
   1.134 -
   1.135 -        CSR_CXBC(s) = tmd.tmd1.bcnt;
   1.136 -        CSR_CXST(s) = ((uint32_t *)&tmd)[1] >> 16;
   1.137 +        CSR_CXBC(s) = s->tmd.tmd1.bcnt;
   1.138 +        CSR_CXST(s) = ((uint32_t *)&(s->tmd))[1] >> 16;
   1.139      } else {
   1.140          CSR_CXBC(s) = CSR_CXST(s) = 0;
   1.141      }
   1.142 @@ -373,14 +353,11 @@ static int pcnet_can_receive(void *opaqu
   1.143      if (CSR_STOP(s) || CSR_SPND(s))
   1.144          return 0;
   1.145          
   1.146 -    if (s->recv_pos > 0)
   1.147 -        return 0;
   1.148 -
   1.149      pcnet_rdte_poll(s);
   1.150      if (!(CSR_CRST(s) & 0x8000)) {
   1.151          return 0;
   1.152      }
   1.153 -    return sizeof(s->buffer)-16;
   1.154 +    return sizeof(s->rx_buffer)-16;
   1.155  }
   1.156  
   1.157  #define MIN_BUF_SIZE 60
   1.158 @@ -389,7 +366,7 @@ static void pcnet_receive(void *opaque, 
   1.159  {
   1.160      PCNetState *s = opaque;
   1.161      int is_padr = 0, is_bcast = 0, is_ladr = 0;
   1.162 -    uint8_t buf1[60];
   1.163 +    int pad;
   1.164  
   1.165      if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size)
   1.166          return;
   1.167 @@ -399,12 +376,10 @@ static void pcnet_receive(void *opaque, 
   1.168  #endif
   1.169  
   1.170      /* if too small buffer, then expand it */
   1.171 -    if (size < MIN_BUF_SIZE) {
   1.172 -        memcpy(buf1, buf, size);
   1.173 -        memset(buf1 + size, 0, MIN_BUF_SIZE - size);
   1.174 -        buf = buf1;
   1.175 -        size = MIN_BUF_SIZE;
   1.176 -    }
   1.177 +    if (size < MIN_BUF_SIZE)
   1.178 +        pad = MIN_BUF_SIZE - size + 4;
   1.179 +    else 
   1.180 +	pad = 4;
   1.181  
   1.182      if (CSR_PROM(s) 
   1.183          || (is_padr=padr_match(s, buf, size)) 
   1.184 @@ -413,124 +388,74 @@ static void pcnet_receive(void *opaque, 
   1.185  
   1.186          pcnet_rdte_poll(s);
   1.187  
   1.188 -        if (!(CSR_CRST(s) & 0x8000) && s->rdra) {
   1.189 -            struct pcnet_RMD rmd;
   1.190 -            int rcvrc = CSR_RCVRC(s)-1,i;
   1.191 -            target_phys_addr_t nrda;
   1.192 -            for (i = CSR_RCVRL(s)-1; i > 0; i--, rcvrc--) {
   1.193 -                if (rcvrc <= 1)
   1.194 -                    rcvrc = CSR_RCVRL(s);
   1.195 -                nrda = s->rdra +
   1.196 -                    (CSR_RCVRL(s) - rcvrc) *
   1.197 -                    (BCR_SWSTYLE(s) ? 16 : 8 );
   1.198 -                RMDLOAD(&rmd, PHYSADDR(s,nrda));                  
   1.199 -                if (rmd.rmd1.own) {                
   1.200 +	if (size > 2000) {
   1.201  #ifdef PCNET_DEBUG_RMD
   1.202 -                    printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n", 
   1.203 -                                rcvrc, CSR_RCVRC(s));
   1.204 +	    printf("pcnet - oversize packet discarded.\n");
   1.205  #endif
   1.206 -                    CSR_RCVRC(s) = rcvrc;
   1.207 -                    pcnet_rdte_poll(s);
   1.208 -                    break;
   1.209 -                }
   1.210 -            }
   1.211 -        }
   1.212 -
   1.213 -        if (!(CSR_CRST(s) & 0x8000)) {
   1.214 +	} else if (!(CSR_CRST(s) & 0x8000)) {
   1.215  #ifdef PCNET_DEBUG_RMD
   1.216              printf("pcnet - no buffer: RCVRC=%d\n", CSR_RCVRC(s));
   1.217  #endif
   1.218              s->csr[0] |= 0x1000; /* Set MISS flag */
   1.219              CSR_MISSC(s)++;
   1.220          } else {
   1.221 -            uint8_t *src = &s->buffer[8];
   1.222 +            uint8_t *src = &s->rx_buffer[8];
   1.223              target_phys_addr_t crda = CSR_CRDA(s);
   1.224 -            struct pcnet_RMD rmd;
   1.225 +            target_phys_addr_t nrda = CSR_NRDA(s);
   1.226 +            target_phys_addr_t nnrda = CSR_NNRD(s);
   1.227              int pktcount = 0;
   1.228 +	    int packet_size = size + pad;
   1.229  
   1.230              memcpy(src, buf, size);
   1.231 -            
   1.232 -            if (!CSR_ASTRP_RCV(s)) {
   1.233 -                uint32_t fcs = ~0;
   1.234 -#if 0            
   1.235 -                uint8_t *p = s->buffer;
   1.236 -                
   1.237 -                ((uint32_t *)p)[0] = ((uint32_t *)p)[1] = 0xaaaaaaaa;
   1.238 -                p[7] = 0xab;
   1.239 -#else
   1.240 -                uint8_t *p = src;
   1.241 -#endif
   1.242 -
   1.243 -                while (size < 46) {
   1.244 -                    src[size++] = 0;
   1.245 -                }
   1.246 -                
   1.247 -                while (p != &src[size]) {
   1.248 -                    CRC(fcs, *p++);
   1.249 -                }
   1.250 -                ((uint32_t *)&src[size])[0] = htonl(fcs);
   1.251 -                size += 4; /* FCS at end of packet */
   1.252 -            } else size += 4;
   1.253 +	    memset(src + size, 0, pad); 
   1.254 +            size += pad;
   1.255  
   1.256  #ifdef PCNET_DEBUG_MATCH
   1.257              PRINT_PKTHDR(buf);
   1.258  #endif
   1.259  
   1.260 -            RMDLOAD(&rmd, PHYSADDR(s,crda));
   1.261 -            /*if (!CSR_LAPPEN(s))*/
   1.262 -                rmd.rmd1.stp = 1;
   1.263 -
   1.264 -#define PCNET_RECV_STORE() do {                                 \
   1.265 -    int count = MIN(4096 - rmd.rmd1.bcnt,size);                 \
   1.266 -    target_phys_addr_t rbadr = PHYSADDR(s, rmd.rmd0.rbadr);     \
   1.267 -    cpu_physical_memory_write(rbadr, src, count);               \
   1.268 -    cpu_physical_memory_set_dirty(rbadr);                       \
   1.269 -    cpu_physical_memory_set_dirty(rbadr+count);                 \
   1.270 -    src += count; size -= count;                                \
   1.271 -    rmd.rmd2.mcnt = count; rmd.rmd1.own = 0;                    \
   1.272 -    RMDSTORE(&rmd, PHYSADDR(s,crda));                           \
   1.273 -    pktcount++;                                                 \
   1.274 -} while (0)
   1.275 +	    s->crmd.rmd1.stp = 1;
   1.276 +	    do {
   1.277 +		int count = MIN(4096 - s->crmd.rmd1.bcnt,size);
   1.278 +		target_phys_addr_t rbadr = PHYSADDR(s, s->crmd.rmd0.rbadr);
   1.279 +		cpu_physical_memory_write(rbadr, src, count);
   1.280 +		cpu_physical_memory_set_dirty(rbadr);
   1.281 +		cpu_physical_memory_set_dirty(rbadr+count);
   1.282 +		src += count; size -= count;
   1.283 +		if (size > 0 && s->nrmd.rmd1.own) {
   1.284 +		    RMDSTORE(&(s->crmd), PHYSADDR(s,crda));
   1.285 +		    crda = nrda;
   1.286 +		    nrda = nnrda;
   1.287 +		    s->crmd = s->nrmd;
   1.288 +		    s->nrmd = s->nnrmd;
   1.289 +		    s->nnrmd.rmd1.own = 0;
   1.290 +		}
   1.291 +		pktcount++;
   1.292 +	    } while (size > 0 && s->crmd.rmd1.own);
   1.293  
   1.294 -            PCNET_RECV_STORE();
   1.295 -            if ((size > 0) && CSR_NRDA(s)) {
   1.296 -                target_phys_addr_t nrda = CSR_NRDA(s);
   1.297 -                RMDLOAD(&rmd, PHYSADDR(s,nrda));
   1.298 -                if (rmd.rmd1.own) {
   1.299 -                    crda = nrda;
   1.300 -                    PCNET_RECV_STORE();
   1.301 -                    if ((size > 0) && (nrda=CSR_NNRD(s))) {
   1.302 -                        RMDLOAD(&rmd, PHYSADDR(s,nrda));
   1.303 -                        if (rmd.rmd1.own) {
   1.304 -                            crda = nrda;
   1.305 -                            PCNET_RECV_STORE();
   1.306 -                        }
   1.307 -                    }
   1.308 -                }                
   1.309 +            if (size == 0) {
   1.310 +                s->crmd.rmd1.enp = 1;
   1.311 +		s->crmd.rmd2.mcnt = packet_size;
   1.312 +                s->crmd.rmd1.pam = !CSR_PROM(s) && is_padr;
   1.313 +                s->crmd.rmd1.lafm = !CSR_PROM(s) && is_ladr;
   1.314 +                s->crmd.rmd1.bam = !CSR_PROM(s) && is_bcast;
   1.315 +            } else {
   1.316 +                s->crmd.rmd1.oflo = 1;
   1.317 +                s->crmd.rmd1.buff = 1;
   1.318 +                s->crmd.rmd1.err = 1;
   1.319              }
   1.320 -
   1.321 -#undef PCNET_RECV_STORE
   1.322 -
   1.323 -            RMDLOAD(&rmd, PHYSADDR(s,crda));
   1.324 -            if (size == 0) {
   1.325 -                rmd.rmd1.enp = 1;
   1.326 -                rmd.rmd1.pam = !CSR_PROM(s) && is_padr;
   1.327 -                rmd.rmd1.lafm = !CSR_PROM(s) && is_ladr;
   1.328 -                rmd.rmd1.bam = !CSR_PROM(s) && is_bcast;
   1.329 -            } else {
   1.330 -                rmd.rmd1.oflo = 1;
   1.331 -                rmd.rmd1.buff = 1;
   1.332 -                rmd.rmd1.err = 1;
   1.333 -            }
   1.334 -            RMDSTORE(&rmd, PHYSADDR(s,crda));
   1.335 +            RMDSTORE(&(s->crmd), PHYSADDR(s,crda));
   1.336              s->csr[0] |= 0x0400;
   1.337 +	    s->crmd = s->nrmd;
   1.338 +	    s->nrmd = s->nnrmd;
   1.339 +	    s->nnrmd.rmd1.own = 0;
   1.340  
   1.341  #ifdef PCNET_DEBUG
   1.342              printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n", 
   1.343                  CSR_RCVRC(s), PHYSADDR(s,CSR_CRDA(s)), pktcount);
   1.344  #endif
   1.345  #ifdef PCNET_DEBUG_RMD
   1.346 -            PRINT_RMD(&rmd);
   1.347 +            PRINT_RMD(&s->crmd);
   1.348  #endif        
   1.349  
   1.350              while (pktcount--) {
   1.351 @@ -551,80 +476,88 @@ static void pcnet_receive(void *opaque, 
   1.352  
   1.353  static void pcnet_transmit(PCNetState *s)
   1.354  {
   1.355 -    target_phys_addr_t xmit_cxda = 0;
   1.356 +    target_phys_addr_t start_addr = 0;
   1.357 +    struct pcnet_TMD start_tmd;
   1.358      int count = CSR_XMTRL(s)-1;
   1.359 -    s->xmit_pos = -1;
   1.360 +    int xmit_pos = 0;
   1.361 +    int len;
   1.362 +
   1.363      
   1.364      if (!CSR_TXON(s)) {
   1.365          s->csr[0] &= ~0x0008;
   1.366          return;
   1.367      }
   1.368      
   1.369 -    txagain:
   1.370 -    if (pcnet_tdte_poll(s)) {
   1.371 -        struct pcnet_TMD tmd;
   1.372 -
   1.373 -        TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));                
   1.374 +    while (pcnet_tdte_poll(s)) {
   1.375  
   1.376  #ifdef PCNET_DEBUG_TMD
   1.377          printf("  TMDLOAD 0x%08x\n", PHYSADDR(s,CSR_CXDA(s)));
   1.378 -        PRINT_TMD(&tmd);
   1.379 +        PRINT_TMD(&(s->tmd));
   1.380  #endif
   1.381 -        if (tmd.tmd1.stp) {
   1.382 -            s->xmit_pos = 0;                
   1.383 -            if (!tmd.tmd1.enp) {
   1.384 -                cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr),
   1.385 -                        s->buffer, 4096 - tmd.tmd1.bcnt);
   1.386 -                s->xmit_pos += 4096 - tmd.tmd1.bcnt;
   1.387 -            } 
   1.388 -            xmit_cxda = PHYSADDR(s,CSR_CXDA(s));
   1.389 -        }
   1.390 -        if (tmd.tmd1.enp && (s->xmit_pos >= 0)) {
   1.391 -            cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr),
   1.392 -                    s->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt);
   1.393 -            s->xmit_pos += 4096 - tmd.tmd1.bcnt;
   1.394 -
   1.395 -	    tmd.tmd1.own = 0;
   1.396 -	    TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s)));
   1.397 -
   1.398 -#ifdef PCNET_DEBUG
   1.399 -            printf("pcnet_transmit size=%d\n", s->xmit_pos);
   1.400 -#endif            
   1.401 -            if (CSR_LOOP(s))
   1.402 -                pcnet_receive(s, s->buffer, s->xmit_pos);
   1.403 -            else
   1.404 -                qemu_send_packet(s->nd, s->buffer, s->xmit_pos);
   1.405 -
   1.406 -            s->csr[0] &= ~0x0008;   /* clear TDMD */
   1.407 -            s->csr[4] |= 0x0004;    /* set TXSTRT */
   1.408 -            s->xmit_pos = -1;
   1.409 -        } else {
   1.410 -	    tmd.tmd1.own = 0;
   1.411 -	    TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s)));
   1.412 -	}
   1.413 -        if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && tmd.tmd1.ltint))
   1.414 -            s->csr[0] |= 0x0200;    /* set TINT */
   1.415 -
   1.416 -        if (CSR_XMTRC(s)<=1)
   1.417 +	len = 4096 - s->tmd.tmd1.bcnt;
   1.418 +        if (CSR_XMTRC(s) <= 1)
   1.419              CSR_XMTRC(s) = CSR_XMTRL(s);
   1.420          else
   1.421              CSR_XMTRC(s)--;
   1.422 -        if (count--)
   1.423 -            goto txagain;
   1.424  
   1.425 -    } else 
   1.426 -    if (s->xmit_pos >= 0) {
   1.427 -        struct pcnet_TMD tmd;
   1.428 -        TMDLOAD(&tmd, PHYSADDR(s,xmit_cxda));                
   1.429 -        tmd.tmd2.buff = tmd.tmd2.uflo = tmd.tmd1.err = 1;
   1.430 -        tmd.tmd1.own = 0;
   1.431 -        TMDSTORE(&tmd, PHYSADDR(s,xmit_cxda));
   1.432 +	/* handle start followed by start */
   1.433 +        if (s->tmd.tmd1.stp && start_addr) {
   1.434 +	    TMDSTORE(&start_tmd, start_addr);
   1.435 +	    start_addr = 0;
   1.436 +	    xmit_pos = 0;
   1.437 +	}
   1.438 +	if ((xmit_pos + len) < sizeof(s->tx_buffer)) {
   1.439 +	    cpu_physical_memory_read(PHYSADDR(s, s->tmd.tmd0.tbadr),
   1.440 +			s->tx_buffer + xmit_pos, len);
   1.441 +	    xmit_pos += len;
   1.442 +	} else {
   1.443 +	    s->tmd.tmd2.buff = s->tmd.tmd2.uflo = s->tmd.tmd1.err = 1;
   1.444 +	    TMDSTORE(&(s->tmd), PHYSADDR(s,CSR_CXDA(s)));
   1.445 +	    if (start_addr == PHYSADDR(s,CSR_CXDA(s)))
   1.446 +	    	start_addr = 0;		/* don't clear own bit twice */
   1.447 +	    continue;
   1.448 +	}
   1.449 +        if (s->tmd.tmd1.stp) {
   1.450 +	    if (s->tmd.tmd1.enp) {
   1.451 +		if (CSR_LOOP(s))
   1.452 +		    pcnet_receive(s, s->tx_buffer, xmit_pos);
   1.453 +		else
   1.454 +		    qemu_send_packet(s->nd, s->tx_buffer, xmit_pos);
   1.455 +
   1.456 +		s->csr[4] |= 0x0008;    /* set TXSTRT */
   1.457 +		TMDSTORE(&(s->tmd), PHYSADDR(s,CSR_CXDA(s)));
   1.458 +		xmit_pos = 0;
   1.459 +		count--;
   1.460 +	    } else {
   1.461 +	        start_tmd = s->tmd;
   1.462 +		start_addr = PHYSADDR(s,CSR_CXDA(s));
   1.463 +	    }
   1.464 +        } else if (s->tmd.tmd1.enp) {
   1.465 +	    TMDSTORE(&(s->tmd), PHYSADDR(s,CSR_CXDA(s)));
   1.466 +	    if (start_addr) {
   1.467 +		TMDSTORE(&start_tmd, start_addr);
   1.468 +	    }
   1.469 +	    start_addr = 0;
   1.470 +	    xmit_pos = 0;
   1.471 +	    count--;
   1.472 +
   1.473 +        } else {
   1.474 +	    TMDSTORE(&(s->tmd), PHYSADDR(s,CSR_CXDA(s)));
   1.475 +	}
   1.476 +        if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && s->tmd.tmd1.ltint))
   1.477 +            s->csr[0] |= 0x0200;    /* set TINT */
   1.478 +
   1.479 +        if (count <= 0)
   1.480 +            break;
   1.481 +
   1.482 +    }
   1.483 +    if (start_addr) {
   1.484 +        start_tmd.tmd2.buff = start_tmd.tmd2.uflo = start_tmd.tmd1.err = 1;
   1.485 +        TMDSTORE(&start_tmd, PHYSADDR(s,start_addr));
   1.486          s->csr[0] |= 0x0200;    /* set TINT */
   1.487          if (!CSR_DXSUFLO(s)) {
   1.488              s->csr[0] &= ~0x0010;
   1.489 -        } else
   1.490 -        if (count--)
   1.491 -          goto txagain;
   1.492 +        }
   1.493      }
   1.494  }
   1.495  
     2.1 --- a/tools/ioemu/hw/pcnet.h	Sun Mar 26 11:35:11 2006 +0100
     2.2 +++ b/tools/ioemu/hw/pcnet.h	Sun Mar 26 11:39:04 2006 +0100
     2.3 @@ -177,6 +177,26 @@ struct pcnet_RMD {
     2.4      } rmd3;    
     2.5  };
     2.6  
     2.7 +typedef struct PCNetState_st PCNetState;
     2.8 +
     2.9 +struct PCNetState_st {
    2.10 +    PCIDevice dev;
    2.11 +    NetDriverState *nd;
    2.12 +    int mmio_io_addr, rap, isr, lnkst;
    2.13 +    target_phys_addr_t rdra, tdra;
    2.14 +    uint8_t prom[16];
    2.15 +    uint16_t csr[128];
    2.16 +    uint16_t bcr[32];
    2.17 +    uint64_t timer;
    2.18 +    int recv_pos;
    2.19 +    uint8_t tx_buffer[2048];
    2.20 +    uint8_t rx_buffer[2048];
    2.21 +    struct pcnet_TMD tmd;
    2.22 +    struct pcnet_RMD crmd;
    2.23 +    struct pcnet_RMD nrmd;
    2.24 +    struct pcnet_RMD nnrmd;
    2.25 +};
    2.26 +
    2.27  
    2.28  #define PRINT_TMD(T) printf(    \
    2.29          "TMD0 : TBADR=0x%08x\n" \
    2.30 @@ -230,18 +250,17 @@ static inline void pcnet_tmd_load(PCNetS
    2.31          cpu_physical_memory_read(addr+4, (void *)&tmd->tmd1, 4);
    2.32          cpu_physical_memory_read(addr, (void *)&tmd->tmd0, 4);
    2.33      } else {
    2.34 -        uint32_t xda[4];
    2.35 -        cpu_physical_memory_read(addr,
    2.36 -                (void *)&xda[0], sizeof(xda));
    2.37 -        ((uint32_t *)tmd)[0] = xda[2];
    2.38 -        ((uint32_t *)tmd)[1] = xda[1];
    2.39 -        ((uint32_t *)tmd)[2] = xda[0];
    2.40 -        ((uint32_t *)tmd)[3] = xda[3];
    2.41 +        uint32_t xda[2];
    2.42 +        cpu_physical_memory_read(addr+4, (void *)&xda[0], sizeof(xda));
    2.43 +        ((uint32_t *)tmd)[0] = xda[1];
    2.44 +        ((uint32_t *)tmd)[1] = xda[0];
    2.45 +        ((uint32_t *)tmd)[2] = 0;
    2.46      }
    2.47  }
    2.48  
    2.49  static inline void pcnet_tmd_store(PCNetState *s, struct pcnet_TMD *tmd, target_phys_addr_t addr)
    2.50  {
    2.51 +    tmd->tmd1.own = 0;
    2.52      cpu_physical_memory_set_dirty(addr);
    2.53      if (!BCR_SWSTYLE(s)) {
    2.54          uint16_t xda[4];
    2.55 @@ -259,13 +278,10 @@ static inline void pcnet_tmd_store(PCNet
    2.56              cpu_physical_memory_write(addr+8, (void *)&tmd->tmd2, 4);
    2.57              cpu_physical_memory_write(addr+4, (void *)&tmd->tmd1, 4);
    2.58          } else {
    2.59 -            uint32_t xda[4];
    2.60 +            uint32_t xda[2];
    2.61              xda[0] = ((uint32_t *)tmd)[2];
    2.62              xda[1] = ((uint32_t *)tmd)[1];
    2.63 -            xda[2] = ((uint32_t *)tmd)[0];
    2.64 -            xda[3] = ((uint32_t *)tmd)[3];
    2.65 -            cpu_physical_memory_write(addr,
    2.66 -                    (void *)&xda[0], sizeof(xda));
    2.67 +            cpu_physical_memory_write(addr, (void *)&xda[0], sizeof(xda));
    2.68          }
    2.69          cpu_physical_memory_set_dirty(addr+15);
    2.70      }
    2.71 @@ -286,22 +302,21 @@ static inline void pcnet_rmd_load(PCNetS
    2.72      }
    2.73      else
    2.74      if (BCR_SWSTYLE(s) != 3) {
    2.75 -        rmd->rmd2.zeros = 0;
    2.76 +        ((uint32_t *)rmd)[2] = 0;
    2.77          cpu_physical_memory_read(addr+4, (void *)&rmd->rmd1, 4);
    2.78          cpu_physical_memory_read(addr, (void *)&rmd->rmd0, 4);
    2.79      } else {
    2.80 -        uint32_t rda[4];
    2.81 -        cpu_physical_memory_read(addr,
    2.82 -                (void *)&rda[0], sizeof(rda));
    2.83 -        ((uint32_t *)rmd)[0] = rda[2];
    2.84 -        ((uint32_t *)rmd)[1] = rda[1];
    2.85 -        ((uint32_t *)rmd)[2] = rda[0];
    2.86 -        ((uint32_t *)rmd)[3] = rda[3];
    2.87 +        uint32_t rda[2];
    2.88 +        cpu_physical_memory_read(addr+4, (void *)&rda[0], sizeof(rda));
    2.89 +        ((uint32_t *)rmd)[0] = rda[1];
    2.90 +        ((uint32_t *)rmd)[1] = rda[0];
    2.91 +        ((uint32_t *)rmd)[2] = 0;
    2.92      }
    2.93  }
    2.94  
    2.95  static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr)
    2.96  {
    2.97 +    rmd->rmd1.own = 0;
    2.98      cpu_physical_memory_set_dirty(addr);
    2.99      if (!BCR_SWSTYLE(s)) {
   2.100          uint16_t rda[4];                        \
   2.101 @@ -319,13 +334,10 @@ static inline void pcnet_rmd_store(PCNet
   2.102              cpu_physical_memory_write(addr+8, (void *)&rmd->rmd2, 4);
   2.103              cpu_physical_memory_write(addr+4, (void *)&rmd->rmd1, 4);
   2.104          } else {
   2.105 -            uint32_t rda[4];
   2.106 +            uint32_t rda[2];
   2.107              rda[0] = ((uint32_t *)rmd)[2];
   2.108              rda[1] = ((uint32_t *)rmd)[1];
   2.109 -            rda[2] = ((uint32_t *)rmd)[0];
   2.110 -            rda[3] = ((uint32_t *)rmd)[3];
   2.111 -            cpu_physical_memory_write(addr,
   2.112 -                    (void *)&rda[0], sizeof(rda));
   2.113 +            cpu_physical_memory_write(addr, (void *)&rda[0], sizeof(rda));
   2.114          }
   2.115          cpu_physical_memory_set_dirty(addr+15);
   2.116      }
   2.117 @@ -340,79 +352,16 @@ static inline void pcnet_rmd_store(PCNet
   2.118  
   2.119  #define RMDSTORE(RMD,ADDR) pcnet_rmd_store(s,RMD,ADDR)
   2.120  
   2.121 -#if 1
   2.122 -
   2.123 -#define CHECK_RMD(ADDR,RES) do {                \
   2.124 -    struct pcnet_RMD rmd;                       \
   2.125 -    RMDLOAD(&rmd,(ADDR));                       \
   2.126 -    (RES) |= (rmd.rmd1.ones != 15);             \
   2.127 -} while (0)
   2.128 -
   2.129 -#define CHECK_TMD(ADDR,RES) do {                \
   2.130 -    struct pcnet_TMD tmd;                       \
   2.131 -    TMDLOAD(&tmd,(ADDR));                       \
   2.132 -    (RES) |= (tmd.tmd1.ones != 15);             \
   2.133 +#define CHECK_RMD(RMD,ADDR,RES) do {            \
   2.134 +    RMDLOAD((RMD),(ADDR));                      \
   2.135 +    (RES) |= ((RMD)->rmd1.ones != 15);          \
   2.136  } while (0)
   2.137  
   2.138 -#else
   2.139 -
   2.140 -#define CHECK_RMD(ADDR,RES) do {                \
   2.141 -    switch (BCR_SWSTYLE(s)) {                   \
   2.142 -    case 0x00:                                  \
   2.143 -        do {                                    \
   2.144 -            uint16_t rda[4];                    \
   2.145 -            cpu_physical_memory_read((ADDR),    \
   2.146 -                (void *)&rda[0], sizeof(rda));  \
   2.147 -            (RES) |= (rda[2] & 0xf000)!=0xf000; \
   2.148 -            (RES) |= (rda[3] & 0xf000)!=0x0000; \
   2.149 -        } while (0);                            \
   2.150 -        break;                                  \
   2.151 -    case 0x01:                                  \
   2.152 -    case 0x02:                                  \
   2.153 -        do {                                    \
   2.154 -            uint32_t rda[4];                    \
   2.155 -            cpu_physical_memory_read((ADDR),    \
   2.156 -                (void *)&rda[0], sizeof(rda)); \
   2.157 -            (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
   2.158 -            (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \
   2.159 -        } while (0);                            \
   2.160 -        break;                                  \
   2.161 -    case 0x03:                                  \
   2.162 -        do {                                    \
   2.163 -            uint32_t rda[4];                    \
   2.164 -            cpu_physical_memory_read((ADDR),    \
   2.165 -                (void *)&rda[0], sizeof(rda)); \
   2.166 -            (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \
   2.167 -            (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
   2.168 -        } while (0);                            \
   2.169 -        break;                                  \
   2.170 -    }                                           \
   2.171 +#define CHECK_TMD(ADDR,RES) do {            \
   2.172 +    TMDLOAD(&(s->tmd),(ADDR));                       \
   2.173 +    (RES) |= (s->tmd.tmd1.ones != 15);             \
   2.174  } while (0)
   2.175  
   2.176 -#define CHECK_TMD(ADDR,RES) do {                \
   2.177 -    switch (BCR_SWSTYLE(s)) {                   \
   2.178 -    case 0x00:                                  \
   2.179 -        do {                                    \
   2.180 -            uint16_t xda[4];                    \
   2.181 -            cpu_physical_memory_read((ADDR),    \
   2.182 -                (void *)&xda[0], sizeof(xda));  \
   2.183 -            (RES) |= (xda[2] & 0xf000)!=0xf000;\
   2.184 -        } while (0);                            \
   2.185 -        break;                                  \
   2.186 -    case 0x01:                                  \
   2.187 -    case 0x02:                                  \
   2.188 -    case 0x03:                                  \
   2.189 -        do {                                    \
   2.190 -            uint32_t xda[4];                    \
   2.191 -            cpu_physical_memory_read((ADDR),    \
   2.192 -                (void *)&xda[0], sizeof(xda));  \
   2.193 -            (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \
   2.194 -        } while (0);                            \
   2.195 -        break;                                  \
   2.196 -    }                                           \
   2.197 -} while (0)
   2.198 -
   2.199 -#endif
   2.200  
   2.201  #define PRINT_PKTHDR(BUF) do {                  \
   2.202      struct ether_header *hdr = (void *)(BUF);   \