Commit 5a4b61a9 authored by Frank Blaschka's avatar Frank Blaschka Committed by Jeff Garzik

qeth: Announce tx checksumming for qeth devices in TSO/EDDP mode

TSO requires tx checksumming. For non GSO frames in TSO/EDDP mode we
have to manually calculate the checksum.
Signed-off-by: default avatarFrank Blaschka <frank.blaschka@de.ibm.com>
Signed-off-by: default avatarUrsula Braun <braunu@de.ibm.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent ecee51b7
...@@ -4555,6 +4555,53 @@ qeth_get_elements_no(struct qeth_card *card, void *hdr, ...@@ -4555,6 +4555,53 @@ qeth_get_elements_no(struct qeth_card *card, void *hdr,
return elements_needed; return elements_needed;
} }
static void qeth_tx_csum(struct sk_buff *skb)
{
int tlen;
if (skb->protocol == htons(ETH_P_IP)) {
tlen = ntohs(ip_hdr(skb)->tot_len) - (ip_hdr(skb)->ihl << 2);
switch (ip_hdr(skb)->protocol) {
case IPPROTO_TCP:
tcp_hdr(skb)->check = 0;
tcp_hdr(skb)->check = csum_tcpudp_magic(
ip_hdr(skb)->saddr, ip_hdr(skb)->daddr,
tlen, ip_hdr(skb)->protocol,
skb_checksum(skb, skb_transport_offset(skb),
tlen, 0));
break;
case IPPROTO_UDP:
udp_hdr(skb)->check = 0;
udp_hdr(skb)->check = csum_tcpudp_magic(
ip_hdr(skb)->saddr, ip_hdr(skb)->daddr,
tlen, ip_hdr(skb)->protocol,
skb_checksum(skb, skb_transport_offset(skb),
tlen, 0));
break;
}
} else if (skb->protocol == htons(ETH_P_IPV6)) {
switch (ipv6_hdr(skb)->nexthdr) {
case IPPROTO_TCP:
tcp_hdr(skb)->check = 0;
tcp_hdr(skb)->check = csum_ipv6_magic(
&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
ipv6_hdr(skb)->payload_len,
ipv6_hdr(skb)->nexthdr,
skb_checksum(skb, skb_transport_offset(skb),
ipv6_hdr(skb)->payload_len, 0));
break;
case IPPROTO_UDP:
udp_hdr(skb)->check = 0;
udp_hdr(skb)->check = csum_ipv6_magic(
&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
ipv6_hdr(skb)->payload_len,
ipv6_hdr(skb)->nexthdr,
skb_checksum(skb, skb_transport_offset(skb),
ipv6_hdr(skb)->payload_len, 0));
break;
}
}
}
static int static int
qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
...@@ -4640,6 +4687,10 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) ...@@ -4640,6 +4687,10 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
elements_needed += elems; elements_needed += elems;
} }
if ((large_send == QETH_LARGE_SEND_NO) &&
(skb->ip_summed == CHECKSUM_PARTIAL))
qeth_tx_csum(new_skb);
if (card->info.type != QETH_CARD_TYPE_IQD) if (card->info.type != QETH_CARD_TYPE_IQD)
rc = qeth_do_send_packet(card, queue, new_skb, hdr, rc = qeth_do_send_packet(card, queue, new_skb, hdr,
elements_needed, ctx); elements_needed, ctx);
...@@ -6387,20 +6438,18 @@ qeth_deregister_addr_entry(struct qeth_card *card, struct qeth_ipaddr *addr) ...@@ -6387,20 +6438,18 @@ qeth_deregister_addr_entry(struct qeth_card *card, struct qeth_ipaddr *addr)
static u32 static u32
qeth_ethtool_get_tx_csum(struct net_device *dev) qeth_ethtool_get_tx_csum(struct net_device *dev)
{ {
/* We may need to say that we support tx csum offload if return (dev->features & NETIF_F_HW_CSUM) != 0;
* we do EDDP or TSO. There are discussions going on to
* enforce rules in the stack and in ethtool that make
* SG and TSO depend on HW_CSUM. At the moment there are
* no such rules....
* If we say yes here, we have to checksum outbound packets
* any time. */
return 0;
} }
static int static int
qeth_ethtool_set_tx_csum(struct net_device *dev, u32 data) qeth_ethtool_set_tx_csum(struct net_device *dev, u32 data)
{ {
return -EINVAL; if (data)
dev->features |= NETIF_F_HW_CSUM;
else
dev->features &= ~NETIF_F_HW_CSUM;
return 0;
} }
static u32 static u32
...@@ -7414,7 +7463,8 @@ qeth_start_ipa_tso(struct qeth_card *card) ...@@ -7414,7 +7463,8 @@ qeth_start_ipa_tso(struct qeth_card *card)
} }
if (rc && (card->options.large_send == QETH_LARGE_SEND_TSO)){ if (rc && (card->options.large_send == QETH_LARGE_SEND_TSO)){
card->options.large_send = QETH_LARGE_SEND_NO; card->options.large_send = QETH_LARGE_SEND_NO;
card->dev->features &= ~ (NETIF_F_TSO | NETIF_F_SG); card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG |
NETIF_F_HW_CSUM);
} }
return rc; return rc;
} }
...@@ -7554,22 +7604,26 @@ qeth_set_large_send(struct qeth_card *card, enum qeth_large_send_types type) ...@@ -7554,22 +7604,26 @@ qeth_set_large_send(struct qeth_card *card, enum qeth_large_send_types type)
card->options.large_send = type; card->options.large_send = type;
switch (card->options.large_send) { switch (card->options.large_send) {
case QETH_LARGE_SEND_EDDP: case QETH_LARGE_SEND_EDDP:
card->dev->features |= NETIF_F_TSO | NETIF_F_SG; card->dev->features |= NETIF_F_TSO | NETIF_F_SG |
NETIF_F_HW_CSUM;
break; break;
case QETH_LARGE_SEND_TSO: case QETH_LARGE_SEND_TSO:
if (qeth_is_supported(card, IPA_OUTBOUND_TSO)){ if (qeth_is_supported(card, IPA_OUTBOUND_TSO)){
card->dev->features |= NETIF_F_TSO | NETIF_F_SG; card->dev->features |= NETIF_F_TSO | NETIF_F_SG |
NETIF_F_HW_CSUM;
} else { } else {
PRINT_WARN("TSO not supported on %s. " PRINT_WARN("TSO not supported on %s. "
"large_send set to 'no'.\n", "large_send set to 'no'.\n",
card->dev->name); card->dev->name);
card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG); card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG |
NETIF_F_HW_CSUM);
card->options.large_send = QETH_LARGE_SEND_NO; card->options.large_send = QETH_LARGE_SEND_NO;
rc = -EOPNOTSUPP; rc = -EOPNOTSUPP;
} }
break; break;
default: /* includes QETH_LARGE_SEND_NO */ default: /* includes QETH_LARGE_SEND_NO */
card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG); card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG |
NETIF_F_HW_CSUM);
break; break;
} }
if (card->state == CARD_STATE_UP) if (card->state == CARD_STATE_UP)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment