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 } 261