sdp_bcopy.c revision 256281
1270866Simp/*
2270866Simp * Copyright (c) 2006 Mellanox Technologies Ltd.  All rights reserved.
3270866Simp *
4270866Simp * This software is available to you under a choice of one of two
5270866Simp * licenses.  You may choose to be licensed under the terms of the GNU
6270866Simp * General Public License (GPL) Version 2, available from the file
7270866Simp * COPYING in the main directory of this source tree, or the
8270866Simp * OpenIB.org BSD license below:
9270866Simp *
10270866Simp *     Redistribution and use in source and binary forms, with or
11270866Simp *     without modification, are permitted provided that the following
12270866Simp *     conditions are met:
13270866Simp *
14270866Simp *      - Redistributions of source code must retain the above
15270866Simp *        copyright notice, this list of conditions and the following
16270866Simp *        disclaimer.
17270866Simp *
18270866Simp *      - Redistributions in binary form must reproduce the above
19270866Simp *        copyright notice, this list of conditions and the following
20270866Simp *        disclaimer in the documentation and/or other materials
21270866Simp *        provided with the distribution.
22270866Simp *
23270866Simp * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24270866Simp * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25270866Simp * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26270866Simp * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27270866Simp * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28270866Simp * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29270866Simp * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30270866Simp * SOFTWARE.
31270866Simp *
32270866Simp * $Id$
33270866Simp */
34270866Simp#include "sdp.h"
35270866Simp
36270866Simpstatic void sdp_nagle_timeout(void *data);
37270866Simp
38270866Simp#ifdef CONFIG_INFINIBAND_SDP_DEBUG_DATA
39270866Simpvoid _dump_packet(const char *func, int line, struct socket *sk, char *str,
40270866Simp		struct mbuf *mb, const struct sdp_bsdh *h)
41270866Simp{
42270866Simp	struct sdp_hh *hh;
43270866Simp	struct sdp_hah *hah;
44270866Simp	struct sdp_chrecvbuf *req_size;
45270866Simp	struct sdp_rrch *rrch;
46270866Simp	struct sdp_srcah *srcah;
47270866Simp	int len = 0;
48270866Simp	char buf[256];
49270866Simp	len += snprintf(buf, 255-len, "%s mb: %p mid: %2x:%-20s flags: 0x%x "
50270866Simp			"bufs: 0x%x len: 0x%x mseq: 0x%x mseq_ack: 0x%x | ",
51270866Simp			str, mb, h->mid, mid2str(h->mid), h->flags,
52270866Simp			ntohs(h->bufs), ntohl(h->len), ntohl(h->mseq),
53270866Simp			ntohl(h->mseq_ack));
54270866Simp
55270866Simp	switch (h->mid) {
56270866Simp	case SDP_MID_HELLO:
57270866Simp		hh = (struct sdp_hh *)h;
58270866Simp		len += snprintf(buf + len, 255-len,
59270866Simp				"max_adverts: %d  majv_minv: 0x%x "
60270866Simp				"localrcvsz: 0x%x desremrcvsz: 0x%x |",
61270866Simp				hh->max_adverts, hh->majv_minv,
62270866Simp				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
104static inline int
105sdp_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
137static void
138sdp_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_NOWAIT);
155
156	sowwakeup(ssk->socket);
157out:
158	if (sk->so_snd.sb_sndptr)
159		callout_reset(&ssk->nagle_timer, SDP_NAGLE_TIMEOUT,
160		    sdp_nagle_timeout, ssk);
161}
162
163void
164sdp_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	}
180again:
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
254allocfail:
255	ssk->nagle_last_unacked = -1;
256	callout_reset(&ssk->nagle_timer, 1, sdp_nagle_timeout, ssk);
257	return;
258}
259