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