diff options
Diffstat (limited to 'drivers/s390/net')
-rw-r--r-- | drivers/s390/net/qeth_core.h | 1 | ||||
-rw-r--r-- | drivers/s390/net/qeth_core_main.c | 104 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l2_main.c | 7 | ||||
-rw-r--r-- | drivers/s390/net/qeth_l3_main.c | 26 |
4 files changed, 65 insertions, 73 deletions
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 0b4250d3a25d..d79892782a2b 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h | |||
@@ -869,6 +869,7 @@ void qeth_core_get_drvinfo(struct net_device *, struct ethtool_drvinfo *); | |||
869 | void qeth_dbf_longtext(debug_info_t *id, int level, char *text, ...); | 869 | void qeth_dbf_longtext(debug_info_t *id, int level, char *text, ...); |
870 | int qeth_core_ethtool_get_settings(struct net_device *, struct ethtool_cmd *); | 870 | int qeth_core_ethtool_get_settings(struct net_device *, struct ethtool_cmd *); |
871 | int qeth_set_access_ctrl_online(struct qeth_card *card); | 871 | int qeth_set_access_ctrl_online(struct qeth_card *card); |
872 | int qeth_hdr_chk_and_bounce(struct sk_buff *, int); | ||
872 | 873 | ||
873 | /* exports for OSN */ | 874 | /* exports for OSN */ |
874 | int qeth_osn_assist(struct net_device *, void *, int); | 875 | int qeth_osn_assist(struct net_device *, void *, int); |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 3cdd2705b75a..656a6e78a2ee 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
@@ -57,48 +57,6 @@ static void qeth_free_buffer_pool(struct qeth_card *); | |||
57 | static int qeth_qdio_establish(struct qeth_card *); | 57 | static int qeth_qdio_establish(struct qeth_card *); |
58 | 58 | ||
59 | 59 | ||
60 | static inline void __qeth_fill_buffer_frag(struct sk_buff *skb, | ||
61 | struct qdio_buffer *buffer, int is_tso, | ||
62 | int *next_element_to_fill) | ||
63 | { | ||
64 | struct skb_frag_struct *frag; | ||
65 | int fragno; | ||
66 | unsigned long addr; | ||
67 | int element, cnt, dlen; | ||
68 | |||
69 | fragno = skb_shinfo(skb)->nr_frags; | ||
70 | element = *next_element_to_fill; | ||
71 | dlen = 0; | ||
72 | |||
73 | if (is_tso) | ||
74 | buffer->element[element].flags = | ||
75 | SBAL_FLAGS_MIDDLE_FRAG; | ||
76 | else | ||
77 | buffer->element[element].flags = | ||
78 | SBAL_FLAGS_FIRST_FRAG; | ||
79 | dlen = skb->len - skb->data_len; | ||
80 | if (dlen) { | ||
81 | buffer->element[element].addr = skb->data; | ||
82 | buffer->element[element].length = dlen; | ||
83 | element++; | ||
84 | } | ||
85 | for (cnt = 0; cnt < fragno; cnt++) { | ||
86 | frag = &skb_shinfo(skb)->frags[cnt]; | ||
87 | addr = (page_to_pfn(frag->page) << PAGE_SHIFT) + | ||
88 | frag->page_offset; | ||
89 | buffer->element[element].addr = (char *)addr; | ||
90 | buffer->element[element].length = frag->size; | ||
91 | if (cnt < (fragno - 1)) | ||
92 | buffer->element[element].flags = | ||
93 | SBAL_FLAGS_MIDDLE_FRAG; | ||
94 | else | ||
95 | buffer->element[element].flags = | ||
96 | SBAL_FLAGS_LAST_FRAG; | ||
97 | element++; | ||
98 | } | ||
99 | *next_element_to_fill = element; | ||
100 | } | ||
101 | |||
102 | static inline const char *qeth_get_cardname(struct qeth_card *card) | 60 | static inline const char *qeth_get_cardname(struct qeth_card *card) |
103 | { | 61 | { |
104 | if (card->info.guestlan) { | 62 | if (card->info.guestlan) { |
@@ -3020,13 +2978,11 @@ EXPORT_SYMBOL_GPL(qeth_get_priority_queue); | |||
3020 | int qeth_get_elements_no(struct qeth_card *card, void *hdr, | 2978 | int qeth_get_elements_no(struct qeth_card *card, void *hdr, |
3021 | struct sk_buff *skb, int elems) | 2979 | struct sk_buff *skb, int elems) |
3022 | { | 2980 | { |
3023 | int elements_needed = 0; | 2981 | int dlen = skb->len - skb->data_len; |
2982 | int elements_needed = PFN_UP((unsigned long)skb->data + dlen - 1) - | ||
2983 | PFN_DOWN((unsigned long)skb->data); | ||
3024 | 2984 | ||
3025 | if (skb_shinfo(skb)->nr_frags > 0) | 2985 | elements_needed += skb_shinfo(skb)->nr_frags; |
3026 | elements_needed = (skb_shinfo(skb)->nr_frags + 1); | ||
3027 | if (elements_needed == 0) | ||
3028 | elements_needed = 1 + (((((unsigned long) skb->data) % | ||
3029 | PAGE_SIZE) + skb->len) >> PAGE_SHIFT); | ||
3030 | if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { | 2986 | if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { |
3031 | QETH_DBF_MESSAGE(2, "Invalid size of IP packet " | 2987 | QETH_DBF_MESSAGE(2, "Invalid size of IP packet " |
3032 | "(Number=%d / Length=%d). Discarded.\n", | 2988 | "(Number=%d / Length=%d). Discarded.\n", |
@@ -3037,15 +2993,35 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr, | |||
3037 | } | 2993 | } |
3038 | EXPORT_SYMBOL_GPL(qeth_get_elements_no); | 2994 | EXPORT_SYMBOL_GPL(qeth_get_elements_no); |
3039 | 2995 | ||
2996 | int qeth_hdr_chk_and_bounce(struct sk_buff *skb, int len) | ||
2997 | { | ||
2998 | int hroom, inpage, rest; | ||
2999 | |||
3000 | if (((unsigned long)skb->data & PAGE_MASK) != | ||
3001 | (((unsigned long)skb->data + len - 1) & PAGE_MASK)) { | ||
3002 | hroom = skb_headroom(skb); | ||
3003 | inpage = PAGE_SIZE - ((unsigned long) skb->data % PAGE_SIZE); | ||
3004 | rest = len - inpage; | ||
3005 | if (rest > hroom) | ||
3006 | return 1; | ||
3007 | memmove(skb->data - rest, skb->data, skb->len - skb->data_len); | ||
3008 | skb->data -= rest; | ||
3009 | QETH_DBF_MESSAGE(2, "skb bounce len: %d rest: %d\n", len, rest); | ||
3010 | } | ||
3011 | return 0; | ||
3012 | } | ||
3013 | EXPORT_SYMBOL_GPL(qeth_hdr_chk_and_bounce); | ||
3014 | |||
3040 | static inline void __qeth_fill_buffer(struct sk_buff *skb, | 3015 | static inline void __qeth_fill_buffer(struct sk_buff *skb, |
3041 | struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill, | 3016 | struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill, |
3042 | int offset) | 3017 | int offset) |
3043 | { | 3018 | { |
3044 | int length = skb->len; | 3019 | int length = skb->len - skb->data_len; |
3045 | int length_here; | 3020 | int length_here; |
3046 | int element; | 3021 | int element; |
3047 | char *data; | 3022 | char *data; |
3048 | int first_lap ; | 3023 | int first_lap, cnt; |
3024 | struct skb_frag_struct *frag; | ||
3049 | 3025 | ||
3050 | element = *next_element_to_fill; | 3026 | element = *next_element_to_fill; |
3051 | data = skb->data; | 3027 | data = skb->data; |
@@ -3068,10 +3044,14 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb, | |||
3068 | length -= length_here; | 3044 | length -= length_here; |
3069 | if (!length) { | 3045 | if (!length) { |
3070 | if (first_lap) | 3046 | if (first_lap) |
3071 | buffer->element[element].flags = 0; | 3047 | if (skb_shinfo(skb)->nr_frags) |
3048 | buffer->element[element].flags = | ||
3049 | SBAL_FLAGS_FIRST_FRAG; | ||
3050 | else | ||
3051 | buffer->element[element].flags = 0; | ||
3072 | else | 3052 | else |
3073 | buffer->element[element].flags = | 3053 | buffer->element[element].flags = |
3074 | SBAL_FLAGS_LAST_FRAG; | 3054 | SBAL_FLAGS_MIDDLE_FRAG; |
3075 | } else { | 3055 | } else { |
3076 | if (first_lap) | 3056 | if (first_lap) |
3077 | buffer->element[element].flags = | 3057 | buffer->element[element].flags = |
@@ -3084,6 +3064,18 @@ static inline void __qeth_fill_buffer(struct sk_buff *skb, | |||
3084 | element++; | 3064 | element++; |
3085 | first_lap = 0; | 3065 | first_lap = 0; |
3086 | } | 3066 | } |
3067 | |||
3068 | for (cnt = 0; cnt < skb_shinfo(skb)->nr_frags; cnt++) { | ||
3069 | frag = &skb_shinfo(skb)->frags[cnt]; | ||
3070 | buffer->element[element].addr = (char *)page_to_phys(frag->page) | ||
3071 | + frag->page_offset; | ||
3072 | buffer->element[element].length = frag->size; | ||
3073 | buffer->element[element].flags = SBAL_FLAGS_MIDDLE_FRAG; | ||
3074 | element++; | ||
3075 | } | ||
3076 | |||
3077 | if (buffer->element[element - 1].flags) | ||
3078 | buffer->element[element - 1].flags = SBAL_FLAGS_LAST_FRAG; | ||
3087 | *next_element_to_fill = element; | 3079 | *next_element_to_fill = element; |
3088 | } | 3080 | } |
3089 | 3081 | ||
@@ -3124,12 +3116,8 @@ static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue, | |||
3124 | buf->next_element_to_fill++; | 3116 | buf->next_element_to_fill++; |
3125 | } | 3117 | } |
3126 | 3118 | ||
3127 | if (skb_shinfo(skb)->nr_frags == 0) | 3119 | __qeth_fill_buffer(skb, buffer, large_send, |
3128 | __qeth_fill_buffer(skb, buffer, large_send, | 3120 | (int *)&buf->next_element_to_fill, offset); |
3129 | (int *)&buf->next_element_to_fill, offset); | ||
3130 | else | ||
3131 | __qeth_fill_buffer_frag(skb, buffer, large_send, | ||
3132 | (int *)&buf->next_element_to_fill); | ||
3133 | 3121 | ||
3134 | if (!queue->do_pack) { | 3122 | if (!queue->do_pack) { |
3135 | QETH_CARD_TEXT(queue->card, 6, "fillbfnp"); | 3123 | QETH_CARD_TEXT(queue->card, 6, "fillbfnp"); |
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index e7942ccab987..32d07c2dcc67 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c | |||
@@ -712,10 +712,13 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
712 | goto tx_drop; | 712 | goto tx_drop; |
713 | } | 713 | } |
714 | 714 | ||
715 | if (card->info.type != QETH_CARD_TYPE_IQD) | 715 | if (card->info.type != QETH_CARD_TYPE_IQD) { |
716 | if (qeth_hdr_chk_and_bounce(new_skb, | ||
717 | sizeof(struct qeth_hdr_layer2))) | ||
718 | goto tx_drop; | ||
716 | rc = qeth_do_send_packet(card, queue, new_skb, hdr, | 719 | rc = qeth_do_send_packet(card, queue, new_skb, hdr, |
717 | elements); | 720 | elements); |
718 | else | 721 | } else |
719 | rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, | 722 | rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, |
720 | elements, data_offset, hd_len); | 723 | elements, data_offset, hd_len); |
721 | if (!rc) { | 724 | if (!rc) { |
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index b5733e405ed9..61d348e51920 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c | |||
@@ -2904,19 +2904,11 @@ static inline int qeth_l3_tso_elements(struct sk_buff *skb) | |||
2904 | unsigned long tcpd = (unsigned long)tcp_hdr(skb) + | 2904 | unsigned long tcpd = (unsigned long)tcp_hdr(skb) + |
2905 | tcp_hdr(skb)->doff * 4; | 2905 | tcp_hdr(skb)->doff * 4; |
2906 | int tcpd_len = skb->len - (tcpd - (unsigned long)skb->data); | 2906 | int tcpd_len = skb->len - (tcpd - (unsigned long)skb->data); |
2907 | int elements = PFN_UP(tcpd + tcpd_len) - PFN_DOWN(tcpd); | 2907 | int elements = PFN_UP(tcpd + tcpd_len - 1) - PFN_DOWN(tcpd); |
2908 | elements += skb_shinfo(skb)->nr_frags; | 2908 | elements += skb_shinfo(skb)->nr_frags; |
2909 | return elements; | 2909 | return elements; |
2910 | } | 2910 | } |
2911 | 2911 | ||
2912 | static inline int qeth_l3_tso_check(struct sk_buff *skb) | ||
2913 | { | ||
2914 | int len = ((unsigned long)tcp_hdr(skb) + tcp_hdr(skb)->doff * 4) - | ||
2915 | (unsigned long)skb->data; | ||
2916 | return (((unsigned long)skb->data & PAGE_MASK) != | ||
2917 | (((unsigned long)skb->data + len) & PAGE_MASK)); | ||
2918 | } | ||
2919 | |||
2920 | static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | 2912 | static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) |
2921 | { | 2913 | { |
2922 | int rc; | 2914 | int rc; |
@@ -3016,8 +3008,6 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
3016 | (cast_type == RTN_UNSPEC)) { | 3008 | (cast_type == RTN_UNSPEC)) { |
3017 | hdr = (struct qeth_hdr *)skb_push(new_skb, | 3009 | hdr = (struct qeth_hdr *)skb_push(new_skb, |
3018 | sizeof(struct qeth_hdr_tso)); | 3010 | sizeof(struct qeth_hdr_tso)); |
3019 | if (qeth_l3_tso_check(new_skb)) | ||
3020 | QETH_DBF_MESSAGE(2, "tso skb misaligned\n"); | ||
3021 | memset(hdr, 0, sizeof(struct qeth_hdr_tso)); | 3011 | memset(hdr, 0, sizeof(struct qeth_hdr_tso)); |
3022 | qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type); | 3012 | qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type); |
3023 | qeth_tso_fill_header(card, hdr, new_skb); | 3013 | qeth_tso_fill_header(card, hdr, new_skb); |
@@ -3048,10 +3038,20 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
3048 | elements_needed += elems; | 3038 | elements_needed += elems; |
3049 | nr_frags = skb_shinfo(new_skb)->nr_frags; | 3039 | nr_frags = skb_shinfo(new_skb)->nr_frags; |
3050 | 3040 | ||
3051 | if (card->info.type != QETH_CARD_TYPE_IQD) | 3041 | if (card->info.type != QETH_CARD_TYPE_IQD) { |
3042 | int len; | ||
3043 | if (large_send == QETH_LARGE_SEND_TSO) | ||
3044 | len = ((unsigned long)tcp_hdr(new_skb) + | ||
3045 | tcp_hdr(new_skb)->doff * 4) - | ||
3046 | (unsigned long)new_skb->data; | ||
3047 | else | ||
3048 | len = sizeof(struct qeth_hdr_layer3); | ||
3049 | |||
3050 | if (qeth_hdr_chk_and_bounce(new_skb, len)) | ||
3051 | goto tx_drop; | ||
3052 | rc = qeth_do_send_packet(card, queue, new_skb, hdr, | 3052 | rc = qeth_do_send_packet(card, queue, new_skb, hdr, |
3053 | elements_needed); | 3053 | elements_needed); |
3054 | else | 3054 | } else |
3055 | rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, | 3055 | rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, |
3056 | elements_needed, data_offset, 0); | 3056 | elements_needed, data_offset, 0); |
3057 | 3057 | ||