Path: blob/main/sys/ofed/drivers/infiniband/ulp/sdp/sdp_bcopy.c
39566 views
/*-1* SPDX-License-Identifier: BSD-2-Clause OR GPL-2.02*3* Copyright (c) 2006 Mellanox Technologies Ltd. All rights reserved.4*5* This software is available to you under a choice of one of two6* licenses. You may choose to be licensed under the terms of the GNU7* General Public License (GPL) Version 2, available from the file8* COPYING in the main directory of this source tree, or the9* OpenIB.org BSD license below:10*11* Redistribution and use in source and binary forms, with or12* without modification, are permitted provided that the following13* conditions are met:14*15* - Redistributions of source code must retain the above16* copyright notice, this list of conditions and the following17* disclaimer.18*19* - Redistributions in binary form must reproduce the above20* copyright notice, this list of conditions and the following21* disclaimer in the documentation and/or other materials22* provided with the distribution.23*24* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,25* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF26* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND27* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS28* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN29* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN30* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE31* SOFTWARE.32*33* $Id$34*/35#include "sdp.h"3637static void sdp_nagle_timeout(void *data);3839#ifdef CONFIG_INFINIBAND_SDP_DEBUG_DATA40void _dump_packet(const char *func, int line, struct socket *sk, char *str,41struct mbuf *mb, const struct sdp_bsdh *h)42{43struct sdp_hh *hh;44struct sdp_hah *hah;45struct sdp_chrecvbuf *req_size;46struct sdp_rrch *rrch;47struct sdp_srcah *srcah;48int len = 0;49char buf[256];50len += snprintf(buf, 255-len, "%s mb: %p mid: %2x:%-20s flags: 0x%x "51"bufs: 0x%x len: 0x%x mseq: 0x%x mseq_ack: 0x%x | ",52str, mb, h->mid, mid2str(h->mid), h->flags,53ntohs(h->bufs), ntohl(h->len), ntohl(h->mseq),54ntohl(h->mseq_ack));5556switch (h->mid) {57case SDP_MID_HELLO:58hh = (struct sdp_hh *)h;59len += snprintf(buf + len, 255-len,60"max_adverts: %d majv_minv: 0x%x "61"localrcvsz: 0x%x desremrcvsz: 0x%x |",62hh->max_adverts, hh->majv_minv,63ntohl(hh->localrcvsz),64ntohl(hh->desremrcvsz));65break;66case SDP_MID_HELLO_ACK:67hah = (struct sdp_hah *)h;68len += snprintf(buf + len, 255-len, "actrcvz: 0x%x |",69ntohl(hah->actrcvsz));70break;71case SDP_MID_CHRCVBUF:72case SDP_MID_CHRCVBUF_ACK:73req_size = (struct sdp_chrecvbuf *)(h+1);74len += snprintf(buf + len, 255-len, "req_size: 0x%x |",75ntohl(req_size->size));76break;77case SDP_MID_DATA:78len += snprintf(buf + len, 255-len, "data_len: 0x%lx |",79ntohl(h->len) - sizeof(struct sdp_bsdh));80break;81case SDP_MID_RDMARDCOMPL:82rrch = (struct sdp_rrch *)(h+1);8384len += snprintf(buf + len, 255-len, " | len: 0x%x |",85ntohl(rrch->len));86break;87case SDP_MID_SRCAVAIL:88srcah = (struct sdp_srcah *)(h+1);8990len += snprintf(buf + len, 255-len, " | payload: 0x%lx, "91"len: 0x%x, rkey: 0x%x, vaddr: 0x%jx |",92ntohl(h->len) - sizeof(struct sdp_bsdh) -93sizeof(struct sdp_srcah),94ntohl(srcah->len), ntohl(srcah->rkey),95be64_to_cpu(srcah->vaddr));96break;97default:98break;99}100buf[len] = 0;101_sdp_printk(func, line, KERN_WARNING, sk, "%s: %s\n", str, buf);102}103#endif104105static inline int106sdp_nagle_off(struct sdp_sock *ssk, struct mbuf *mb)107{108109struct sdp_bsdh *h;110111h = mtod(mb, struct sdp_bsdh *);112int send_now =113#ifdef SDP_ZCOPY114BZCOPY_STATE(mb) ||115#endif116unlikely(h->mid != SDP_MID_DATA) ||117(ssk->flags & SDP_NODELAY) ||118!ssk->nagle_last_unacked ||119mb->m_pkthdr.len >= ssk->xmit_size_goal / 4 ||120(mb->m_flags & M_PUSH);121122if (send_now) {123unsigned long mseq = ring_head(ssk->tx_ring);124ssk->nagle_last_unacked = mseq;125} else {126if (!callout_pending(&ssk->nagle_timer)) {127callout_reset(&ssk->nagle_timer, SDP_NAGLE_TIMEOUT,128sdp_nagle_timeout, ssk);129sdp_dbg_data(ssk->socket, "Starting nagle timer\n");130}131}132sdp_dbg_data(ssk->socket, "send_now = %d last_unacked = %ld\n",133send_now, ssk->nagle_last_unacked);134135return send_now;136}137138static void139sdp_nagle_timeout(void *data)140{141struct sdp_sock *ssk = (struct sdp_sock *)data;142struct socket *sk = ssk->socket;143144sdp_dbg_data(sk, "last_unacked = %ld\n", ssk->nagle_last_unacked);145146if (!callout_active(&ssk->nagle_timer))147return;148callout_deactivate(&ssk->nagle_timer);149150if (!ssk->nagle_last_unacked)151goto out;152if (ssk->state == TCPS_CLOSED)153return;154ssk->nagle_last_unacked = 0;155sdp_post_sends(ssk, M_NOWAIT);156157sowwakeup(ssk->socket);158out:159if (sk->so_snd.sb_sndptr)160callout_reset(&ssk->nagle_timer, SDP_NAGLE_TIMEOUT,161sdp_nagle_timeout, ssk);162}163164void165sdp_post_sends(struct sdp_sock *ssk, int wait)166{167struct mbuf *mb;168int post_count = 0;169struct socket *sk;170int low;171172sk = ssk->socket;173if (unlikely(!ssk->id)) {174if (sk->so_snd.sb_sndptr) {175sdp_dbg(ssk->socket,176"Send on socket without cmid ECONNRESET.\n");177sdp_notify(ssk, ECONNRESET);178}179return;180}181again:182if (sdp_tx_ring_slots_left(ssk) < SDP_TX_SIZE / 2)183sdp_xmit_poll(ssk, 1);184185if (ssk->recv_request &&186ring_tail(ssk->rx_ring) >= ssk->recv_request_head &&187tx_credits(ssk) >= SDP_MIN_TX_CREDITS &&188sdp_tx_ring_slots_left(ssk)) {189mb = sdp_alloc_mb_chrcvbuf_ack(sk,190ssk->recv_bytes - SDP_HEAD_SIZE, wait);191if (mb == NULL)192goto allocfail;193ssk->recv_request = 0;194sdp_post_send(ssk, mb);195post_count++;196}197198if (tx_credits(ssk) <= SDP_MIN_TX_CREDITS &&199sdp_tx_ring_slots_left(ssk) && sk->so_snd.sb_sndptr &&200sdp_nagle_off(ssk, sk->so_snd.sb_sndptr)) {201SDPSTATS_COUNTER_INC(send_miss_no_credits);202}203204while (tx_credits(ssk) > SDP_MIN_TX_CREDITS &&205sdp_tx_ring_slots_left(ssk) && (mb = sk->so_snd.sb_sndptr) &&206sdp_nagle_off(ssk, mb)) {207struct mbuf *n;208209SOCKBUF_LOCK(&sk->so_snd);210sk->so_snd.sb_sndptr = mb->m_nextpkt;211sk->so_snd.sb_mb = mb->m_nextpkt;212mb->m_nextpkt = NULL;213SB_EMPTY_FIXUP(&sk->so_snd);214for (n = mb; n != NULL; n = n->m_next)215sbfree(&sk->so_snd, n);216SOCKBUF_UNLOCK(&sk->so_snd);217sdp_post_send(ssk, mb);218post_count++;219}220221if (credit_update_needed(ssk) && ssk->state >= TCPS_ESTABLISHED &&222ssk->state < TCPS_FIN_WAIT_2) {223mb = sdp_alloc_mb_data(ssk->socket, wait);224if (mb == NULL)225goto allocfail;226sdp_post_send(ssk, mb);227228SDPSTATS_COUNTER_INC(post_send_credits);229post_count++;230}231232/* send DisConn if needed233* Do not send DisConn if there is only 1 credit. Compliance with CA4-82234* If one credit is available, an implementation shall only send SDP235* messages that provide additional credits and also do not contain ULP236* payload. */237if ((ssk->flags & SDP_NEEDFIN) && !sk->so_snd.sb_sndptr &&238tx_credits(ssk) > 1) {239mb = sdp_alloc_mb_disconnect(sk, wait);240if (mb == NULL)241goto allocfail;242ssk->flags &= ~SDP_NEEDFIN;243sdp_post_send(ssk, mb);244post_count++;245}246low = (sdp_tx_ring_slots_left(ssk) <= SDP_MIN_TX_CREDITS);247if (post_count || low) {248if (low)249sdp_arm_tx_cq(ssk);250if (sdp_xmit_poll(ssk, low))251goto again;252}253return;254255allocfail:256ssk->nagle_last_unacked = -1;257callout_reset(&ssk->nagle_timer, 1, sdp_nagle_timeout, ssk);258return;259}260261262