2005-04-16 15:20:36 -07:00
/*
2006-02-01 03:06:31 -08:00
* linux / drivers / s390 / net / qeth_tso . h
2005-04-16 15:20:36 -07:00
*
* Header file for qeth TCP Segmentation Offload support .
*
* Copyright 2004 IBM Corporation
*
2005-11-10 13:51:42 +01:00
* Author ( s ) : Frank Pavlic < fpavlic @ de . ibm . com >
2005-04-16 15:20:36 -07:00
*
*/
# ifndef __QETH_TSO_H__
# define __QETH_TSO_H__
2005-05-12 20:39:09 +02:00
# 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"
2005-04-16 15:20:36 -07:00
2005-05-12 20:39:09 +02:00
static inline struct qeth_hdr_tso *
qeth_tso_prepare_skb ( struct qeth_card * card , struct sk_buff * * skb )
{
QETH_DBF_TEXT ( trace , 5 , " tsoprsk " ) ;
2006-09-15 16:26:19 +02:00
return qeth_push_skb ( card , * skb , sizeof ( struct qeth_hdr_tso ) ) ;
2005-05-12 20:39:09 +02:00
}
/**
* 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 ;
2005-04-16 15:20:36 -07:00
2005-05-12 20:39:09 +02:00
QETH_DBF_TEXT ( trace , 5 , " tsofhdr " ) ;
hdr = ( struct qeth_hdr_tso * ) skb - > data ;
2007-04-20 22:47:35 -07:00
iph = ip_hdr ( skb ) ;
2007-04-10 21:04:22 -07:00
tcph = tcp_hdr ( skb ) ;
2005-05-12 20:39:09 +02:00
/*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 */
2006-06-22 02:40:14 -07:00
hdr - > ext . mss = skb_shinfo ( skb ) - > gso_size ;
2005-05-12 20:39:09 +02:00
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 )
{
2007-04-20 22:47:35 -07:00
struct iphdr * iph = ip_hdr ( skb ) ;
2007-04-25 17:54:47 -07:00
struct ipv6hdr * ip6h = ipv6_hdr ( skb ) ;
2007-04-10 21:04:22 -07:00
struct tcphdr * tcph = tcp_hdr ( skb ) ;
2005-05-12 20:39:09 +02:00
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 ;
}
2005-04-16 15:20:36 -07:00
static inline int
2005-05-12 20:39:09 +02:00
qeth_tso_prepare_packet ( struct qeth_card * card , struct sk_buff * skb ,
int ipv , int cast_type )
2005-04-16 15:20:36 -07:00
{
2005-05-12 20:39:09 +02:00
struct qeth_hdr_tso * hdr ;
2005-04-16 15:20:36 -07:00
2005-05-12 20:39:09 +02:00
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 ;
2005-05-12 20:37:53 +02:00
}
static inline void
__qeth_fill_buffer_frag ( struct sk_buff * skb , struct qdio_buffer * buffer ,
int is_tso , int * next_element_to_fill )
{
struct skb_frag_struct * frag ;
int fragno ;
unsigned long addr ;
2005-05-12 20:39:09 +02:00
int element , cnt , dlen ;
2006-05-26 21:58:38 -04:00
2005-05-12 20:39:09 +02:00
fragno = skb_shinfo ( skb ) - > nr_frags ;
element = * next_element_to_fill ;
dlen = 0 ;
2006-05-26 21:58:38 -04:00
2005-05-12 20:39:09 +02:00
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 + + ;
2005-04-16 15:20:36 -07:00
}
2005-05-12 20:39:09 +02:00
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 + + ;
}
* next_element_to_fill = element ;
2005-04-16 15:20:36 -07:00
}
# endif /* __QETH_TSO_H__ */