aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/net
diff options
context:
space:
mode:
authorFrank Blaschka <frank.blaschka@de.ibm.com>2010-05-11 15:34:45 -0400
committerDavid S. Miller <davem@davemloft.net>2010-05-16 03:50:10 -0400
commitf6b85b6c42ccc20316a25f6ccbe7a984c5a1304d (patch)
tree6016fd9f624871b427819173e59f49f311ed7649 /drivers/s390/net
parent2d6c9ffcca7808f42ba6b953da0ba60e19a9cbbd (diff)
qeth: exploit HW TX checksumming
OSA supports HW TX checksumming in layer 3 mode. Enable this feature and remove software fallback used for TSO. Cleanup checksum bits to indicate OSA can do checksumming only for IPv4 TCP and UDP. Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/s390/net')
-rw-r--r--drivers/s390/net/qeth_core.h3
-rw-r--r--drivers/s390/net/qeth_l3_main.c92
2 files changed, 69 insertions, 26 deletions
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index fcd005aad989..bab0febf0725 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -351,7 +351,7 @@ enum qeth_header_ids {
351#define QETH_HDR_EXT_SRC_MAC_ADDR 0x08 351#define QETH_HDR_EXT_SRC_MAC_ADDR 0x08
352#define QETH_HDR_EXT_CSUM_HDR_REQ 0x10 352#define QETH_HDR_EXT_CSUM_HDR_REQ 0x10
353#define QETH_HDR_EXT_CSUM_TRANSP_REQ 0x20 353#define QETH_HDR_EXT_CSUM_TRANSP_REQ 0x20
354#define QETH_HDR_EXT_UDP_TSO 0x40 /*bit off for TCP*/ 354#define QETH_HDR_EXT_UDP 0x40 /*bit off for TCP*/
355 355
356static inline int qeth_is_last_sbale(struct qdio_buffer_element *sbale) 356static inline int qeth_is_last_sbale(struct qdio_buffer_element *sbale)
357{ 357{
@@ -630,6 +630,7 @@ struct qeth_card_info {
630 int unique_id; 630 int unique_id;
631 struct qeth_card_blkt blkt; 631 struct qeth_card_blkt blkt;
632 __u32 csum_mask; 632 __u32 csum_mask;
633 __u32 tx_csum_mask;
633 enum qeth_ipa_promisc_modes promisc_mode; 634 enum qeth_ipa_promisc_modes promisc_mode;
634}; 635};
635 636
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 35b6d3d2bd73..8bcad24ccf37 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -54,16 +54,16 @@ int qeth_l3_set_large_send(struct qeth_card *card,
54 if (card->options.large_send == QETH_LARGE_SEND_TSO) { 54 if (card->options.large_send == QETH_LARGE_SEND_TSO) {
55 if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) { 55 if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) {
56 card->dev->features |= NETIF_F_TSO | NETIF_F_SG | 56 card->dev->features |= NETIF_F_TSO | NETIF_F_SG |
57 NETIF_F_HW_CSUM; 57 NETIF_F_IP_CSUM;
58 } else { 58 } else {
59 card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | 59 card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG |
60 NETIF_F_HW_CSUM); 60 NETIF_F_IP_CSUM);
61 card->options.large_send = QETH_LARGE_SEND_NO; 61 card->options.large_send = QETH_LARGE_SEND_NO;
62 rc = -EOPNOTSUPP; 62 rc = -EOPNOTSUPP;
63 } 63 }
64 } else { 64 } else {
65 card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | 65 card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG |
66 NETIF_F_HW_CSUM); 66 NETIF_F_IP_CSUM);
67 card->options.large_send = QETH_LARGE_SEND_NO; 67 card->options.large_send = QETH_LARGE_SEND_NO;
68 } 68 }
69 return rc; 69 return rc;
@@ -1108,6 +1108,13 @@ static int qeth_l3_default_setassparms_cb(struct qeth_card *card,
1108 card->info.csum_mask = cmd->data.setassparms.data.flags_32bit; 1108 card->info.csum_mask = cmd->data.setassparms.data.flags_32bit;
1109 QETH_DBF_TEXT_(TRACE, 3, "csum:%d", card->info.csum_mask); 1109 QETH_DBF_TEXT_(TRACE, 3, "csum:%d", card->info.csum_mask);
1110 } 1110 }
1111 if (cmd->data.setassparms.hdr.assist_no == IPA_OUTBOUND_CHECKSUM &&
1112 cmd->data.setassparms.hdr.command_code == IPA_CMD_ASS_START) {
1113 card->info.tx_csum_mask =
1114 cmd->data.setassparms.data.flags_32bit;
1115 QETH_DBF_TEXT_(TRACE, 3, "tcsu:%d", card->info.tx_csum_mask);
1116 }
1117
1111 return 0; 1118 return 0;
1112} 1119}
1113 1120
@@ -1536,6 +1543,28 @@ static int qeth_l3_start_ipa_checksum(struct qeth_card *card)
1536 return rc; 1543 return rc;
1537} 1544}
1538 1545
1546static int qeth_l3_start_ipa_tx_checksum(struct qeth_card *card)
1547{
1548 int rc = 0;
1549
1550 if (!qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM))
1551 return rc;
1552 rc = qeth_l3_send_simple_setassparms(card, IPA_OUTBOUND_CHECKSUM,
1553 IPA_CMD_ASS_START, 0);
1554 if (rc)
1555 goto err_out;
1556 rc = qeth_l3_send_simple_setassparms(card, IPA_OUTBOUND_CHECKSUM,
1557 IPA_CMD_ASS_ENABLE, card->info.tx_csum_mask);
1558 if (rc)
1559 goto err_out;
1560 dev_info(&card->gdev->dev, "HW TX Checksumming enabled\n");
1561 return rc;
1562err_out:
1563 dev_warn(&card->gdev->dev, "Enabling HW TX checksumming for %s "
1564 "failed, using SW TX checksumming\n", QETH_CARD_IFNAME(card));
1565 return rc;
1566}
1567
1539static int qeth_l3_start_ipa_tso(struct qeth_card *card) 1568static int qeth_l3_start_ipa_tso(struct qeth_card *card)
1540{ 1569{
1541 int rc; 1570 int rc;
@@ -1578,6 +1607,7 @@ static int qeth_l3_start_ipassists(struct qeth_card *card)
1578 qeth_l3_start_ipa_ipv6(card); /* go on*/ 1607 qeth_l3_start_ipa_ipv6(card); /* go on*/
1579 qeth_l3_start_ipa_broadcast(card); /* go on*/ 1608 qeth_l3_start_ipa_broadcast(card); /* go on*/
1580 qeth_l3_start_ipa_checksum(card); /* go on*/ 1609 qeth_l3_start_ipa_checksum(card); /* go on*/
1610 qeth_l3_start_ipa_tx_checksum(card);
1581 qeth_l3_start_ipa_tso(card); /* go on*/ 1611 qeth_l3_start_ipa_tso(card); /* go on*/
1582 return 0; 1612 return 0;
1583} 1613}
@@ -2817,6 +2847,21 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
2817 } 2847 }
2818} 2848}
2819 2849
2850static inline void qeth_l3_hdr_csum(struct qeth_card *card,
2851 struct qeth_hdr *hdr, struct sk_buff *skb)
2852{
2853 struct iphdr *iph = ip_hdr(skb);
2854
2855 /* tcph->check contains already the pseudo hdr checksum
2856 * so just set the header flags
2857 */
2858 if (iph->protocol == IPPROTO_UDP)
2859 hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_UDP;
2860 hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_CSUM_TRANSP_REQ;
2861 if (card->options.performance_stats)
2862 card->perf_stats.tx_csum++;
2863}
2864
2820static void qeth_tso_fill_header(struct qeth_card *card, 2865static void qeth_tso_fill_header(struct qeth_card *card,
2821 struct qeth_hdr *qhdr, struct sk_buff *skb) 2866 struct qeth_hdr *qhdr, struct sk_buff *skb)
2822{ 2867{
@@ -2852,21 +2897,6 @@ static void qeth_tso_fill_header(struct qeth_card *card,
2852 } 2897 }
2853} 2898}
2854 2899
2855static void qeth_tx_csum(struct sk_buff *skb)
2856{
2857 __wsum csum;
2858 int offset;
2859
2860 skb_set_transport_header(skb, skb->csum_start - skb_headroom(skb));
2861 offset = skb->csum_start - skb_headroom(skb);
2862 BUG_ON(offset >= skb_headlen(skb));
2863 csum = skb_checksum(skb, offset, skb->len - offset, 0);
2864
2865 offset += skb->csum_offset;
2866 BUG_ON(offset + sizeof(__sum16) > skb_headlen(skb));
2867 *(__sum16 *)(skb->data + offset) = csum_fold(csum);
2868}
2869
2870static inline int qeth_l3_tso_elements(struct sk_buff *skb) 2900static inline int qeth_l3_tso_elements(struct sk_buff *skb)
2871{ 2901{
2872 unsigned long tcpd = (unsigned long)tcp_hdr(skb) + 2902 unsigned long tcpd = (unsigned long)tcp_hdr(skb) +
@@ -2923,12 +2953,6 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
2923 2953
2924 if (skb_is_gso(skb)) 2954 if (skb_is_gso(skb))
2925 large_send = card->options.large_send; 2955 large_send = card->options.large_send;
2926 else
2927 if (skb->ip_summed == CHECKSUM_PARTIAL) {
2928 qeth_tx_csum(skb);
2929 if (card->options.performance_stats)
2930 card->perf_stats.tx_csum++;
2931 }
2932 2956
2933 if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) && 2957 if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) &&
2934 (skb_shinfo(skb)->nr_frags == 0)) { 2958 (skb_shinfo(skb)->nr_frags == 0)) {
@@ -3007,6 +3031,9 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
3007 cast_type); 3031 cast_type);
3008 hdr->hdr.l3.length = new_skb->len - data_offset; 3032 hdr->hdr.l3.length = new_skb->len - data_offset;
3009 } 3033 }
3034
3035 if (skb->ip_summed == CHECKSUM_PARTIAL)
3036 qeth_l3_hdr_csum(card, hdr, new_skb);
3010 } 3037 }
3011 3038
3012 elems = qeth_get_elements_no(card, (void *)hdr, new_skb, 3039 elems = qeth_get_elements_no(card, (void *)hdr, new_skb,
@@ -3132,10 +3159,25 @@ static int qeth_l3_ethtool_set_tso(struct net_device *dev, u32 data)
3132 return rc; 3159 return rc;
3133} 3160}
3134 3161
3162static int qeth_l3_ethtool_set_tx_csum(struct net_device *dev, u32 data)
3163{
3164 struct qeth_card *card = dev->ml_priv;
3165
3166 if (data) {
3167 if (qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM))
3168 dev->features |= NETIF_F_IP_CSUM;
3169 else
3170 return -EPERM;
3171 } else
3172 dev->features &= ~NETIF_F_IP_CSUM;
3173
3174 return 0;
3175}
3176
3135static const struct ethtool_ops qeth_l3_ethtool_ops = { 3177static const struct ethtool_ops qeth_l3_ethtool_ops = {
3136 .get_link = ethtool_op_get_link, 3178 .get_link = ethtool_op_get_link,
3137 .get_tx_csum = ethtool_op_get_tx_csum, 3179 .get_tx_csum = ethtool_op_get_tx_csum,
3138 .set_tx_csum = ethtool_op_set_tx_hw_csum, 3180 .set_tx_csum = qeth_l3_ethtool_set_tx_csum,
3139 .get_rx_csum = qeth_l3_ethtool_get_rx_csum, 3181 .get_rx_csum = qeth_l3_ethtool_get_rx_csum,
3140 .set_rx_csum = qeth_l3_ethtool_set_rx_csum, 3182 .set_rx_csum = qeth_l3_ethtool_set_rx_csum,
3141 .get_sg = ethtool_op_get_sg, 3183 .get_sg = ethtool_op_get_sg,