162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2014-2017 Oracle. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2003-2007 Network Appliance, Inc. All rights reserved. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This software is available to you under a choice of one of two 762306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 862306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 962306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the BSD-type 1062306a36Sopenharmony_ci * license below: 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 1362306a36Sopenharmony_ci * modification, are permitted provided that the following conditions 1462306a36Sopenharmony_ci * are met: 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Redistributions of source code must retain the above copyright 1762306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * Redistributions in binary form must reproduce the above 2062306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2162306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials provided 2262306a36Sopenharmony_ci * with the distribution. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * Neither the name of the Network Appliance, Inc. nor the names of 2562306a36Sopenharmony_ci * its contributors may be used to endorse or promote products 2662306a36Sopenharmony_ci * derived from this software without specific prior written 2762306a36Sopenharmony_ci * permission. 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3062306a36Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3162306a36Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3262306a36Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3362306a36Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3462306a36Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3562306a36Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3662306a36Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3762306a36Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3862306a36Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3962306a36Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* 4362306a36Sopenharmony_ci * verbs.c 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * Encapsulates the major functions managing: 4662306a36Sopenharmony_ci * o adapters 4762306a36Sopenharmony_ci * o endpoints 4862306a36Sopenharmony_ci * o connections 4962306a36Sopenharmony_ci * o buffer memory 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#include <linux/interrupt.h> 5362306a36Sopenharmony_ci#include <linux/slab.h> 5462306a36Sopenharmony_ci#include <linux/sunrpc/addr.h> 5562306a36Sopenharmony_ci#include <linux/sunrpc/svc_rdma.h> 5662306a36Sopenharmony_ci#include <linux/log2.h> 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#include <asm-generic/barrier.h> 5962306a36Sopenharmony_ci#include <asm/bitops.h> 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#include <rdma/ib_cm.h> 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#include "xprt_rdma.h" 6462306a36Sopenharmony_ci#include <trace/events/rpcrdma.h> 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic int rpcrdma_sendctxs_create(struct rpcrdma_xprt *r_xprt); 6762306a36Sopenharmony_cistatic void rpcrdma_sendctxs_destroy(struct rpcrdma_xprt *r_xprt); 6862306a36Sopenharmony_cistatic void rpcrdma_sendctx_put_locked(struct rpcrdma_xprt *r_xprt, 6962306a36Sopenharmony_ci struct rpcrdma_sendctx *sc); 7062306a36Sopenharmony_cistatic int rpcrdma_reqs_setup(struct rpcrdma_xprt *r_xprt); 7162306a36Sopenharmony_cistatic void rpcrdma_reqs_reset(struct rpcrdma_xprt *r_xprt); 7262306a36Sopenharmony_cistatic void rpcrdma_rep_destroy(struct rpcrdma_rep *rep); 7362306a36Sopenharmony_cistatic void rpcrdma_reps_unmap(struct rpcrdma_xprt *r_xprt); 7462306a36Sopenharmony_cistatic void rpcrdma_mrs_create(struct rpcrdma_xprt *r_xprt); 7562306a36Sopenharmony_cistatic void rpcrdma_mrs_destroy(struct rpcrdma_xprt *r_xprt); 7662306a36Sopenharmony_cistatic void rpcrdma_ep_get(struct rpcrdma_ep *ep); 7762306a36Sopenharmony_cistatic int rpcrdma_ep_put(struct rpcrdma_ep *ep); 7862306a36Sopenharmony_cistatic struct rpcrdma_regbuf * 7962306a36Sopenharmony_cirpcrdma_regbuf_alloc(size_t size, enum dma_data_direction direction); 8062306a36Sopenharmony_cistatic void rpcrdma_regbuf_dma_unmap(struct rpcrdma_regbuf *rb); 8162306a36Sopenharmony_cistatic void rpcrdma_regbuf_free(struct rpcrdma_regbuf *rb); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* Wait for outstanding transport work to finish. ib_drain_qp 8462306a36Sopenharmony_ci * handles the drains in the wrong order for us, so open code 8562306a36Sopenharmony_ci * them here. 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_cistatic void rpcrdma_xprt_drain(struct rpcrdma_xprt *r_xprt) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci struct rpcrdma_ep *ep = r_xprt->rx_ep; 9062306a36Sopenharmony_ci struct rdma_cm_id *id = ep->re_id; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci /* Wait for rpcrdma_post_recvs() to leave its critical 9362306a36Sopenharmony_ci * section. 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_ci if (atomic_inc_return(&ep->re_receiving) > 1) 9662306a36Sopenharmony_ci wait_for_completion(&ep->re_done); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* Flush Receives, then wait for deferred Reply work 9962306a36Sopenharmony_ci * to complete. 10062306a36Sopenharmony_ci */ 10162306a36Sopenharmony_ci ib_drain_rq(id->qp); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci /* Deferred Reply processing might have scheduled 10462306a36Sopenharmony_ci * local invalidations. 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_ci ib_drain_sq(id->qp); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci rpcrdma_ep_put(ep); 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci/* Ensure xprt_force_disconnect() is invoked exactly once when a 11262306a36Sopenharmony_ci * connection is closed or lost. (The important thing is it needs 11362306a36Sopenharmony_ci * to be invoked "at least" once). 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_civoid rpcrdma_force_disconnect(struct rpcrdma_ep *ep) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci if (atomic_add_unless(&ep->re_force_disconnect, 1, 1)) 11862306a36Sopenharmony_ci xprt_force_disconnect(ep->re_xprt); 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/** 12262306a36Sopenharmony_ci * rpcrdma_flush_disconnect - Disconnect on flushed completion 12362306a36Sopenharmony_ci * @r_xprt: transport to disconnect 12462306a36Sopenharmony_ci * @wc: work completion entry 12562306a36Sopenharmony_ci * 12662306a36Sopenharmony_ci * Must be called in process context. 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_civoid rpcrdma_flush_disconnect(struct rpcrdma_xprt *r_xprt, struct ib_wc *wc) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci if (wc->status != IB_WC_SUCCESS) 13162306a36Sopenharmony_ci rpcrdma_force_disconnect(r_xprt->rx_ep); 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci/** 13562306a36Sopenharmony_ci * rpcrdma_wc_send - Invoked by RDMA provider for each polled Send WC 13662306a36Sopenharmony_ci * @cq: completion queue 13762306a36Sopenharmony_ci * @wc: WCE for a completed Send WR 13862306a36Sopenharmony_ci * 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_cistatic void rpcrdma_wc_send(struct ib_cq *cq, struct ib_wc *wc) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci struct ib_cqe *cqe = wc->wr_cqe; 14362306a36Sopenharmony_ci struct rpcrdma_sendctx *sc = 14462306a36Sopenharmony_ci container_of(cqe, struct rpcrdma_sendctx, sc_cqe); 14562306a36Sopenharmony_ci struct rpcrdma_xprt *r_xprt = cq->cq_context; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* WARNING: Only wr_cqe and status are reliable at this point */ 14862306a36Sopenharmony_ci trace_xprtrdma_wc_send(wc, &sc->sc_cid); 14962306a36Sopenharmony_ci rpcrdma_sendctx_put_locked(r_xprt, sc); 15062306a36Sopenharmony_ci rpcrdma_flush_disconnect(r_xprt, wc); 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci/** 15462306a36Sopenharmony_ci * rpcrdma_wc_receive - Invoked by RDMA provider for each polled Receive WC 15562306a36Sopenharmony_ci * @cq: completion queue 15662306a36Sopenharmony_ci * @wc: WCE for a completed Receive WR 15762306a36Sopenharmony_ci * 15862306a36Sopenharmony_ci */ 15962306a36Sopenharmony_cistatic void rpcrdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci struct ib_cqe *cqe = wc->wr_cqe; 16262306a36Sopenharmony_ci struct rpcrdma_rep *rep = container_of(cqe, struct rpcrdma_rep, 16362306a36Sopenharmony_ci rr_cqe); 16462306a36Sopenharmony_ci struct rpcrdma_xprt *r_xprt = cq->cq_context; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* WARNING: Only wr_cqe and status are reliable at this point */ 16762306a36Sopenharmony_ci trace_xprtrdma_wc_receive(wc, &rep->rr_cid); 16862306a36Sopenharmony_ci --r_xprt->rx_ep->re_receive_count; 16962306a36Sopenharmony_ci if (wc->status != IB_WC_SUCCESS) 17062306a36Sopenharmony_ci goto out_flushed; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* status == SUCCESS means all fields in wc are trustworthy */ 17362306a36Sopenharmony_ci rpcrdma_set_xdrlen(&rep->rr_hdrbuf, wc->byte_len); 17462306a36Sopenharmony_ci rep->rr_wc_flags = wc->wc_flags; 17562306a36Sopenharmony_ci rep->rr_inv_rkey = wc->ex.invalidate_rkey; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci ib_dma_sync_single_for_cpu(rdmab_device(rep->rr_rdmabuf), 17862306a36Sopenharmony_ci rdmab_addr(rep->rr_rdmabuf), 17962306a36Sopenharmony_ci wc->byte_len, DMA_FROM_DEVICE); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci rpcrdma_reply_handler(rep); 18262306a36Sopenharmony_ci return; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ciout_flushed: 18562306a36Sopenharmony_ci rpcrdma_flush_disconnect(r_xprt, wc); 18662306a36Sopenharmony_ci rpcrdma_rep_put(&r_xprt->rx_buf, rep); 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic void rpcrdma_update_cm_private(struct rpcrdma_ep *ep, 19062306a36Sopenharmony_ci struct rdma_conn_param *param) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci const struct rpcrdma_connect_private *pmsg = param->private_data; 19362306a36Sopenharmony_ci unsigned int rsize, wsize; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* Default settings for RPC-over-RDMA Version One */ 19662306a36Sopenharmony_ci rsize = RPCRDMA_V1_DEF_INLINE_SIZE; 19762306a36Sopenharmony_ci wsize = RPCRDMA_V1_DEF_INLINE_SIZE; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (pmsg && 20062306a36Sopenharmony_ci pmsg->cp_magic == rpcrdma_cmp_magic && 20162306a36Sopenharmony_ci pmsg->cp_version == RPCRDMA_CMP_VERSION) { 20262306a36Sopenharmony_ci rsize = rpcrdma_decode_buffer_size(pmsg->cp_send_size); 20362306a36Sopenharmony_ci wsize = rpcrdma_decode_buffer_size(pmsg->cp_recv_size); 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci if (rsize < ep->re_inline_recv) 20762306a36Sopenharmony_ci ep->re_inline_recv = rsize; 20862306a36Sopenharmony_ci if (wsize < ep->re_inline_send) 20962306a36Sopenharmony_ci ep->re_inline_send = wsize; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci rpcrdma_set_max_header_sizes(ep); 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci/** 21562306a36Sopenharmony_ci * rpcrdma_cm_event_handler - Handle RDMA CM events 21662306a36Sopenharmony_ci * @id: rdma_cm_id on which an event has occurred 21762306a36Sopenharmony_ci * @event: details of the event 21862306a36Sopenharmony_ci * 21962306a36Sopenharmony_ci * Called with @id's mutex held. Returns 1 if caller should 22062306a36Sopenharmony_ci * destroy @id, otherwise 0. 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_cistatic int 22362306a36Sopenharmony_cirpcrdma_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct sockaddr *sap = (struct sockaddr *)&id->route.addr.dst_addr; 22662306a36Sopenharmony_ci struct rpcrdma_ep *ep = id->context; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci might_sleep(); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci switch (event->event) { 23162306a36Sopenharmony_ci case RDMA_CM_EVENT_ADDR_RESOLVED: 23262306a36Sopenharmony_ci case RDMA_CM_EVENT_ROUTE_RESOLVED: 23362306a36Sopenharmony_ci ep->re_async_rc = 0; 23462306a36Sopenharmony_ci complete(&ep->re_done); 23562306a36Sopenharmony_ci return 0; 23662306a36Sopenharmony_ci case RDMA_CM_EVENT_ADDR_ERROR: 23762306a36Sopenharmony_ci ep->re_async_rc = -EPROTO; 23862306a36Sopenharmony_ci complete(&ep->re_done); 23962306a36Sopenharmony_ci return 0; 24062306a36Sopenharmony_ci case RDMA_CM_EVENT_ROUTE_ERROR: 24162306a36Sopenharmony_ci ep->re_async_rc = -ENETUNREACH; 24262306a36Sopenharmony_ci complete(&ep->re_done); 24362306a36Sopenharmony_ci return 0; 24462306a36Sopenharmony_ci case RDMA_CM_EVENT_DEVICE_REMOVAL: 24562306a36Sopenharmony_ci pr_info("rpcrdma: removing device %s for %pISpc\n", 24662306a36Sopenharmony_ci ep->re_id->device->name, sap); 24762306a36Sopenharmony_ci fallthrough; 24862306a36Sopenharmony_ci case RDMA_CM_EVENT_ADDR_CHANGE: 24962306a36Sopenharmony_ci ep->re_connect_status = -ENODEV; 25062306a36Sopenharmony_ci goto disconnected; 25162306a36Sopenharmony_ci case RDMA_CM_EVENT_ESTABLISHED: 25262306a36Sopenharmony_ci rpcrdma_ep_get(ep); 25362306a36Sopenharmony_ci ep->re_connect_status = 1; 25462306a36Sopenharmony_ci rpcrdma_update_cm_private(ep, &event->param.conn); 25562306a36Sopenharmony_ci trace_xprtrdma_inline_thresh(ep); 25662306a36Sopenharmony_ci wake_up_all(&ep->re_connect_wait); 25762306a36Sopenharmony_ci break; 25862306a36Sopenharmony_ci case RDMA_CM_EVENT_CONNECT_ERROR: 25962306a36Sopenharmony_ci ep->re_connect_status = -ENOTCONN; 26062306a36Sopenharmony_ci goto wake_connect_worker; 26162306a36Sopenharmony_ci case RDMA_CM_EVENT_UNREACHABLE: 26262306a36Sopenharmony_ci ep->re_connect_status = -ENETUNREACH; 26362306a36Sopenharmony_ci goto wake_connect_worker; 26462306a36Sopenharmony_ci case RDMA_CM_EVENT_REJECTED: 26562306a36Sopenharmony_ci ep->re_connect_status = -ECONNREFUSED; 26662306a36Sopenharmony_ci if (event->status == IB_CM_REJ_STALE_CONN) 26762306a36Sopenharmony_ci ep->re_connect_status = -ENOTCONN; 26862306a36Sopenharmony_ciwake_connect_worker: 26962306a36Sopenharmony_ci wake_up_all(&ep->re_connect_wait); 27062306a36Sopenharmony_ci return 0; 27162306a36Sopenharmony_ci case RDMA_CM_EVENT_DISCONNECTED: 27262306a36Sopenharmony_ci ep->re_connect_status = -ECONNABORTED; 27362306a36Sopenharmony_cidisconnected: 27462306a36Sopenharmony_ci rpcrdma_force_disconnect(ep); 27562306a36Sopenharmony_ci return rpcrdma_ep_put(ep); 27662306a36Sopenharmony_ci default: 27762306a36Sopenharmony_ci break; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci return 0; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic struct rdma_cm_id *rpcrdma_create_id(struct rpcrdma_xprt *r_xprt, 28462306a36Sopenharmony_ci struct rpcrdma_ep *ep) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci unsigned long wtimeout = msecs_to_jiffies(RDMA_RESOLVE_TIMEOUT) + 1; 28762306a36Sopenharmony_ci struct rpc_xprt *xprt = &r_xprt->rx_xprt; 28862306a36Sopenharmony_ci struct rdma_cm_id *id; 28962306a36Sopenharmony_ci int rc; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci init_completion(&ep->re_done); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci id = rdma_create_id(xprt->xprt_net, rpcrdma_cm_event_handler, ep, 29462306a36Sopenharmony_ci RDMA_PS_TCP, IB_QPT_RC); 29562306a36Sopenharmony_ci if (IS_ERR(id)) 29662306a36Sopenharmony_ci return id; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci ep->re_async_rc = -ETIMEDOUT; 29962306a36Sopenharmony_ci rc = rdma_resolve_addr(id, NULL, (struct sockaddr *)&xprt->addr, 30062306a36Sopenharmony_ci RDMA_RESOLVE_TIMEOUT); 30162306a36Sopenharmony_ci if (rc) 30262306a36Sopenharmony_ci goto out; 30362306a36Sopenharmony_ci rc = wait_for_completion_interruptible_timeout(&ep->re_done, wtimeout); 30462306a36Sopenharmony_ci if (rc < 0) 30562306a36Sopenharmony_ci goto out; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci rc = ep->re_async_rc; 30862306a36Sopenharmony_ci if (rc) 30962306a36Sopenharmony_ci goto out; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci ep->re_async_rc = -ETIMEDOUT; 31262306a36Sopenharmony_ci rc = rdma_resolve_route(id, RDMA_RESOLVE_TIMEOUT); 31362306a36Sopenharmony_ci if (rc) 31462306a36Sopenharmony_ci goto out; 31562306a36Sopenharmony_ci rc = wait_for_completion_interruptible_timeout(&ep->re_done, wtimeout); 31662306a36Sopenharmony_ci if (rc < 0) 31762306a36Sopenharmony_ci goto out; 31862306a36Sopenharmony_ci rc = ep->re_async_rc; 31962306a36Sopenharmony_ci if (rc) 32062306a36Sopenharmony_ci goto out; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci return id; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ciout: 32562306a36Sopenharmony_ci rdma_destroy_id(id); 32662306a36Sopenharmony_ci return ERR_PTR(rc); 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic void rpcrdma_ep_destroy(struct kref *kref) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci struct rpcrdma_ep *ep = container_of(kref, struct rpcrdma_ep, re_kref); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (ep->re_id->qp) { 33462306a36Sopenharmony_ci rdma_destroy_qp(ep->re_id); 33562306a36Sopenharmony_ci ep->re_id->qp = NULL; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci if (ep->re_attr.recv_cq) 33962306a36Sopenharmony_ci ib_free_cq(ep->re_attr.recv_cq); 34062306a36Sopenharmony_ci ep->re_attr.recv_cq = NULL; 34162306a36Sopenharmony_ci if (ep->re_attr.send_cq) 34262306a36Sopenharmony_ci ib_free_cq(ep->re_attr.send_cq); 34362306a36Sopenharmony_ci ep->re_attr.send_cq = NULL; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci if (ep->re_pd) 34662306a36Sopenharmony_ci ib_dealloc_pd(ep->re_pd); 34762306a36Sopenharmony_ci ep->re_pd = NULL; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci kfree(ep); 35062306a36Sopenharmony_ci module_put(THIS_MODULE); 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_cistatic noinline void rpcrdma_ep_get(struct rpcrdma_ep *ep) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci kref_get(&ep->re_kref); 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci/* Returns: 35962306a36Sopenharmony_ci * %0 if @ep still has a positive kref count, or 36062306a36Sopenharmony_ci * %1 if @ep was destroyed successfully. 36162306a36Sopenharmony_ci */ 36262306a36Sopenharmony_cistatic noinline int rpcrdma_ep_put(struct rpcrdma_ep *ep) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci return kref_put(&ep->re_kref, rpcrdma_ep_destroy); 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic int rpcrdma_ep_create(struct rpcrdma_xprt *r_xprt) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci struct rpcrdma_connect_private *pmsg; 37062306a36Sopenharmony_ci struct ib_device *device; 37162306a36Sopenharmony_ci struct rdma_cm_id *id; 37262306a36Sopenharmony_ci struct rpcrdma_ep *ep; 37362306a36Sopenharmony_ci int rc; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci ep = kzalloc(sizeof(*ep), XPRTRDMA_GFP_FLAGS); 37662306a36Sopenharmony_ci if (!ep) 37762306a36Sopenharmony_ci return -ENOTCONN; 37862306a36Sopenharmony_ci ep->re_xprt = &r_xprt->rx_xprt; 37962306a36Sopenharmony_ci kref_init(&ep->re_kref); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci id = rpcrdma_create_id(r_xprt, ep); 38262306a36Sopenharmony_ci if (IS_ERR(id)) { 38362306a36Sopenharmony_ci kfree(ep); 38462306a36Sopenharmony_ci return PTR_ERR(id); 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci __module_get(THIS_MODULE); 38762306a36Sopenharmony_ci device = id->device; 38862306a36Sopenharmony_ci ep->re_id = id; 38962306a36Sopenharmony_ci reinit_completion(&ep->re_done); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci ep->re_max_requests = r_xprt->rx_xprt.max_reqs; 39262306a36Sopenharmony_ci ep->re_inline_send = xprt_rdma_max_inline_write; 39362306a36Sopenharmony_ci ep->re_inline_recv = xprt_rdma_max_inline_read; 39462306a36Sopenharmony_ci rc = frwr_query_device(ep, device); 39562306a36Sopenharmony_ci if (rc) 39662306a36Sopenharmony_ci goto out_destroy; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci r_xprt->rx_buf.rb_max_requests = cpu_to_be32(ep->re_max_requests); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci ep->re_attr.srq = NULL; 40162306a36Sopenharmony_ci ep->re_attr.cap.max_inline_data = 0; 40262306a36Sopenharmony_ci ep->re_attr.sq_sig_type = IB_SIGNAL_REQ_WR; 40362306a36Sopenharmony_ci ep->re_attr.qp_type = IB_QPT_RC; 40462306a36Sopenharmony_ci ep->re_attr.port_num = ~0; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci ep->re_send_batch = ep->re_max_requests >> 3; 40762306a36Sopenharmony_ci ep->re_send_count = ep->re_send_batch; 40862306a36Sopenharmony_ci init_waitqueue_head(&ep->re_connect_wait); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci ep->re_attr.send_cq = ib_alloc_cq_any(device, r_xprt, 41162306a36Sopenharmony_ci ep->re_attr.cap.max_send_wr, 41262306a36Sopenharmony_ci IB_POLL_WORKQUEUE); 41362306a36Sopenharmony_ci if (IS_ERR(ep->re_attr.send_cq)) { 41462306a36Sopenharmony_ci rc = PTR_ERR(ep->re_attr.send_cq); 41562306a36Sopenharmony_ci ep->re_attr.send_cq = NULL; 41662306a36Sopenharmony_ci goto out_destroy; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci ep->re_attr.recv_cq = ib_alloc_cq_any(device, r_xprt, 42062306a36Sopenharmony_ci ep->re_attr.cap.max_recv_wr, 42162306a36Sopenharmony_ci IB_POLL_WORKQUEUE); 42262306a36Sopenharmony_ci if (IS_ERR(ep->re_attr.recv_cq)) { 42362306a36Sopenharmony_ci rc = PTR_ERR(ep->re_attr.recv_cq); 42462306a36Sopenharmony_ci ep->re_attr.recv_cq = NULL; 42562306a36Sopenharmony_ci goto out_destroy; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci ep->re_receive_count = 0; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci /* Initialize cma parameters */ 43062306a36Sopenharmony_ci memset(&ep->re_remote_cma, 0, sizeof(ep->re_remote_cma)); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci /* Prepare RDMA-CM private message */ 43362306a36Sopenharmony_ci pmsg = &ep->re_cm_private; 43462306a36Sopenharmony_ci pmsg->cp_magic = rpcrdma_cmp_magic; 43562306a36Sopenharmony_ci pmsg->cp_version = RPCRDMA_CMP_VERSION; 43662306a36Sopenharmony_ci pmsg->cp_flags |= RPCRDMA_CMP_F_SND_W_INV_OK; 43762306a36Sopenharmony_ci pmsg->cp_send_size = rpcrdma_encode_buffer_size(ep->re_inline_send); 43862306a36Sopenharmony_ci pmsg->cp_recv_size = rpcrdma_encode_buffer_size(ep->re_inline_recv); 43962306a36Sopenharmony_ci ep->re_remote_cma.private_data = pmsg; 44062306a36Sopenharmony_ci ep->re_remote_cma.private_data_len = sizeof(*pmsg); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci /* Client offers RDMA Read but does not initiate */ 44362306a36Sopenharmony_ci ep->re_remote_cma.initiator_depth = 0; 44462306a36Sopenharmony_ci ep->re_remote_cma.responder_resources = 44562306a36Sopenharmony_ci min_t(int, U8_MAX, device->attrs.max_qp_rd_atom); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci /* Limit transport retries so client can detect server 44862306a36Sopenharmony_ci * GID changes quickly. RPC layer handles re-establishing 44962306a36Sopenharmony_ci * transport connection and retransmission. 45062306a36Sopenharmony_ci */ 45162306a36Sopenharmony_ci ep->re_remote_cma.retry_count = 6; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* RPC-over-RDMA handles its own flow control. In addition, 45462306a36Sopenharmony_ci * make all RNR NAKs visible so we know that RPC-over-RDMA 45562306a36Sopenharmony_ci * flow control is working correctly (no NAKs should be seen). 45662306a36Sopenharmony_ci */ 45762306a36Sopenharmony_ci ep->re_remote_cma.flow_control = 0; 45862306a36Sopenharmony_ci ep->re_remote_cma.rnr_retry_count = 0; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci ep->re_pd = ib_alloc_pd(device, 0); 46162306a36Sopenharmony_ci if (IS_ERR(ep->re_pd)) { 46262306a36Sopenharmony_ci rc = PTR_ERR(ep->re_pd); 46362306a36Sopenharmony_ci ep->re_pd = NULL; 46462306a36Sopenharmony_ci goto out_destroy; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci rc = rdma_create_qp(id, ep->re_pd, &ep->re_attr); 46862306a36Sopenharmony_ci if (rc) 46962306a36Sopenharmony_ci goto out_destroy; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci r_xprt->rx_ep = ep; 47262306a36Sopenharmony_ci return 0; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ciout_destroy: 47562306a36Sopenharmony_ci rpcrdma_ep_put(ep); 47662306a36Sopenharmony_ci rdma_destroy_id(id); 47762306a36Sopenharmony_ci return rc; 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci/** 48162306a36Sopenharmony_ci * rpcrdma_xprt_connect - Connect an unconnected transport 48262306a36Sopenharmony_ci * @r_xprt: controlling transport instance 48362306a36Sopenharmony_ci * 48462306a36Sopenharmony_ci * Returns 0 on success or a negative errno. 48562306a36Sopenharmony_ci */ 48662306a36Sopenharmony_ciint rpcrdma_xprt_connect(struct rpcrdma_xprt *r_xprt) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci struct rpc_xprt *xprt = &r_xprt->rx_xprt; 48962306a36Sopenharmony_ci struct rpcrdma_ep *ep; 49062306a36Sopenharmony_ci int rc; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci rc = rpcrdma_ep_create(r_xprt); 49362306a36Sopenharmony_ci if (rc) 49462306a36Sopenharmony_ci return rc; 49562306a36Sopenharmony_ci ep = r_xprt->rx_ep; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci xprt_clear_connected(xprt); 49862306a36Sopenharmony_ci rpcrdma_reset_cwnd(r_xprt); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci /* Bump the ep's reference count while there are 50162306a36Sopenharmony_ci * outstanding Receives. 50262306a36Sopenharmony_ci */ 50362306a36Sopenharmony_ci rpcrdma_ep_get(ep); 50462306a36Sopenharmony_ci rpcrdma_post_recvs(r_xprt, 1, true); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci rc = rdma_connect(ep->re_id, &ep->re_remote_cma); 50762306a36Sopenharmony_ci if (rc) 50862306a36Sopenharmony_ci goto out; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (xprt->reestablish_timeout < RPCRDMA_INIT_REEST_TO) 51162306a36Sopenharmony_ci xprt->reestablish_timeout = RPCRDMA_INIT_REEST_TO; 51262306a36Sopenharmony_ci wait_event_interruptible(ep->re_connect_wait, 51362306a36Sopenharmony_ci ep->re_connect_status != 0); 51462306a36Sopenharmony_ci if (ep->re_connect_status <= 0) { 51562306a36Sopenharmony_ci rc = ep->re_connect_status; 51662306a36Sopenharmony_ci goto out; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci rc = rpcrdma_sendctxs_create(r_xprt); 52062306a36Sopenharmony_ci if (rc) { 52162306a36Sopenharmony_ci rc = -ENOTCONN; 52262306a36Sopenharmony_ci goto out; 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci rc = rpcrdma_reqs_setup(r_xprt); 52662306a36Sopenharmony_ci if (rc) { 52762306a36Sopenharmony_ci rc = -ENOTCONN; 52862306a36Sopenharmony_ci goto out; 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci rpcrdma_mrs_create(r_xprt); 53162306a36Sopenharmony_ci frwr_wp_create(r_xprt); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ciout: 53462306a36Sopenharmony_ci trace_xprtrdma_connect(r_xprt, rc); 53562306a36Sopenharmony_ci return rc; 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci/** 53962306a36Sopenharmony_ci * rpcrdma_xprt_disconnect - Disconnect underlying transport 54062306a36Sopenharmony_ci * @r_xprt: controlling transport instance 54162306a36Sopenharmony_ci * 54262306a36Sopenharmony_ci * Caller serializes. Either the transport send lock is held, 54362306a36Sopenharmony_ci * or we're being called to destroy the transport. 54462306a36Sopenharmony_ci * 54562306a36Sopenharmony_ci * On return, @r_xprt is completely divested of all hardware 54662306a36Sopenharmony_ci * resources and prepared for the next ->connect operation. 54762306a36Sopenharmony_ci */ 54862306a36Sopenharmony_civoid rpcrdma_xprt_disconnect(struct rpcrdma_xprt *r_xprt) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci struct rpcrdma_ep *ep = r_xprt->rx_ep; 55162306a36Sopenharmony_ci struct rdma_cm_id *id; 55262306a36Sopenharmony_ci int rc; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci if (!ep) 55562306a36Sopenharmony_ci return; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci id = ep->re_id; 55862306a36Sopenharmony_ci rc = rdma_disconnect(id); 55962306a36Sopenharmony_ci trace_xprtrdma_disconnect(r_xprt, rc); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci rpcrdma_xprt_drain(r_xprt); 56262306a36Sopenharmony_ci rpcrdma_reps_unmap(r_xprt); 56362306a36Sopenharmony_ci rpcrdma_reqs_reset(r_xprt); 56462306a36Sopenharmony_ci rpcrdma_mrs_destroy(r_xprt); 56562306a36Sopenharmony_ci rpcrdma_sendctxs_destroy(r_xprt); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci if (rpcrdma_ep_put(ep)) 56862306a36Sopenharmony_ci rdma_destroy_id(id); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci r_xprt->rx_ep = NULL; 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci/* Fixed-size circular FIFO queue. This implementation is wait-free and 57462306a36Sopenharmony_ci * lock-free. 57562306a36Sopenharmony_ci * 57662306a36Sopenharmony_ci * Consumer is the code path that posts Sends. This path dequeues a 57762306a36Sopenharmony_ci * sendctx for use by a Send operation. Multiple consumer threads 57862306a36Sopenharmony_ci * are serialized by the RPC transport lock, which allows only one 57962306a36Sopenharmony_ci * ->send_request call at a time. 58062306a36Sopenharmony_ci * 58162306a36Sopenharmony_ci * Producer is the code path that handles Send completions. This path 58262306a36Sopenharmony_ci * enqueues a sendctx that has been completed. Multiple producer 58362306a36Sopenharmony_ci * threads are serialized by the ib_poll_cq() function. 58462306a36Sopenharmony_ci */ 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci/* rpcrdma_sendctxs_destroy() assumes caller has already quiesced 58762306a36Sopenharmony_ci * queue activity, and rpcrdma_xprt_drain has flushed all remaining 58862306a36Sopenharmony_ci * Send requests. 58962306a36Sopenharmony_ci */ 59062306a36Sopenharmony_cistatic void rpcrdma_sendctxs_destroy(struct rpcrdma_xprt *r_xprt) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci struct rpcrdma_buffer *buf = &r_xprt->rx_buf; 59362306a36Sopenharmony_ci unsigned long i; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci if (!buf->rb_sc_ctxs) 59662306a36Sopenharmony_ci return; 59762306a36Sopenharmony_ci for (i = 0; i <= buf->rb_sc_last; i++) 59862306a36Sopenharmony_ci kfree(buf->rb_sc_ctxs[i]); 59962306a36Sopenharmony_ci kfree(buf->rb_sc_ctxs); 60062306a36Sopenharmony_ci buf->rb_sc_ctxs = NULL; 60162306a36Sopenharmony_ci} 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_cistatic struct rpcrdma_sendctx *rpcrdma_sendctx_create(struct rpcrdma_ep *ep) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci struct rpcrdma_sendctx *sc; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci sc = kzalloc(struct_size(sc, sc_sges, ep->re_attr.cap.max_send_sge), 60862306a36Sopenharmony_ci XPRTRDMA_GFP_FLAGS); 60962306a36Sopenharmony_ci if (!sc) 61062306a36Sopenharmony_ci return NULL; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci sc->sc_cqe.done = rpcrdma_wc_send; 61362306a36Sopenharmony_ci sc->sc_cid.ci_queue_id = ep->re_attr.send_cq->res.id; 61462306a36Sopenharmony_ci sc->sc_cid.ci_completion_id = 61562306a36Sopenharmony_ci atomic_inc_return(&ep->re_completion_ids); 61662306a36Sopenharmony_ci return sc; 61762306a36Sopenharmony_ci} 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_cistatic int rpcrdma_sendctxs_create(struct rpcrdma_xprt *r_xprt) 62062306a36Sopenharmony_ci{ 62162306a36Sopenharmony_ci struct rpcrdma_buffer *buf = &r_xprt->rx_buf; 62262306a36Sopenharmony_ci struct rpcrdma_sendctx *sc; 62362306a36Sopenharmony_ci unsigned long i; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci /* Maximum number of concurrent outstanding Send WRs. Capping 62662306a36Sopenharmony_ci * the circular queue size stops Send Queue overflow by causing 62762306a36Sopenharmony_ci * the ->send_request call to fail temporarily before too many 62862306a36Sopenharmony_ci * Sends are posted. 62962306a36Sopenharmony_ci */ 63062306a36Sopenharmony_ci i = r_xprt->rx_ep->re_max_requests + RPCRDMA_MAX_BC_REQUESTS; 63162306a36Sopenharmony_ci buf->rb_sc_ctxs = kcalloc(i, sizeof(sc), XPRTRDMA_GFP_FLAGS); 63262306a36Sopenharmony_ci if (!buf->rb_sc_ctxs) 63362306a36Sopenharmony_ci return -ENOMEM; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci buf->rb_sc_last = i - 1; 63662306a36Sopenharmony_ci for (i = 0; i <= buf->rb_sc_last; i++) { 63762306a36Sopenharmony_ci sc = rpcrdma_sendctx_create(r_xprt->rx_ep); 63862306a36Sopenharmony_ci if (!sc) 63962306a36Sopenharmony_ci return -ENOMEM; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci buf->rb_sc_ctxs[i] = sc; 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci buf->rb_sc_head = 0; 64562306a36Sopenharmony_ci buf->rb_sc_tail = 0; 64662306a36Sopenharmony_ci return 0; 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci/* The sendctx queue is not guaranteed to have a size that is a 65062306a36Sopenharmony_ci * power of two, thus the helpers in circ_buf.h cannot be used. 65162306a36Sopenharmony_ci * The other option is to use modulus (%), which can be expensive. 65262306a36Sopenharmony_ci */ 65362306a36Sopenharmony_cistatic unsigned long rpcrdma_sendctx_next(struct rpcrdma_buffer *buf, 65462306a36Sopenharmony_ci unsigned long item) 65562306a36Sopenharmony_ci{ 65662306a36Sopenharmony_ci return likely(item < buf->rb_sc_last) ? item + 1 : 0; 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci/** 66062306a36Sopenharmony_ci * rpcrdma_sendctx_get_locked - Acquire a send context 66162306a36Sopenharmony_ci * @r_xprt: controlling transport instance 66262306a36Sopenharmony_ci * 66362306a36Sopenharmony_ci * Returns pointer to a free send completion context; or NULL if 66462306a36Sopenharmony_ci * the queue is empty. 66562306a36Sopenharmony_ci * 66662306a36Sopenharmony_ci * Usage: Called to acquire an SGE array before preparing a Send WR. 66762306a36Sopenharmony_ci * 66862306a36Sopenharmony_ci * The caller serializes calls to this function (per transport), and 66962306a36Sopenharmony_ci * provides an effective memory barrier that flushes the new value 67062306a36Sopenharmony_ci * of rb_sc_head. 67162306a36Sopenharmony_ci */ 67262306a36Sopenharmony_cistruct rpcrdma_sendctx *rpcrdma_sendctx_get_locked(struct rpcrdma_xprt *r_xprt) 67362306a36Sopenharmony_ci{ 67462306a36Sopenharmony_ci struct rpcrdma_buffer *buf = &r_xprt->rx_buf; 67562306a36Sopenharmony_ci struct rpcrdma_sendctx *sc; 67662306a36Sopenharmony_ci unsigned long next_head; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci next_head = rpcrdma_sendctx_next(buf, buf->rb_sc_head); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (next_head == READ_ONCE(buf->rb_sc_tail)) 68162306a36Sopenharmony_ci goto out_emptyq; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci /* ORDER: item must be accessed _before_ head is updated */ 68462306a36Sopenharmony_ci sc = buf->rb_sc_ctxs[next_head]; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci /* Releasing the lock in the caller acts as a memory 68762306a36Sopenharmony_ci * barrier that flushes rb_sc_head. 68862306a36Sopenharmony_ci */ 68962306a36Sopenharmony_ci buf->rb_sc_head = next_head; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci return sc; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ciout_emptyq: 69462306a36Sopenharmony_ci /* The queue is "empty" if there have not been enough Send 69562306a36Sopenharmony_ci * completions recently. This is a sign the Send Queue is 69662306a36Sopenharmony_ci * backing up. Cause the caller to pause and try again. 69762306a36Sopenharmony_ci */ 69862306a36Sopenharmony_ci xprt_wait_for_buffer_space(&r_xprt->rx_xprt); 69962306a36Sopenharmony_ci r_xprt->rx_stats.empty_sendctx_q++; 70062306a36Sopenharmony_ci return NULL; 70162306a36Sopenharmony_ci} 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci/** 70462306a36Sopenharmony_ci * rpcrdma_sendctx_put_locked - Release a send context 70562306a36Sopenharmony_ci * @r_xprt: controlling transport instance 70662306a36Sopenharmony_ci * @sc: send context to release 70762306a36Sopenharmony_ci * 70862306a36Sopenharmony_ci * Usage: Called from Send completion to return a sendctxt 70962306a36Sopenharmony_ci * to the queue. 71062306a36Sopenharmony_ci * 71162306a36Sopenharmony_ci * The caller serializes calls to this function (per transport). 71262306a36Sopenharmony_ci */ 71362306a36Sopenharmony_cistatic void rpcrdma_sendctx_put_locked(struct rpcrdma_xprt *r_xprt, 71462306a36Sopenharmony_ci struct rpcrdma_sendctx *sc) 71562306a36Sopenharmony_ci{ 71662306a36Sopenharmony_ci struct rpcrdma_buffer *buf = &r_xprt->rx_buf; 71762306a36Sopenharmony_ci unsigned long next_tail; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci /* Unmap SGEs of previously completed but unsignaled 72062306a36Sopenharmony_ci * Sends by walking up the queue until @sc is found. 72162306a36Sopenharmony_ci */ 72262306a36Sopenharmony_ci next_tail = buf->rb_sc_tail; 72362306a36Sopenharmony_ci do { 72462306a36Sopenharmony_ci next_tail = rpcrdma_sendctx_next(buf, next_tail); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci /* ORDER: item must be accessed _before_ tail is updated */ 72762306a36Sopenharmony_ci rpcrdma_sendctx_unmap(buf->rb_sc_ctxs[next_tail]); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci } while (buf->rb_sc_ctxs[next_tail] != sc); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci /* Paired with READ_ONCE */ 73262306a36Sopenharmony_ci smp_store_release(&buf->rb_sc_tail, next_tail); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci xprt_write_space(&r_xprt->rx_xprt); 73562306a36Sopenharmony_ci} 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_cistatic void 73862306a36Sopenharmony_cirpcrdma_mrs_create(struct rpcrdma_xprt *r_xprt) 73962306a36Sopenharmony_ci{ 74062306a36Sopenharmony_ci struct rpcrdma_buffer *buf = &r_xprt->rx_buf; 74162306a36Sopenharmony_ci struct rpcrdma_ep *ep = r_xprt->rx_ep; 74262306a36Sopenharmony_ci struct ib_device *device = ep->re_id->device; 74362306a36Sopenharmony_ci unsigned int count; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci /* Try to allocate enough to perform one full-sized I/O */ 74662306a36Sopenharmony_ci for (count = 0; count < ep->re_max_rdma_segs; count++) { 74762306a36Sopenharmony_ci struct rpcrdma_mr *mr; 74862306a36Sopenharmony_ci int rc; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci mr = kzalloc_node(sizeof(*mr), XPRTRDMA_GFP_FLAGS, 75162306a36Sopenharmony_ci ibdev_to_node(device)); 75262306a36Sopenharmony_ci if (!mr) 75362306a36Sopenharmony_ci break; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci rc = frwr_mr_init(r_xprt, mr); 75662306a36Sopenharmony_ci if (rc) { 75762306a36Sopenharmony_ci kfree(mr); 75862306a36Sopenharmony_ci break; 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci spin_lock(&buf->rb_lock); 76262306a36Sopenharmony_ci rpcrdma_mr_push(mr, &buf->rb_mrs); 76362306a36Sopenharmony_ci list_add(&mr->mr_all, &buf->rb_all_mrs); 76462306a36Sopenharmony_ci spin_unlock(&buf->rb_lock); 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci r_xprt->rx_stats.mrs_allocated += count; 76862306a36Sopenharmony_ci trace_xprtrdma_createmrs(r_xprt, count); 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_cistatic void 77262306a36Sopenharmony_cirpcrdma_mr_refresh_worker(struct work_struct *work) 77362306a36Sopenharmony_ci{ 77462306a36Sopenharmony_ci struct rpcrdma_buffer *buf = container_of(work, struct rpcrdma_buffer, 77562306a36Sopenharmony_ci rb_refresh_worker); 77662306a36Sopenharmony_ci struct rpcrdma_xprt *r_xprt = container_of(buf, struct rpcrdma_xprt, 77762306a36Sopenharmony_ci rx_buf); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci rpcrdma_mrs_create(r_xprt); 78062306a36Sopenharmony_ci xprt_write_space(&r_xprt->rx_xprt); 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci/** 78462306a36Sopenharmony_ci * rpcrdma_mrs_refresh - Wake the MR refresh worker 78562306a36Sopenharmony_ci * @r_xprt: controlling transport instance 78662306a36Sopenharmony_ci * 78762306a36Sopenharmony_ci */ 78862306a36Sopenharmony_civoid rpcrdma_mrs_refresh(struct rpcrdma_xprt *r_xprt) 78962306a36Sopenharmony_ci{ 79062306a36Sopenharmony_ci struct rpcrdma_buffer *buf = &r_xprt->rx_buf; 79162306a36Sopenharmony_ci struct rpcrdma_ep *ep = r_xprt->rx_ep; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci /* If there is no underlying connection, it's no use 79462306a36Sopenharmony_ci * to wake the refresh worker. 79562306a36Sopenharmony_ci */ 79662306a36Sopenharmony_ci if (ep->re_connect_status != 1) 79762306a36Sopenharmony_ci return; 79862306a36Sopenharmony_ci queue_work(system_highpri_wq, &buf->rb_refresh_worker); 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci/** 80262306a36Sopenharmony_ci * rpcrdma_req_create - Allocate an rpcrdma_req object 80362306a36Sopenharmony_ci * @r_xprt: controlling r_xprt 80462306a36Sopenharmony_ci * @size: initial size, in bytes, of send and receive buffers 80562306a36Sopenharmony_ci * 80662306a36Sopenharmony_ci * Returns an allocated and fully initialized rpcrdma_req or NULL. 80762306a36Sopenharmony_ci */ 80862306a36Sopenharmony_cistruct rpcrdma_req *rpcrdma_req_create(struct rpcrdma_xprt *r_xprt, 80962306a36Sopenharmony_ci size_t size) 81062306a36Sopenharmony_ci{ 81162306a36Sopenharmony_ci struct rpcrdma_buffer *buffer = &r_xprt->rx_buf; 81262306a36Sopenharmony_ci struct rpcrdma_req *req; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci req = kzalloc(sizeof(*req), XPRTRDMA_GFP_FLAGS); 81562306a36Sopenharmony_ci if (req == NULL) 81662306a36Sopenharmony_ci goto out1; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci req->rl_sendbuf = rpcrdma_regbuf_alloc(size, DMA_TO_DEVICE); 81962306a36Sopenharmony_ci if (!req->rl_sendbuf) 82062306a36Sopenharmony_ci goto out2; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci req->rl_recvbuf = rpcrdma_regbuf_alloc(size, DMA_NONE); 82362306a36Sopenharmony_ci if (!req->rl_recvbuf) 82462306a36Sopenharmony_ci goto out3; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci INIT_LIST_HEAD(&req->rl_free_mrs); 82762306a36Sopenharmony_ci INIT_LIST_HEAD(&req->rl_registered); 82862306a36Sopenharmony_ci spin_lock(&buffer->rb_lock); 82962306a36Sopenharmony_ci list_add(&req->rl_all, &buffer->rb_allreqs); 83062306a36Sopenharmony_ci spin_unlock(&buffer->rb_lock); 83162306a36Sopenharmony_ci return req; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ciout3: 83462306a36Sopenharmony_ci rpcrdma_regbuf_free(req->rl_sendbuf); 83562306a36Sopenharmony_ciout2: 83662306a36Sopenharmony_ci kfree(req); 83762306a36Sopenharmony_ciout1: 83862306a36Sopenharmony_ci return NULL; 83962306a36Sopenharmony_ci} 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci/** 84262306a36Sopenharmony_ci * rpcrdma_req_setup - Per-connection instance setup of an rpcrdma_req object 84362306a36Sopenharmony_ci * @r_xprt: controlling transport instance 84462306a36Sopenharmony_ci * @req: rpcrdma_req object to set up 84562306a36Sopenharmony_ci * 84662306a36Sopenharmony_ci * Returns zero on success, and a negative errno on failure. 84762306a36Sopenharmony_ci */ 84862306a36Sopenharmony_ciint rpcrdma_req_setup(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req) 84962306a36Sopenharmony_ci{ 85062306a36Sopenharmony_ci struct rpcrdma_regbuf *rb; 85162306a36Sopenharmony_ci size_t maxhdrsize; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci /* Compute maximum header buffer size in bytes */ 85462306a36Sopenharmony_ci maxhdrsize = rpcrdma_fixed_maxsz + 3 + 85562306a36Sopenharmony_ci r_xprt->rx_ep->re_max_rdma_segs * rpcrdma_readchunk_maxsz; 85662306a36Sopenharmony_ci maxhdrsize *= sizeof(__be32); 85762306a36Sopenharmony_ci rb = rpcrdma_regbuf_alloc(__roundup_pow_of_two(maxhdrsize), 85862306a36Sopenharmony_ci DMA_TO_DEVICE); 85962306a36Sopenharmony_ci if (!rb) 86062306a36Sopenharmony_ci goto out; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci if (!__rpcrdma_regbuf_dma_map(r_xprt, rb)) 86362306a36Sopenharmony_ci goto out_free; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci req->rl_rdmabuf = rb; 86662306a36Sopenharmony_ci xdr_buf_init(&req->rl_hdrbuf, rdmab_data(rb), rdmab_length(rb)); 86762306a36Sopenharmony_ci return 0; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ciout_free: 87062306a36Sopenharmony_ci rpcrdma_regbuf_free(rb); 87162306a36Sopenharmony_ciout: 87262306a36Sopenharmony_ci return -ENOMEM; 87362306a36Sopenharmony_ci} 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci/* ASSUMPTION: the rb_allreqs list is stable for the duration, 87662306a36Sopenharmony_ci * and thus can be walked without holding rb_lock. Eg. the 87762306a36Sopenharmony_ci * caller is holding the transport send lock to exclude 87862306a36Sopenharmony_ci * device removal or disconnection. 87962306a36Sopenharmony_ci */ 88062306a36Sopenharmony_cistatic int rpcrdma_reqs_setup(struct rpcrdma_xprt *r_xprt) 88162306a36Sopenharmony_ci{ 88262306a36Sopenharmony_ci struct rpcrdma_buffer *buf = &r_xprt->rx_buf; 88362306a36Sopenharmony_ci struct rpcrdma_req *req; 88462306a36Sopenharmony_ci int rc; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci list_for_each_entry(req, &buf->rb_allreqs, rl_all) { 88762306a36Sopenharmony_ci rc = rpcrdma_req_setup(r_xprt, req); 88862306a36Sopenharmony_ci if (rc) 88962306a36Sopenharmony_ci return rc; 89062306a36Sopenharmony_ci } 89162306a36Sopenharmony_ci return 0; 89262306a36Sopenharmony_ci} 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_cistatic void rpcrdma_req_reset(struct rpcrdma_req *req) 89562306a36Sopenharmony_ci{ 89662306a36Sopenharmony_ci /* Credits are valid for only one connection */ 89762306a36Sopenharmony_ci req->rl_slot.rq_cong = 0; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci rpcrdma_regbuf_free(req->rl_rdmabuf); 90062306a36Sopenharmony_ci req->rl_rdmabuf = NULL; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci rpcrdma_regbuf_dma_unmap(req->rl_sendbuf); 90362306a36Sopenharmony_ci rpcrdma_regbuf_dma_unmap(req->rl_recvbuf); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci frwr_reset(req); 90662306a36Sopenharmony_ci} 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci/* ASSUMPTION: the rb_allreqs list is stable for the duration, 90962306a36Sopenharmony_ci * and thus can be walked without holding rb_lock. Eg. the 91062306a36Sopenharmony_ci * caller is holding the transport send lock to exclude 91162306a36Sopenharmony_ci * device removal or disconnection. 91262306a36Sopenharmony_ci */ 91362306a36Sopenharmony_cistatic void rpcrdma_reqs_reset(struct rpcrdma_xprt *r_xprt) 91462306a36Sopenharmony_ci{ 91562306a36Sopenharmony_ci struct rpcrdma_buffer *buf = &r_xprt->rx_buf; 91662306a36Sopenharmony_ci struct rpcrdma_req *req; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci list_for_each_entry(req, &buf->rb_allreqs, rl_all) 91962306a36Sopenharmony_ci rpcrdma_req_reset(req); 92062306a36Sopenharmony_ci} 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_cistatic noinline 92362306a36Sopenharmony_cistruct rpcrdma_rep *rpcrdma_rep_create(struct rpcrdma_xprt *r_xprt, 92462306a36Sopenharmony_ci bool temp) 92562306a36Sopenharmony_ci{ 92662306a36Sopenharmony_ci struct rpcrdma_buffer *buf = &r_xprt->rx_buf; 92762306a36Sopenharmony_ci struct rpcrdma_rep *rep; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci rep = kzalloc(sizeof(*rep), XPRTRDMA_GFP_FLAGS); 93062306a36Sopenharmony_ci if (rep == NULL) 93162306a36Sopenharmony_ci goto out; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci rep->rr_rdmabuf = rpcrdma_regbuf_alloc(r_xprt->rx_ep->re_inline_recv, 93462306a36Sopenharmony_ci DMA_FROM_DEVICE); 93562306a36Sopenharmony_ci if (!rep->rr_rdmabuf) 93662306a36Sopenharmony_ci goto out_free; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci rep->rr_cid.ci_completion_id = 93962306a36Sopenharmony_ci atomic_inc_return(&r_xprt->rx_ep->re_completion_ids); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci xdr_buf_init(&rep->rr_hdrbuf, rdmab_data(rep->rr_rdmabuf), 94262306a36Sopenharmony_ci rdmab_length(rep->rr_rdmabuf)); 94362306a36Sopenharmony_ci rep->rr_cqe.done = rpcrdma_wc_receive; 94462306a36Sopenharmony_ci rep->rr_rxprt = r_xprt; 94562306a36Sopenharmony_ci rep->rr_recv_wr.next = NULL; 94662306a36Sopenharmony_ci rep->rr_recv_wr.wr_cqe = &rep->rr_cqe; 94762306a36Sopenharmony_ci rep->rr_recv_wr.sg_list = &rep->rr_rdmabuf->rg_iov; 94862306a36Sopenharmony_ci rep->rr_recv_wr.num_sge = 1; 94962306a36Sopenharmony_ci rep->rr_temp = temp; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci spin_lock(&buf->rb_lock); 95262306a36Sopenharmony_ci list_add(&rep->rr_all, &buf->rb_all_reps); 95362306a36Sopenharmony_ci spin_unlock(&buf->rb_lock); 95462306a36Sopenharmony_ci return rep; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ciout_free: 95762306a36Sopenharmony_ci kfree(rep); 95862306a36Sopenharmony_ciout: 95962306a36Sopenharmony_ci return NULL; 96062306a36Sopenharmony_ci} 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_cistatic void rpcrdma_rep_free(struct rpcrdma_rep *rep) 96362306a36Sopenharmony_ci{ 96462306a36Sopenharmony_ci rpcrdma_regbuf_free(rep->rr_rdmabuf); 96562306a36Sopenharmony_ci kfree(rep); 96662306a36Sopenharmony_ci} 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_cistatic void rpcrdma_rep_destroy(struct rpcrdma_rep *rep) 96962306a36Sopenharmony_ci{ 97062306a36Sopenharmony_ci struct rpcrdma_buffer *buf = &rep->rr_rxprt->rx_buf; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci spin_lock(&buf->rb_lock); 97362306a36Sopenharmony_ci list_del(&rep->rr_all); 97462306a36Sopenharmony_ci spin_unlock(&buf->rb_lock); 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci rpcrdma_rep_free(rep); 97762306a36Sopenharmony_ci} 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_cistatic struct rpcrdma_rep *rpcrdma_rep_get_locked(struct rpcrdma_buffer *buf) 98062306a36Sopenharmony_ci{ 98162306a36Sopenharmony_ci struct llist_node *node; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci /* Calls to llist_del_first are required to be serialized */ 98462306a36Sopenharmony_ci node = llist_del_first(&buf->rb_free_reps); 98562306a36Sopenharmony_ci if (!node) 98662306a36Sopenharmony_ci return NULL; 98762306a36Sopenharmony_ci return llist_entry(node, struct rpcrdma_rep, rr_node); 98862306a36Sopenharmony_ci} 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci/** 99162306a36Sopenharmony_ci * rpcrdma_rep_put - Release rpcrdma_rep back to free list 99262306a36Sopenharmony_ci * @buf: buffer pool 99362306a36Sopenharmony_ci * @rep: rep to release 99462306a36Sopenharmony_ci * 99562306a36Sopenharmony_ci */ 99662306a36Sopenharmony_civoid rpcrdma_rep_put(struct rpcrdma_buffer *buf, struct rpcrdma_rep *rep) 99762306a36Sopenharmony_ci{ 99862306a36Sopenharmony_ci llist_add(&rep->rr_node, &buf->rb_free_reps); 99962306a36Sopenharmony_ci} 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci/* Caller must ensure the QP is quiescent (RQ is drained) before 100262306a36Sopenharmony_ci * invoking this function, to guarantee rb_all_reps is not 100362306a36Sopenharmony_ci * changing. 100462306a36Sopenharmony_ci */ 100562306a36Sopenharmony_cistatic void rpcrdma_reps_unmap(struct rpcrdma_xprt *r_xprt) 100662306a36Sopenharmony_ci{ 100762306a36Sopenharmony_ci struct rpcrdma_buffer *buf = &r_xprt->rx_buf; 100862306a36Sopenharmony_ci struct rpcrdma_rep *rep; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci list_for_each_entry(rep, &buf->rb_all_reps, rr_all) { 101162306a36Sopenharmony_ci rpcrdma_regbuf_dma_unmap(rep->rr_rdmabuf); 101262306a36Sopenharmony_ci rep->rr_temp = true; /* Mark this rep for destruction */ 101362306a36Sopenharmony_ci } 101462306a36Sopenharmony_ci} 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_cistatic void rpcrdma_reps_destroy(struct rpcrdma_buffer *buf) 101762306a36Sopenharmony_ci{ 101862306a36Sopenharmony_ci struct rpcrdma_rep *rep; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci spin_lock(&buf->rb_lock); 102162306a36Sopenharmony_ci while ((rep = list_first_entry_or_null(&buf->rb_all_reps, 102262306a36Sopenharmony_ci struct rpcrdma_rep, 102362306a36Sopenharmony_ci rr_all)) != NULL) { 102462306a36Sopenharmony_ci list_del(&rep->rr_all); 102562306a36Sopenharmony_ci spin_unlock(&buf->rb_lock); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci rpcrdma_rep_free(rep); 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci spin_lock(&buf->rb_lock); 103062306a36Sopenharmony_ci } 103162306a36Sopenharmony_ci spin_unlock(&buf->rb_lock); 103262306a36Sopenharmony_ci} 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci/** 103562306a36Sopenharmony_ci * rpcrdma_buffer_create - Create initial set of req/rep objects 103662306a36Sopenharmony_ci * @r_xprt: transport instance to (re)initialize 103762306a36Sopenharmony_ci * 103862306a36Sopenharmony_ci * Returns zero on success, otherwise a negative errno. 103962306a36Sopenharmony_ci */ 104062306a36Sopenharmony_ciint rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt) 104162306a36Sopenharmony_ci{ 104262306a36Sopenharmony_ci struct rpcrdma_buffer *buf = &r_xprt->rx_buf; 104362306a36Sopenharmony_ci int i, rc; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci buf->rb_bc_srv_max_requests = 0; 104662306a36Sopenharmony_ci spin_lock_init(&buf->rb_lock); 104762306a36Sopenharmony_ci INIT_LIST_HEAD(&buf->rb_mrs); 104862306a36Sopenharmony_ci INIT_LIST_HEAD(&buf->rb_all_mrs); 104962306a36Sopenharmony_ci INIT_WORK(&buf->rb_refresh_worker, rpcrdma_mr_refresh_worker); 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci INIT_LIST_HEAD(&buf->rb_send_bufs); 105262306a36Sopenharmony_ci INIT_LIST_HEAD(&buf->rb_allreqs); 105362306a36Sopenharmony_ci INIT_LIST_HEAD(&buf->rb_all_reps); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci rc = -ENOMEM; 105662306a36Sopenharmony_ci for (i = 0; i < r_xprt->rx_xprt.max_reqs; i++) { 105762306a36Sopenharmony_ci struct rpcrdma_req *req; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci req = rpcrdma_req_create(r_xprt, 106062306a36Sopenharmony_ci RPCRDMA_V1_DEF_INLINE_SIZE * 2); 106162306a36Sopenharmony_ci if (!req) 106262306a36Sopenharmony_ci goto out; 106362306a36Sopenharmony_ci list_add(&req->rl_list, &buf->rb_send_bufs); 106462306a36Sopenharmony_ci } 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci init_llist_head(&buf->rb_free_reps); 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci return 0; 106962306a36Sopenharmony_ciout: 107062306a36Sopenharmony_ci rpcrdma_buffer_destroy(buf); 107162306a36Sopenharmony_ci return rc; 107262306a36Sopenharmony_ci} 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci/** 107562306a36Sopenharmony_ci * rpcrdma_req_destroy - Destroy an rpcrdma_req object 107662306a36Sopenharmony_ci * @req: unused object to be destroyed 107762306a36Sopenharmony_ci * 107862306a36Sopenharmony_ci * Relies on caller holding the transport send lock to protect 107962306a36Sopenharmony_ci * removing req->rl_all from buf->rb_all_reqs safely. 108062306a36Sopenharmony_ci */ 108162306a36Sopenharmony_civoid rpcrdma_req_destroy(struct rpcrdma_req *req) 108262306a36Sopenharmony_ci{ 108362306a36Sopenharmony_ci struct rpcrdma_mr *mr; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci list_del(&req->rl_all); 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci while ((mr = rpcrdma_mr_pop(&req->rl_free_mrs))) { 108862306a36Sopenharmony_ci struct rpcrdma_buffer *buf = &mr->mr_xprt->rx_buf; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci spin_lock(&buf->rb_lock); 109162306a36Sopenharmony_ci list_del(&mr->mr_all); 109262306a36Sopenharmony_ci spin_unlock(&buf->rb_lock); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci frwr_mr_release(mr); 109562306a36Sopenharmony_ci } 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci rpcrdma_regbuf_free(req->rl_recvbuf); 109862306a36Sopenharmony_ci rpcrdma_regbuf_free(req->rl_sendbuf); 109962306a36Sopenharmony_ci rpcrdma_regbuf_free(req->rl_rdmabuf); 110062306a36Sopenharmony_ci kfree(req); 110162306a36Sopenharmony_ci} 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci/** 110462306a36Sopenharmony_ci * rpcrdma_mrs_destroy - Release all of a transport's MRs 110562306a36Sopenharmony_ci * @r_xprt: controlling transport instance 110662306a36Sopenharmony_ci * 110762306a36Sopenharmony_ci * Relies on caller holding the transport send lock to protect 110862306a36Sopenharmony_ci * removing mr->mr_list from req->rl_free_mrs safely. 110962306a36Sopenharmony_ci */ 111062306a36Sopenharmony_cistatic void rpcrdma_mrs_destroy(struct rpcrdma_xprt *r_xprt) 111162306a36Sopenharmony_ci{ 111262306a36Sopenharmony_ci struct rpcrdma_buffer *buf = &r_xprt->rx_buf; 111362306a36Sopenharmony_ci struct rpcrdma_mr *mr; 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci cancel_work_sync(&buf->rb_refresh_worker); 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci spin_lock(&buf->rb_lock); 111862306a36Sopenharmony_ci while ((mr = list_first_entry_or_null(&buf->rb_all_mrs, 111962306a36Sopenharmony_ci struct rpcrdma_mr, 112062306a36Sopenharmony_ci mr_all)) != NULL) { 112162306a36Sopenharmony_ci list_del(&mr->mr_list); 112262306a36Sopenharmony_ci list_del(&mr->mr_all); 112362306a36Sopenharmony_ci spin_unlock(&buf->rb_lock); 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci frwr_mr_release(mr); 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci spin_lock(&buf->rb_lock); 112862306a36Sopenharmony_ci } 112962306a36Sopenharmony_ci spin_unlock(&buf->rb_lock); 113062306a36Sopenharmony_ci} 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci/** 113362306a36Sopenharmony_ci * rpcrdma_buffer_destroy - Release all hw resources 113462306a36Sopenharmony_ci * @buf: root control block for resources 113562306a36Sopenharmony_ci * 113662306a36Sopenharmony_ci * ORDERING: relies on a prior rpcrdma_xprt_drain : 113762306a36Sopenharmony_ci * - No more Send or Receive completions can occur 113862306a36Sopenharmony_ci * - All MRs, reps, and reqs are returned to their free lists 113962306a36Sopenharmony_ci */ 114062306a36Sopenharmony_civoid 114162306a36Sopenharmony_cirpcrdma_buffer_destroy(struct rpcrdma_buffer *buf) 114262306a36Sopenharmony_ci{ 114362306a36Sopenharmony_ci rpcrdma_reps_destroy(buf); 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci while (!list_empty(&buf->rb_send_bufs)) { 114662306a36Sopenharmony_ci struct rpcrdma_req *req; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci req = list_first_entry(&buf->rb_send_bufs, 114962306a36Sopenharmony_ci struct rpcrdma_req, rl_list); 115062306a36Sopenharmony_ci list_del(&req->rl_list); 115162306a36Sopenharmony_ci rpcrdma_req_destroy(req); 115262306a36Sopenharmony_ci } 115362306a36Sopenharmony_ci} 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci/** 115662306a36Sopenharmony_ci * rpcrdma_mr_get - Allocate an rpcrdma_mr object 115762306a36Sopenharmony_ci * @r_xprt: controlling transport 115862306a36Sopenharmony_ci * 115962306a36Sopenharmony_ci * Returns an initialized rpcrdma_mr or NULL if no free 116062306a36Sopenharmony_ci * rpcrdma_mr objects are available. 116162306a36Sopenharmony_ci */ 116262306a36Sopenharmony_cistruct rpcrdma_mr * 116362306a36Sopenharmony_cirpcrdma_mr_get(struct rpcrdma_xprt *r_xprt) 116462306a36Sopenharmony_ci{ 116562306a36Sopenharmony_ci struct rpcrdma_buffer *buf = &r_xprt->rx_buf; 116662306a36Sopenharmony_ci struct rpcrdma_mr *mr; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci spin_lock(&buf->rb_lock); 116962306a36Sopenharmony_ci mr = rpcrdma_mr_pop(&buf->rb_mrs); 117062306a36Sopenharmony_ci spin_unlock(&buf->rb_lock); 117162306a36Sopenharmony_ci return mr; 117262306a36Sopenharmony_ci} 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci/** 117562306a36Sopenharmony_ci * rpcrdma_reply_put - Put reply buffers back into pool 117662306a36Sopenharmony_ci * @buffers: buffer pool 117762306a36Sopenharmony_ci * @req: object to return 117862306a36Sopenharmony_ci * 117962306a36Sopenharmony_ci */ 118062306a36Sopenharmony_civoid rpcrdma_reply_put(struct rpcrdma_buffer *buffers, struct rpcrdma_req *req) 118162306a36Sopenharmony_ci{ 118262306a36Sopenharmony_ci if (req->rl_reply) { 118362306a36Sopenharmony_ci rpcrdma_rep_put(buffers, req->rl_reply); 118462306a36Sopenharmony_ci req->rl_reply = NULL; 118562306a36Sopenharmony_ci } 118662306a36Sopenharmony_ci} 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci/** 118962306a36Sopenharmony_ci * rpcrdma_buffer_get - Get a request buffer 119062306a36Sopenharmony_ci * @buffers: Buffer pool from which to obtain a buffer 119162306a36Sopenharmony_ci * 119262306a36Sopenharmony_ci * Returns a fresh rpcrdma_req, or NULL if none are available. 119362306a36Sopenharmony_ci */ 119462306a36Sopenharmony_cistruct rpcrdma_req * 119562306a36Sopenharmony_cirpcrdma_buffer_get(struct rpcrdma_buffer *buffers) 119662306a36Sopenharmony_ci{ 119762306a36Sopenharmony_ci struct rpcrdma_req *req; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci spin_lock(&buffers->rb_lock); 120062306a36Sopenharmony_ci req = list_first_entry_or_null(&buffers->rb_send_bufs, 120162306a36Sopenharmony_ci struct rpcrdma_req, rl_list); 120262306a36Sopenharmony_ci if (req) 120362306a36Sopenharmony_ci list_del_init(&req->rl_list); 120462306a36Sopenharmony_ci spin_unlock(&buffers->rb_lock); 120562306a36Sopenharmony_ci return req; 120662306a36Sopenharmony_ci} 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci/** 120962306a36Sopenharmony_ci * rpcrdma_buffer_put - Put request/reply buffers back into pool 121062306a36Sopenharmony_ci * @buffers: buffer pool 121162306a36Sopenharmony_ci * @req: object to return 121262306a36Sopenharmony_ci * 121362306a36Sopenharmony_ci */ 121462306a36Sopenharmony_civoid rpcrdma_buffer_put(struct rpcrdma_buffer *buffers, struct rpcrdma_req *req) 121562306a36Sopenharmony_ci{ 121662306a36Sopenharmony_ci rpcrdma_reply_put(buffers, req); 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci spin_lock(&buffers->rb_lock); 121962306a36Sopenharmony_ci list_add(&req->rl_list, &buffers->rb_send_bufs); 122062306a36Sopenharmony_ci spin_unlock(&buffers->rb_lock); 122162306a36Sopenharmony_ci} 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci/* Returns a pointer to a rpcrdma_regbuf object, or NULL. 122462306a36Sopenharmony_ci * 122562306a36Sopenharmony_ci * xprtrdma uses a regbuf for posting an outgoing RDMA SEND, or for 122662306a36Sopenharmony_ci * receiving the payload of RDMA RECV operations. During Long Calls 122762306a36Sopenharmony_ci * or Replies they may be registered externally via frwr_map. 122862306a36Sopenharmony_ci */ 122962306a36Sopenharmony_cistatic struct rpcrdma_regbuf * 123062306a36Sopenharmony_cirpcrdma_regbuf_alloc(size_t size, enum dma_data_direction direction) 123162306a36Sopenharmony_ci{ 123262306a36Sopenharmony_ci struct rpcrdma_regbuf *rb; 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci rb = kmalloc(sizeof(*rb), XPRTRDMA_GFP_FLAGS); 123562306a36Sopenharmony_ci if (!rb) 123662306a36Sopenharmony_ci return NULL; 123762306a36Sopenharmony_ci rb->rg_data = kmalloc(size, XPRTRDMA_GFP_FLAGS); 123862306a36Sopenharmony_ci if (!rb->rg_data) { 123962306a36Sopenharmony_ci kfree(rb); 124062306a36Sopenharmony_ci return NULL; 124162306a36Sopenharmony_ci } 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci rb->rg_device = NULL; 124462306a36Sopenharmony_ci rb->rg_direction = direction; 124562306a36Sopenharmony_ci rb->rg_iov.length = size; 124662306a36Sopenharmony_ci return rb; 124762306a36Sopenharmony_ci} 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci/** 125062306a36Sopenharmony_ci * rpcrdma_regbuf_realloc - re-allocate a SEND/RECV buffer 125162306a36Sopenharmony_ci * @rb: regbuf to reallocate 125262306a36Sopenharmony_ci * @size: size of buffer to be allocated, in bytes 125362306a36Sopenharmony_ci * @flags: GFP flags 125462306a36Sopenharmony_ci * 125562306a36Sopenharmony_ci * Returns true if reallocation was successful. If false is 125662306a36Sopenharmony_ci * returned, @rb is left untouched. 125762306a36Sopenharmony_ci */ 125862306a36Sopenharmony_cibool rpcrdma_regbuf_realloc(struct rpcrdma_regbuf *rb, size_t size, gfp_t flags) 125962306a36Sopenharmony_ci{ 126062306a36Sopenharmony_ci void *buf; 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci buf = kmalloc(size, flags); 126362306a36Sopenharmony_ci if (!buf) 126462306a36Sopenharmony_ci return false; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci rpcrdma_regbuf_dma_unmap(rb); 126762306a36Sopenharmony_ci kfree(rb->rg_data); 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci rb->rg_data = buf; 127062306a36Sopenharmony_ci rb->rg_iov.length = size; 127162306a36Sopenharmony_ci return true; 127262306a36Sopenharmony_ci} 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci/** 127562306a36Sopenharmony_ci * __rpcrdma_regbuf_dma_map - DMA-map a regbuf 127662306a36Sopenharmony_ci * @r_xprt: controlling transport instance 127762306a36Sopenharmony_ci * @rb: regbuf to be mapped 127862306a36Sopenharmony_ci * 127962306a36Sopenharmony_ci * Returns true if the buffer is now DMA mapped to @r_xprt's device 128062306a36Sopenharmony_ci */ 128162306a36Sopenharmony_cibool __rpcrdma_regbuf_dma_map(struct rpcrdma_xprt *r_xprt, 128262306a36Sopenharmony_ci struct rpcrdma_regbuf *rb) 128362306a36Sopenharmony_ci{ 128462306a36Sopenharmony_ci struct ib_device *device = r_xprt->rx_ep->re_id->device; 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci if (rb->rg_direction == DMA_NONE) 128762306a36Sopenharmony_ci return false; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci rb->rg_iov.addr = ib_dma_map_single(device, rdmab_data(rb), 129062306a36Sopenharmony_ci rdmab_length(rb), rb->rg_direction); 129162306a36Sopenharmony_ci if (ib_dma_mapping_error(device, rdmab_addr(rb))) { 129262306a36Sopenharmony_ci trace_xprtrdma_dma_maperr(rdmab_addr(rb)); 129362306a36Sopenharmony_ci return false; 129462306a36Sopenharmony_ci } 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci rb->rg_device = device; 129762306a36Sopenharmony_ci rb->rg_iov.lkey = r_xprt->rx_ep->re_pd->local_dma_lkey; 129862306a36Sopenharmony_ci return true; 129962306a36Sopenharmony_ci} 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_cistatic void rpcrdma_regbuf_dma_unmap(struct rpcrdma_regbuf *rb) 130262306a36Sopenharmony_ci{ 130362306a36Sopenharmony_ci if (!rb) 130462306a36Sopenharmony_ci return; 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci if (!rpcrdma_regbuf_is_mapped(rb)) 130762306a36Sopenharmony_ci return; 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci ib_dma_unmap_single(rb->rg_device, rdmab_addr(rb), rdmab_length(rb), 131062306a36Sopenharmony_ci rb->rg_direction); 131162306a36Sopenharmony_ci rb->rg_device = NULL; 131262306a36Sopenharmony_ci} 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_cistatic void rpcrdma_regbuf_free(struct rpcrdma_regbuf *rb) 131562306a36Sopenharmony_ci{ 131662306a36Sopenharmony_ci rpcrdma_regbuf_dma_unmap(rb); 131762306a36Sopenharmony_ci if (rb) 131862306a36Sopenharmony_ci kfree(rb->rg_data); 131962306a36Sopenharmony_ci kfree(rb); 132062306a36Sopenharmony_ci} 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci/** 132362306a36Sopenharmony_ci * rpcrdma_post_recvs - Refill the Receive Queue 132462306a36Sopenharmony_ci * @r_xprt: controlling transport instance 132562306a36Sopenharmony_ci * @needed: current credit grant 132662306a36Sopenharmony_ci * @temp: mark Receive buffers to be deleted after one use 132762306a36Sopenharmony_ci * 132862306a36Sopenharmony_ci */ 132962306a36Sopenharmony_civoid rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, int needed, bool temp) 133062306a36Sopenharmony_ci{ 133162306a36Sopenharmony_ci struct rpcrdma_buffer *buf = &r_xprt->rx_buf; 133262306a36Sopenharmony_ci struct rpcrdma_ep *ep = r_xprt->rx_ep; 133362306a36Sopenharmony_ci struct ib_recv_wr *wr, *bad_wr; 133462306a36Sopenharmony_ci struct rpcrdma_rep *rep; 133562306a36Sopenharmony_ci int count, rc; 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci rc = 0; 133862306a36Sopenharmony_ci count = 0; 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci if (likely(ep->re_receive_count > needed)) 134162306a36Sopenharmony_ci goto out; 134262306a36Sopenharmony_ci needed -= ep->re_receive_count; 134362306a36Sopenharmony_ci if (!temp) 134462306a36Sopenharmony_ci needed += RPCRDMA_MAX_RECV_BATCH; 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci if (atomic_inc_return(&ep->re_receiving) > 1) 134762306a36Sopenharmony_ci goto out; 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci /* fast path: all needed reps can be found on the free list */ 135062306a36Sopenharmony_ci wr = NULL; 135162306a36Sopenharmony_ci while (needed) { 135262306a36Sopenharmony_ci rep = rpcrdma_rep_get_locked(buf); 135362306a36Sopenharmony_ci if (rep && rep->rr_temp) { 135462306a36Sopenharmony_ci rpcrdma_rep_destroy(rep); 135562306a36Sopenharmony_ci continue; 135662306a36Sopenharmony_ci } 135762306a36Sopenharmony_ci if (!rep) 135862306a36Sopenharmony_ci rep = rpcrdma_rep_create(r_xprt, temp); 135962306a36Sopenharmony_ci if (!rep) 136062306a36Sopenharmony_ci break; 136162306a36Sopenharmony_ci if (!rpcrdma_regbuf_dma_map(r_xprt, rep->rr_rdmabuf)) { 136262306a36Sopenharmony_ci rpcrdma_rep_put(buf, rep); 136362306a36Sopenharmony_ci break; 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci rep->rr_cid.ci_queue_id = ep->re_attr.recv_cq->res.id; 136762306a36Sopenharmony_ci trace_xprtrdma_post_recv(rep); 136862306a36Sopenharmony_ci rep->rr_recv_wr.next = wr; 136962306a36Sopenharmony_ci wr = &rep->rr_recv_wr; 137062306a36Sopenharmony_ci --needed; 137162306a36Sopenharmony_ci ++count; 137262306a36Sopenharmony_ci } 137362306a36Sopenharmony_ci if (!wr) 137462306a36Sopenharmony_ci goto out; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci rc = ib_post_recv(ep->re_id->qp, wr, 137762306a36Sopenharmony_ci (const struct ib_recv_wr **)&bad_wr); 137862306a36Sopenharmony_ci if (rc) { 137962306a36Sopenharmony_ci trace_xprtrdma_post_recvs_err(r_xprt, rc); 138062306a36Sopenharmony_ci for (wr = bad_wr; wr;) { 138162306a36Sopenharmony_ci struct rpcrdma_rep *rep; 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci rep = container_of(wr, struct rpcrdma_rep, rr_recv_wr); 138462306a36Sopenharmony_ci wr = wr->next; 138562306a36Sopenharmony_ci rpcrdma_rep_put(buf, rep); 138662306a36Sopenharmony_ci --count; 138762306a36Sopenharmony_ci } 138862306a36Sopenharmony_ci } 138962306a36Sopenharmony_ci if (atomic_dec_return(&ep->re_receiving) > 0) 139062306a36Sopenharmony_ci complete(&ep->re_done); 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ciout: 139362306a36Sopenharmony_ci trace_xprtrdma_post_recvs(r_xprt, count); 139462306a36Sopenharmony_ci ep->re_receive_count += count; 139562306a36Sopenharmony_ci return; 139662306a36Sopenharmony_ci} 1397