From nobody Tue Apr 30 00:18:49 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1510701937161888.8542943227004; Tue, 14 Nov 2017 15:25:37 -0800 (PST) Received: from localhost ([::1]:33981 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eEka5-0008Sj-S1 for importer@patchew.org; Tue, 14 Nov 2017 18:25:25 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:32992) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eEkYX-0007RX-O5 for qemu-devel@nongnu.org; Tue, 14 Nov 2017 18:23:51 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eEkYU-0006xo-LH for qemu-devel@nongnu.org; Tue, 14 Nov 2017 18:23:49 -0500 Received: from mail-pg0-x241.google.com ([2607:f8b0:400e:c05::241]:56542) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1eEkYU-0006xc-Cr for qemu-devel@nongnu.org; Tue, 14 Nov 2017 18:23:46 -0500 Received: by mail-pg0-x241.google.com with SMTP id z184so11163688pgd.13 for ; Tue, 14 Nov 2017 15:23:46 -0800 (PST) Received: from eswierk-sc.localdomain (67-207-112-138.static.wiline.com. [67.207.112.138]) by smtp.gmail.com with ESMTPSA id d9sm20150979pfk.117.2017.11.14.15.23.43 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 14 Nov 2017 15:23:44 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=skyportsystems.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Zya9D78fyCdpEPEdRrzTg6cFc+/jxWZRsIvXT9SAPQo=; b=RUFwOTqN4TMaXXgxwdjfLEVXGDUzPLu2EL5wPefdleH8OrFW+tr9ufivzhCEBcFxNN uj85/zbyodYLi/MYQopYCBcNQHDfJS2Y0AmkyLhXhNBCptOX1v5k4E28wMmKEDDDwDct an0lPEY1HgUB6a0IpaHkAu/4oGAWXWiqhZnHQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Zya9D78fyCdpEPEdRrzTg6cFc+/jxWZRsIvXT9SAPQo=; b=IVLI/mJbOmGAqcAW6NLBF7NZa6hgnZpRWRlcMCiYjq5B/dqWQoTAX0zzkL26MZE7p/ GQAxuGqtIFoc4hgb2uWWZ/ASMLgI6VCXyezgZWZN50TGiSFL9mNI5p9v/ab/zny+L3Zq nrLtFrSl1NuSzUvv/TfO12Y07soVtWrbya7QJGpIhbhq7aHQdaZ0+CrkW22cvenyp4nF IaXjZwneuoQFA9C75YDzgbZrfIMZK1psjY4o4n/EeRDxPhMrTuH/DWPv+wqo6nalakeA aBc2SOIj86NAZe9S34ns+WWVN3Y6SEQ8rcShpIxQahVRt0MticumCGQL7ESVmps0AG2t xW+A== X-Gm-Message-State: AJaThX7UUyQQHJIX2fqkzc9kRXtRx7+jK6LtammKHhJw9x22kJ5rE3MU uHzUM0t+4xMFMIkymQHzFfz2qg== X-Google-Smtp-Source: AGs4zMary7NPLj8s6h/lSo/0AD5kYgV9wnRQSYWYgQ3CSL/qqP8lsw32P719NX2R7UXpKTZWUQL0pw== X-Received: by 10.84.131.161 with SMTP id d30mr10150628pld.332.1510701825352; Tue, 14 Nov 2017 15:23:45 -0800 (PST) To: Jason Wang , "Daniel P . Berrange" , Stefan Hajnoczi Date: Tue, 14 Nov 2017 15:23:33 -0800 Message-Id: <1510701814-52973-2-git-send-email-eswierk@skyportsystems.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1510701814-52973-1-git-send-email-eswierk@skyportsystems.com> References: <1510701814-52973-1-git-send-email-eswierk@skyportsystems.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:400e:c05::241 Subject: [Qemu-devel] [PATCH 1/2] e1000, e1000e: Move per-packet TX offload flags out of context state X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Ed Swierk via Qemu-devel Reply-To: Ed Swierk Cc: Ed Swierk , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" sum_needed and cptse flags are received from the guest within each transmit data descriptor. They are not part of the offload context; instead, they determine how to apply a previously received context to the packet being transmitted: - If cptse is set, perform both segmentation and checksum offload using the parameters in the TSO context; otherwise just do checksum offload. (Currently the e1000 device incorrectly stores only one context, which will be fixed in a subsequent patch.) - Depending on the bits set in sum_needed, possibly perform L4 checksum offload and/or IP checksum offload, using the parameters in the appropriate context. Move these flags out of struct e1000x_txd_props, which is otherwise dedicated to storing values from a context descriptor, and into the per-packet TX struct. Signed-off-by: Ed Swierk --- hw/net/e1000.c | 30 ++++++++++++++++-------------- hw/net/e1000e.c | 4 ++-- hw/net/e1000e_core.c | 16 ++++++++-------- hw/net/e1000e_core.h | 2 ++ hw/net/e1000x_common.h | 2 -- 5 files changed, 28 insertions(+), 26 deletions(-) diff --git a/hw/net/e1000.c b/hw/net/e1000.c index 9324949..471cdd9 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -98,6 +98,8 @@ typedef struct E1000State_st { unsigned char data[0x10000]; uint16_t size; unsigned char vlan_needed; + unsigned char sum_needed; + bool cptse; e1000x_txd_props props; uint16_t tso_frames; } tx; @@ -540,7 +542,7 @@ xmit_seg(E1000State *s) unsigned int frames =3D s->tx.tso_frames, css, sofar; struct e1000_tx *tp =3D &s->tx; =20 - if (tp->props.tse && tp->props.cptse) { + if (tp->props.tse && tp->cptse) { css =3D tp->props.ipcss; DBGOUT(TXSUM, "frames %d size %d ipcss %d\n", frames, tp->size, css); @@ -564,7 +566,7 @@ xmit_seg(E1000State *s) } } else /* UDP */ stw_be_p(tp->data+css+4, len); - if (tp->props.sum_needed & E1000_TXD_POPTS_TXSM) { + if (tp->sum_needed & E1000_TXD_POPTS_TXSM) { unsigned int phsum; // add pseudo-header length before checksum calculation void *sp =3D tp->data + tp->props.tucso; @@ -576,11 +578,11 @@ xmit_seg(E1000State *s) tp->tso_frames++; } =20 - if (tp->props.sum_needed & E1000_TXD_POPTS_TXSM) { + if (tp->sum_needed & E1000_TXD_POPTS_TXSM) { putsum(tp->data, tp->size, tp->props.tucso, tp->props.tucss, tp->props.tucse); } - if (tp->props.sum_needed & E1000_TXD_POPTS_IXSM) { + if (tp->sum_needed & E1000_TXD_POPTS_IXSM) { putsum(tp->data, tp->size, tp->props.ipcso, tp->props.ipcss, tp->props.ipcse); } @@ -624,17 +626,17 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *= dp) } else if (dtype =3D=3D (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) { // data descriptor if (tp->size =3D=3D 0) { - tp->props.sum_needed =3D le32_to_cpu(dp->upper.data) >> 8; + tp->sum_needed =3D le32_to_cpu(dp->upper.data) >> 8; } - tp->props.cptse =3D (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0; + tp->cptse =3D (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0; } else { // legacy descriptor - tp->props.cptse =3D 0; + tp->cptse =3D 0; } =20 if (e1000x_vlan_enabled(s->mac_reg) && e1000x_is_vlan_txd(txd_lower) && - (tp->props.cptse || txd_lower & E1000_TXD_CMD_EOP)) { + (tp->cptse || txd_lower & E1000_TXD_CMD_EOP)) { tp->vlan_needed =3D 1; stw_be_p(tp->vlan_header, le16_to_cpu(s->mac_reg[VET])); @@ -643,7 +645,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) } =20 addr =3D le64_to_cpu(dp->buffer_addr); - if (tp->props.tse && tp->props.cptse) { + if (tp->props.tse && tp->cptse) { msh =3D tp->props.hdr_len + tp->props.mss; do { bytes =3D split_size; @@ -665,7 +667,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) } split_size -=3D bytes; } while (bytes && split_size); - } else if (!tp->props.tse && tp->props.cptse) { + } else if (!tp->props.tse && tp->cptse) { // context descriptor TSE is not set, while data descriptor TSE is= set DBGOUT(TXERR, "TCP segmentation error\n"); } else { @@ -676,14 +678,14 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *= dp) =20 if (!(txd_lower & E1000_TXD_CMD_EOP)) return; - if (!(tp->props.tse && tp->props.cptse && tp->size < tp->props.hdr_len= )) { + if (!(tp->props.tse && tp->cptse && tp->size < tp->props.hdr_len)) { xmit_seg(s); } tp->tso_frames =3D 0; - tp->props.sum_needed =3D 0; + tp->sum_needed =3D 0; tp->vlan_needed =3D 0; tp->size =3D 0; - tp->props.cptse =3D 0; + tp->cptse =3D 0; } =20 static uint32_t @@ -1459,7 +1461,7 @@ static const VMStateDescription vmstate_e1000 =3D { VMSTATE_UINT16(tx.props.mss, E1000State), VMSTATE_UINT16(tx.size, E1000State), VMSTATE_UINT16(tx.tso_frames, E1000State), - VMSTATE_UINT8(tx.props.sum_needed, E1000State), + VMSTATE_UINT8(tx.sum_needed, E1000State), VMSTATE_INT8(tx.props.ip, E1000State), VMSTATE_INT8(tx.props.tcp, E1000State), VMSTATE_BUFFER(tx.header, E1000State), diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c index bad43f4..bc97a40 100644 --- a/hw/net/e1000e.c +++ b/hw/net/e1000e.c @@ -547,7 +547,7 @@ static const VMStateDescription e1000e_vmstate_tx =3D { .version_id =3D 1, .minimum_version_id =3D 1, .fields =3D (VMStateField[]) { - VMSTATE_UINT8(props.sum_needed, struct e1000e_tx), + VMSTATE_UINT8(sum_needed, struct e1000e_tx), VMSTATE_UINT8(props.ipcss, struct e1000e_tx), VMSTATE_UINT8(props.ipcso, struct e1000e_tx), VMSTATE_UINT16(props.ipcse, struct e1000e_tx), @@ -560,7 +560,7 @@ static const VMStateDescription e1000e_vmstate_tx =3D { VMSTATE_INT8(props.ip, struct e1000e_tx), VMSTATE_INT8(props.tcp, struct e1000e_tx), VMSTATE_BOOL(props.tse, struct e1000e_tx), - VMSTATE_BOOL(props.cptse, struct e1000e_tx), + VMSTATE_BOOL(cptse, struct e1000e_tx), VMSTATE_BOOL(skip_cp, struct e1000e_tx), VMSTATE_END_OF_LIST() } diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c index badb1fe..b66bd70 100644 --- a/hw/net/e1000e_core.c +++ b/hw/net/e1000e_core.c @@ -632,18 +632,18 @@ e1000e_rss_parse_packet(E1000ECore *core, static void e1000e_setup_tx_offloads(E1000ECore *core, struct e1000e_tx *tx) { - if (tx->props.tse && tx->props.cptse) { + if (tx->props.tse && tx->cptse) { net_tx_pkt_build_vheader(tx->tx_pkt, true, true, tx->props.mss); net_tx_pkt_update_ip_checksums(tx->tx_pkt); e1000x_inc_reg_if_not_full(core->mac, TSCTC); return; } =20 - if (tx->props.sum_needed & E1000_TXD_POPTS_TXSM) { + if (tx->sum_needed & E1000_TXD_POPTS_TXSM) { net_tx_pkt_build_vheader(tx->tx_pkt, false, true, 0); } =20 - if (tx->props.sum_needed & E1000_TXD_POPTS_IXSM) { + if (tx->sum_needed & E1000_TXD_POPTS_IXSM) { net_tx_pkt_update_ip_hdr_checksum(tx->tx_pkt); } } @@ -715,13 +715,13 @@ e1000e_process_tx_desc(E1000ECore *core, return; } else if (dtype =3D=3D (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) { /* data descriptor */ - tx->props.sum_needed =3D le32_to_cpu(dp->upper.data) >> 8; - tx->props.cptse =3D (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0; + tx->sum_needed =3D le32_to_cpu(dp->upper.data) >> 8; + tx->cptse =3D (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0; e1000e_process_ts_option(core, dp); } else { /* legacy descriptor */ e1000e_process_ts_option(core, dp); - tx->props.cptse =3D 0; + tx->cptse =3D 0; } =20 addr =3D le64_to_cpu(dp->buffer_addr); @@ -747,8 +747,8 @@ e1000e_process_tx_desc(E1000ECore *core, tx->skip_cp =3D false; net_tx_pkt_reset(tx->tx_pkt); =20 - tx->props.sum_needed =3D 0; - tx->props.cptse =3D 0; + tx->sum_needed =3D 0; + tx->cptse =3D 0; } } =20 diff --git a/hw/net/e1000e_core.h b/hw/net/e1000e_core.h index 5f413a9..be4b4e9 100644 --- a/hw/net/e1000e_core.h +++ b/hw/net/e1000e_core.h @@ -71,6 +71,8 @@ struct E1000Core { e1000x_txd_props props; =20 bool skip_cp; + unsigned char sum_needed; + bool cptse; struct NetTxPkt *tx_pkt; } tx[E1000E_NUM_QUEUES]; =20 diff --git a/hw/net/e1000x_common.h b/hw/net/e1000x_common.h index 21bf28e..1116c35 100644 --- a/hw/net/e1000x_common.h +++ b/hw/net/e1000x_common.h @@ -193,7 +193,6 @@ void e1000x_update_regs_on_autoneg_done(uint32_t *mac, = uint16_t *phy); void e1000x_increase_size_stats(uint32_t *mac, const int *size_regs, int s= ize); =20 typedef struct e1000x_txd_props { - unsigned char sum_needed; uint8_t ipcss; uint8_t ipcso; uint16_t ipcse; @@ -206,7 +205,6 @@ typedef struct e1000x_txd_props { int8_t ip; int8_t tcp; bool tse; - bool cptse; } e1000x_txd_props; =20 void e1000x_read_tx_ctx_descr(struct e1000_context_desc *d, --=20 1.9.1 From nobody Tue Apr 30 00:18:49 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1510702030551734.6377529118482; Tue, 14 Nov 2017 15:27:10 -0800 (PST) Received: from localhost ([::1]:33990 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eEkbl-0001DE-KP for importer@patchew.org; Tue, 14 Nov 2017 18:27:09 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:32990) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eEkYX-0007RV-Ni for qemu-devel@nongnu.org; Tue, 14 Nov 2017 18:23:51 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eEkYV-0006yG-PC for qemu-devel@nongnu.org; Tue, 14 Nov 2017 18:23:49 -0500 Received: from mail-pg0-x241.google.com ([2607:f8b0:400e:c05::241]:51209) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1eEkYV-0006xv-GP for qemu-devel@nongnu.org; Tue, 14 Nov 2017 18:23:47 -0500 Received: by mail-pg0-x241.google.com with SMTP id p9so16545874pgc.8 for ; Tue, 14 Nov 2017 15:23:47 -0800 (PST) Received: from eswierk-sc.localdomain (67-207-112-138.static.wiline.com. [67.207.112.138]) by smtp.gmail.com with ESMTPSA id d9sm20150979pfk.117.2017.11.14.15.23.45 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 14 Nov 2017 15:23:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=skyportsystems.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=fPk80ZRpX5bp7zkzKBiNnWYa83lv4WziNPGUeuVISho=; b=NFAm1WB+hrDBCngKZ9k/wHkb9qvQaW0h78Xdw/MqCcM6DE45VbcD4o5UU2LTxVMuR0 V2eHlvoqh8TrE/GRBLwznRwaTCbLpYDPoCQ8at34vdUdA5K0ENZLowdvqiT9CVhqaMcf VCHSi4NOtr9fjzHfMJ6BDH5ip9wqIukpkz23s= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=fPk80ZRpX5bp7zkzKBiNnWYa83lv4WziNPGUeuVISho=; b=c8iFpYjfcnHHuiQLfDBy3OjsgW0lR7NiesdS6DAP8tXhvAqRMhBDbDZxqoRh0o5VER g+jGVnqq6Zq67wlzePtZL5YNkbEqwUQdKlwhEwmgf3bNJhbQ47wc+H0h9uLi9VPS1if4 8DKmUatgPtDRCZ0m24tgzRZpcv/YkeC0rFsBW9QK5hJN9Mh+47Hk0JFo0Ewwgcuy0T6/ lF4aqhVe7cuiyZQHJ0st6Pa4v0/Co45dJR53jnQ089wRFUbXobEvMDZ0yc6Zwz2x+gXM JsZlAwlqezv1rsNA//My8DCQrB5X41VowSXf+BtuxYA4wrN0TebkGLoVJLkVV/Za55HZ 6jsg== X-Gm-Message-State: AJaThX6RuifCnZBJjdfWm9b9XgRdgkEpjG2yu1qTuu17x0wzpHoDpF+B bIAxCOzTeMUAB8oosiES59M6mtFmMNE= X-Google-Smtp-Source: AGs4zMZ315NsLuJYwsD0xzpcovgH5XkkhEp8VUEVizyV7EnwK1BXjUmvFMwK648Gd0B1HUJeQuDZgQ== X-Received: by 10.159.255.71 with SMTP id u7mr4291517pls.41.1510701826504; Tue, 14 Nov 2017 15:23:46 -0800 (PST) To: Jason Wang , "Daniel P . Berrange" , Stefan Hajnoczi Date: Tue, 14 Nov 2017 15:23:34 -0800 Message-Id: <1510701814-52973-3-git-send-email-eswierk@skyportsystems.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1510701814-52973-1-git-send-email-eswierk@skyportsystems.com> References: <1510701814-52973-1-git-send-email-eswierk@skyportsystems.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:400e:c05::241 Subject: [Qemu-devel] [PATCH 2/2] e1000: Separate TSO and non-TSO contexts, fixing UDP TX corruption X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Ed Swierk via Qemu-devel Reply-To: Ed Swierk Cc: Ed Swierk , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" The device is supposed to maintain two distinct contexts for transmit offloads: one has parameters for both segmentation and checksum offload, the other only for checksum offload. The guest driver can send two context descriptors, one for each context (the TSE flag specifies which). Then the guest can refer to one or the other context in subsequent transmit data descriptors, depending on what offloads it wants applied to each packet. Currently the e1000 device stores just one context, and misinterprets the TSE flags in the context and data descriptors. This is often okay: Linux happens to send a fresh context descriptor before every data descriptor, so forgetting the other context doesn't matter. Windows does rely on separate contexts for TSO vs. non-TSO packets, but for mostly-TCP traffic the two contexts have identical TCP-specific offload parameters so confusing them doesn't matter. One case where this confusion matters is when a Windows guest sets up a TSO context for TCP and a non-TSO context for UDP, and then transmits both TCP and UDP traffic in parallel. The e1000 device sometimes ends up using TCP-specific parameters while doing checksum offload on a UDP datagram: it writes the checksum to offset 16 (the correct location for a TCP checksum), stomping on two bytes of UDP data, and leaving the wrong value in the actual UDP checksum field at offset 6. (Even worse, the host network stack may then recompute the UDP checksum, "correcting" it to match the corrupt data before sending it out a physical interface.) Correct this by tracking the TSO context independently of the non-TSO context, and selecting the appropriate context based on the TSE flag in each transmit data descriptor. Signed-off-by: Ed Swierk --- hw/net/e1000.c | 70 +++++++++++++++++++++++++++++++++---------------------= ---- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/hw/net/e1000.c b/hw/net/e1000.c index 471cdd9..d642314 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -101,6 +101,7 @@ typedef struct E1000State_st { unsigned char sum_needed; bool cptse; e1000x_txd_props props; + e1000x_txd_props tso_props; uint16_t tso_frames; } tx; =20 @@ -541,35 +542,37 @@ xmit_seg(E1000State *s) uint16_t len; unsigned int frames =3D s->tx.tso_frames, css, sofar; struct e1000_tx *tp =3D &s->tx; + struct e1000x_txd_props *props =3D tp->cptse ? &tp->tso_props : &tp->p= rops; =20 - if (tp->props.tse && tp->cptse) { - css =3D tp->props.ipcss; + if (tp->cptse) { + css =3D props->ipcss; DBGOUT(TXSUM, "frames %d size %d ipcss %d\n", frames, tp->size, css); - if (tp->props.ip) { /* IPv4 */ + if (props->ip) { /* IPv4 */ stw_be_p(tp->data+css+2, tp->size - css); stw_be_p(tp->data+css+4, lduw_be_p(tp->data + css + 4) + frames); } else { /* IPv6 */ stw_be_p(tp->data+css+4, tp->size - css); } - css =3D tp->props.tucss; + css =3D props->tucss; len =3D tp->size - css; - DBGOUT(TXSUM, "tcp %d tucss %d len %d\n", tp->props.tcp, css, len); - if (tp->props.tcp) { - sofar =3D frames * tp->props.mss; + DBGOUT(TXSUM, "tcp %d tucss %d len %d\n", props->tcp, css, len); + if (props->tcp) { + sofar =3D frames * props->mss; stl_be_p(tp->data+css+4, ldl_be_p(tp->data+css+4)+sofar); /* s= eq */ - if (tp->props.paylen - sofar > tp->props.mss) { + if (props->paylen - sofar > props->mss) { tp->data[css + 13] &=3D ~9; /* PSH, FIN */ } else if (frames) { e1000x_inc_reg_if_not_full(s->mac_reg, TSCTC); } - } else /* UDP */ + } else { /* UDP */ stw_be_p(tp->data+css+4, len); + } if (tp->sum_needed & E1000_TXD_POPTS_TXSM) { unsigned int phsum; // add pseudo-header length before checksum calculation - void *sp =3D tp->data + tp->props.tucso; + void *sp =3D tp->data + props->tucso; =20 phsum =3D lduw_be_p(sp) + len; phsum =3D (phsum >> 16) + (phsum & 0xffff); @@ -579,12 +582,10 @@ xmit_seg(E1000State *s) } =20 if (tp->sum_needed & E1000_TXD_POPTS_TXSM) { - putsum(tp->data, tp->size, tp->props.tucso, - tp->props.tucss, tp->props.tucse); + putsum(tp->data, tp->size, props->tucso, props->tucss, props->tucs= e); } if (tp->sum_needed & E1000_TXD_POPTS_IXSM) { - putsum(tp->data, tp->size, tp->props.ipcso, - tp->props.ipcss, tp->props.ipcse); + putsum(tp->data, tp->size, props->ipcso, props->ipcss, props->ipcs= e); } if (tp->vlan_needed) { memmove(tp->vlan, tp->data, 4); @@ -616,11 +617,11 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *= dp) =20 s->mit_ide |=3D (txd_lower & E1000_TXD_CMD_IDE); if (dtype =3D=3D E1000_TXD_CMD_DEXT) { /* context descriptor */ - e1000x_read_tx_ctx_descr(xp, &tp->props); - tp->tso_frames =3D 0; - if (tp->props.tucso =3D=3D 0) { /* this is probably wrong */ - DBGOUT(TXSUM, "TCP/UDP: cso 0!\n"); - tp->props.tucso =3D tp->props.tucss + (tp->props.tcp ? 16 : 6); + if (le32_to_cpu(xp->cmd_and_length) & E1000_TXD_CMD_TSE) { + e1000x_read_tx_ctx_descr(xp, &tp->tso_props); + tp->tso_frames =3D 0; + } else { + e1000x_read_tx_ctx_descr(xp, &tp->props); } return; } else if (dtype =3D=3D (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) { @@ -645,8 +646,8 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) } =20 addr =3D le64_to_cpu(dp->buffer_addr); - if (tp->props.tse && tp->cptse) { - msh =3D tp->props.hdr_len + tp->props.mss; + if (tp->cptse) { + msh =3D tp->tso_props.hdr_len + tp->tso_props.mss; do { bytes =3D split_size; if (tp->size + bytes > msh) @@ -655,21 +656,19 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *= dp) bytes =3D MIN(sizeof(tp->data) - tp->size, bytes); pci_dma_read(d, addr, tp->data + tp->size, bytes); sz =3D tp->size + bytes; - if (sz >=3D tp->props.hdr_len && tp->size < tp->props.hdr_len)= { - memmove(tp->header, tp->data, tp->props.hdr_len); + if (sz >=3D tp->tso_props.hdr_len + && tp->size < tp->tso_props.hdr_len) { + memmove(tp->header, tp->data, tp->tso_props.hdr_len); } tp->size =3D sz; addr +=3D bytes; if (sz =3D=3D msh) { xmit_seg(s); - memmove(tp->data, tp->header, tp->props.hdr_len); - tp->size =3D tp->props.hdr_len; + memmove(tp->data, tp->header, tp->tso_props.hdr_len); + tp->size =3D tp->tso_props.hdr_len; } split_size -=3D bytes; } while (bytes && split_size); - } else if (!tp->props.tse && tp->cptse) { - // context descriptor TSE is not set, while data descriptor TSE is= set - DBGOUT(TXERR, "TCP segmentation error\n"); } else { split_size =3D MIN(sizeof(tp->data) - tp->size, split_size); pci_dma_read(d, addr, tp->data + tp->size, split_size); @@ -678,7 +677,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) =20 if (!(txd_lower & E1000_TXD_CMD_EOP)) return; - if (!(tp->props.tse && tp->cptse && tp->size < tp->props.hdr_len)) { + if (!(tp->cptse && tp->size < tp->tso_props.hdr_len)) { xmit_seg(s); } tp->tso_frames =3D 0; @@ -1435,7 +1434,7 @@ static const VMStateDescription vmstate_e1000_full_ma= c_state =3D { =20 static const VMStateDescription vmstate_e1000 =3D { .name =3D "e1000", - .version_id =3D 2, + .version_id =3D 3, .minimum_version_id =3D 1, .pre_save =3D e1000_pre_save, .post_load =3D e1000_post_load, @@ -1508,6 +1507,17 @@ static const VMStateDescription vmstate_e1000 =3D { VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, RA, 32), VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, MTA, 128), VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, VFTA, 128), + VMSTATE_UINT8_V(tx.tso_props.ipcss, E1000State, 3), + VMSTATE_UINT8_V(tx.tso_props.ipcso, E1000State, 3), + VMSTATE_UINT16_V(tx.tso_props.ipcse, E1000State, 3), + VMSTATE_UINT8_V(tx.tso_props.tucss, E1000State, 3), + VMSTATE_UINT8_V(tx.tso_props.tucso, E1000State, 3), + VMSTATE_UINT16_V(tx.tso_props.tucse, E1000State, 3), + VMSTATE_UINT32_V(tx.tso_props.paylen, E1000State, 3), + VMSTATE_UINT8_V(tx.tso_props.hdr_len, E1000State, 3), + VMSTATE_UINT16_V(tx.tso_props.mss, E1000State, 3), + VMSTATE_INT8_V(tx.tso_props.ip, E1000State, 3), + VMSTATE_INT8_V(tx.tso_props.tcp, E1000State, 3), VMSTATE_END_OF_LIST() }, .subsections =3D (const VMStateDescription*[]) { --=20 1.9.1