diff options
author | Kittipon Meesompop <kmeesomp@linux.vnet.ibm.com> | 2018-04-26 03:42:22 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-04-27 13:38:49 -0400 |
commit | 571f9dd8026b44fe52d9ca9ed6a68c53aad1f3ba (patch) | |
tree | f416457ad6ff96730b6ba225d86ed121945b1ae0 | |
parent | a8155b009f133445e874fb84c43f85091b345617 (diff) |
s390/qeth: add IPv6 TX checksum offload support
Check if a qeth device supports IPv6 TX checksum offload, and advertise
NETIF_F_IPV6_CSUM accordingly. Add support for setting the relevant bits
in IPv6 packet descriptors.
Currently this has only limited use (ie. UDP, or Jumbo Frames). For any
TCP traffic with a standard MSS, the TCP checksum gets calculated
as part of the linear GSO segmentation.
Signed-off-by: Kittipon Meesompop <kmeesomp@linux.vnet.ibm.com>
Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/s390/net/qeth_core.h | 13 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_main.c | 18 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_mpc.h | 1 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l2_main.c | 14 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l3_main.c | 7 |
5 files changed, 38 insertions, 15 deletions
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 7cbc9bf5d6b0..2a5fec55bf60 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h | |||
@@ -878,14 +878,17 @@ static inline void qeth_rx_csum(struct qeth_card *card, struct sk_buff *skb, | |||
878 | } | 878 | } |
879 | } | 879 | } |
880 | 880 | ||
881 | static inline void qeth_tx_csum(struct sk_buff *skb, u8 *flags) | 881 | static inline void qeth_tx_csum(struct sk_buff *skb, u8 *flags, int ipv) |
882 | { | 882 | { |
883 | *flags |= QETH_HDR_EXT_CSUM_TRANSP_REQ; | 883 | *flags |= QETH_HDR_EXT_CSUM_TRANSP_REQ; |
884 | if (ip_hdr(skb)->protocol == IPPROTO_UDP) | 884 | if ((ipv == 4 && ip_hdr(skb)->protocol == IPPROTO_UDP) || |
885 | (ipv == 6 && ipv6_hdr(skb)->nexthdr == IPPROTO_UDP)) | ||
885 | *flags |= QETH_HDR_EXT_UDP; | 886 | *flags |= QETH_HDR_EXT_UDP; |
886 | /* some HW requires combined L3+L4 csum offload: */ | 887 | if (ipv == 4) { |
887 | *flags |= QETH_HDR_EXT_CSUM_HDR_REQ; | 888 | /* some HW requires combined L3+L4 csum offload: */ |
888 | ip_hdr(skb)->check = 0; | 889 | *flags |= QETH_HDR_EXT_CSUM_HDR_REQ; |
890 | ip_hdr(skb)->check = 0; | ||
891 | } | ||
889 | } | 892 | } |
890 | 893 | ||
891 | static inline void qeth_put_buffer_pool_entry(struct qeth_card *card, | 894 | static inline void qeth_put_buffer_pool_entry(struct qeth_card *card, |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 5e4a509822f1..55b05d9c1cb6 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
@@ -6349,12 +6349,12 @@ static int qeth_ipa_checksum_run_cmd(struct qeth_card *card, | |||
6349 | static int qeth_send_checksum_on(struct qeth_card *card, int cstype, | 6349 | static int qeth_send_checksum_on(struct qeth_card *card, int cstype, |
6350 | enum qeth_prot_versions prot) | 6350 | enum qeth_prot_versions prot) |
6351 | { | 6351 | { |
6352 | const __u32 required_features = QETH_IPA_CHECKSUM_IP_HDR | | 6352 | u32 required_features = QETH_IPA_CHECKSUM_UDP | QETH_IPA_CHECKSUM_TCP; |
6353 | QETH_IPA_CHECKSUM_UDP | | ||
6354 | QETH_IPA_CHECKSUM_TCP; | ||
6355 | struct qeth_checksum_cmd chksum_cb; | 6353 | struct qeth_checksum_cmd chksum_cb; |
6356 | int rc; | 6354 | int rc; |
6357 | 6355 | ||
6356 | if (prot == QETH_PROT_IPV4) | ||
6357 | required_features |= QETH_IPA_CHECKSUM_IP_HDR; | ||
6358 | rc = qeth_ipa_checksum_run_cmd(card, cstype, IPA_CMD_ASS_START, 0, | 6358 | rc = qeth_ipa_checksum_run_cmd(card, cstype, IPA_CMD_ASS_START, 0, |
6359 | &chksum_cb, prot); | 6359 | &chksum_cb, prot); |
6360 | if (!rc) { | 6360 | if (!rc) { |
@@ -6430,8 +6430,8 @@ static int qeth_set_ipa_tso(struct qeth_card *card, int on) | |||
6430 | return rc; | 6430 | return rc; |
6431 | } | 6431 | } |
6432 | 6432 | ||
6433 | #define QETH_HW_FEATURES (NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_TSO) | 6433 | #define QETH_HW_FEATURES (NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_TSO | \ |
6434 | 6434 | NETIF_F_IPV6_CSUM) | |
6435 | /** | 6435 | /** |
6436 | * qeth_recover_features() - Restore device features after recovery | 6436 | * qeth_recover_features() - Restore device features after recovery |
6437 | * @dev: the recovering net_device | 6437 | * @dev: the recovering net_device |
@@ -6471,6 +6471,12 @@ int qeth_set_features(struct net_device *dev, netdev_features_t features) | |||
6471 | if (rc) | 6471 | if (rc) |
6472 | changed ^= NETIF_F_IP_CSUM; | 6472 | changed ^= NETIF_F_IP_CSUM; |
6473 | } | 6473 | } |
6474 | if (changed & NETIF_F_IPV6_CSUM) { | ||
6475 | rc = qeth_set_ipa_csum(card, features & NETIF_F_IPV6_CSUM, | ||
6476 | IPA_OUTBOUND_CHECKSUM, QETH_PROT_IPV6); | ||
6477 | if (rc) | ||
6478 | changed ^= NETIF_F_IPV6_CSUM; | ||
6479 | } | ||
6474 | if ((changed & NETIF_F_RXCSUM)) { | 6480 | if ((changed & NETIF_F_RXCSUM)) { |
6475 | rc = qeth_set_ipa_csum(card, features & NETIF_F_RXCSUM, | 6481 | rc = qeth_set_ipa_csum(card, features & NETIF_F_RXCSUM, |
6476 | IPA_INBOUND_CHECKSUM, QETH_PROT_IPV4); | 6482 | IPA_INBOUND_CHECKSUM, QETH_PROT_IPV4); |
@@ -6500,6 +6506,8 @@ netdev_features_t qeth_fix_features(struct net_device *dev, | |||
6500 | QETH_DBF_TEXT(SETUP, 2, "fixfeat"); | 6506 | QETH_DBF_TEXT(SETUP, 2, "fixfeat"); |
6501 | if (!qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM)) | 6507 | if (!qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM)) |
6502 | features &= ~NETIF_F_IP_CSUM; | 6508 | features &= ~NETIF_F_IP_CSUM; |
6509 | if (!qeth_is_supported6(card, IPA_OUTBOUND_CHECKSUM_V6)) | ||
6510 | features &= ~NETIF_F_IPV6_CSUM; | ||
6503 | if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM)) | 6511 | if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM)) |
6504 | features &= ~NETIF_F_RXCSUM; | 6512 | features &= ~NETIF_F_RXCSUM; |
6505 | if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) | 6513 | if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) |
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index f4d1ec0b8f5a..af3c35fbfa9e 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h | |||
@@ -246,6 +246,7 @@ enum qeth_ipa_funcs { | |||
246 | IPA_QUERY_ARP_ASSIST = 0x00040000L, | 246 | IPA_QUERY_ARP_ASSIST = 0x00040000L, |
247 | IPA_INBOUND_TSO = 0x00080000L, | 247 | IPA_INBOUND_TSO = 0x00080000L, |
248 | IPA_OUTBOUND_TSO = 0x00100000L, | 248 | IPA_OUTBOUND_TSO = 0x00100000L, |
249 | IPA_OUTBOUND_CHECKSUM_V6 = 0x00800000L, | ||
249 | }; | 250 | }; |
250 | 251 | ||
251 | /* SETIP/DELIP IPA Command: ***************************************************/ | 252 | /* SETIP/DELIP IPA Command: ***************************************************/ |
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 945df56434fd..5b1780fa4cb5 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c | |||
@@ -660,7 +660,8 @@ out: | |||
660 | } | 660 | } |
661 | 661 | ||
662 | static int qeth_l2_xmit_osa(struct qeth_card *card, struct sk_buff *skb, | 662 | static int qeth_l2_xmit_osa(struct qeth_card *card, struct sk_buff *skb, |
663 | struct qeth_qdio_out_q *queue, int cast_type) | 663 | struct qeth_qdio_out_q *queue, int cast_type, |
664 | int ipv) | ||
664 | { | 665 | { |
665 | int push_len = sizeof(struct qeth_hdr); | 666 | int push_len = sizeof(struct qeth_hdr); |
666 | unsigned int elements, nr_frags; | 667 | unsigned int elements, nr_frags; |
@@ -699,7 +700,7 @@ static int qeth_l2_xmit_osa(struct qeth_card *card, struct sk_buff *skb, | |||
699 | } | 700 | } |
700 | qeth_l2_fill_header(hdr, skb, cast_type, skb->len - push_len); | 701 | qeth_l2_fill_header(hdr, skb, cast_type, skb->len - push_len); |
701 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | 702 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
702 | qeth_tx_csum(skb, &hdr->hdr.l2.flags[1]); | 703 | qeth_tx_csum(skb, &hdr->hdr.l2.flags[1], ipv); |
703 | if (card->options.performance_stats) | 704 | if (card->options.performance_stats) |
704 | card->perf_stats.tx_csum++; | 705 | card->perf_stats.tx_csum++; |
705 | } | 706 | } |
@@ -754,6 +755,7 @@ static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb, | |||
754 | { | 755 | { |
755 | struct qeth_card *card = dev->ml_priv; | 756 | struct qeth_card *card = dev->ml_priv; |
756 | int cast_type = qeth_l2_get_cast_type(card, skb); | 757 | int cast_type = qeth_l2_get_cast_type(card, skb); |
758 | int ipv = qeth_get_ip_version(skb); | ||
757 | struct qeth_qdio_out_q *queue; | 759 | struct qeth_qdio_out_q *queue; |
758 | int tx_bytes = skb->len; | 760 | int tx_bytes = skb->len; |
759 | int rc; | 761 | int rc; |
@@ -761,7 +763,7 @@ static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb, | |||
761 | if (card->qdio.do_prio_queueing || (cast_type && | 763 | if (card->qdio.do_prio_queueing || (cast_type && |
762 | card->info.is_multicast_different)) | 764 | card->info.is_multicast_different)) |
763 | queue = card->qdio.out_qs[qeth_get_priority_queue(card, skb, | 765 | queue = card->qdio.out_qs[qeth_get_priority_queue(card, skb, |
764 | qeth_get_ip_version(skb), cast_type)]; | 766 | ipv, cast_type)]; |
765 | else | 767 | else |
766 | queue = card->qdio.out_qs[card->qdio.default_out_queue]; | 768 | queue = card->qdio.out_qs[card->qdio.default_out_queue]; |
767 | 769 | ||
@@ -784,7 +786,7 @@ static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb, | |||
784 | rc = qeth_l2_xmit_iqd(card, skb, queue, cast_type); | 786 | rc = qeth_l2_xmit_iqd(card, skb, queue, cast_type); |
785 | break; | 787 | break; |
786 | default: | 788 | default: |
787 | rc = qeth_l2_xmit_osa(card, skb, queue, cast_type); | 789 | rc = qeth_l2_xmit_osa(card, skb, queue, cast_type, ipv); |
788 | } | 790 | } |
789 | 791 | ||
790 | if (!rc) { | 792 | if (!rc) { |
@@ -995,6 +997,10 @@ static int qeth_l2_setup_netdev(struct qeth_card *card) | |||
995 | card->dev->vlan_features |= NETIF_F_RXCSUM; | 997 | card->dev->vlan_features |= NETIF_F_RXCSUM; |
996 | } | 998 | } |
997 | } | 999 | } |
1000 | if (qeth_is_supported6(card, IPA_OUTBOUND_CHECKSUM_V6)) { | ||
1001 | card->dev->hw_features |= NETIF_F_IPV6_CSUM; | ||
1002 | card->dev->vlan_features |= NETIF_F_IPV6_CSUM; | ||
1003 | } | ||
998 | 1004 | ||
999 | card->info.broadcast_capable = 1; | 1005 | card->info.broadcast_capable = 1; |
1000 | qeth_l2_request_initial_mac(card); | 1006 | qeth_l2_request_initial_mac(card); |
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index dd233fe3d6c4..e7fa479adf47 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c | |||
@@ -2281,7 +2281,7 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, | |||
2281 | } | 2281 | } |
2282 | 2282 | ||
2283 | if (new_skb->ip_summed == CHECKSUM_PARTIAL) { | 2283 | if (new_skb->ip_summed == CHECKSUM_PARTIAL) { |
2284 | qeth_tx_csum(new_skb, &hdr->hdr.l3.ext_flags); | 2284 | qeth_tx_csum(new_skb, &hdr->hdr.l3.ext_flags, ipv); |
2285 | if (card->options.performance_stats) | 2285 | if (card->options.performance_stats) |
2286 | card->perf_stats.tx_csum++; | 2286 | card->perf_stats.tx_csum++; |
2287 | } | 2287 | } |
@@ -2507,6 +2507,11 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) | |||
2507 | card->dev->vlan_features |= NETIF_F_TSO | | 2507 | card->dev->vlan_features |= NETIF_F_TSO | |
2508 | NETIF_F_RXCSUM | NETIF_F_IP_CSUM; | 2508 | NETIF_F_RXCSUM | NETIF_F_IP_CSUM; |
2509 | } | 2509 | } |
2510 | |||
2511 | if (qeth_is_supported6(card, IPA_OUTBOUND_CHECKSUM_V6)) { | ||
2512 | card->dev->hw_features |= NETIF_F_IPV6_CSUM; | ||
2513 | card->dev->vlan_features |= NETIF_F_IPV6_CSUM; | ||
2514 | } | ||
2510 | } else if (card->info.type == QETH_CARD_TYPE_IQD) { | 2515 | } else if (card->info.type == QETH_CARD_TYPE_IQD) { |
2511 | card->dev = alloc_netdev(0, "hsi%d", NET_NAME_UNKNOWN, | 2516 | card->dev = alloc_netdev(0, "hsi%d", NET_NAME_UNKNOWN, |
2512 | ether_setup); | 2517 | ether_setup); |