]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/ofed/drivers/infiniband/ulp/sdp/sdp_bcopy.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / ofed / drivers / infiniband / ulp / sdp / sdp_bcopy.c
1 /*
2  * Copyright (c) 2006 Mellanox Technologies Ltd.  All rights reserved.
3  *
4  * This software is available to you under a choice of one of two
5  * licenses.  You may choose to be licensed under the terms of the GNU
6  * General Public License (GPL) Version 2, available from the file
7  * COPYING in the main directory of this source tree, or the
8  * OpenIB.org BSD license below:
9  *
10  *     Redistribution and use in source and binary forms, with or
11  *     without modification, are permitted provided that the following
12  *     conditions are met:
13  *
14  *      - Redistributions of source code must retain the above
15  *        copyright notice, this list of conditions and the following
16  *        disclaimer.
17  *
18  *      - Redistributions in binary form must reproduce the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer in the documentation and/or other materials
21  *        provided with the distribution.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30  * SOFTWARE.
31  *
32  * $Id$
33  */
34 #include "sdp.h"
35
36 static void sdp_nagle_timeout(void *data);
37
38 #ifdef CONFIG_INFINIBAND_SDP_DEBUG_DATA
39 void _dump_packet(const char *func, int line, struct socket *sk, char *str,
40                 struct mbuf *mb, const struct sdp_bsdh *h)
41 {
42         struct sdp_hh *hh;
43         struct sdp_hah *hah;
44         struct sdp_chrecvbuf *req_size;
45         struct sdp_rrch *rrch;
46         struct sdp_srcah *srcah;
47         int len = 0;
48         char buf[256];
49         len += snprintf(buf, 255-len, "%s mb: %p mid: %2x:%-20s flags: 0x%x "
50                         "bufs: 0x%x len: 0x%x mseq: 0x%x mseq_ack: 0x%x | ",
51                         str, mb, h->mid, mid2str(h->mid), h->flags,
52                         ntohs(h->bufs), ntohl(h->len), ntohl(h->mseq),
53                         ntohl(h->mseq_ack));
54
55         switch (h->mid) {
56         case SDP_MID_HELLO:
57                 hh = (struct sdp_hh *)h;
58                 len += snprintf(buf + len, 255-len,
59                                 "max_adverts: %d  majv_minv: 0x%x "
60                                 "localrcvsz: 0x%x desremrcvsz: 0x%x |",
61                                 hh->max_adverts, hh->majv_minv,
62                                 ntohl(hh->localrcvsz),
63                                 ntohl(hh->desremrcvsz));
64                 break;
65         case SDP_MID_HELLO_ACK:
66                 hah = (struct sdp_hah *)h;
67                 len += snprintf(buf + len, 255-len, "actrcvz: 0x%x |",
68                                 ntohl(hah->actrcvsz));
69                 break;
70         case SDP_MID_CHRCVBUF:
71         case SDP_MID_CHRCVBUF_ACK:
72                 req_size = (struct sdp_chrecvbuf *)(h+1);
73                 len += snprintf(buf + len, 255-len, "req_size: 0x%x |",
74                                 ntohl(req_size->size));
75                 break;
76         case SDP_MID_DATA:
77                 len += snprintf(buf + len, 255-len, "data_len: 0x%lx |",
78                         ntohl(h->len) - sizeof(struct sdp_bsdh));
79                 break;
80         case SDP_MID_RDMARDCOMPL:
81                 rrch = (struct sdp_rrch *)(h+1);
82
83                 len += snprintf(buf + len, 255-len, " | len: 0x%x |",
84                                 ntohl(rrch->len));
85                 break;
86         case SDP_MID_SRCAVAIL:
87                 srcah = (struct sdp_srcah *)(h+1);
88
89                 len += snprintf(buf + len, 255-len, " | payload: 0x%lx, "
90                                 "len: 0x%x, rkey: 0x%x, vaddr: 0x%jx |",
91                                 ntohl(h->len) - sizeof(struct sdp_bsdh) - 
92                                 sizeof(struct sdp_srcah),
93                                 ntohl(srcah->len), ntohl(srcah->rkey),
94                                 be64_to_cpu(srcah->vaddr));
95                 break;
96         default:
97                 break;
98         }
99         buf[len] = 0;
100         _sdp_printk(func, line, KERN_WARNING, sk, "%s: %s\n", str, buf);
101 }
102 #endif
103
104 static inline int
105 sdp_nagle_off(struct sdp_sock *ssk, struct mbuf *mb)
106 {
107
108         struct sdp_bsdh *h;
109
110         h = mtod(mb, struct sdp_bsdh *);
111         int send_now =
112 #ifdef SDP_ZCOPY
113                 BZCOPY_STATE(mb) ||
114 #endif
115                 unlikely(h->mid != SDP_MID_DATA) ||
116                 (ssk->flags & SDP_NODELAY) ||
117                 !ssk->nagle_last_unacked ||
118                 mb->m_pkthdr.len >= ssk->xmit_size_goal / 4 ||
119                 (mb->m_flags & M_PUSH);
120
121         if (send_now) {
122                 unsigned long mseq = ring_head(ssk->tx_ring);
123                 ssk->nagle_last_unacked = mseq;
124         } else {
125                 if (!callout_pending(&ssk->nagle_timer)) {
126                         callout_reset(&ssk->nagle_timer, SDP_NAGLE_TIMEOUT,
127                             sdp_nagle_timeout, ssk);
128                         sdp_dbg_data(ssk->socket, "Starting nagle timer\n");
129                 }
130         }
131         sdp_dbg_data(ssk->socket, "send_now = %d last_unacked = %ld\n",
132                 send_now, ssk->nagle_last_unacked);
133
134         return send_now;
135 }
136
137 static void
138 sdp_nagle_timeout(void *data)
139 {
140         struct sdp_sock *ssk = (struct sdp_sock *)data;
141         struct socket *sk = ssk->socket;
142
143         sdp_dbg_data(sk, "last_unacked = %ld\n", ssk->nagle_last_unacked);
144
145         if (!callout_active(&ssk->nagle_timer))
146                 return;
147         callout_deactivate(&ssk->nagle_timer);
148
149         if (!ssk->nagle_last_unacked)
150                 goto out;
151         if (ssk->state == TCPS_CLOSED)
152                 return;
153         ssk->nagle_last_unacked = 0;
154         sdp_post_sends(ssk, M_DONTWAIT);
155
156         sowwakeup(ssk->socket);
157 out:
158         if (sk->so_snd.sb_sndptr)
159                 callout_reset(&ssk->nagle_timer, SDP_NAGLE_TIMEOUT,
160                     sdp_nagle_timeout, ssk);
161 }
162
163 void
164 sdp_post_sends(struct sdp_sock *ssk, int wait)
165 {
166         struct mbuf *mb;
167         int post_count = 0;
168         struct socket *sk;
169         int low;
170
171         sk = ssk->socket;
172         if (unlikely(!ssk->id)) {
173                 if (sk->so_snd.sb_sndptr) {
174                         sdp_dbg(ssk->socket,
175                                 "Send on socket without cmid ECONNRESET.\n");
176                         sdp_notify(ssk, ECONNRESET);
177                 }
178                 return;
179         }
180 again:
181         if (sdp_tx_ring_slots_left(ssk) < SDP_TX_SIZE / 2)
182                 sdp_xmit_poll(ssk,  1);
183
184         if (ssk->recv_request &&
185             ring_tail(ssk->rx_ring) >= ssk->recv_request_head &&
186             tx_credits(ssk) >= SDP_MIN_TX_CREDITS &&
187             sdp_tx_ring_slots_left(ssk)) {
188                 mb = sdp_alloc_mb_chrcvbuf_ack(sk,
189                     ssk->recv_bytes - SDP_HEAD_SIZE, wait);
190                 if (mb == NULL)
191                         goto allocfail;
192                 ssk->recv_request = 0;
193                 sdp_post_send(ssk, mb);
194                 post_count++;
195         }
196
197         if (tx_credits(ssk) <= SDP_MIN_TX_CREDITS &&
198             sdp_tx_ring_slots_left(ssk) && sk->so_snd.sb_sndptr &&
199             sdp_nagle_off(ssk, sk->so_snd.sb_sndptr)) {
200                 SDPSTATS_COUNTER_INC(send_miss_no_credits);
201         }
202
203         while (tx_credits(ssk) > SDP_MIN_TX_CREDITS &&
204             sdp_tx_ring_slots_left(ssk) && (mb = sk->so_snd.sb_sndptr) &&
205             sdp_nagle_off(ssk, mb)) {
206                 struct mbuf *n;
207
208                 SOCKBUF_LOCK(&sk->so_snd);
209                 sk->so_snd.sb_sndptr = mb->m_nextpkt;
210                 sk->so_snd.sb_mb = mb->m_nextpkt;
211                 mb->m_nextpkt = NULL;
212                 SB_EMPTY_FIXUP(&sk->so_snd);
213                 for (n = mb; n != NULL; n = n->m_next)
214                         sbfree(&sk->so_snd, n);
215                 SOCKBUF_UNLOCK(&sk->so_snd);
216                 sdp_post_send(ssk, mb);
217                 post_count++;
218         }
219
220         if (credit_update_needed(ssk) && ssk->state >= TCPS_ESTABLISHED &&
221             ssk->state < TCPS_FIN_WAIT_2) {
222                 mb = sdp_alloc_mb_data(ssk->socket, wait);
223                 if (mb == NULL)
224                         goto allocfail;
225                 sdp_post_send(ssk, mb);
226
227                 SDPSTATS_COUNTER_INC(post_send_credits);
228                 post_count++;
229         }
230
231         /* send DisConn if needed
232          * Do not send DisConn if there is only 1 credit. Compliance with CA4-82
233          * If one credit is available, an implementation shall only send SDP
234          * messages that provide additional credits and also do not contain ULP
235          * payload. */
236         if ((ssk->flags & SDP_NEEDFIN) && !sk->so_snd.sb_sndptr &&
237             tx_credits(ssk) > 1) {
238                 mb = sdp_alloc_mb_disconnect(sk, wait);
239                 if (mb == NULL)
240                         goto allocfail;
241                 ssk->flags &= ~SDP_NEEDFIN;
242                 sdp_post_send(ssk, mb);
243                 post_count++;
244         }
245         low = (sdp_tx_ring_slots_left(ssk) <= SDP_MIN_TX_CREDITS);
246         if (post_count || low) {
247                 if (low)
248                         sdp_arm_tx_cq(ssk);
249                 if (sdp_xmit_poll(ssk, low))
250                         goto again;
251         }
252         return;
253
254 allocfail:
255         ssk->nagle_last_unacked = -1;
256         callout_reset(&ssk->nagle_timer, 1, sdp_nagle_timeout, ssk);
257         return;
258 }