Index: qemu/hw/e1000.c =================================================================== --- hw/e1000.c (revision 4451) +++ hw/e1000.c (working copy) @@ -76,7 +76,6 @@ PCIDevice dev; VLANClientState *vc; NICInfo *nd; - uint32_t instance; uint32_t mmio_base; int mmio_index; @@ -105,6 +104,7 @@ char tse; char ip; char tcp; + char cptse; // current packet tse bit } tx; struct { @@ -308,7 +308,7 @@ unsigned int frames = s->tx.tso_frames, css, sofar, n; struct e1000_tx *tp = &s->tx; - if (tp->tse) { + if (tp->tse && tp->cptse) { css = tp->ipcss; DBGOUT(TXSUM, "frames %d size %d ipcss %d\n", frames, tp->size, css); @@ -382,37 +382,49 @@ tp->tucso = tp->tucss + (tp->tcp ? 16 : 6); } return; - } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) + } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) { + // data descriptor tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8; + tp->cptse = ( txd_lower & E1000_TXD_CMD_TSE ) ? 1 : 0; + } else + // legacy descriptor + tp->cptse = 0; addr = le64_to_cpu(dp->buffer_addr); - if (tp->tse) { + if (tp->tse && tp->cptse) { hdr = tp->hdr_len; msh = hdr + tp->mss; + do { + bytes = split_size; + if (tp->size + bytes > msh) + bytes = msh - tp->size; + cpu_physical_memory_read(addr, tp->data + tp->size, bytes); + if ((sz = tp->size + bytes) >= hdr && tp->size < hdr) + memmove(tp->header, tp->data, hdr); + tp->size = sz; + addr += bytes; + if (sz == msh) { + xmit_seg(s); + memmove(tp->data, tp->header, hdr); + tp->size = hdr; + } + } while (split_size -= bytes); + } else if (!tp->tse && tp->cptse) { + // context descriptor TSE is not set, while data descriptor TSE is set + DBGOUT(TXERR, "TCP segmentaion Error\n"); + } else { + cpu_physical_memory_read(addr, tp->data + tp->size, split_size); + tp->size += split_size; } - do { - bytes = split_size; - if (tp->size + bytes > msh) - bytes = msh - tp->size; - cpu_physical_memory_read(addr, tp->data + tp->size, bytes); - if ((sz = tp->size + bytes) >= hdr && tp->size < hdr) - memmove(tp->header, tp->data, hdr); - tp->size = sz; - addr += bytes; - if (sz == msh) { - xmit_seg(s); - memmove(tp->data, tp->header, hdr); - tp->size = hdr; - } - } while (split_size -= bytes); if (!(txd_lower & E1000_TXD_CMD_EOP)) return; - if (tp->size > hdr) + if (!(tp->tse && tp->cptse && tp->size < hdr)) xmit_seg(s); tp->tso_frames = 0; tp->sum_needed = 0; tp->size = 0; + tp->cptse = 0; } static uint32_t @@ -801,7 +813,6 @@ int i, j; pci_device_save(&s->dev, f); - qemu_put_be32s(f, &s->instance); qemu_put_be32s(f, &s->mmio_base); qemu_put_be32s(f, &s->rxbuf_size); qemu_put_be32s(f, &s->rxbuf_min_shift); @@ -846,7 +857,8 @@ if ((ret = pci_device_load(&s->dev, f)) < 0) return ret; - qemu_get_be32s(f, &s->instance); + if (version_id == 1) + qemu_get_be32s(f, &i); /* once some unused instance id */ qemu_get_be32s(f, &s->mmio_base); qemu_get_be32s(f, &s->rxbuf_size); qemu_get_be32s(f, &s->rxbuf_min_shift); @@ -945,7 +957,6 @@ { E1000State *d; uint8_t *pci_conf; - static int instance; uint16_t checksum = 0; char *info_str = "e1000"; int i; @@ -976,8 +987,6 @@ pci_register_io_region((PCIDevice *)d, 1, IOPORT_SIZE, PCI_ADDRESS_SPACE_IO, ioport_map); - d->instance = instance++; - d->nd = nd; memmove(d->eeprom_data, e1000_eeprom_template, sizeof e1000_eeprom_template); @@ -1003,5 +1012,5 @@ d->nd->macaddr[0], d->nd->macaddr[1], d->nd->macaddr[2], d->nd->macaddr[3], d->nd->macaddr[4], d->nd->macaddr[5]); - register_savevm(info_str, d->instance, 1, nic_save, nic_load, d); + register_savevm(info_str, -1, 2, nic_save, nic_load, d); }