diff options
author | Chris Leech <christopher.leech@intel.com> | 2006-05-23 21:05:53 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-06-18 00:25:56 -0400 |
commit | 1a2449a87bb7606113b1aa1a9d3c3e78ef189a1c (patch) | |
tree | 86e833a8694f201de138697646e7e8469e9c8ef6 /net/ipv4/tcp_input.c | |
parent | 9593782585e0cf70babe787a8463d492a68b1744 (diff) |
[I/OAT]: TCP recv offload to I/OAT
Locks down user pages and sets up for DMA in tcp_recvmsg, then calls
dma_async_try_early_copy in tcp_v4_do_rcv
Signed-off-by: Chris Leech <christopher.leech@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_input.c')
-rw-r--r-- | net/ipv4/tcp_input.c | 74 |
1 files changed, 67 insertions, 7 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index b5521a9d3dc1..c6d62f0a9966 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -71,6 +71,7 @@ | |||
71 | #include <net/inet_common.h> | 71 | #include <net/inet_common.h> |
72 | #include <linux/ipsec.h> | 72 | #include <linux/ipsec.h> |
73 | #include <asm/unaligned.h> | 73 | #include <asm/unaligned.h> |
74 | #include <net/netdma.h> | ||
74 | 75 | ||
75 | int sysctl_tcp_timestamps = 1; | 76 | int sysctl_tcp_timestamps = 1; |
76 | int sysctl_tcp_window_scaling = 1; | 77 | int sysctl_tcp_window_scaling = 1; |
@@ -3785,6 +3786,50 @@ static inline int tcp_checksum_complete_user(struct sock *sk, struct sk_buff *sk | |||
3785 | __tcp_checksum_complete_user(sk, skb); | 3786 | __tcp_checksum_complete_user(sk, skb); |
3786 | } | 3787 | } |
3787 | 3788 | ||
3789 | #ifdef CONFIG_NET_DMA | ||
3790 | static int tcp_dma_try_early_copy(struct sock *sk, struct sk_buff *skb, int hlen) | ||
3791 | { | ||
3792 | struct tcp_sock *tp = tcp_sk(sk); | ||
3793 | int chunk = skb->len - hlen; | ||
3794 | int dma_cookie; | ||
3795 | int copied_early = 0; | ||
3796 | |||
3797 | if (tp->ucopy.wakeup) | ||
3798 | return 0; | ||
3799 | |||
3800 | if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list) | ||
3801 | tp->ucopy.dma_chan = get_softnet_dma(); | ||
3802 | |||
3803 | if (tp->ucopy.dma_chan && skb->ip_summed == CHECKSUM_UNNECESSARY) { | ||
3804 | |||
3805 | dma_cookie = dma_skb_copy_datagram_iovec(tp->ucopy.dma_chan, | ||
3806 | skb, hlen, tp->ucopy.iov, chunk, tp->ucopy.pinned_list); | ||
3807 | |||
3808 | if (dma_cookie < 0) | ||
3809 | goto out; | ||
3810 | |||
3811 | tp->ucopy.dma_cookie = dma_cookie; | ||
3812 | copied_early = 1; | ||
3813 | |||
3814 | tp->ucopy.len -= chunk; | ||
3815 | tp->copied_seq += chunk; | ||
3816 | tcp_rcv_space_adjust(sk); | ||
3817 | |||
3818 | if ((tp->ucopy.len == 0) || | ||
3819 | (tcp_flag_word(skb->h.th) & TCP_FLAG_PSH) || | ||
3820 | (atomic_read(&sk->sk_rmem_alloc) > (sk->sk_rcvbuf >> 1))) { | ||
3821 | tp->ucopy.wakeup = 1; | ||
3822 | sk->sk_data_ready(sk, 0); | ||
3823 | } | ||
3824 | } else if (chunk > 0) { | ||
3825 | tp->ucopy.wakeup = 1; | ||
3826 | sk->sk_data_ready(sk, 0); | ||
3827 | } | ||
3828 | out: | ||
3829 | return copied_early; | ||
3830 | } | ||
3831 | #endif /* CONFIG_NET_DMA */ | ||
3832 | |||
3788 | /* | 3833 | /* |
3789 | * TCP receive function for the ESTABLISHED state. | 3834 | * TCP receive function for the ESTABLISHED state. |
3790 | * | 3835 | * |
@@ -3901,14 +3946,23 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, | |||
3901 | } | 3946 | } |
3902 | } else { | 3947 | } else { |
3903 | int eaten = 0; | 3948 | int eaten = 0; |
3949 | int copied_early = 0; | ||
3904 | 3950 | ||
3905 | if (tp->ucopy.task == current && | 3951 | if (tp->copied_seq == tp->rcv_nxt && |
3906 | tp->copied_seq == tp->rcv_nxt && | 3952 | len - tcp_header_len <= tp->ucopy.len) { |
3907 | len - tcp_header_len <= tp->ucopy.len && | 3953 | #ifdef CONFIG_NET_DMA |
3908 | sock_owned_by_user(sk)) { | 3954 | if (tcp_dma_try_early_copy(sk, skb, tcp_header_len)) { |
3909 | __set_current_state(TASK_RUNNING); | 3955 | copied_early = 1; |
3956 | eaten = 1; | ||
3957 | } | ||
3958 | #endif | ||
3959 | if (tp->ucopy.task == current && sock_owned_by_user(sk) && !copied_early) { | ||
3960 | __set_current_state(TASK_RUNNING); | ||
3910 | 3961 | ||
3911 | if (!tcp_copy_to_iovec(sk, skb, tcp_header_len)) { | 3962 | if (!tcp_copy_to_iovec(sk, skb, tcp_header_len)) |
3963 | eaten = 1; | ||
3964 | } | ||
3965 | if (eaten) { | ||
3912 | /* Predicted packet is in window by definition. | 3966 | /* Predicted packet is in window by definition. |
3913 | * seq == rcv_nxt and rcv_wup <= rcv_nxt. | 3967 | * seq == rcv_nxt and rcv_wup <= rcv_nxt. |
3914 | * Hence, check seq<=rcv_wup reduces to: | 3968 | * Hence, check seq<=rcv_wup reduces to: |
@@ -3924,8 +3978,9 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, | |||
3924 | __skb_pull(skb, tcp_header_len); | 3978 | __skb_pull(skb, tcp_header_len); |
3925 | tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; | 3979 | tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; |
3926 | NET_INC_STATS_BH(LINUX_MIB_TCPHPHITSTOUSER); | 3980 | NET_INC_STATS_BH(LINUX_MIB_TCPHPHITSTOUSER); |
3927 | eaten = 1; | ||
3928 | } | 3981 | } |
3982 | if (copied_early) | ||
3983 | tcp_cleanup_rbuf(sk, skb->len); | ||
3929 | } | 3984 | } |
3930 | if (!eaten) { | 3985 | if (!eaten) { |
3931 | if (tcp_checksum_complete_user(sk, skb)) | 3986 | if (tcp_checksum_complete_user(sk, skb)) |
@@ -3966,6 +4021,11 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, | |||
3966 | 4021 | ||
3967 | __tcp_ack_snd_check(sk, 0); | 4022 | __tcp_ack_snd_check(sk, 0); |
3968 | no_ack: | 4023 | no_ack: |
4024 | #ifdef CONFIG_NET_DMA | ||
4025 | if (copied_early) | ||
4026 | __skb_queue_tail(&sk->sk_async_wait_queue, skb); | ||
4027 | else | ||
4028 | #endif | ||
3969 | if (eaten) | 4029 | if (eaten) |
3970 | __kfree_skb(skb); | 4030 | __kfree_skb(skb); |
3971 | else | 4031 | else |