diff options
author | Julian Wiedmann <jwi@linux.ibm.com> | 2018-09-17 11:36:04 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-09-17 12:10:25 -0400 |
commit | 69d7ce80df6d0d2fdbb8f0ff9ec4643aabfa6b99 (patch) | |
tree | 8ce99875ee8eb96574f027d108e8aaefd94c3aaa | |
parent | 356156b60affae4372ed9d3dc8936ff22e8849b0 (diff) |
s390/qeth: remove qeth_hdr_chk_and_bounce()
Restructure the OSN xmit path to handle misaligned HW headers properly,
without shifting the packet data around.
Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/s390/net/qeth_core.h | 1 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_main.c | 21 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l2_main.c | 37 |
3 files changed, 28 insertions, 31 deletions
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 1c9fce609eb9..be213b5c2552 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h | |||
@@ -1021,7 +1021,6 @@ void qeth_dbf_longtext(debug_info_t *id, int level, char *text, ...); | |||
1021 | int qeth_core_ethtool_get_link_ksettings(struct net_device *netdev, | 1021 | int qeth_core_ethtool_get_link_ksettings(struct net_device *netdev, |
1022 | struct ethtool_link_ksettings *cmd); | 1022 | struct ethtool_link_ksettings *cmd); |
1023 | int qeth_set_access_ctrl_online(struct qeth_card *card, int fallback); | 1023 | int qeth_set_access_ctrl_online(struct qeth_card *card, int fallback); |
1024 | int qeth_hdr_chk_and_bounce(struct sk_buff *, struct qeth_hdr **, int); | ||
1025 | int qeth_configure_cq(struct qeth_card *, enum qeth_cq); | 1024 | int qeth_configure_cq(struct qeth_card *, enum qeth_cq); |
1026 | int qeth_hw_trap(struct qeth_card *, enum qeth_diags_trap_action); | 1025 | int qeth_hw_trap(struct qeth_card *, enum qeth_diags_trap_action); |
1027 | void qeth_trace_features(struct qeth_card *); | 1026 | void qeth_trace_features(struct qeth_card *); |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 7426167eace2..c7f7061a7205 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
@@ -3823,27 +3823,6 @@ unsigned int qeth_count_elements(struct sk_buff *skb, unsigned int data_offset) | |||
3823 | } | 3823 | } |
3824 | EXPORT_SYMBOL_GPL(qeth_count_elements); | 3824 | EXPORT_SYMBOL_GPL(qeth_count_elements); |
3825 | 3825 | ||
3826 | int qeth_hdr_chk_and_bounce(struct sk_buff *skb, struct qeth_hdr **hdr, int len) | ||
3827 | { | ||
3828 | int hroom, inpage, rest; | ||
3829 | |||
3830 | if (((unsigned long)skb->data & PAGE_MASK) != | ||
3831 | (((unsigned long)skb->data + len - 1) & PAGE_MASK)) { | ||
3832 | hroom = skb_headroom(skb); | ||
3833 | inpage = PAGE_SIZE - ((unsigned long) skb->data % PAGE_SIZE); | ||
3834 | rest = len - inpage; | ||
3835 | if (rest > hroom) | ||
3836 | return 1; | ||
3837 | memmove(skb->data - rest, skb->data, skb_headlen(skb)); | ||
3838 | skb->data -= rest; | ||
3839 | skb->tail -= rest; | ||
3840 | *hdr = (struct qeth_hdr *)skb->data; | ||
3841 | QETH_DBF_MESSAGE(2, "skb bounce len: %d rest: %d\n", len, rest); | ||
3842 | } | ||
3843 | return 0; | ||
3844 | } | ||
3845 | EXPORT_SYMBOL_GPL(qeth_hdr_chk_and_bounce); | ||
3846 | |||
3847 | #define QETH_HDR_CACHE_OBJ_SIZE (sizeof(struct qeth_hdr_tso) + \ | 3826 | #define QETH_HDR_CACHE_OBJ_SIZE (sizeof(struct qeth_hdr_tso) + \ |
3848 | MAX_TCP_HEADER) | 3827 | MAX_TCP_HEADER) |
3849 | 3828 | ||
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 24b531ca2827..33b65471a68a 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c | |||
@@ -650,19 +650,38 @@ static void qeth_l2_set_rx_mode(struct net_device *dev) | |||
650 | static int qeth_l2_xmit_osn(struct qeth_card *card, struct sk_buff *skb, | 650 | static int qeth_l2_xmit_osn(struct qeth_card *card, struct sk_buff *skb, |
651 | struct qeth_qdio_out_q *queue) | 651 | struct qeth_qdio_out_q *queue) |
652 | { | 652 | { |
653 | unsigned int elements; | 653 | struct qeth_hdr *hdr = (struct qeth_hdr *)skb->data; |
654 | struct qeth_hdr *hdr; | 654 | addr_t end = (addr_t)(skb->data + sizeof(*hdr)); |
655 | addr_t start = (addr_t)skb->data; | ||
656 | unsigned int elements = 0; | ||
657 | unsigned int hd_len = 0; | ||
658 | int rc; | ||
655 | 659 | ||
656 | if (skb->protocol == htons(ETH_P_IPV6)) | 660 | if (skb->protocol == htons(ETH_P_IPV6)) |
657 | return -EPROTONOSUPPORT; | 661 | return -EPROTONOSUPPORT; |
658 | 662 | ||
659 | hdr = (struct qeth_hdr *)skb->data; | 663 | if (qeth_get_elements_for_range(start, end) > 1) { |
660 | elements = qeth_count_elements(skb, 0); | 664 | /* Misaligned HW header, move it to its own buffer element. */ |
661 | if (elements > QETH_MAX_BUFFER_ELEMENTS(card)) | 665 | hdr = kmem_cache_alloc(qeth_core_header_cache, GFP_ATOMIC); |
662 | return -E2BIG; | 666 | if (!hdr) |
663 | if (qeth_hdr_chk_and_bounce(skb, &hdr, sizeof(*hdr))) | 667 | return -ENOMEM; |
664 | return -EINVAL; | 668 | hd_len = sizeof(*hdr); |
665 | return qeth_do_send_packet(card, queue, skb, hdr, 0, 0, elements); | 669 | skb_copy_from_linear_data(skb, (char *)hdr, hd_len); |
670 | elements++; | ||
671 | } | ||
672 | |||
673 | elements += qeth_count_elements(skb, hd_len); | ||
674 | if (elements > QETH_MAX_BUFFER_ELEMENTS(card)) { | ||
675 | rc = -E2BIG; | ||
676 | goto out; | ||
677 | } | ||
678 | |||
679 | rc = qeth_do_send_packet(card, queue, skb, hdr, hd_len, hd_len, | ||
680 | elements); | ||
681 | out: | ||
682 | if (rc && hd_len) | ||
683 | kmem_cache_free(qeth_core_header_cache, hdr); | ||
684 | return rc; | ||
666 | } | 685 | } |
667 | 686 | ||
668 | static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb, | 687 | static netdev_tx_t qeth_l2_hard_start_xmit(struct sk_buff *skb, |