Commit 1b0009dbd41e68ca2b19bc7a20dc5499c31938cd

Authored by balrog
1 parent 526ccb7a

e1000: only use TSE if enabled for current packet (Anthony Xu).

Previously, all data descriptors used TSE context descriptor by default,
It's not correct, per spec, data descriptor uses TSE bit to indicate
whether use TSE,
Legacy data descripter never use TSE.
This patch fixed this bug.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4878 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 32 additions and 19 deletions
hw/e1000.c
@@ -105,6 +105,7 @@ typedef struct E1000State_st { @@ -105,6 +105,7 @@ typedef struct E1000State_st {
105 char tse; 105 char tse;
106 char ip; 106 char ip;
107 char tcp; 107 char tcp;
  108 + char cptse; // current packet tse bit
108 } tx; 109 } tx;
109 110
110 struct { 111 struct {
@@ -308,7 +309,7 @@ xmit_seg(E1000State *s) @@ -308,7 +309,7 @@ xmit_seg(E1000State *s)
308 unsigned int frames = s->tx.tso_frames, css, sofar, n; 309 unsigned int frames = s->tx.tso_frames, css, sofar, n;
309 struct e1000_tx *tp = &s->tx; 310 struct e1000_tx *tp = &s->tx;
310 311
311 - if (tp->tse) { 312 + if (tp->tse && tp->cptse) {
312 css = tp->ipcss; 313 css = tp->ipcss;
313 DBGOUT(TXSUM, "frames %d size %d ipcss %d\n", 314 DBGOUT(TXSUM, "frames %d size %d ipcss %d\n",
314 frames, tp->size, css); 315 frames, tp->size, css);
@@ -382,37 +383,49 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) @@ -382,37 +383,49 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
382 tp->tucso = tp->tucss + (tp->tcp ? 16 : 6); 383 tp->tucso = tp->tucss + (tp->tcp ? 16 : 6);
383 } 384 }
384 return; 385 return;
385 - } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) 386 + } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) {
  387 + // data descriptor
386 tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8; 388 tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8;
  389 + tp->cptse = ( txd_lower & E1000_TXD_CMD_TSE ) ? 1 : 0;
  390 + } else
  391 + // legacy descriptor
  392 + tp->cptse = 0;
387 393
388 addr = le64_to_cpu(dp->buffer_addr); 394 addr = le64_to_cpu(dp->buffer_addr);
389 - if (tp->tse) { 395 + if (tp->tse && tp->cptse) {
390 hdr = tp->hdr_len; 396 hdr = tp->hdr_len;
391 msh = hdr + tp->mss; 397 msh = hdr + tp->mss;
  398 + do {
  399 + bytes = split_size;
  400 + if (tp->size + bytes > msh)
  401 + bytes = msh - tp->size;
  402 + cpu_physical_memory_read(addr, tp->data + tp->size, bytes);
  403 + if ((sz = tp->size + bytes) >= hdr && tp->size < hdr)
  404 + memmove(tp->header, tp->data, hdr);
  405 + tp->size = sz;
  406 + addr += bytes;
  407 + if (sz == msh) {
  408 + xmit_seg(s);
  409 + memmove(tp->data, tp->header, hdr);
  410 + tp->size = hdr;
  411 + }
  412 + } while (split_size -= bytes);
  413 + } else if (!tp->tse && tp->cptse) {
  414 + // context descriptor TSE is not set, while data descriptor TSE is set
  415 + DBGOUT(TXERR, "TCP segmentaion Error\n");
  416 + } else {
  417 + cpu_physical_memory_read(addr, tp->data + tp->size, split_size);
  418 + tp->size += split_size;
392 } 419 }
393 - do {  
394 - bytes = split_size;  
395 - if (tp->size + bytes > msh)  
396 - bytes = msh - tp->size;  
397 - cpu_physical_memory_read(addr, tp->data + tp->size, bytes);  
398 - if ((sz = tp->size + bytes) >= hdr && tp->size < hdr)  
399 - memmove(tp->header, tp->data, hdr);  
400 - tp->size = sz;  
401 - addr += bytes;  
402 - if (sz == msh) {  
403 - xmit_seg(s);  
404 - memmove(tp->data, tp->header, hdr);  
405 - tp->size = hdr;  
406 - }  
407 - } while (split_size -= bytes);  
408 420
409 if (!(txd_lower & E1000_TXD_CMD_EOP)) 421 if (!(txd_lower & E1000_TXD_CMD_EOP))
410 return; 422 return;
411 - if (tp->size > hdr) 423 + if (!(tp->tse && tp->cptse && tp->size < hdr))
412 xmit_seg(s); 424 xmit_seg(s);
413 tp->tso_frames = 0; 425 tp->tso_frames = 0;
414 tp->sum_needed = 0; 426 tp->sum_needed = 0;
415 tp->size = 0; 427 tp->size = 0;
  428 + tp->cptse = 0;
416 } 429 }
417 430
418 static uint32_t 431 static uint32_t