From patchwork Fri Jul 22 18:47:27 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bernard Metzler X-Patchwork-Id: 1000392 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.4) with ESMTP id p6MIju6R025778 for ; Fri, 22 Jul 2011 18:47:40 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754924Ab1GVSrj (ORCPT ); Fri, 22 Jul 2011 14:47:39 -0400 Received: from mtagate1.uk.ibm.com ([194.196.100.161]:34163 "EHLO mtagate1.uk.ibm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754919Ab1GVSri (ORCPT ); Fri, 22 Jul 2011 14:47:38 -0400 Received: from d06nrmr1307.portsmouth.uk.ibm.com (d06nrmr1307.portsmouth.uk.ibm.com [9.149.38.129]) by mtagate1.uk.ibm.com (8.13.1/8.13.1) with ESMTP id p6MIlTwm029153 for ; Fri, 22 Jul 2011 18:47:29 GMT Received: from d06av08.portsmouth.uk.ibm.com (d06av08.portsmouth.uk.ibm.com [9.149.37.249]) by d06nrmr1307.portsmouth.uk.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id p6MIlSwI2457634 for ; Fri, 22 Jul 2011 19:47:28 +0100 Received: from d06av08.portsmouth.uk.ibm.com (loopback [127.0.0.1]) by d06av08.portsmouth.uk.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id p6MIlSMd013705 for ; Fri, 22 Jul 2011 19:47:28 +0100 Received: from aare.zurich.ibm.com (aare.zurich.ibm.com [9.4.2.232]) by d06av08.portsmouth.uk.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id p6MIlSVm013702 for ; Fri, 22 Jul 2011 19:47:28 +0100 Received: from localhost.localdomain (achilles.zurich.ibm.com [9.4.243.2]) by aare.zurich.ibm.com (AIX6.1/8.13.4/8.13.4) with ESMTP id p6MIlS4U7536772; Fri, 22 Jul 2011 20:47:28 +0200 From: Bernard Metzler To: linux-rdma@vger.kernel.org Cc: Bernard Metzler Subject: [PATCH 03/14] SIWv3: Main header file: siw.h Date: Fri, 22 Jul 2011 20:47:27 +0200 Message-Id: <1311360447-15153-1-git-send-email-bmt@zurich.ibm.com> X-Mailer: git-send-email 1.5.4.3 Sender: linux-rdma-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-rdma@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Fri, 22 Jul 2011 18:47:40 +0000 (UTC) --- drivers/infiniband/hw/siw/siw.h | 840 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 840 insertions(+), 0 deletions(-) create mode 100644 drivers/infiniband/hw/siw/siw.h diff --git a/drivers/infiniband/hw/siw/siw.h b/drivers/infiniband/hw/siw/siw.h new file mode 100644 index 0000000..29af8cd --- /dev/null +++ b/drivers/infiniband/hw/siw/siw.h @@ -0,0 +1,840 @@ +/* + * Software iWARP device driver for Linux + * + * Authors: Bernard Metzler + * + * Copyright (c) 2008-2011, IBM Corporation + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of IBM nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _SIW_H +#define _SIW_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* MLOCK_LIMIT */ + +#include /* struct ib_umem_chunk */ + +#include "siw_user.h" +#include "iwarp.h" + +enum siw_if_type { + SIW_IF_OFED = 0, /* only via standard ofed syscall if */ + SIW_IF_MAPPED = 1 /* private qp and cq mapping */ +}; + +#define DEVICE_ID_SOFTIWARP 0x0815 +#define VERSION_ID_SOFTIWARP 0x0001 +#define SIW_VENDOR_ID 0 +#define SIW_VENDORT_PART_ID 0 +#define SIW_SW_VERSION 1 +#define SIW_MAX_QP (1024 * 100) +#define SIW_MAX_QP_WR (1024 * 32) +#define SIW_MAX_ORD 128 +#define SIW_MAX_IRD 128 +#define SIW_MAX_SGE 4 +#define SIW_MAX_SGE_RD 1 /* iwarp limitation. we could relax */ +#define SIW_MAX_CQ (1024 * 100) +#define SIW_MAX_CQE (SIW_MAX_QP_WR * 100) +#define SIW_MAX_MR (SIW_MAX_QP * 10) +#define SIW_MAX_PD SIW_MAX_QP +#define SIW_MAX_MW 0 /* to be set if MW's are supported */ +#define SIW_MAX_FMR 0 +#define SIW_MAX_SRQ SIW_MAX_QP +#define SIW_MAX_SRQ_WR (SIW_MAX_QP_WR * 10) + +#define SENDPAGE_THRESH 256 /* min bytes for using sendpage() */ +#define SOCKBUFSIZE (PAGE_SIZE * 40) +#define SQ_USER_MAXBURST 10 + +#define SIW_NODE_DESC "Software iWARP stack" + + +struct siw_devinfo { + unsigned device; + unsigned version; + + /* close match to ib_device_attr where appropriate */ + u32 vendor_id; + u32 vendor_part_id; + u32 sw_version; + int max_qp; + int max_qp_wr; + int max_ord; /* max. outbound read queue depth */ + int max_ird; /* max. inbound read queue depth */ + + enum ib_device_cap_flags cap_flags; + int max_sge; + int max_sge_rd; + int max_cq; + int max_cqe; + u64 max_mr_size; + int max_mr; + int max_pd; + int max_mw; + int max_fmr; + int max_srq; + int max_srq_wr; + int max_srq_sge; + /* end ib_device_attr */ + + enum siw_if_type iftype; +}; + + +struct siw_dev { + struct ib_device ofa_dev; + struct list_head list; + struct net_device *netdev; + struct siw_devinfo attrs; + int is_registered; /* Registered with OFA core */ + + /* physical port state (only one port per device) */ + enum ib_port_state state; + + /* object management */ + struct list_head cep_list; + struct list_head qp_list; + spinlock_t idr_lock; + struct idr qp_idr; + struct idr cq_idr; + struct idr pd_idr; + struct idr mem_idr; /* MRs & MWs */ + + /* active objects statistics */ + atomic_t num_qp; + atomic_t num_cq; + atomic_t num_pd; + atomic_t num_mem; + atomic_t num_srq; + atomic_t num_cep; + + struct dentry *debugfs; +}; + +struct siw_objhdr { + u32 id; /* for idr based object lookup */ + struct kref ref; + struct siw_dev *sdev; +}; + + +struct siw_ucontext { + struct ib_ucontext ib_ucontext; +}; + +struct siw_pd { + struct siw_objhdr hdr; + struct ib_pd ofa_pd; +}; + +enum siw_access_flags { + SR_MEM_LREAD = (1<<0), + SR_MEM_LWRITE = (1<<1), + SR_MEM_RREAD = (1<<2), + SR_MEM_RWRITE = (1<<3), + + SR_MEM_FLAGS_LOCAL = + (SR_MEM_LREAD | SR_MEM_LWRITE), + SR_MEM_FLAGS_REMOTE = + (SR_MEM_RWRITE | SR_MEM_RREAD) +}; + +#define STAG_VALID 1 +#define STAG_INVALID 0 +#define SIW_STAG_MAX 0xffffffff + +struct siw_mr; + +/* + * generic memory representation for registered siw memory. + * memory lookup always via higher 24 bit of stag (stag index). + * the stag is stored as part of the siw object header (id). + * object relates to memory window if embedded mr pointer is valid + */ +struct siw_mem { + struct siw_objhdr hdr; + + struct siw_mr *mr; /* assoc. MR if MW, NULL if MR */ + + u32 stag_state:1, /* VALID or INVALID */ + is_zbva:1, /* zero based virt. addr. */ + mw_bind_enabled:1, /* check only if MR */ + remote_inval_enabled:1, /* VALID or INVALID */ + consumer_owns_key:1, /* key/index split ? */ + rsvd:27; + + enum siw_access_flags perms; /* local/remote READ & WRITE */ + + u64 va; /* VA of memory */ + u64 len; /* amount of memory bytes */ + u32 fbo; /* first byte offset */ +}; + +#define SIW_MEM_IS_MW(m) ((m)->mr != NULL) +#define SIW_INLINED_DATA(w) ((w)->wr.hdr.flags & IB_SEND_INLINE) + +/* + * MR and MW definition. + * Used OFA structs ib_mr/ib_mw holding: + * lkey, rkey, MW reference count on MR + */ +struct siw_mr { + struct ib_mr ofa_mr; + struct siw_mem mem; + struct ib_umem *umem; + struct siw_pd *pd; +}; + +struct siw_mw { + struct ib_mw ofa_mw; + struct siw_mem mem; +}; + +/********** WR definitions ****************/ + +enum siw_wr_opcode { + SIW_WR_RDMA_WRITE = IB_WR_RDMA_WRITE, + SIW_WR_RDMA_WRITE_WITH_IMM = IB_WR_RDMA_WRITE_WITH_IMM, + SIW_WR_SEND = IB_WR_SEND, + SIW_WR_SEND_WITH_IMM = IB_WR_SEND_WITH_IMM, + SIW_WR_RDMA_READ_REQ = IB_WR_RDMA_READ, + + /* Unsupported */ + SIW_WR_ATOMIC_CMP_AND_SWP = IB_WR_ATOMIC_CMP_AND_SWP, + SIW_WR_ATOMIC_FETCH_AND_ADD = IB_WR_ATOMIC_FETCH_AND_ADD, + SIW_WR_INVAL_STAG = IB_WR_LOCAL_INV, + SIW_WR_FASTREG = IB_WR_FAST_REG_MR, + + SIW_WR_RECEIVE, + SIW_WR_RDMA_READ_RESP, /* pseudo WQE */ + SIW_WR_NUM +}; + +#define opcode_ofa2siw(code) (enum siw_wr_opcode)code + +#define SIW_WQE_IS_TX(wqe) 1 /* add BIND/FASTREG/INVAL_STAG */ + +struct siw_sge { + u64 addr; /* HBO */ + unsigned int len; /* HBO */ + u32 lkey; /* HBO */ + union { + struct siw_mem *obj; /* reference to registered memory */ + char *buf; /* linear kernel buffer */ + } mem; +}; + +struct siw_wr_common { + enum siw_wr_opcode type; + enum ib_send_flags flags; + u64 id; +}; + +/* + * All WRs below having an SGL (with 1 ore more SGEs) must start with + * the layout given by struct siw_wr_with_sgl! + */ +struct siw_wr_with_sgl { + struct siw_wr_common hdr; + int num_sge; + struct siw_sge sge[0]; /* Start of source or dest. SGL */ +}; + +struct siw_wr_send { + struct siw_wr_common hdr; + int num_sge; + struct siw_sge sge[SIW_MAX_SGE]; +}; + +struct siw_wr_rmda_write { + struct siw_wr_common hdr; + int num_sge; + struct siw_sge sge[SIW_MAX_SGE]; + u64 raddr; + u32 rtag; +}; + +struct siw_wr_rdma_rread { + struct siw_wr_common hdr; + int num_sge; + struct siw_sge sge[SIW_MAX_SGE]; + u64 raddr; + u32 rtag; +}; + +/* + * Inline data are kept within the work request itself occupying + * the space of sge[1] .. sge[n]. Therefore, inline data cannot be + * supported if SIW_MAX_SGE is below 2 elements. + */ +#if SIW_MAX_SGE < 2 +#error "SIW_MAX_SGE must be at least 2" +#endif + +#define SIW_MAX_INLINE (sizeof(struct siw_sge) * (SIW_MAX_SGE - 1)) + +struct siw_wr_inline_data { + struct siw_wr_common hdr; + int num_sge; /* always 1 */ + struct siw_sge sge; /* single SGE, points to data */ + char data[SIW_MAX_INLINE]; +}; + + +struct siw_wr_rdma_rresp { + struct siw_wr_common hdr; + int num_sge; /* must be 1 */ + struct siw_sge sge; + u64 raddr; + u32 rtag; +}; + +struct siw_wr_bind { + struct siw_wr_common hdr; + u32 rtag; + u32 ltag; + struct siw_mr *mr; + u64 addr; + u32 len; + enum siw_access_flags perms; +}; + +struct siw_wr_recv { + struct siw_wr_common hdr; + int num_sge; + struct siw_sge sge[SIW_MAX_SGE]; +}; + +enum siw_wr_state { + SR_WR_QUEUED = 0, /* processing has not started yet */ + SR_WR_INPROGRESS = 1, /* initiated processing of the WR */ + SR_WR_DONE = 2, +}; + +/* better name it siw_qe? */ +struct siw_wqe { + struct list_head list; + union { + struct siw_wr_common hdr; + struct siw_wr_with_sgl sgl; + struct siw_wr_inline_data inlined_data; + struct siw_wr_send send; + struct siw_wr_rmda_write write; + struct siw_wr_rdma_rread rread; + struct siw_wr_rdma_rresp rresp; + struct siw_wr_bind bind; + struct siw_wr_recv recv; + } wr; + struct siw_qp *qp; + enum siw_wr_state wr_status; + enum ib_wc_status wc_status; + u32 bytes; /* # bytes to processed */ + u32 processed; /* # bytes processed */ + int error; +}; + +enum siw_cq_armed { + SIW_CQ_NOTIFY_NOT = 0, + SIW_CQ_NOTIFY_SOLICITED, + SIW_CQ_NOTIFY_ALL +}; + +struct siw_cq { + struct ib_cq ofa_cq; + struct siw_objhdr hdr; + enum siw_cq_armed notify; + spinlock_t lock; + struct list_head queue; /* simple list of cqe's */ + atomic_t qlen; /* number of elements */ +}; + +enum siw_qp_state { + SIW_QP_STATE_IDLE = 0, + SIW_QP_STATE_RTR = 1, + SIW_QP_STATE_RTS = 2, + SIW_QP_STATE_CLOSING = 3, + SIW_QP_STATE_TERMINATE = 4, + SIW_QP_STATE_ERROR = 5, + SIW_QP_STATE_MORIBUND = 6, /* destroy called but still referenced */ + SIW_QP_STATE_UNDEF = 7, + SIW_QP_STATE_COUNT = 8 +}; + +enum siw_qp_flags { + SIW_RDMA_BIND_ENABLED = (1 << 0), + SIW_RDMA_WRITE_ENABLED = (1 << 1), + SIW_RDMA_READ_ENABLED = (1 << 2), + SIW_KERNEL_VERBS = (1 << 3), + /* + * QP currently being destroyed + */ + SIW_QP_IN_DESTROY = (1 << 8) +}; + +enum siw_qp_attr_mask { + SIW_QP_ATTR_STATE = (1 << 0), + SIW_QP_ATTR_ACCESS_FLAGS = (1 << 1), + SIW_QP_ATTR_LLP_HANDLE = (1 << 2), + SIW_QP_ATTR_ORD = (1 << 3), + SIW_QP_ATTR_IRD = (1 << 4), + SIW_QP_ATTR_SQ_SIZE = (1 << 5), + SIW_QP_ATTR_RQ_SIZE = (1 << 6), + SIW_QP_ATTR_MPA = (1 << 7) +}; + +struct siw_mpa_attrs { + __u8 marker_rcv; /* always 0 */ + __u8 marker_snd; /* always 0, consider support */ + __u8 crc; + __u8 unused; +}; + +struct siw_sk_upcalls { + void (*sk_state_change)(struct sock *sk); + void (*sk_data_ready)(struct sock *sk, int bytes); + void (*sk_write_space)(struct sock *sk); + void (*sk_error_report)(struct sock *sk); +}; + +struct siw_sq_work { + struct work_struct work; +}; + +struct siw_srq { + struct ib_srq ofa_srq; + struct siw_pd *pd; + struct list_head freeq; + spinlock_t freeq_lock; + struct list_head rq; + spinlock_t lock; + u32 max_sge; + atomic_t space; /* current space for posting wqe's */ + u32 limit; /* low watermark for async event */ + u32 max_wr; /* max # of wqe's allowed */ + char armed; /* inform user if limit hit */ + char kernel_verbs; /* '1' if kernel client */ +}; + +struct siw_qp_attrs { + enum siw_qp_state state; + char terminate_buffer[52]; + u32 terminate_msg_length; + u32 ddp_rdmap_version; /* 0 or 1 */ + char *stream_msg_buf; + u32 stream_msg_buf_length; + u32 rq_hiwat; + u32 sq_size; + u32 rq_size; + u32 sq_max_sges; + u32 sq_max_sges_rdmaw; + u32 rq_max_sges; + u32 ord; + u32 ird; + struct siw_mpa_attrs mpa; + enum siw_qp_flags flags; + + struct socket *llp_stream_handle; +}; + +enum siw_tx_ctx { + SIW_SEND_HDR = 0, /* start or continue sending HDR */ + SIW_SEND_DATA = 1, /* start or continue sending DDP payload */ + SIW_SEND_TRAILER = 2, /* start or continue sending TRAILER */ + SIW_SEND_SHORT_FPDU = 3 /* send whole FPDU hdr|data|trailer at once */ +}; + +enum siw_rx_state { + SIW_GET_HDR = 0, /* await new hdr or within hdr */ + SIW_GET_DATA_START = 1, /* start of inbound DDP payload */ + SIW_GET_DATA_MORE = 2, /* continuation of (misaligned) DDP payload */ + SIW_GET_TRAILER = 3 /* await new trailer or within trailer */ +}; + + +struct siw_iwarp_rx { + struct sk_buff *skb; + union iwarp_hdrs hdr; + struct mpa_trailer trailer; + /* + * local destination memory of inbound iwarp operation. + * valid, if already resolved, NULL otherwise. + */ + union { + struct siw_wqe *wqe; /* SEND, RRESP */ + struct siw_mem *mem; /* WRITE */ + } dest; + + struct hash_desc mpa_crc_hd; + /* + * Next expected DDP MSN for each QN + + * expected steering tag + + * expected DDP tagget offset (all HBO) + */ + u32 ddp_msn[RDMAP_UNTAGGED_QN_COUNT]; + u32 ddp_stag; + u64 ddp_to; + + /* + * For each FPDU, main RX loop runs through 3 stages: + * Receiving protocol headers, placing DDP payload and receiving + * trailer information (CRC + eventual padding). + * Next two variables keep state on receive status of the + * current FPDU part (hdr, data, trailer). + */ + int fpdu_part_rcvd;/* bytes in pkt part copied */ + int fpdu_part_rem; /* bytes in pkt part not seen */ + + int skb_new; /* pending unread bytes in skb */ + int skb_offset; /* offset in skb */ + int skb_copied; /* processed bytes in skb */ + + int sge_idx; /* current sge in rx */ + unsigned int sge_off; /* already rcvd in curr. sge */ + struct ib_umem_chunk *umem_chunk; /* chunk used by sge and off */ + int pg_idx; /* page used in chunk */ + unsigned int pg_off; /* offset within that page */ + + enum siw_rx_state state; + + u8 crc_enabled:1, + first_ddp_seg:1, /* this is first DDP seg */ + more_ddp_segs:1, /* more DDP segs expected */ + rx_suspend:1, /* stop rcv DDP segs. */ + prev_rdmap_opcode:4; /* opcode of prev msg */ + char pad; /* # of pad bytes expected */ +}; + +#define siw_rx_data(qp, rctx) \ + (iwarp_pktinfo[__rdmap_opcode(&rctx->hdr.ctrl)].proc_data(qp, rctx)) + +/* + * Shorthands for short packets w/o payload + * to be transmitted more efficient. + */ +struct siw_send_pkt { + struct iwarp_send send; + __be32 crc; +}; + +struct siw_write_pkt { + struct iwarp_rdma_write write; + __be32 crc; +}; + +struct siw_rreq_pkt { + struct iwarp_rdma_rreq rreq; + __be32 crc; +}; + +struct siw_rresp_pkt { + struct iwarp_rdma_rresp rresp; + __be32 crc; +}; + +struct siw_iwarp_tx { + union { + union iwarp_hdrs hdr; + + /* Generic part of FPDU header */ + struct iwarp_ctrl ctrl; + struct iwarp_ctrl_untagged c_untagged; + struct iwarp_ctrl_tagged c_tagged; + + /* FPDU headers */ + struct iwarp_rdma_write rwrite; + struct iwarp_rdma_rreq rreq; + struct iwarp_rdma_rresp rresp; + struct iwarp_terminate terminate; + struct iwarp_send send; + struct iwarp_send_inv send_inv; + + /* complete short FPDUs */ + struct siw_send_pkt send_pkt; + struct siw_write_pkt write_pkt; + struct siw_rreq_pkt rreq_pkt; + struct siw_rresp_pkt rresp_pkt; + } pkt; + + struct mpa_trailer trailer; + /* DDP MSN for untagged messages */ + u32 ddp_msn[RDMAP_UNTAGGED_QN_COUNT]; + + enum siw_tx_ctx state; + wait_queue_head_t waitq; + + u16 ctrl_len; /* ddp+rdmap hdr */ + u16 ctrl_sent; + int bytes_unsent; /* ddp payload bytes */ + + struct hash_desc mpa_crc_hd; + + atomic_t in_use; /* tx currently under way */ + + u8 crc_enabled:1, /* compute and ship crc */ + do_crc:1, /* do crc for segment */ + use_sendpage:1, /* send w/o copy */ + new_tcpseg:1, /* start new tcp segment */ + tx_suspend:1, /* stop sending DDP segs. */ + pad:2, /* # pad in current fpdu */ + rsvd:2; + + u8 unused; + u16 fpdu_len; /* len of FPDU to tx */ + + int tcp_seglen; /* remaining tcp seg space */ + struct siw_wqe *wqe; + + int sge_idx; /* current sge in tx */ + u32 sge_off; /* already sent in curr. sge */ + struct ib_umem_chunk *umem_chunk; /* chunk used by sge and off */ + int pg_idx; /* page used in mem chunk */ +}; + +struct siw_qp { + struct ib_qp ofa_qp; + struct siw_objhdr hdr; + struct list_head devq; + int cpu; + struct siw_iwarp_rx rx_ctx; + struct siw_iwarp_tx tx_ctx; + + struct siw_cep *cep; + struct rw_semaphore state_lock; + + struct siw_pd *pd; + struct siw_cq *scq; + struct siw_cq *rcq; + + struct siw_qp_attrs attrs; + + struct list_head freeq; + spinlock_t freeq_lock; + struct list_head sq; + spinlock_t sq_lock; + atomic_t sq_space; + struct list_head irq; + atomic_t irq_space; + struct siw_srq *srq; + struct list_head rq; + spinlock_t rq_lock; + atomic_t rq_space; + struct list_head orq; + atomic_t orq_space; + spinlock_t orq_lock; + + struct siw_sq_work sq_work; +}; + +#define lock_sq(qp) spin_lock(&qp->sq_lock) +#define unlock_sq(qp) spin_unlock(&qp->sq_lock) + +#define lock_sq_rxsave(qp, flags) spin_lock_irqsave(&qp->sq_lock, flags) +#define unlock_sq_rxsave(qp, flags) spin_unlock_irqrestore(&qp->sq_lock, flags) + +#define lock_rq(qp) spin_lock(&qp->rq_lock) +#define unlock_rq(qp) spin_unlock(&qp->rq_lock) + +#define lock_rq_rxsave(qp, flags) spin_lock_irqsave(&qp->rq_lock, flags) +#define unlock_rq_rxsave(qp, flags) spin_unlock_irqrestore(&qp->rq_lock, flags) + +#define lock_srq(srq) spin_lock(&srq->lock) +#define unlock_srq(srq) spin_unlock(&srq->lock) + +#define lock_srq_rxsave(srq, flags) spin_lock_irqsave(&srq->lock, flags) +#define unlock_srq_rxsave(srq, flags) spin_unlock_irqrestore(&srq->lock, flags) + +#define lock_cq(cq) spin_lock(&cq->lock) +#define unlock_cq(cq) spin_unlock(&cq->lock) + +#define lock_cq_rxsave(cq, flags) spin_lock_irqsave(&cq->lock, flags) +#define unlock_cq_rxsave(cq, flags)\ + spin_unlock_irqrestore(&cq->lock, flags) + +#define lock_orq(qp) spin_lock(&qp->orq_lock) +#define unlock_orq(qp) spin_unlock(&qp->orq_lock) + +#define lock_orq_rxsave(qp, flags) spin_lock_irqsave(&qp->orq_lock, flags) +#define unlock_orq_rxsave(qp, flags)\ + spin_unlock_irqrestore(&qp->orq_lock, flags) + +#define RX_QP(rx) container_of(rx, struct siw_qp, rx_ctx) +#define TX_QP(tx) container_of(tx, struct siw_qp, tx_ctx) +#define QP_ID(qp) ((qp)->hdr.id) +#define OBJ_ID(obj) ((obj)->hdr.id) +#define RX_QPID(rx) QP_ID(RX_QP(rx)) +#define TX_QPID(tx) QP_ID(TX_QP(tx)) + +/* helper macros */ +#define tx_wqe(qp) ((qp)->tx_ctx.wqe) +#define rx_wqe(qp) ((qp)->rx_ctx.dest.wqe) +#define rx_mem(qp) ((qp)->rx_ctx.dest.mem) +#define wr_id(wqe) ((wqe)->wr.hdr.id) +#define wr_type(wqe) ((wqe)->wr.hdr.type) +#define wr_flags(wqe) ((wqe)->wr.hdr.flags) +#define list_entry_wqe(pos) list_entry(pos, struct siw_wqe, list) +#define list_first_wqe(pos) list_first_entry(pos, struct siw_wqe, list) + +#define ORD_SUSPEND_SQ(qp) (!atomic_read(&(qp)->orq_space)) +#define TX_ACTIVE(qp) (tx_wqe(qp) != NULL) +#define SQ_EMPTY(qp) list_empty(&((qp)->sq)) +#define ORQ_EMPTY(qp) list_empty(&((qp)->orq)) +#define IRQ_EMPTY(qp) list_empty(&((qp)->irq)) +#define TX_ACTIVE_RRESP(qp) (TX_ACTIVE(qp) &&\ + wr_type(tx_wqe(qp)) == SIW_WR_RDMA_READ_RESP) + +#define TX_IDLE(qp) (!TX_ACTIVE(qp) && SQ_EMPTY(qp) && \ + IRQ_EMPTY(qp) && ORQ_EMPTY(qp)) + +#define TX_MORE_WQE(qp) (!SQ_EMPTY(qp) || !IRQ_EMPTY(qp)) + +struct iwarp_msg_info { + int hdr_len; + struct iwarp_ctrl ctrl; + int (*proc_data) (struct siw_qp *, struct siw_iwarp_rx *); +}; + +extern struct iwarp_msg_info iwarp_pktinfo[RDMAP_TERMINATE + 1]; +extern struct siw_dev *siw; + + +/* QP general functions */ +int siw_qp_modify(struct siw_qp *, struct siw_qp_attrs *, + enum siw_qp_attr_mask); + +void siw_qp_llp_close(struct siw_qp *); +void siw_qp_cm_drop(struct siw_qp *, int); + + +struct ib_qp *siw_get_ofaqp(struct ib_device *, int); +void siw_qp_get_ref(struct ib_qp *); +void siw_qp_put_ref(struct ib_qp *); + +int siw_no_mad(struct ib_device *, int, u8, struct ib_wc *, struct ib_grh *, + struct ib_mad *, struct ib_mad *); + +enum siw_qp_state siw_map_ibstate(enum ib_qp_state); + +int siw_check_mem(struct siw_pd *, struct siw_mem *, u64, + enum siw_access_flags, int); +int siw_check_sge(struct siw_pd *, struct siw_sge *, + enum siw_access_flags, u32, int); +int siw_check_sgl(struct siw_pd *, struct siw_sge *, + enum siw_access_flags, u32, int); + +void siw_rq_complete(struct siw_wqe *, struct siw_qp *); +void siw_sq_complete(struct list_head *, struct siw_qp *, int, + enum ib_send_flags); + + +/* QP TX path functions */ +int siw_qp_sq_process(struct siw_qp *, int); +int siw_sq_worker_init(void); +void siw_sq_worker_exit(void); +int siw_sq_queue_work(struct siw_qp *qp); + +/* QP RX path functions */ +int siw_proc_send(struct siw_qp *, struct siw_iwarp_rx *); +int siw_init_rresp(struct siw_qp *, struct siw_iwarp_rx *); +int siw_proc_rreq(struct siw_qp *, struct siw_iwarp_rx *); +int siw_proc_rresp(struct siw_qp *, struct siw_iwarp_rx *); +int siw_proc_write(struct siw_qp *, struct siw_iwarp_rx *); +int siw_proc_terminate(struct siw_qp*, struct siw_iwarp_rx *); +int siw_proc_unsupp(struct siw_qp *, struct siw_iwarp_rx *); + +int siw_tcp_rx_data(read_descriptor_t *rd_desc, struct sk_buff *skb, + unsigned int off, size_t len); + +/* MPA utilities */ +int siw_crc_array(struct hash_desc *, u8 *, size_t); +int siw_crc_sg(struct hash_desc *, struct scatterlist *, int, int); + + +/* Varia */ +void siw_cq_flush(struct siw_cq *); +void siw_sq_flush(struct siw_qp *); +void siw_rq_flush(struct siw_qp *); +int siw_reap_cqe(struct siw_cq *, struct ib_wc *); + +/* RDMA core event dipatching */ +void siw_qp_event(struct siw_qp *, enum ib_event_type); +void siw_cq_event(struct siw_cq *, enum ib_event_type); +void siw_srq_event(struct siw_srq *, enum ib_event_type); +void siw_port_event(struct siw_dev *, u8, enum ib_event_type); + +static inline struct siw_wqe * +siw_next_tx_wqe(struct siw_qp *qp) { + struct siw_wqe *wqe; + + if (!list_empty(&qp->irq)) + wqe = list_first_entry(&qp->irq, struct siw_wqe, list); + else if (!list_empty(&qp->sq)) + wqe = list_first_entry(&qp->sq, struct siw_wqe, list); + else + wqe = NULL; + return wqe; +} + +static inline void +siw_rreq_queue(struct siw_wqe *wqe, struct siw_qp *qp) +{ + unsigned long flags; + + lock_orq_rxsave(qp, flags); + list_move_tail(&wqe->list, &qp->orq); + atomic_dec(&qp->orq_space); + unlock_orq_rxsave(qp, flags); +} + + +static inline struct ib_umem_chunk * +mem_chunk_next(struct ib_umem_chunk *chunk) +{ + return list_entry(chunk->list.next, struct ib_umem_chunk, list); +} + + +static inline struct siw_mr *siw_mem2mr(struct siw_mem *m) +{ + if (!SIW_MEM_IS_MW(m)) + return container_of(m, struct siw_mr, mem); + return m->mr; +} + +#endif