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 83504dee3f5..ad33e6f466f 100644 --- a/drivers/s390/net/qeth_tso.h +++ b/drivers/s390/net/qeth_tso.h @@ -1,5 +1,5 @@ /* - * linux/drivers/s390/net/qeth_tso.h ($Revision: 1.4 $) + * linux/drivers/s390/net/qeth_tso.h ($Revision: 1.7 $) * * Header file for qeth TCP Segmentation Offload support. * @@ -7,52 +7,148 @@ * * Author(s): Frank Pavlic <pavlic@de.ibm.com> * - * $Revision: 1.4 $ $Date: 2005/03/24 09:04:18 $ + * $Revision: 1.7 $ $Date: 2005/05/04 20:19:18 $ * */ #ifndef __QETH_TSO_H__ #define __QETH_TSO_H__ +#include <linux/skbuff.h> +#include <linux/tcp.h> +#include <linux/ip.h> +#include <linux/ipv6.h> +#include <net/ip6_checksum.h> +#include "qeth.h" +#include "qeth_mpc.h" -extern int -qeth_tso_send_packet(struct qeth_card *, struct sk_buff *, - struct qeth_qdio_out_q *, int , int); -struct qeth_hdr_ext_tso { - __u16 hdr_tot_len; - __u8 imb_hdr_no; - __u8 reserved; - __u8 hdr_type; - __u8 hdr_version; - __u16 hdr_len; - __u32 payload_len; - __u16 mss; - __u16 dg_hdr_len; - __u8 padding[16]; -} __attribute__ ((packed)); +static inline struct qeth_hdr_tso * +qeth_tso_prepare_skb(struct qeth_card *card, struct sk_buff **skb) +{ + QETH_DBF_TEXT(trace, 5, "tsoprsk"); + return qeth_push_skb(card, skb, sizeof(struct qeth_hdr_tso)); +} + +/** + * fill header for a TSO packet + */ +static inline void +qeth_tso_fill_header(struct qeth_card *card, struct sk_buff *skb) +{ + struct qeth_hdr_tso *hdr; + struct tcphdr *tcph; + struct iphdr *iph; + + QETH_DBF_TEXT(trace, 5, "tsofhdr"); + + hdr = (struct qeth_hdr_tso *) skb->data; + iph = skb->nh.iph; + tcph = skb->h.th; + /*fix header to TSO values ...*/ + hdr->hdr.hdr.l3.id = QETH_HEADER_TYPE_TSO; + /*set values which are fix for the first approach ...*/ + hdr->ext.hdr_tot_len = (__u16) sizeof(struct qeth_hdr_ext_tso); + hdr->ext.imb_hdr_no = 1; + hdr->ext.hdr_type = 1; + hdr->ext.hdr_version = 1; + hdr->ext.hdr_len = 28; + /*insert non-fix values */ + hdr->ext.mss = skb_shinfo(skb)->tso_size; + hdr->ext.dg_hdr_len = (__u16)(iph->ihl*4 + tcph->doff*4); + hdr->ext.payload_len = (__u16)(skb->len - hdr->ext.dg_hdr_len - + sizeof(struct qeth_hdr_tso)); +} + +/** + * change some header values as requested by hardware + */ +static inline void +qeth_tso_set_tcpip_header(struct qeth_card *card, struct sk_buff *skb) +{ + struct iphdr *iph; + struct ipv6hdr *ip6h; + struct tcphdr *tcph; -struct qeth_hdr_tso { - struct qeth_hdr hdr; /*hdr->hdr.l3.xxx*/ - struct qeth_hdr_ext_tso ext; -} __attribute__ ((packed)); + iph = skb->nh.iph; + ip6h = skb->nh.ipv6h; + tcph = skb->h.th; -/*some helper functions*/ + tcph->check = 0; + if (skb->protocol == ETH_P_IPV6) { + ip6h->payload_len = 0; + tcph->check = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, + 0, IPPROTO_TCP, 0); + return; + } + /*OSA want us to set these values ...*/ + tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, + 0, IPPROTO_TCP, 0); + iph->tot_len = 0; + iph->check = 0; +} static inline int -qeth_get_elements_no(struct qeth_card *card, void *hdr, struct sk_buff *skb) +qeth_tso_prepare_packet(struct qeth_card *card, struct sk_buff *skb, + int ipv, int cast_type) +{ + struct qeth_hdr_tso *hdr; + + QETH_DBF_TEXT(trace, 5, "tsoprep"); + + hdr = (struct qeth_hdr_tso *) qeth_tso_prepare_skb(card, &skb); + if (hdr == NULL) { + QETH_DBF_TEXT(trace, 4, "tsoperr"); + return -ENOMEM; + } + memset(hdr, 0, sizeof(struct qeth_hdr_tso)); + /*fill first 32 bytes of qdio header as used + *FIXME: TSO has two struct members + * with different names but same size + * */ + qeth_fill_header(card, &hdr->hdr, skb, ipv, cast_type); + qeth_tso_fill_header(card, skb); + qeth_tso_set_tcpip_header(card, skb); + return 0; +} + +static inline void +__qeth_fill_buffer_frag(struct sk_buff *skb, struct qdio_buffer *buffer, + int is_tso, int *next_element_to_fill) { - int elements_needed = 0; - - if (skb_shinfo(skb)->nr_frags > 0) - elements_needed = (skb_shinfo(skb)->nr_frags + 1); - if (elements_needed == 0 ) - elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE) - + skb->len) >> PAGE_SHIFT); - if (elements_needed > QETH_MAX_BUFFER_ELEMENTS(card)){ - PRINT_ERR("qeth_do_send_packet: invalid size of " - "IP packet. Discarded."); - return 0; + struct skb_frag_struct *frag; + int fragno; + unsigned long addr; + int element, cnt, dlen; + + fragno = skb_shinfo(skb)->nr_frags; + element = *next_element_to_fill; + dlen = 0; + + if (is_tso) + buffer->element[element].flags = + SBAL_FLAGS_MIDDLE_FRAG; + else + buffer->element[element].flags = + SBAL_FLAGS_FIRST_FRAG; + if ( (dlen = (skb->len - skb->data_len)) ) { + buffer->element[element].addr = skb->data; + buffer->element[element].length = dlen; + element++; + } + for (cnt = 0; cnt < fragno; cnt++) { + frag = &skb_shinfo(skb)->frags[cnt]; + addr = (page_to_pfn(frag->page) << PAGE_SHIFT) + + frag->page_offset; + buffer->element[element].addr = (char *)addr; + buffer->element[element].length = frag->size; + if (cnt < (fragno - 1)) + buffer->element[element].flags = + SBAL_FLAGS_MIDDLE_FRAG; + else + buffer->element[element].flags = + SBAL_FLAGS_LAST_FRAG; + element++; } - return elements_needed; + *next_element_to_fill = element; } #endif /* __QETH_TSO_H__ */ |