aboutsummaryrefslogtreecommitdiff
path: root/hw/net
diff options
context:
space:
mode:
Diffstat (limited to 'hw/net')
-rw-r--r--hw/net/rtl8139.c47
1 files changed, 24 insertions, 23 deletions
diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c
index e6643e3c9d..700b1b66b6 100644
--- a/hw/net/rtl8139.c
+++ b/hw/net/rtl8139.c
@@ -77,7 +77,6 @@
( ( input ) & ( size - 1 ) )
#define ETHER_TYPE_LEN 2
-#define ETH_MTU 1500
#define VLAN_TCI_LEN 2
#define VLAN_HLEN (ETHER_TYPE_LEN + VLAN_TCI_LEN)
@@ -1934,8 +1933,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
#define CP_TX_LS (1<<28)
/* large send packet flag */
#define CP_TX_LGSEN (1<<27)
-/* large send MSS mask, bits 16...25 */
-#define CP_TC_LGSEN_MSS_MASK ((1 << 12) - 1)
+/* large send MSS mask, bits 16...26 */
+#define CP_TC_LGSEN_MSS_SHIFT 16
+#define CP_TC_LGSEN_MSS_MASK ((1 << 11) - 1)
/* IP checksum offload flag */
#define CP_TX_IPCS (1<<18)
@@ -2027,18 +2027,21 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
s->currCPlusTxDesc = 0;
}
+ /* Build the Tx Status Descriptor */
+ uint32_t tx_status = txdw0;
+
/* transfer ownership to target */
- txdw0 &= ~CP_TX_OWN;
+ tx_status &= ~CP_TX_OWN;
/* reset error indicator bits */
- txdw0 &= ~CP_TX_STATUS_UNF;
- txdw0 &= ~CP_TX_STATUS_TES;
- txdw0 &= ~CP_TX_STATUS_OWC;
- txdw0 &= ~CP_TX_STATUS_LNKF;
- txdw0 &= ~CP_TX_STATUS_EXC;
+ tx_status &= ~CP_TX_STATUS_UNF;
+ tx_status &= ~CP_TX_STATUS_TES;
+ tx_status &= ~CP_TX_STATUS_OWC;
+ tx_status &= ~CP_TX_STATUS_LNKF;
+ tx_status &= ~CP_TX_STATUS_EXC;
/* update ring data */
- val = cpu_to_le32(txdw0);
+ val = cpu_to_le32(tx_status);
pci_dma_write(d, cplus_tx_ring_desc, (uint8_t *)&val, 4);
/* Now decide if descriptor being processed is holding the last segment of packet */
@@ -2132,7 +2135,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
}
ip_data_len -= hlen;
- if (txdw0 & CP_TX_IPCS)
+ if (!(txdw0 & CP_TX_LGSEN) && (txdw0 & CP_TX_IPCS))
{
DPRINTF("+++ C+ mode need IP checksum\n");
@@ -2149,10 +2152,11 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
goto skip_offload;
}
- int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK;
+ int large_send_mss = (txdw0 >> CP_TC_LGSEN_MSS_SHIFT) &
+ CP_TC_LGSEN_MSS_MASK;
- DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d "
- "frame data %d specified MSS=%d\n", ETH_MTU,
+ DPRINTF("+++ C+ mode offloaded task TSO IP data %d "
+ "frame data %d specified MSS=%d\n",
ip_data_len, saved_size - ETH_HLEN, large_send_mss);
int tcp_send_offset = 0;
@@ -2177,25 +2181,22 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
goto skip_offload;
}
- /* ETH_MTU = ip header len + tcp header len + payload */
int tcp_data_len = ip_data_len - tcp_hlen;
- int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen;
DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP "
- "data len %d TCP chunk size %d\n", ip_data_len,
- tcp_hlen, tcp_data_len, tcp_chunk_size);
+ "data len %d\n", ip_data_len, tcp_hlen, tcp_data_len);
/* note the cycle below overwrites IP header data,
but restores it from saved_ip_header before sending packet */
int is_last_frame = 0;
- for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size)
+ for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += large_send_mss)
{
- uint16_t chunk_size = tcp_chunk_size;
+ uint16_t chunk_size = large_send_mss;
/* check if this is the last frame */
- if (tcp_send_offset + tcp_chunk_size >= tcp_data_len)
+ if (tcp_send_offset + large_send_mss >= tcp_data_len)
{
is_last_frame = 1;
chunk_size = tcp_data_len - tcp_send_offset;
@@ -2244,7 +2245,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size);
/* increment IP id for subsequent frames */
- ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id));
+ ip->ip_id = cpu_to_be16(tcp_send_offset/large_send_mss + be16_to_cpu(ip->ip_id));
ip->ip_sum = 0;
ip->ip_sum = ip_checksum(eth_payload_data, hlen);
@@ -2265,7 +2266,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
/* Stop sending this frame */
saved_size = 0;
}
- else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS))
+ else if (!(txdw0 & CP_TX_LGSEN) && (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS)))
{
DPRINTF("+++ C+ mode need TCP or UDP checksum\n");