diff options
Diffstat (limited to 'drivers/s390/net/qeth_tso.h')
-rw-r--r-- | drivers/s390/net/qeth_tso.h | 166 |
1 files changed, 131 insertions, 35 deletions
diff --git a/drivers/s390/net/qeth_tso.h b/drivers/s390/net/qeth_tso.h index 83504dee3f57..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.4 $) | 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,52 +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.4 $ $Date: 2005/03/24 09:04:18 $ | 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; | ||
41 | |||
42 | QETH_DBF_TEXT(trace, 5, "tsofhdr"); | ||
43 | |||
44 | hdr = (struct qeth_hdr_tso *) skb->data; | ||
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; | ||
33 | 71 | ||
34 | struct qeth_hdr_tso { | 72 | iph = skb->nh.iph; |
35 | struct qeth_hdr hdr; /*hdr->hdr.l3.xxx*/ | 73 | ip6h = skb->nh.ipv6h; |
36 | struct qeth_hdr_ext_tso ext; | 74 | tcph = skb->h.th; |
37 | } __attribute__ ((packed)); | ||
38 | 75 | ||
39 | /*some helper functions*/ | 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 | } | ||
40 | 89 | ||
41 | static inline int | 90 | static inline int |
42 | 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) | ||
93 | { | ||
94 | struct qeth_hdr_tso *hdr; | ||
95 | |||
96 | QETH_DBF_TEXT(trace, 5, "tsoprep"); | ||
97 | |||
98 | hdr = (struct qeth_hdr_tso *) qeth_tso_prepare_skb(card, &skb); | ||
99 | if (hdr == NULL) { | ||
100 | QETH_DBF_TEXT(trace, 4, "tsoperr"); | ||
101 | return -ENOMEM; | ||
102 | } | ||
103 | memset(hdr, 0, sizeof(struct qeth_hdr_tso)); | ||
104 | /*fill first 32 bytes of qdio header as used | ||
105 | *FIXME: TSO has two struct members | ||
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; | ||
112 | } | ||
113 | |||
114 | static inline void | ||
115 | __qeth_fill_buffer_frag(struct sk_buff *skb, struct qdio_buffer *buffer, | ||
116 | int is_tso, int *next_element_to_fill) | ||
43 | { | 117 | { |
44 | int elements_needed = 0; | 118 | struct skb_frag_struct *frag; |
45 | 119 | int fragno; | |
46 | if (skb_shinfo(skb)->nr_frags > 0) | 120 | unsigned long addr; |
47 | elements_needed = (skb_shinfo(skb)->nr_frags + 1); | 121 | int element, cnt, dlen; |
48 | if (elements_needed == 0 ) | 122 | |
49 | elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE) | 123 | fragno = skb_shinfo(skb)->nr_frags; |
50 | + skb->len) >> PAGE_SHIFT); | 124 | element = *next_element_to_fill; |
51 | if (elements_needed > QETH_MAX_BUFFER_ELEMENTS(card)){ | 125 | dlen = 0; |
52 | PRINT_ERR("qeth_do_send_packet: invalid size of " | 126 | |
53 | "IP packet. Discarded."); | 127 | if (is_tso) |
54 | return 0; | 128 | buffer->element[element].flags = |
129 | SBAL_FLAGS_MIDDLE_FRAG; | ||
130 | else | ||
131 | buffer->element[element].flags = | ||
132 | SBAL_FLAGS_FIRST_FRAG; | ||
133 | if ( (dlen = (skb->len - skb->data_len)) ) { | ||
134 | buffer->element[element].addr = skb->data; | ||
135 | buffer->element[element].length = dlen; | ||
136 | element++; | ||
137 | } | ||
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++; | ||
55 | } | 151 | } |
56 | return elements_needed; | 152 | *next_element_to_fill = element; |
57 | } | 153 | } |
58 | #endif /* __QETH_TSO_H__ */ | 154 | #endif /* __QETH_TSO_H__ */ |