diff options
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__ */ |