diff options
author | Frank Pavlic <pavlic@de.ibm.com> | 2005-05-12 14:39:09 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-05-15 18:06:17 -0400 |
commit | 05e08a2a297371564020f76d1bf8b3a931d5e1ed (patch) | |
tree | 0aac8cafdec747a792c46dff1b934db642b0a054 /drivers/s390/net/qeth_tso.h | |
parent | 9a4558193662e933588ee53e0202c103a68c9366 (diff) |
[PATCH] s390: qeth bug fixes
[patch 10/10] s390: qeth bug fixes.
From: Frank Pavlic <pavlic@de.ibm.com>
qeth network driver related changes:
- due to OSA hardware changes in TCP Segmentation Offload
support we are able now to pack TSO packets too.
This fits perfectly in design of qeth buffer handling and
sending data respectively.
- remove skb_realloc_headroom from the sending path since
hard_header_len value provides enough headroom now.
- device recovery behaviour improvement
- bug fixed in Enhanced Device Driver Packing functionality
Signed-off-by: Frank Pavlic <pavlic@de.ibm.com>
Diffstat (limited to 'drivers/s390/net/qeth_tso.h')
-rw-r--r-- | drivers/s390/net/qeth_tso.h | 193 |
1 files changed, 122 insertions, 71 deletions
diff --git a/drivers/s390/net/qeth_tso.h b/drivers/s390/net/qeth_tso.h index ff585ae49b6c..ad33e6f466f1 100644 --- a/drivers/s390/net/qeth_tso.h +++ b/drivers/s390/net/qeth_tso.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/s390/net/qeth_tso.h ($Revision: 1.5 $) | 2 | * linux/drivers/s390/net/qeth_tso.h ($Revision: 1.7 $) |
3 | * | 3 | * |
4 | * Header file for qeth TCP Segmentation Offload support. | 4 | * Header file for qeth TCP Segmentation Offload support. |
5 | * | 5 | * |
@@ -7,97 +7,148 @@ | |||
7 | * | 7 | * |
8 | * Author(s): Frank Pavlic <pavlic@de.ibm.com> | 8 | * Author(s): Frank Pavlic <pavlic@de.ibm.com> |
9 | * | 9 | * |
10 | * $Revision: 1.5 $ $Date: 2005/04/01 21:40:41 $ | 10 | * $Revision: 1.7 $ $Date: 2005/05/04 20:19:18 $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | #ifndef __QETH_TSO_H__ | 13 | #ifndef __QETH_TSO_H__ |
14 | #define __QETH_TSO_H__ | 14 | #define __QETH_TSO_H__ |
15 | 15 | ||
16 | #include <linux/skbuff.h> | ||
17 | #include <linux/tcp.h> | ||
18 | #include <linux/ip.h> | ||
19 | #include <linux/ipv6.h> | ||
20 | #include <net/ip6_checksum.h> | ||
21 | #include "qeth.h" | ||
22 | #include "qeth_mpc.h" | ||
16 | 23 | ||
17 | extern int | ||
18 | qeth_tso_send_packet(struct qeth_card *, struct sk_buff *, | ||
19 | struct qeth_qdio_out_q *, int , int); | ||
20 | 24 | ||
21 | struct qeth_hdr_ext_tso { | 25 | static inline struct qeth_hdr_tso * |
22 | __u16 hdr_tot_len; | 26 | qeth_tso_prepare_skb(struct qeth_card *card, struct sk_buff **skb) |
23 | __u8 imb_hdr_no; | 27 | { |
24 | __u8 reserved; | 28 | QETH_DBF_TEXT(trace, 5, "tsoprsk"); |
25 | __u8 hdr_type; | 29 | return qeth_push_skb(card, skb, sizeof(struct qeth_hdr_tso)); |
26 | __u8 hdr_version; | 30 | } |
27 | __u16 hdr_len; | 31 | |
28 | __u32 payload_len; | 32 | /** |
29 | __u16 mss; | 33 | * fill header for a TSO packet |
30 | __u16 dg_hdr_len; | 34 | */ |
31 | __u8 padding[16]; | 35 | static inline void |
32 | } __attribute__ ((packed)); | 36 | qeth_tso_fill_header(struct qeth_card *card, struct sk_buff *skb) |
37 | { | ||
38 | struct qeth_hdr_tso *hdr; | ||
39 | struct tcphdr *tcph; | ||
40 | struct iphdr *iph; | ||
33 | 41 | ||
34 | struct qeth_hdr_tso { | 42 | QETH_DBF_TEXT(trace, 5, "tsofhdr"); |
35 | struct qeth_hdr hdr; /*hdr->hdr.l3.xxx*/ | 43 | |
36 | struct qeth_hdr_ext_tso ext; | 44 | hdr = (struct qeth_hdr_tso *) skb->data; |
37 | } __attribute__ ((packed)); | 45 | iph = skb->nh.iph; |
46 | tcph = skb->h.th; | ||
47 | /*fix header to TSO values ...*/ | ||
48 | hdr->hdr.hdr.l3.id = QETH_HEADER_TYPE_TSO; | ||
49 | /*set values which are fix for the first approach ...*/ | ||
50 | hdr->ext.hdr_tot_len = (__u16) sizeof(struct qeth_hdr_ext_tso); | ||
51 | hdr->ext.imb_hdr_no = 1; | ||
52 | hdr->ext.hdr_type = 1; | ||
53 | hdr->ext.hdr_version = 1; | ||
54 | hdr->ext.hdr_len = 28; | ||
55 | /*insert non-fix values */ | ||
56 | hdr->ext.mss = skb_shinfo(skb)->tso_size; | ||
57 | hdr->ext.dg_hdr_len = (__u16)(iph->ihl*4 + tcph->doff*4); | ||
58 | hdr->ext.payload_len = (__u16)(skb->len - hdr->ext.dg_hdr_len - | ||
59 | sizeof(struct qeth_hdr_tso)); | ||
60 | } | ||
61 | |||
62 | /** | ||
63 | * change some header values as requested by hardware | ||
64 | */ | ||
65 | static inline void | ||
66 | qeth_tso_set_tcpip_header(struct qeth_card *card, struct sk_buff *skb) | ||
67 | { | ||
68 | struct iphdr *iph; | ||
69 | struct ipv6hdr *ip6h; | ||
70 | struct tcphdr *tcph; | ||
71 | |||
72 | iph = skb->nh.iph; | ||
73 | ip6h = skb->nh.ipv6h; | ||
74 | tcph = skb->h.th; | ||
75 | |||
76 | tcph->check = 0; | ||
77 | if (skb->protocol == ETH_P_IPV6) { | ||
78 | ip6h->payload_len = 0; | ||
79 | tcph->check = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, | ||
80 | 0, IPPROTO_TCP, 0); | ||
81 | return; | ||
82 | } | ||
83 | /*OSA want us to set these values ...*/ | ||
84 | tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, | ||
85 | 0, IPPROTO_TCP, 0); | ||
86 | iph->tot_len = 0; | ||
87 | iph->check = 0; | ||
88 | } | ||
38 | 89 | ||
39 | /*some helper functions*/ | ||
40 | static inline int | 90 | static inline int |
41 | qeth_get_elements_no(struct qeth_card *card, void *hdr, struct sk_buff *skb) | 91 | qeth_tso_prepare_packet(struct qeth_card *card, struct sk_buff *skb, |
92 | int ipv, int cast_type) | ||
42 | { | 93 | { |
43 | int elements_needed = 0; | 94 | struct qeth_hdr_tso *hdr; |
44 | 95 | ||
45 | if (skb_shinfo(skb)->nr_frags > 0) | 96 | QETH_DBF_TEXT(trace, 5, "tsoprep"); |
46 | elements_needed = (skb_shinfo(skb)->nr_frags + 1); | 97 | |
47 | if (elements_needed == 0 ) | 98 | hdr = (struct qeth_hdr_tso *) qeth_tso_prepare_skb(card, &skb); |
48 | elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE) | 99 | if (hdr == NULL) { |
49 | + skb->len) >> PAGE_SHIFT); | 100 | QETH_DBF_TEXT(trace, 4, "tsoperr"); |
50 | if (elements_needed > QETH_MAX_BUFFER_ELEMENTS(card)){ | 101 | return -ENOMEM; |
51 | PRINT_ERR("qeth_do_send_packet: invalid size of " | 102 | } |
52 | "IP packet. Discarded."); | 103 | memset(hdr, 0, sizeof(struct qeth_hdr_tso)); |
53 | return 0; | 104 | /*fill first 32 bytes of qdio header as used |
54 | } | 105 | *FIXME: TSO has two struct members |
55 | return elements_needed; | 106 | * with different names but same size |
107 | * */ | ||
108 | qeth_fill_header(card, &hdr->hdr, skb, ipv, cast_type); | ||
109 | qeth_tso_fill_header(card, skb); | ||
110 | qeth_tso_set_tcpip_header(card, skb); | ||
111 | return 0; | ||
56 | } | 112 | } |
57 | 113 | ||
58 | static inline void | 114 | static inline void |
59 | __qeth_fill_buffer_frag(struct sk_buff *skb, struct qdio_buffer *buffer, | 115 | __qeth_fill_buffer_frag(struct sk_buff *skb, struct qdio_buffer *buffer, |
60 | int is_tso, int *next_element_to_fill) | 116 | int is_tso, int *next_element_to_fill) |
61 | { | 117 | { |
62 | int length = skb->len; | ||
63 | struct skb_frag_struct *frag; | 118 | struct skb_frag_struct *frag; |
64 | int fragno; | 119 | int fragno; |
65 | unsigned long addr; | 120 | unsigned long addr; |
66 | int element; | 121 | int element, cnt, dlen; |
67 | int first_lap = 1; | 122 | |
68 | 123 | fragno = skb_shinfo(skb)->nr_frags; | |
69 | fragno = skb_shinfo(skb)->nr_frags; /* start with last frag */ | 124 | element = *next_element_to_fill; |
70 | element = *next_element_to_fill + fragno; | 125 | dlen = 0; |
71 | while (length > 0) { | 126 | |
72 | if (fragno > 0) { | 127 | if (is_tso) |
73 | frag = &skb_shinfo(skb)->frags[fragno - 1]; | 128 | buffer->element[element].flags = |
74 | addr = (page_to_pfn(frag->page) << PAGE_SHIFT) + | 129 | SBAL_FLAGS_MIDDLE_FRAG; |
75 | frag->page_offset; | 130 | else |
76 | buffer->element[element].addr = (char *)addr; | 131 | buffer->element[element].flags = |
77 | buffer->element[element].length = frag->size; | 132 | SBAL_FLAGS_FIRST_FRAG; |
78 | length -= frag->size; | 133 | if ( (dlen = (skb->len - skb->data_len)) ) { |
79 | if (first_lap) | 134 | buffer->element[element].addr = skb->data; |
80 | buffer->element[element].flags = | 135 | buffer->element[element].length = dlen; |
81 | SBAL_FLAGS_LAST_FRAG; | 136 | element++; |
82 | else | ||
83 | buffer->element[element].flags = | ||
84 | SBAL_FLAGS_MIDDLE_FRAG; | ||
85 | } else { | ||
86 | buffer->element[element].addr = skb->data; | ||
87 | buffer->element[element].length = length; | ||
88 | length = 0; | ||
89 | if (is_tso) | ||
90 | buffer->element[element].flags = | ||
91 | SBAL_FLAGS_MIDDLE_FRAG; | ||
92 | else | ||
93 | buffer->element[element].flags = | ||
94 | SBAL_FLAGS_FIRST_FRAG; | ||
95 | } | ||
96 | element--; | ||
97 | fragno--; | ||
98 | first_lap = 0; | ||
99 | } | 137 | } |
100 | *next_element_to_fill += skb_shinfo(skb)->nr_frags + 1; | 138 | for (cnt = 0; cnt < fragno; cnt++) { |
139 | frag = &skb_shinfo(skb)->frags[cnt]; | ||
140 | addr = (page_to_pfn(frag->page) << PAGE_SHIFT) + | ||
141 | frag->page_offset; | ||
142 | buffer->element[element].addr = (char *)addr; | ||
143 | buffer->element[element].length = frag->size; | ||
144 | if (cnt < (fragno - 1)) | ||
145 | buffer->element[element].flags = | ||
146 | SBAL_FLAGS_MIDDLE_FRAG; | ||
147 | else | ||
148 | buffer->element[element].flags = | ||
149 | SBAL_FLAGS_LAST_FRAG; | ||
150 | element++; | ||
151 | } | ||
152 | *next_element_to_fill = element; | ||
101 | } | 153 | } |
102 | |||
103 | #endif /* __QETH_TSO_H__ */ | 154 | #endif /* __QETH_TSO_H__ */ |