From 5c68564d80b7e4acff16ce069e5e3d412d73ce69 Mon Sep 17 00:00:00 2001 From: Bryan Cantrill Date: Wed, 31 Oct 2012 05:51:14 -0700 Subject: [PATCH] 3304 need workaround for QEMU bug that induces bad e1000g checksums Reviewed by: Hans Rosenfeld Reviewed by: Robert Mustacchi Reviewed by: Richard Lowe Reviewed by: Garrett D'Amore Approved by: Eric Schrock --- usr/src/uts/common/io/e1000g/e1000g_tx.c | 38 +++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/usr/src/uts/common/io/e1000g/e1000g_tx.c b/usr/src/uts/common/io/e1000g/e1000g_tx.c index e86e14e1c6..1f8a51d291 100644 --- a/usr/src/uts/common/io/e1000g/e1000g_tx.c +++ b/usr/src/uts/common/io/e1000g/e1000g_tx.c @@ -24,6 +24,10 @@ */ /* + * Copyright (c) 2012, Joyent, Inc. All rights reserved. + */ + +/* * ********************************************************************** * * * Module Name: * @@ -610,6 +614,7 @@ e1000g_fill_tx_ring(e1000g_tx_ring_t *tx_ring, LIST_DESCRIBER *pending_list, struct e1000_tx_desc *first_data_desc; struct e1000_tx_desc *next_desc; struct e1000_tx_desc *descriptor; + struct e1000_data_desc zeroed; int desc_count; boolean_t buff_overrun_flag; int i; @@ -624,6 +629,7 @@ e1000g_fill_tx_ring(e1000g_tx_ring_t *tx_ring, LIST_DESCRIBER *pending_list, first_packet = NULL; packet = NULL; buff_overrun_flag = B_FALSE; + zeroed.upper.data = 0; next_desc = tx_ring->tbd_next; @@ -649,6 +655,32 @@ e1000g_fill_tx_ring(e1000g_tx_ring_t *tx_ring, LIST_DESCRIBER *pending_list, first_data_desc = next_desc; + /* + * According to the documentation, the packet options field (POPTS) is + * "ignored except on the first data descriptor of a packet." However, + * there is a bug in QEMU (638955) whereby the POPTS field within a + * given data descriptor is used to interpret that data descriptor -- + * regardless of whether or not the descriptor is the first in a packet + * or not. For a packet that spans multiple descriptors, the (virtual) + * HW checksum (either TCP/UDP or IP or both) will therefore _not_ be + * performed on descriptors after the first, resulting in incorrect + * checksums and mysteriously dropped/retransmitted packets. Other + * drivers do not have this issue because they (harmlessly) set the + * POPTS field on every data descriptor to be the intended options for + * the entire packet. To circumvent this QEMU bug, we engage in this + * same behavior iff the subsystem vendor and device IDs indicate that + * this is an emulated QEMU device (1af4,1100). + */ + if (hw->subsystem_vendor_id == 0x1af4 && + hw->subsystem_device_id == 0x1100 && + cur_context->cksum_flags) { + if (cur_context->cksum_flags & HCK_IPV4_HDRCKSUM) + zeroed.upper.fields.popts |= E1000_TXD_POPTS_IXSM; + + if (cur_context->cksum_flags & HCK_PARTIALCKSUM) + zeroed.upper.fields.popts |= E1000_TXD_POPTS_TXSM; + } + packet = (p_tx_sw_packet_t)QUEUE_GET_HEAD(pending_list); while (packet) { ASSERT(packet->num_desc); @@ -663,7 +695,7 @@ e1000g_fill_tx_ring(e1000g_tx_ring_t *tx_ring, LIST_DESCRIBER *pending_list, packet->desc[i].length; /* Zero out status */ - descriptor->upper.data = 0; + descriptor->upper.data = zeroed.upper.data; descriptor->lower.data |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; @@ -708,7 +740,7 @@ e1000g_fill_tx_ring(e1000g_tx_ring_t *tx_ring, LIST_DESCRIBER *pending_list, E1000_TX_BUFFER_OEVRRUN_THRESHOLD; /* Zero out status */ - next_desc->upper.data = 0; + next_desc->upper.data = zeroed.upper.data; next_desc->lower.data |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; @@ -771,7 +803,7 @@ e1000g_fill_tx_ring(e1000g_tx_ring_t *tx_ring, LIST_DESCRIBER *pending_list, next_desc->lower.data = 4; /* Zero out status */ - next_desc->upper.data = 0; + next_desc->upper.data = zeroed.upper.data; /* It must be part of a LSO packet */ next_desc->lower.data |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D | -- 2.11.4.GIT