diff options
author | Frank Blaschka <frank.blaschka@de.ibm.com> | 2007-08-29 05:26:55 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-08-31 06:52:58 -0400 |
commit | 5a4b61a95a9b742d8a966950d23f386c34a733f2 (patch) | |
tree | 76c60e9e5c30304c6434f2eb7365778989ae9bb7 | |
parent | ecee51b755335d3ff254199fc1a2775ea451eecf (diff) |
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: Frank Blaschka <frank.blaschka@de.ibm.com>
Signed-off-by: Ursula Braun <braunu@de.ibm.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r-- | drivers/s390/net/qeth_main.c | 82 |
1 files changed, 68 insertions, 14 deletions
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 610d27cfd28b..443cde10353e 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c | |||
@@ -4555,6 +4555,53 @@ qeth_get_elements_no(struct qeth_card *card, void *hdr, | |||
4555 | return elements_needed; | 4555 | return elements_needed; |
4556 | } | 4556 | } |
4557 | 4557 | ||
4558 | static void qeth_tx_csum(struct sk_buff *skb) | ||
4559 | { | ||
4560 | int tlen; | ||
4561 | |||
4562 | if (skb->protocol == htons(ETH_P_IP)) { | ||
4563 | tlen = ntohs(ip_hdr(skb)->tot_len) - (ip_hdr(skb)->ihl << 2); | ||
4564 | switch (ip_hdr(skb)->protocol) { | ||
4565 | case IPPROTO_TCP: | ||
4566 | tcp_hdr(skb)->check = 0; | ||
4567 | tcp_hdr(skb)->check = csum_tcpudp_magic( | ||
4568 | ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, | ||
4569 | tlen, ip_hdr(skb)->protocol, | ||
4570 | skb_checksum(skb, skb_transport_offset(skb), | ||
4571 | tlen, 0)); | ||
4572 | break; | ||
4573 | case IPPROTO_UDP: | ||
4574 | udp_hdr(skb)->check = 0; | ||
4575 | udp_hdr(skb)->check = csum_tcpudp_magic( | ||
4576 | ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, | ||
4577 | tlen, ip_hdr(skb)->protocol, | ||
4578 | skb_checksum(skb, skb_transport_offset(skb), | ||
4579 | tlen, 0)); | ||
4580 | break; | ||
4581 | } | ||
4582 | } else if (skb->protocol == htons(ETH_P_IPV6)) { | ||
4583 | switch (ipv6_hdr(skb)->nexthdr) { | ||
4584 | case IPPROTO_TCP: | ||
4585 | tcp_hdr(skb)->check = 0; | ||
4586 | tcp_hdr(skb)->check = csum_ipv6_magic( | ||
4587 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, | ||
4588 | ipv6_hdr(skb)->payload_len, | ||
4589 | ipv6_hdr(skb)->nexthdr, | ||
4590 | skb_checksum(skb, skb_transport_offset(skb), | ||
4591 | ipv6_hdr(skb)->payload_len, 0)); | ||
4592 | break; | ||
4593 | case IPPROTO_UDP: | ||
4594 | udp_hdr(skb)->check = 0; | ||
4595 | udp_hdr(skb)->check = csum_ipv6_magic( | ||
4596 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, | ||
4597 | ipv6_hdr(skb)->payload_len, | ||
4598 | ipv6_hdr(skb)->nexthdr, | ||
4599 | skb_checksum(skb, skb_transport_offset(skb), | ||
4600 | ipv6_hdr(skb)->payload_len, 0)); | ||
4601 | break; | ||
4602 | } | ||
4603 | } | ||
4604 | } | ||
4558 | 4605 | ||
4559 | static int | 4606 | static int |
4560 | qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) | 4607 | 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 | elements_needed += elems; | 4687 | elements_needed += elems; |
4641 | } | 4688 | } |
4642 | 4689 | ||
4690 | if ((large_send == QETH_LARGE_SEND_NO) && | ||
4691 | (skb->ip_summed == CHECKSUM_PARTIAL)) | ||
4692 | qeth_tx_csum(new_skb); | ||
4693 | |||
4643 | if (card->info.type != QETH_CARD_TYPE_IQD) | 4694 | if (card->info.type != QETH_CARD_TYPE_IQD) |
4644 | rc = qeth_do_send_packet(card, queue, new_skb, hdr, | 4695 | rc = qeth_do_send_packet(card, queue, new_skb, hdr, |
4645 | elements_needed, ctx); | 4696 | elements_needed, ctx); |
@@ -6387,20 +6438,18 @@ qeth_deregister_addr_entry(struct qeth_card *card, struct qeth_ipaddr *addr) | |||
6387 | static u32 | 6438 | static u32 |
6388 | qeth_ethtool_get_tx_csum(struct net_device *dev) | 6439 | qeth_ethtool_get_tx_csum(struct net_device *dev) |
6389 | { | 6440 | { |
6390 | /* We may need to say that we support tx csum offload if | 6441 | return (dev->features & NETIF_F_HW_CSUM) != 0; |
6391 | * we do EDDP or TSO. There are discussions going on to | ||
6392 | * enforce rules in the stack and in ethtool that make | ||
6393 | * SG and TSO depend on HW_CSUM. At the moment there are | ||
6394 | * no such rules.... | ||
6395 | * If we say yes here, we have to checksum outbound packets | ||
6396 | * any time. */ | ||
6397 | return 0; | ||
6398 | } | 6442 | } |
6399 | 6443 | ||
6400 | static int | 6444 | static int |
6401 | qeth_ethtool_set_tx_csum(struct net_device *dev, u32 data) | 6445 | qeth_ethtool_set_tx_csum(struct net_device *dev, u32 data) |
6402 | { | 6446 | { |
6403 | return -EINVAL; | 6447 | if (data) |
6448 | dev->features |= NETIF_F_HW_CSUM; | ||
6449 | else | ||
6450 | dev->features &= ~NETIF_F_HW_CSUM; | ||
6451 | |||
6452 | return 0; | ||
6404 | } | 6453 | } |
6405 | 6454 | ||
6406 | static u32 | 6455 | static u32 |
@@ -7414,7 +7463,8 @@ qeth_start_ipa_tso(struct qeth_card *card) | |||
7414 | } | 7463 | } |
7415 | if (rc && (card->options.large_send == QETH_LARGE_SEND_TSO)){ | 7464 | if (rc && (card->options.large_send == QETH_LARGE_SEND_TSO)){ |
7416 | card->options.large_send = QETH_LARGE_SEND_NO; | 7465 | card->options.large_send = QETH_LARGE_SEND_NO; |
7417 | card->dev->features &= ~ (NETIF_F_TSO | NETIF_F_SG); | 7466 | card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | |
7467 | NETIF_F_HW_CSUM); | ||
7418 | } | 7468 | } |
7419 | return rc; | 7469 | return rc; |
7420 | } | 7470 | } |
@@ -7554,22 +7604,26 @@ qeth_set_large_send(struct qeth_card *card, enum qeth_large_send_types type) | |||
7554 | card->options.large_send = type; | 7604 | card->options.large_send = type; |
7555 | switch (card->options.large_send) { | 7605 | switch (card->options.large_send) { |
7556 | case QETH_LARGE_SEND_EDDP: | 7606 | case QETH_LARGE_SEND_EDDP: |
7557 | card->dev->features |= NETIF_F_TSO | NETIF_F_SG; | 7607 | card->dev->features |= NETIF_F_TSO | NETIF_F_SG | |
7608 | NETIF_F_HW_CSUM; | ||
7558 | break; | 7609 | break; |
7559 | case QETH_LARGE_SEND_TSO: | 7610 | case QETH_LARGE_SEND_TSO: |
7560 | if (qeth_is_supported(card, IPA_OUTBOUND_TSO)){ | 7611 | if (qeth_is_supported(card, IPA_OUTBOUND_TSO)){ |
7561 | card->dev->features |= NETIF_F_TSO | NETIF_F_SG; | 7612 | card->dev->features |= NETIF_F_TSO | NETIF_F_SG | |
7613 | NETIF_F_HW_CSUM; | ||
7562 | } else { | 7614 | } else { |
7563 | PRINT_WARN("TSO not supported on %s. " | 7615 | PRINT_WARN("TSO not supported on %s. " |
7564 | "large_send set to 'no'.\n", | 7616 | "large_send set to 'no'.\n", |
7565 | card->dev->name); | 7617 | card->dev->name); |
7566 | card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG); | 7618 | card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | |
7619 | NETIF_F_HW_CSUM); | ||
7567 | card->options.large_send = QETH_LARGE_SEND_NO; | 7620 | card->options.large_send = QETH_LARGE_SEND_NO; |
7568 | rc = -EOPNOTSUPP; | 7621 | rc = -EOPNOTSUPP; |
7569 | } | 7622 | } |
7570 | break; | 7623 | break; |
7571 | default: /* includes QETH_LARGE_SEND_NO */ | 7624 | default: /* includes QETH_LARGE_SEND_NO */ |
7572 | card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG); | 7625 | card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | |
7626 | NETIF_F_HW_CSUM); | ||
7573 | break; | 7627 | break; |
7574 | } | 7628 | } |
7575 | if (card->state == CARD_STATE_UP) | 7629 | if (card->state == CARD_STATE_UP) |