aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/net/qeth_l2_main.c
diff options
context:
space:
mode:
authorJulian Wiedmann <jwi@linux.ibm.com>2018-07-19 06:43:56 -0400
committerDavid S. Miller <davem@davemloft.net>2018-07-21 13:12:30 -0400
commitba86ceee9d1b5aa71fe3db75b2ec5452c9a48307 (patch)
treed4af4b1cab727029b75e594f83c5cf99ecefed75 /drivers/s390/net/qeth_l2_main.c
parentd2a274b25be7218f8400037868a756640e8a4b0d (diff)
s390/qeth: merge linearize-check into HW header construction
When checking whether an skb needs to be linearized to fit into an IO buffer, it's desirable to consider the skb's final size and layout (ie. after the HW header was added). But a subsequent linearization can then cause the re-positioned HW header to violate its alignment restrictions. Dealing with this situation in two different code paths is quite tricky. This patch integrates a) linearize-check and b) HW header construction into one 3 step-sequence: 1. evaluate how the HW header needs to be added (to identify if it takes up an additional buffer element), then 2. check if the required buffer elements exceed the device's limit. Linearize when necessary and re-evaluate the HW header placement. 3. Add the HW header in the best-possible way: a) push, without taking up an additional buffer element b) push, but consume another buffer element c) allocate a header object from the cache. Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/s390/net/qeth_l2_main.c')
-rw-r--r--drivers/s390/net/qeth_l2_main.c29
1 files changed, 2 insertions, 27 deletions
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index a785c5ff73cd..905f3bb3a87c 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -672,39 +672,21 @@ static int qeth_l2_xmit_osa(struct qeth_card *card, struct sk_buff *skb,
672 int ipv) 672 int ipv)
673{ 673{
674 int push_len = sizeof(struct qeth_hdr); 674 int push_len = sizeof(struct qeth_hdr);
675 unsigned int hdr_elements = 0;
676 struct qeth_hdr *hdr = NULL; 675 struct qeth_hdr *hdr = NULL;
677 unsigned int hd_len = 0; 676 unsigned int hd_len = 0;
678 unsigned int elements; 677 unsigned int elements;
679 bool is_sg; 678 bool is_sg;
680 int rc; 679 int rc;
681 680
682 /* fix hardware limitation: as long as we do not have sbal
683 * chaining we can not send long frag lists
684 */
685 if (!qeth_get_elements_no(card, skb, 0, 0)) {
686 rc = skb_linearize(skb);
687
688 if (card->options.performance_stats) {
689 if (rc)
690 card->perf_stats.tx_linfail++;
691 else
692 card->perf_stats.tx_lin++;
693 }
694 if (rc)
695 return rc;
696 }
697
698 rc = skb_cow_head(skb, push_len); 681 rc = skb_cow_head(skb, push_len);
699 if (rc) 682 if (rc)
700 return rc; 683 return rc;
701 push_len = qeth_push_hdr(skb, &hdr, push_len); 684 push_len = qeth_add_hw_header(card, skb, &hdr, push_len, &elements);
702 if (push_len < 0) 685 if (push_len < 0)
703 return push_len; 686 return push_len;
704 if (!push_len) { 687 if (!push_len) {
705 /* hdr was allocated from cache */ 688 /* hdr was allocated from cache */
706 hd_len = sizeof(*hdr); 689 hd_len = sizeof(*hdr);
707 hdr_elements = 1;
708 } 690 }
709 qeth_l2_fill_header(hdr, skb, cast_type, skb->len - push_len); 691 qeth_l2_fill_header(hdr, skb, cast_type, skb->len - push_len);
710 if (skb->ip_summed == CHECKSUM_PARTIAL) { 692 if (skb->ip_summed == CHECKSUM_PARTIAL) {
@@ -713,18 +695,11 @@ static int qeth_l2_xmit_osa(struct qeth_card *card, struct sk_buff *skb,
713 card->perf_stats.tx_csum++; 695 card->perf_stats.tx_csum++;
714 } 696 }
715 697
716 elements = qeth_get_elements_no(card, skb, hdr_elements, 0);
717 if (!elements) {
718 rc = -E2BIG;
719 goto out;
720 }
721 elements += hdr_elements;
722
723 is_sg = skb_is_nonlinear(skb); 698 is_sg = skb_is_nonlinear(skb);
724 /* TODO: remove the skb_orphan() once TX completion is fast enough */ 699 /* TODO: remove the skb_orphan() once TX completion is fast enough */
725 skb_orphan(skb); 700 skb_orphan(skb);
726 rc = qeth_do_send_packet(card, queue, skb, hdr, 0, hd_len, elements); 701 rc = qeth_do_send_packet(card, queue, skb, hdr, 0, hd_len, elements);
727out: 702
728 if (!rc) { 703 if (!rc) {
729 if (card->options.performance_stats) { 704 if (card->options.performance_stats) {
730 card->perf_stats.buf_elements_sent += elements; 705 card->perf_stats.buf_elements_sent += elements;