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 105 char tse;
106 106 char ip;
107 107 char tcp;
  108 + char cptse; // current packet tse bit
108 109 } tx;
109 110  
110 111 struct {
... ... @@ -308,7 +309,7 @@ xmit_seg(E1000State *s)
308 309 unsigned int frames = s->tx.tso_frames, css, sofar, n;
309 310 struct e1000_tx *tp = &s->tx;
310 311  
311   - if (tp->tse) {
  312 + if (tp->tse && tp->cptse) {
312 313 css = tp->ipcss;
313 314 DBGOUT(TXSUM, "frames %d size %d ipcss %d\n",
314 315 frames, tp->size, css);
... ... @@ -382,37 +383,49 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
382 383 tp->tucso = tp->tucss + (tp->tcp ? 16 : 6);
383 384 }
384 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 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 394 addr = le64_to_cpu(dp->buffer_addr);
389   - if (tp->tse) {
  395 + if (tp->tse && tp->cptse) {
390 396 hdr = tp->hdr_len;
391 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 421 if (!(txd_lower & E1000_TXD_CMD_EOP))
410 422 return;
411   - if (tp->size > hdr)
  423 + if (!(tp->tse && tp->cptse && tp->size < hdr))
412 424 xmit_seg(s);
413 425 tp->tso_frames = 0;
414 426 tp->sum_needed = 0;
415 427 tp->size = 0;
  428 + tp->cptse = 0;
416 429 }
417 430  
418 431 static uint32_t
... ...