aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/net/qeth_tso.h
diff options
context:
space:
mode:
authorFrank Pavlic <pavlic@de.ibm.com>2005-05-12 14:39:09 -0400
committerJeff Garzik <jgarzik@pobox.com>2005-05-15 18:06:17 -0400
commit05e08a2a297371564020f76d1bf8b3a931d5e1ed (patch)
tree0aac8cafdec747a792c46dff1b934db642b0a054 /drivers/s390/net/qeth_tso.h
parent9a4558193662e933588ee53e0202c103a68c9366 (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.h193
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
17extern int
18qeth_tso_send_packet(struct qeth_card *, struct sk_buff *,
19 struct qeth_qdio_out_q *, int , int);
20 24
21struct qeth_hdr_ext_tso { 25static inline struct qeth_hdr_tso *
22 __u16 hdr_tot_len; 26qeth_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]; 35static inline void
32} __attribute__ ((packed)); 36qeth_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
34struct 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 */
65static inline void
66qeth_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*/
40static inline int 90static inline int
41qeth_get_elements_no(struct qeth_card *card, void *hdr, struct sk_buff *skb) 91qeth_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
58static inline void 114static 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__ */