mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	Soft RoCE driver
Soft RoCE (RXE) - The software RoCE driver
ib_rxe implements the RDMA transport and registers to the RDMA core
device as a kernel verbs provider. It also implements the packet IO
layer. On the other hand ib_rxe registers to the Linux netdev stack
as a udp encapsulating protocol, in that case RDMA, for sending and
receiving packets over any Ethernet device.  This yields a RDMA
transport over the UDP/Ethernet network layer forming a RoCEv2
compatible device.
The configuration procedure of the Soft RoCE drivers requires
binding to any existing Ethernet network device. This is done with
/sys interface.
A userspace Soft RoCE library (librxe) provides user applications
the ability to run with Soft RoCE devices.  The use of rxe verbs ins
user space requires the inclusion of librxe as a device specifics
plug-in to libibverbs. librxe is packaged separately.
Architecture:
     +-----------------------------------------------------------+
     |                          Application                      |
     +-----------------------------------------------------------+
                            +-----------------------------------+
                            |             libibverbs            |
User                        +-----------------------------------+
                            +----------------+ +----------------+
                            | librxe         | | HW RoCE lib    |
                            +----------------+ +----------------+
+---------------------------------------------------------------+
     +--------------+                           +------------+
     | Sockets      |                           | RDMA ULP   |
     +--------------+                           +------------+
     +--------------+                  +---------------------+
     | TCP/IP       |                  | ib_core             |
     +--------------+                  +---------------------+
                             +------------+ +----------------+
Kernel                       | ib_rxe     | | HW RoCE driver |
                             +------------+ +----------------+
     +------------------------------------+
     | NIC driver                         |
     +------------------------------------+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     +-----------------------------------------------------------+
     |                          Application                      |
     +-----------------------------------------------------------+
                            +-----------------------------------+
                            |             libibverbs            |
User                        +-----------------------------------+
                            +----------------+ +----------------+
                            | librxe         | | HW RoCE lib    |
                            +----------------+ +----------------+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     +--------------+                           +------------+
     | Sockets      |                           | RDMA ULP   |
     +--------------+                           +------------+
     +--------------+                  +---------------------+
     | TCP/IP       |                  | ib_core             |
     +--------------+                  +---------------------+
                             +------------+ +----------------+
Kernel                       | ib_rxe     | | HW RoCE driver |
                             +------------+ +----------------+
     +------------------------------------+
     | NIC driver                         |
     +------------------------------------+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Soft RoCE resources:
[1[ https://github.com/SoftRoCE/librxe-dev librxe - source code in
Github
[2] https://github.com/SoftRoCE/rxe-dev/wiki/rxe-dev:-Home - Soft RoCE
Wiki page
[3] https://github.com/SoftRoCE/librxe-dev - Soft RoCE userspace library
Signed-off-by: Kamal Heib <kamalh@mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
Signed-off-by: Moni Shoua <monis@mellanox.com>
Reviewed-by: Haggai Eran <haggaie@mellanox.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
			
			
This commit is contained in:
		
							parent
							
								
									33688abb28
								
							
						
					
					
						commit
						8700e3e7c4
					
				
					 38 changed files with 13039 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -7444,6 +7444,15 @@ W:	http://www.mellanox.com
 | 
			
		|||
Q:	http://patchwork.ozlabs.org/project/netdev/list/
 | 
			
		||||
F:	drivers/net/ethernet/mellanox/mlxsw/
 | 
			
		||||
 | 
			
		||||
SOFT-ROCE DRIVER (rxe)
 | 
			
		||||
M:	Moni Shoua <monis@mellanox.com>
 | 
			
		||||
L:	linux-rdma@vger.kernel.org
 | 
			
		||||
S:	Supported
 | 
			
		||||
W:	https://github.com/SoftRoCE/rxe-dev/wiki/rxe-dev:-Home
 | 
			
		||||
Q:	http://patchwork.kernel.org/project/linux-rdma/list/
 | 
			
		||||
F:	drivers/infiniband/hw/rxe/
 | 
			
		||||
F:	include/uapi/rdma/rdma_user_rxe.h
 | 
			
		||||
 | 
			
		||||
MEMBARRIER SUPPORT
 | 
			
		||||
M:	Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
 | 
			
		||||
M:	"Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -84,6 +84,7 @@ source "drivers/infiniband/ulp/iser/Kconfig"
 | 
			
		|||
source "drivers/infiniband/ulp/isert/Kconfig"
 | 
			
		||||
 | 
			
		||||
source "drivers/infiniband/sw/rdmavt/Kconfig"
 | 
			
		||||
source "drivers/infiniband/sw/rxe/Kconfig"
 | 
			
		||||
 | 
			
		||||
source "drivers/infiniband/hw/hfi1/Kconfig"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +1,2 @@
 | 
			
		|||
obj-$(CONFIG_INFINIBAND_RDMAVT)		+= rdmavt/
 | 
			
		||||
obj-$(CONFIG_RDMA_RXE)			+= rxe/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										24
									
								
								drivers/infiniband/sw/rxe/Kconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								drivers/infiniband/sw/rxe/Kconfig
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
config RDMA_RXE
 | 
			
		||||
	tristate "Software RDMA over Ethernet (RoCE) driver"
 | 
			
		||||
	depends on INET && PCI && INFINIBAND
 | 
			
		||||
	depends on NET_UDP_TUNNEL
 | 
			
		||||
	---help---
 | 
			
		||||
	This driver implements the InfiniBand RDMA transport over
 | 
			
		||||
	the Linux network stack. It enables a system with a
 | 
			
		||||
	standard Ethernet adapter to interoperate with a RoCE
 | 
			
		||||
	adapter or with another system running the RXE driver.
 | 
			
		||||
	Documentation on InfiniBand and RoCE can be downloaded at
 | 
			
		||||
	www.infinibandta.org and www.openfabrics.org. (See also
 | 
			
		||||
	siw which is a similar software driver for iWARP.)
 | 
			
		||||
 | 
			
		||||
	The driver is split into two layers, one interfaces with the
 | 
			
		||||
	Linux RDMA stack and implements a kernel or user space
 | 
			
		||||
	verbs API. The user space verbs API requires a support
 | 
			
		||||
	library named librxe which is loaded by the generic user
 | 
			
		||||
	space verbs API, libibverbs. The other layer interfaces
 | 
			
		||||
	with the Linux network stack at layer 3.
 | 
			
		||||
 | 
			
		||||
	To configure and work with soft-RoCE driver please use the
 | 
			
		||||
	following wiki page under "configure Soft-RoCE (RXE)" section:
 | 
			
		||||
 | 
			
		||||
	https://github.com/SoftRoCE/rxe-dev/wiki/rxe-dev:-Home
 | 
			
		||||
							
								
								
									
										24
									
								
								drivers/infiniband/sw/rxe/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								drivers/infiniband/sw/rxe/Makefile
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
obj-$(CONFIG_RDMA_RXE) += rdma_rxe.o
 | 
			
		||||
 | 
			
		||||
rdma_rxe-y := \
 | 
			
		||||
	rxe.o \
 | 
			
		||||
	rxe_comp.o \
 | 
			
		||||
	rxe_req.o \
 | 
			
		||||
	rxe_resp.o \
 | 
			
		||||
	rxe_recv.o \
 | 
			
		||||
	rxe_pool.o \
 | 
			
		||||
	rxe_queue.o \
 | 
			
		||||
	rxe_verbs.o \
 | 
			
		||||
	rxe_av.o \
 | 
			
		||||
	rxe_srq.o \
 | 
			
		||||
	rxe_qp.o \
 | 
			
		||||
	rxe_cq.o \
 | 
			
		||||
	rxe_mr.o \
 | 
			
		||||
	rxe_dma.o \
 | 
			
		||||
	rxe_opcode.o \
 | 
			
		||||
	rxe_mmap.o \
 | 
			
		||||
	rxe_icrc.o \
 | 
			
		||||
	rxe_mcast.o \
 | 
			
		||||
	rxe_task.o \
 | 
			
		||||
	rxe_net.o \
 | 
			
		||||
	rxe_sysfs.o
 | 
			
		||||
							
								
								
									
										386
									
								
								drivers/infiniband/sw/rxe/rxe.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										386
									
								
								drivers/infiniband/sw/rxe/rxe.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,386 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "rxe.h"
 | 
			
		||||
#include "rxe_loc.h"
 | 
			
		||||
 | 
			
		||||
MODULE_AUTHOR("Bob Pearson, Frank Zago, John Groves, Kamal Heib");
 | 
			
		||||
MODULE_DESCRIPTION("Soft RDMA transport");
 | 
			
		||||
MODULE_LICENSE("Dual BSD/GPL");
 | 
			
		||||
MODULE_VERSION("0.2");
 | 
			
		||||
 | 
			
		||||
/* free resources for all ports on a device */
 | 
			
		||||
static void rxe_cleanup_ports(struct rxe_dev *rxe)
 | 
			
		||||
{
 | 
			
		||||
	kfree(rxe->port.pkey_tbl);
 | 
			
		||||
	rxe->port.pkey_tbl = NULL;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* free resources for a rxe device all objects created for this device must
 | 
			
		||||
 * have been destroyed
 | 
			
		||||
 */
 | 
			
		||||
static void rxe_cleanup(struct rxe_dev *rxe)
 | 
			
		||||
{
 | 
			
		||||
	rxe_pool_cleanup(&rxe->uc_pool);
 | 
			
		||||
	rxe_pool_cleanup(&rxe->pd_pool);
 | 
			
		||||
	rxe_pool_cleanup(&rxe->ah_pool);
 | 
			
		||||
	rxe_pool_cleanup(&rxe->srq_pool);
 | 
			
		||||
	rxe_pool_cleanup(&rxe->qp_pool);
 | 
			
		||||
	rxe_pool_cleanup(&rxe->cq_pool);
 | 
			
		||||
	rxe_pool_cleanup(&rxe->mr_pool);
 | 
			
		||||
	rxe_pool_cleanup(&rxe->mw_pool);
 | 
			
		||||
	rxe_pool_cleanup(&rxe->mc_grp_pool);
 | 
			
		||||
	rxe_pool_cleanup(&rxe->mc_elem_pool);
 | 
			
		||||
 | 
			
		||||
	rxe_cleanup_ports(rxe);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* called when all references have been dropped */
 | 
			
		||||
void rxe_release(struct kref *kref)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_dev *rxe = container_of(kref, struct rxe_dev, ref_cnt);
 | 
			
		||||
 | 
			
		||||
	rxe_cleanup(rxe);
 | 
			
		||||
	ib_dealloc_device(&rxe->ib_dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rxe_dev_put(struct rxe_dev *rxe)
 | 
			
		||||
{
 | 
			
		||||
	kref_put(&rxe->ref_cnt, rxe_release);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(rxe_dev_put);
 | 
			
		||||
 | 
			
		||||
/* initialize rxe device parameters */
 | 
			
		||||
static int rxe_init_device_param(struct rxe_dev *rxe)
 | 
			
		||||
{
 | 
			
		||||
	rxe->max_inline_data			= RXE_MAX_INLINE_DATA;
 | 
			
		||||
 | 
			
		||||
	rxe->attr.fw_ver			= RXE_FW_VER;
 | 
			
		||||
	rxe->attr.max_mr_size			= RXE_MAX_MR_SIZE;
 | 
			
		||||
	rxe->attr.page_size_cap			= RXE_PAGE_SIZE_CAP;
 | 
			
		||||
	rxe->attr.vendor_id			= RXE_VENDOR_ID;
 | 
			
		||||
	rxe->attr.vendor_part_id		= RXE_VENDOR_PART_ID;
 | 
			
		||||
	rxe->attr.hw_ver			= RXE_HW_VER;
 | 
			
		||||
	rxe->attr.max_qp			= RXE_MAX_QP;
 | 
			
		||||
	rxe->attr.max_qp_wr			= RXE_MAX_QP_WR;
 | 
			
		||||
	rxe->attr.device_cap_flags		= RXE_DEVICE_CAP_FLAGS;
 | 
			
		||||
	rxe->attr.max_sge			= RXE_MAX_SGE;
 | 
			
		||||
	rxe->attr.max_sge_rd			= RXE_MAX_SGE_RD;
 | 
			
		||||
	rxe->attr.max_cq			= RXE_MAX_CQ;
 | 
			
		||||
	rxe->attr.max_cqe			= (1 << RXE_MAX_LOG_CQE) - 1;
 | 
			
		||||
	rxe->attr.max_mr			= RXE_MAX_MR;
 | 
			
		||||
	rxe->attr.max_pd			= RXE_MAX_PD;
 | 
			
		||||
	rxe->attr.max_qp_rd_atom		= RXE_MAX_QP_RD_ATOM;
 | 
			
		||||
	rxe->attr.max_ee_rd_atom		= RXE_MAX_EE_RD_ATOM;
 | 
			
		||||
	rxe->attr.max_res_rd_atom		= RXE_MAX_RES_RD_ATOM;
 | 
			
		||||
	rxe->attr.max_qp_init_rd_atom		= RXE_MAX_QP_INIT_RD_ATOM;
 | 
			
		||||
	rxe->attr.max_ee_init_rd_atom		= RXE_MAX_EE_INIT_RD_ATOM;
 | 
			
		||||
	rxe->attr.atomic_cap			= RXE_ATOMIC_CAP;
 | 
			
		||||
	rxe->attr.max_ee			= RXE_MAX_EE;
 | 
			
		||||
	rxe->attr.max_rdd			= RXE_MAX_RDD;
 | 
			
		||||
	rxe->attr.max_mw			= RXE_MAX_MW;
 | 
			
		||||
	rxe->attr.max_raw_ipv6_qp		= RXE_MAX_RAW_IPV6_QP;
 | 
			
		||||
	rxe->attr.max_raw_ethy_qp		= RXE_MAX_RAW_ETHY_QP;
 | 
			
		||||
	rxe->attr.max_mcast_grp			= RXE_MAX_MCAST_GRP;
 | 
			
		||||
	rxe->attr.max_mcast_qp_attach		= RXE_MAX_MCAST_QP_ATTACH;
 | 
			
		||||
	rxe->attr.max_total_mcast_qp_attach	= RXE_MAX_TOT_MCAST_QP_ATTACH;
 | 
			
		||||
	rxe->attr.max_ah			= RXE_MAX_AH;
 | 
			
		||||
	rxe->attr.max_fmr			= RXE_MAX_FMR;
 | 
			
		||||
	rxe->attr.max_map_per_fmr		= RXE_MAX_MAP_PER_FMR;
 | 
			
		||||
	rxe->attr.max_srq			= RXE_MAX_SRQ;
 | 
			
		||||
	rxe->attr.max_srq_wr			= RXE_MAX_SRQ_WR;
 | 
			
		||||
	rxe->attr.max_srq_sge			= RXE_MAX_SRQ_SGE;
 | 
			
		||||
	rxe->attr.max_fast_reg_page_list_len	= RXE_MAX_FMR_PAGE_LIST_LEN;
 | 
			
		||||
	rxe->attr.max_pkeys			= RXE_MAX_PKEYS;
 | 
			
		||||
	rxe->attr.local_ca_ack_delay		= RXE_LOCAL_CA_ACK_DELAY;
 | 
			
		||||
 | 
			
		||||
	rxe->max_ucontext			= RXE_MAX_UCONTEXT;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* initialize port attributes */
 | 
			
		||||
static int rxe_init_port_param(struct rxe_port *port)
 | 
			
		||||
{
 | 
			
		||||
	port->attr.state		= RXE_PORT_STATE;
 | 
			
		||||
	port->attr.max_mtu		= RXE_PORT_MAX_MTU;
 | 
			
		||||
	port->attr.active_mtu		= RXE_PORT_ACTIVE_MTU;
 | 
			
		||||
	port->attr.gid_tbl_len		= RXE_PORT_GID_TBL_LEN;
 | 
			
		||||
	port->attr.port_cap_flags	= RXE_PORT_PORT_CAP_FLAGS;
 | 
			
		||||
	port->attr.max_msg_sz		= RXE_PORT_MAX_MSG_SZ;
 | 
			
		||||
	port->attr.bad_pkey_cntr	= RXE_PORT_BAD_PKEY_CNTR;
 | 
			
		||||
	port->attr.qkey_viol_cntr	= RXE_PORT_QKEY_VIOL_CNTR;
 | 
			
		||||
	port->attr.pkey_tbl_len		= RXE_PORT_PKEY_TBL_LEN;
 | 
			
		||||
	port->attr.lid			= RXE_PORT_LID;
 | 
			
		||||
	port->attr.sm_lid		= RXE_PORT_SM_LID;
 | 
			
		||||
	port->attr.lmc			= RXE_PORT_LMC;
 | 
			
		||||
	port->attr.max_vl_num		= RXE_PORT_MAX_VL_NUM;
 | 
			
		||||
	port->attr.sm_sl		= RXE_PORT_SM_SL;
 | 
			
		||||
	port->attr.subnet_timeout	= RXE_PORT_SUBNET_TIMEOUT;
 | 
			
		||||
	port->attr.init_type_reply	= RXE_PORT_INIT_TYPE_REPLY;
 | 
			
		||||
	port->attr.active_width		= RXE_PORT_ACTIVE_WIDTH;
 | 
			
		||||
	port->attr.active_speed		= RXE_PORT_ACTIVE_SPEED;
 | 
			
		||||
	port->attr.phys_state		= RXE_PORT_PHYS_STATE;
 | 
			
		||||
	port->mtu_cap			=
 | 
			
		||||
				ib_mtu_enum_to_int(RXE_PORT_ACTIVE_MTU);
 | 
			
		||||
	port->subnet_prefix		= cpu_to_be64(RXE_PORT_SUBNET_PREFIX);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* initialize port state, note IB convention that HCA ports are always
 | 
			
		||||
 * numbered from 1
 | 
			
		||||
 */
 | 
			
		||||
static int rxe_init_ports(struct rxe_dev *rxe)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_port *port = &rxe->port;
 | 
			
		||||
 | 
			
		||||
	rxe_init_port_param(port);
 | 
			
		||||
 | 
			
		||||
	if (!port->attr.pkey_tbl_len || !port->attr.gid_tbl_len)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	port->pkey_tbl = kcalloc(port->attr.pkey_tbl_len,
 | 
			
		||||
			sizeof(*port->pkey_tbl), GFP_KERNEL);
 | 
			
		||||
 | 
			
		||||
	if (!port->pkey_tbl)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	port->pkey_tbl[0] = 0xffff;
 | 
			
		||||
	port->port_guid = rxe->ifc_ops->port_guid(rxe);
 | 
			
		||||
 | 
			
		||||
	spin_lock_init(&port->port_lock);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* init pools of managed objects */
 | 
			
		||||
static int rxe_init_pools(struct rxe_dev *rxe)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	err = rxe_pool_init(rxe, &rxe->uc_pool, RXE_TYPE_UC,
 | 
			
		||||
			    rxe->max_ucontext);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err1;
 | 
			
		||||
 | 
			
		||||
	err = rxe_pool_init(rxe, &rxe->pd_pool, RXE_TYPE_PD,
 | 
			
		||||
			    rxe->attr.max_pd);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err2;
 | 
			
		||||
 | 
			
		||||
	err = rxe_pool_init(rxe, &rxe->ah_pool, RXE_TYPE_AH,
 | 
			
		||||
			    rxe->attr.max_ah);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err3;
 | 
			
		||||
 | 
			
		||||
	err = rxe_pool_init(rxe, &rxe->srq_pool, RXE_TYPE_SRQ,
 | 
			
		||||
			    rxe->attr.max_srq);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err4;
 | 
			
		||||
 | 
			
		||||
	err = rxe_pool_init(rxe, &rxe->qp_pool, RXE_TYPE_QP,
 | 
			
		||||
			    rxe->attr.max_qp);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err5;
 | 
			
		||||
 | 
			
		||||
	err = rxe_pool_init(rxe, &rxe->cq_pool, RXE_TYPE_CQ,
 | 
			
		||||
			    rxe->attr.max_cq);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err6;
 | 
			
		||||
 | 
			
		||||
	err = rxe_pool_init(rxe, &rxe->mr_pool, RXE_TYPE_MR,
 | 
			
		||||
			    rxe->attr.max_mr);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err7;
 | 
			
		||||
 | 
			
		||||
	err = rxe_pool_init(rxe, &rxe->mw_pool, RXE_TYPE_MW,
 | 
			
		||||
			    rxe->attr.max_mw);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err8;
 | 
			
		||||
 | 
			
		||||
	err = rxe_pool_init(rxe, &rxe->mc_grp_pool, RXE_TYPE_MC_GRP,
 | 
			
		||||
			    rxe->attr.max_mcast_grp);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err9;
 | 
			
		||||
 | 
			
		||||
	err = rxe_pool_init(rxe, &rxe->mc_elem_pool, RXE_TYPE_MC_ELEM,
 | 
			
		||||
			    rxe->attr.max_total_mcast_qp_attach);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err10;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err10:
 | 
			
		||||
	rxe_pool_cleanup(&rxe->mc_grp_pool);
 | 
			
		||||
err9:
 | 
			
		||||
	rxe_pool_cleanup(&rxe->mw_pool);
 | 
			
		||||
err8:
 | 
			
		||||
	rxe_pool_cleanup(&rxe->mr_pool);
 | 
			
		||||
err7:
 | 
			
		||||
	rxe_pool_cleanup(&rxe->cq_pool);
 | 
			
		||||
err6:
 | 
			
		||||
	rxe_pool_cleanup(&rxe->qp_pool);
 | 
			
		||||
err5:
 | 
			
		||||
	rxe_pool_cleanup(&rxe->srq_pool);
 | 
			
		||||
err4:
 | 
			
		||||
	rxe_pool_cleanup(&rxe->ah_pool);
 | 
			
		||||
err3:
 | 
			
		||||
	rxe_pool_cleanup(&rxe->pd_pool);
 | 
			
		||||
err2:
 | 
			
		||||
	rxe_pool_cleanup(&rxe->uc_pool);
 | 
			
		||||
err1:
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* initialize rxe device state */
 | 
			
		||||
static int rxe_init(struct rxe_dev *rxe)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	/* init default device parameters */
 | 
			
		||||
	rxe_init_device_param(rxe);
 | 
			
		||||
 | 
			
		||||
	err = rxe_init_ports(rxe);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err1;
 | 
			
		||||
 | 
			
		||||
	err = rxe_init_pools(rxe);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err2;
 | 
			
		||||
 | 
			
		||||
	/* init pending mmap list */
 | 
			
		||||
	spin_lock_init(&rxe->mmap_offset_lock);
 | 
			
		||||
	spin_lock_init(&rxe->pending_lock);
 | 
			
		||||
	INIT_LIST_HEAD(&rxe->pending_mmaps);
 | 
			
		||||
	INIT_LIST_HEAD(&rxe->list);
 | 
			
		||||
 | 
			
		||||
	mutex_init(&rxe->usdev_lock);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err2:
 | 
			
		||||
	rxe_cleanup_ports(rxe);
 | 
			
		||||
err1:
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rxe_set_mtu(struct rxe_dev *rxe, unsigned int ndev_mtu)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_port *port = &rxe->port;
 | 
			
		||||
	enum ib_mtu mtu;
 | 
			
		||||
 | 
			
		||||
	mtu = eth_mtu_int_to_enum(ndev_mtu);
 | 
			
		||||
 | 
			
		||||
	/* Make sure that new MTU in range */
 | 
			
		||||
	mtu = mtu ? min_t(enum ib_mtu, mtu, RXE_PORT_MAX_MTU) : IB_MTU_256;
 | 
			
		||||
 | 
			
		||||
	port->attr.active_mtu = mtu;
 | 
			
		||||
	port->mtu_cap = ib_mtu_enum_to_int(mtu);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(rxe_set_mtu);
 | 
			
		||||
 | 
			
		||||
/* called by ifc layer to create new rxe device.
 | 
			
		||||
 * The caller should allocate memory for rxe by calling ib_alloc_device.
 | 
			
		||||
 */
 | 
			
		||||
int rxe_add(struct rxe_dev *rxe, unsigned int mtu)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	kref_init(&rxe->ref_cnt);
 | 
			
		||||
 | 
			
		||||
	err = rxe_init(rxe);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err1;
 | 
			
		||||
 | 
			
		||||
	err = rxe_set_mtu(rxe, mtu);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err1;
 | 
			
		||||
 | 
			
		||||
	err = rxe_register_device(rxe);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err1:
 | 
			
		||||
	rxe_dev_put(rxe);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(rxe_add);
 | 
			
		||||
 | 
			
		||||
/* called by the ifc layer to remove a device */
 | 
			
		||||
void rxe_remove(struct rxe_dev *rxe)
 | 
			
		||||
{
 | 
			
		||||
	rxe_unregister_device(rxe);
 | 
			
		||||
 | 
			
		||||
	rxe_dev_put(rxe);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(rxe_remove);
 | 
			
		||||
 | 
			
		||||
static int __init rxe_module_init(void)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	/* initialize slab caches for managed objects */
 | 
			
		||||
	err = rxe_cache_init();
 | 
			
		||||
	if (err) {
 | 
			
		||||
		pr_err("rxe: unable to init object pools\n");
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = rxe_net_init();
 | 
			
		||||
	if (err) {
 | 
			
		||||
		pr_err("rxe: unable to init\n");
 | 
			
		||||
		rxe_cache_exit();
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
	pr_info("rxe: loaded\n");
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __exit rxe_module_exit(void)
 | 
			
		||||
{
 | 
			
		||||
	rxe_remove_all();
 | 
			
		||||
	rxe_net_exit();
 | 
			
		||||
	rxe_cache_exit();
 | 
			
		||||
 | 
			
		||||
	pr_info("rxe: unloaded\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module_init(rxe_module_init);
 | 
			
		||||
module_exit(rxe_module_exit);
 | 
			
		||||
							
								
								
									
										77
									
								
								drivers/infiniband/sw/rxe/rxe.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								drivers/infiniband/sw/rxe/rxe.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,77 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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 RXE_H
 | 
			
		||||
#define RXE_H
 | 
			
		||||
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <linux/skbuff.h>
 | 
			
		||||
#include <linux/crc32.h>
 | 
			
		||||
 | 
			
		||||
#include <rdma/ib_verbs.h>
 | 
			
		||||
#include <rdma/ib_user_verbs.h>
 | 
			
		||||
#include <rdma/ib_pack.h>
 | 
			
		||||
#include <rdma/ib_smi.h>
 | 
			
		||||
#include <rdma/ib_umem.h>
 | 
			
		||||
#include <rdma/ib_cache.h>
 | 
			
		||||
#include <rdma/ib_addr.h>
 | 
			
		||||
 | 
			
		||||
#include "rxe_net.h"
 | 
			
		||||
#include "rxe_opcode.h"
 | 
			
		||||
#include "rxe_hdr.h"
 | 
			
		||||
#include "rxe_param.h"
 | 
			
		||||
#include "rxe_verbs.h"
 | 
			
		||||
 | 
			
		||||
#define RXE_UVERBS_ABI_VERSION		(1)
 | 
			
		||||
 | 
			
		||||
#define IB_PHYS_STATE_LINK_UP		(5)
 | 
			
		||||
#define IB_PHYS_STATE_LINK_DOWN		(3)
 | 
			
		||||
 | 
			
		||||
#define RXE_ROCE_V2_SPORT		(0xc000)
 | 
			
		||||
 | 
			
		||||
int rxe_set_mtu(struct rxe_dev *rxe, unsigned int dev_mtu);
 | 
			
		||||
 | 
			
		||||
int rxe_add(struct rxe_dev *rxe, unsigned int mtu);
 | 
			
		||||
void rxe_remove(struct rxe_dev *rxe);
 | 
			
		||||
void rxe_remove_all(void);
 | 
			
		||||
 | 
			
		||||
int rxe_rcv(struct sk_buff *skb);
 | 
			
		||||
 | 
			
		||||
void rxe_dev_put(struct rxe_dev *rxe);
 | 
			
		||||
struct rxe_dev *net_to_rxe(struct net_device *ndev);
 | 
			
		||||
struct rxe_dev *get_rxe_by_name(const char* name);
 | 
			
		||||
 | 
			
		||||
void rxe_port_up(struct rxe_dev *rxe);
 | 
			
		||||
void rxe_port_down(struct rxe_dev *rxe);
 | 
			
		||||
 | 
			
		||||
#endif /* RXE_H */
 | 
			
		||||
							
								
								
									
										98
									
								
								drivers/infiniband/sw/rxe/rxe_av.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								drivers/infiniband/sw/rxe/rxe_av.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,98 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "rxe.h"
 | 
			
		||||
#include "rxe_loc.h"
 | 
			
		||||
 | 
			
		||||
int rxe_av_chk_attr(struct rxe_dev *rxe, struct ib_ah_attr *attr)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_port *port;
 | 
			
		||||
 | 
			
		||||
	if (attr->port_num != 1) {
 | 
			
		||||
		pr_info("rxe: invalid port_num = %d\n", attr->port_num);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	port = &rxe->port;
 | 
			
		||||
 | 
			
		||||
	if (attr->ah_flags & IB_AH_GRH) {
 | 
			
		||||
		if (attr->grh.sgid_index > port->attr.gid_tbl_len) {
 | 
			
		||||
			pr_info("rxe: invalid sgid index = %d\n",
 | 
			
		||||
				attr->grh.sgid_index);
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rxe_av_from_attr(struct rxe_dev *rxe, u8 port_num,
 | 
			
		||||
		     struct rxe_av *av, struct ib_ah_attr *attr)
 | 
			
		||||
{
 | 
			
		||||
	memset(av, 0, sizeof(*av));
 | 
			
		||||
	memcpy(&av->grh, &attr->grh, sizeof(attr->grh));
 | 
			
		||||
	av->port_num = port_num;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rxe_av_to_attr(struct rxe_dev *rxe, struct rxe_av *av,
 | 
			
		||||
		   struct ib_ah_attr *attr)
 | 
			
		||||
{
 | 
			
		||||
	memcpy(&attr->grh, &av->grh, sizeof(av->grh));
 | 
			
		||||
	attr->port_num = av->port_num;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rxe_av_fill_ip_info(struct rxe_dev *rxe,
 | 
			
		||||
			struct rxe_av *av,
 | 
			
		||||
			struct ib_ah_attr *attr,
 | 
			
		||||
			struct ib_gid_attr *sgid_attr,
 | 
			
		||||
			union ib_gid *sgid)
 | 
			
		||||
{
 | 
			
		||||
	rdma_gid2ip(&av->sgid_addr._sockaddr, sgid);
 | 
			
		||||
	rdma_gid2ip(&av->dgid_addr._sockaddr, &attr->grh.dgid);
 | 
			
		||||
	av->network_type = ib_gid_to_network_type(sgid_attr->gid_type, sgid);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct rxe_av *rxe_get_av(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	if (!pkt || !pkt->qp)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	if (qp_type(pkt->qp) == IB_QPT_RC || qp_type(pkt->qp) == IB_QPT_UC)
 | 
			
		||||
		return &pkt->qp->pri_av;
 | 
			
		||||
 | 
			
		||||
	return (pkt->wqe) ? &pkt->wqe->av : NULL;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										734
									
								
								drivers/infiniband/sw/rxe/rxe_comp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										734
									
								
								drivers/infiniband/sw/rxe/rxe_comp.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,734 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/skbuff.h>
 | 
			
		||||
 | 
			
		||||
#include "rxe.h"
 | 
			
		||||
#include "rxe_loc.h"
 | 
			
		||||
#include "rxe_queue.h"
 | 
			
		||||
#include "rxe_task.h"
 | 
			
		||||
 | 
			
		||||
enum comp_state {
 | 
			
		||||
	COMPST_GET_ACK,
 | 
			
		||||
	COMPST_GET_WQE,
 | 
			
		||||
	COMPST_COMP_WQE,
 | 
			
		||||
	COMPST_COMP_ACK,
 | 
			
		||||
	COMPST_CHECK_PSN,
 | 
			
		||||
	COMPST_CHECK_ACK,
 | 
			
		||||
	COMPST_READ,
 | 
			
		||||
	COMPST_ATOMIC,
 | 
			
		||||
	COMPST_WRITE_SEND,
 | 
			
		||||
	COMPST_UPDATE_COMP,
 | 
			
		||||
	COMPST_ERROR_RETRY,
 | 
			
		||||
	COMPST_RNR_RETRY,
 | 
			
		||||
	COMPST_ERROR,
 | 
			
		||||
	COMPST_EXIT, /* We have an issue, and we want to rerun the completer */
 | 
			
		||||
	COMPST_DONE, /* The completer finished successflly */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static char *comp_state_name[] =  {
 | 
			
		||||
	[COMPST_GET_ACK]		= "GET ACK",
 | 
			
		||||
	[COMPST_GET_WQE]		= "GET WQE",
 | 
			
		||||
	[COMPST_COMP_WQE]		= "COMP WQE",
 | 
			
		||||
	[COMPST_COMP_ACK]		= "COMP ACK",
 | 
			
		||||
	[COMPST_CHECK_PSN]		= "CHECK PSN",
 | 
			
		||||
	[COMPST_CHECK_ACK]		= "CHECK ACK",
 | 
			
		||||
	[COMPST_READ]			= "READ",
 | 
			
		||||
	[COMPST_ATOMIC]			= "ATOMIC",
 | 
			
		||||
	[COMPST_WRITE_SEND]		= "WRITE/SEND",
 | 
			
		||||
	[COMPST_UPDATE_COMP]		= "UPDATE COMP",
 | 
			
		||||
	[COMPST_ERROR_RETRY]		= "ERROR RETRY",
 | 
			
		||||
	[COMPST_RNR_RETRY]		= "RNR RETRY",
 | 
			
		||||
	[COMPST_ERROR]			= "ERROR",
 | 
			
		||||
	[COMPST_EXIT]			= "EXIT",
 | 
			
		||||
	[COMPST_DONE]			= "DONE",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static unsigned long rnrnak_usec[32] = {
 | 
			
		||||
	[IB_RNR_TIMER_655_36] = 655360,
 | 
			
		||||
	[IB_RNR_TIMER_000_01] = 10,
 | 
			
		||||
	[IB_RNR_TIMER_000_02] = 20,
 | 
			
		||||
	[IB_RNR_TIMER_000_03] = 30,
 | 
			
		||||
	[IB_RNR_TIMER_000_04] = 40,
 | 
			
		||||
	[IB_RNR_TIMER_000_06] = 60,
 | 
			
		||||
	[IB_RNR_TIMER_000_08] = 80,
 | 
			
		||||
	[IB_RNR_TIMER_000_12] = 120,
 | 
			
		||||
	[IB_RNR_TIMER_000_16] = 160,
 | 
			
		||||
	[IB_RNR_TIMER_000_24] = 240,
 | 
			
		||||
	[IB_RNR_TIMER_000_32] = 320,
 | 
			
		||||
	[IB_RNR_TIMER_000_48] = 480,
 | 
			
		||||
	[IB_RNR_TIMER_000_64] = 640,
 | 
			
		||||
	[IB_RNR_TIMER_000_96] = 960,
 | 
			
		||||
	[IB_RNR_TIMER_001_28] = 1280,
 | 
			
		||||
	[IB_RNR_TIMER_001_92] = 1920,
 | 
			
		||||
	[IB_RNR_TIMER_002_56] = 2560,
 | 
			
		||||
	[IB_RNR_TIMER_003_84] = 3840,
 | 
			
		||||
	[IB_RNR_TIMER_005_12] = 5120,
 | 
			
		||||
	[IB_RNR_TIMER_007_68] = 7680,
 | 
			
		||||
	[IB_RNR_TIMER_010_24] = 10240,
 | 
			
		||||
	[IB_RNR_TIMER_015_36] = 15360,
 | 
			
		||||
	[IB_RNR_TIMER_020_48] = 20480,
 | 
			
		||||
	[IB_RNR_TIMER_030_72] = 30720,
 | 
			
		||||
	[IB_RNR_TIMER_040_96] = 40960,
 | 
			
		||||
	[IB_RNR_TIMER_061_44] = 61410,
 | 
			
		||||
	[IB_RNR_TIMER_081_92] = 81920,
 | 
			
		||||
	[IB_RNR_TIMER_122_88] = 122880,
 | 
			
		||||
	[IB_RNR_TIMER_163_84] = 163840,
 | 
			
		||||
	[IB_RNR_TIMER_245_76] = 245760,
 | 
			
		||||
	[IB_RNR_TIMER_327_68] = 327680,
 | 
			
		||||
	[IB_RNR_TIMER_491_52] = 491520,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline unsigned long rnrnak_jiffies(u8 timeout)
 | 
			
		||||
{
 | 
			
		||||
	return max_t(unsigned long,
 | 
			
		||||
		usecs_to_jiffies(rnrnak_usec[timeout]), 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static enum ib_wc_opcode wr_to_wc_opcode(enum ib_wr_opcode opcode)
 | 
			
		||||
{
 | 
			
		||||
	switch (opcode) {
 | 
			
		||||
	case IB_WR_RDMA_WRITE:			return IB_WC_RDMA_WRITE;
 | 
			
		||||
	case IB_WR_RDMA_WRITE_WITH_IMM:		return IB_WC_RDMA_WRITE;
 | 
			
		||||
	case IB_WR_SEND:			return IB_WC_SEND;
 | 
			
		||||
	case IB_WR_SEND_WITH_IMM:		return IB_WC_SEND;
 | 
			
		||||
	case IB_WR_RDMA_READ:			return IB_WC_RDMA_READ;
 | 
			
		||||
	case IB_WR_ATOMIC_CMP_AND_SWP:		return IB_WC_COMP_SWAP;
 | 
			
		||||
	case IB_WR_ATOMIC_FETCH_AND_ADD:	return IB_WC_FETCH_ADD;
 | 
			
		||||
	case IB_WR_LSO:				return IB_WC_LSO;
 | 
			
		||||
	case IB_WR_SEND_WITH_INV:		return IB_WC_SEND;
 | 
			
		||||
	case IB_WR_RDMA_READ_WITH_INV:		return IB_WC_RDMA_READ;
 | 
			
		||||
	case IB_WR_LOCAL_INV:			return IB_WC_LOCAL_INV;
 | 
			
		||||
	case IB_WR_REG_MR:			return IB_WC_REG_MR;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		return 0xff;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void retransmit_timer(unsigned long data)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_qp *qp = (struct rxe_qp *)data;
 | 
			
		||||
 | 
			
		||||
	if (qp->valid) {
 | 
			
		||||
		qp->comp.timeout = 1;
 | 
			
		||||
		rxe_run_task(&qp->comp.task, 1);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rxe_comp_queue_pkt(struct rxe_dev *rxe, struct rxe_qp *qp,
 | 
			
		||||
			struct sk_buff *skb)
 | 
			
		||||
{
 | 
			
		||||
	int must_sched;
 | 
			
		||||
 | 
			
		||||
	skb_queue_tail(&qp->resp_pkts, skb);
 | 
			
		||||
 | 
			
		||||
	must_sched = skb_queue_len(&qp->resp_pkts) > 1;
 | 
			
		||||
	rxe_run_task(&qp->comp.task, must_sched);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline enum comp_state get_wqe(struct rxe_qp *qp,
 | 
			
		||||
				      struct rxe_pkt_info *pkt,
 | 
			
		||||
				      struct rxe_send_wqe **wqe_p)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_send_wqe *wqe;
 | 
			
		||||
 | 
			
		||||
	/* we come here whether or not we found a response packet to see if
 | 
			
		||||
	 * there are any posted WQEs
 | 
			
		||||
	 */
 | 
			
		||||
	wqe = queue_head(qp->sq.queue);
 | 
			
		||||
	*wqe_p = wqe;
 | 
			
		||||
 | 
			
		||||
	/* no WQE or requester has not started it yet */
 | 
			
		||||
	if (!wqe || wqe->state == wqe_state_posted)
 | 
			
		||||
		return pkt ? COMPST_DONE : COMPST_EXIT;
 | 
			
		||||
 | 
			
		||||
	/* WQE does not require an ack */
 | 
			
		||||
	if (wqe->state == wqe_state_done)
 | 
			
		||||
		return COMPST_COMP_WQE;
 | 
			
		||||
 | 
			
		||||
	/* WQE caused an error */
 | 
			
		||||
	if (wqe->state == wqe_state_error)
 | 
			
		||||
		return COMPST_ERROR;
 | 
			
		||||
 | 
			
		||||
	/* we have a WQE, if we also have an ack check its PSN */
 | 
			
		||||
	return pkt ? COMPST_CHECK_PSN : COMPST_EXIT;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void reset_retry_counters(struct rxe_qp *qp)
 | 
			
		||||
{
 | 
			
		||||
	qp->comp.retry_cnt = qp->attr.retry_cnt;
 | 
			
		||||
	qp->comp.rnr_retry = qp->attr.rnr_retry;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline enum comp_state check_psn(struct rxe_qp *qp,
 | 
			
		||||
					struct rxe_pkt_info *pkt,
 | 
			
		||||
					struct rxe_send_wqe *wqe)
 | 
			
		||||
{
 | 
			
		||||
	s32 diff;
 | 
			
		||||
 | 
			
		||||
	/* check to see if response is past the oldest WQE. if it is, complete
 | 
			
		||||
	 * send/write or error read/atomic
 | 
			
		||||
	 */
 | 
			
		||||
	diff = psn_compare(pkt->psn, wqe->last_psn);
 | 
			
		||||
	if (diff > 0) {
 | 
			
		||||
		if (wqe->state == wqe_state_pending) {
 | 
			
		||||
			if (wqe->mask & WR_ATOMIC_OR_READ_MASK)
 | 
			
		||||
				return COMPST_ERROR_RETRY;
 | 
			
		||||
 | 
			
		||||
			reset_retry_counters(qp);
 | 
			
		||||
			return COMPST_COMP_WQE;
 | 
			
		||||
		} else {
 | 
			
		||||
			return COMPST_DONE;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* compare response packet to expected response */
 | 
			
		||||
	diff = psn_compare(pkt->psn, qp->comp.psn);
 | 
			
		||||
	if (diff < 0) {
 | 
			
		||||
		/* response is most likely a retried packet if it matches an
 | 
			
		||||
		 * uncompleted WQE go complete it else ignore it
 | 
			
		||||
		 */
 | 
			
		||||
		if (pkt->psn == wqe->last_psn)
 | 
			
		||||
			return COMPST_COMP_ACK;
 | 
			
		||||
		else
 | 
			
		||||
			return COMPST_DONE;
 | 
			
		||||
	} else if ((diff > 0) && (wqe->mask & WR_ATOMIC_OR_READ_MASK)) {
 | 
			
		||||
		return COMPST_ERROR_RETRY;
 | 
			
		||||
	} else {
 | 
			
		||||
		return COMPST_CHECK_ACK;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline enum comp_state check_ack(struct rxe_qp *qp,
 | 
			
		||||
					struct rxe_pkt_info *pkt,
 | 
			
		||||
					struct rxe_send_wqe *wqe)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int mask = pkt->mask;
 | 
			
		||||
	u8 syn;
 | 
			
		||||
 | 
			
		||||
	/* Check the sequence only */
 | 
			
		||||
	switch (qp->comp.opcode) {
 | 
			
		||||
	case -1:
 | 
			
		||||
		/* Will catch all *_ONLY cases. */
 | 
			
		||||
		if (!(mask & RXE_START_MASK))
 | 
			
		||||
			return COMPST_ERROR;
 | 
			
		||||
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST:
 | 
			
		||||
	case IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE:
 | 
			
		||||
		if (pkt->opcode != IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE &&
 | 
			
		||||
		    pkt->opcode != IB_OPCODE_RC_RDMA_READ_RESPONSE_LAST) {
 | 
			
		||||
			return COMPST_ERROR;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		WARN_ON(1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Check operation validity. */
 | 
			
		||||
	switch (pkt->opcode) {
 | 
			
		||||
	case IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST:
 | 
			
		||||
	case IB_OPCODE_RC_RDMA_READ_RESPONSE_LAST:
 | 
			
		||||
	case IB_OPCODE_RC_RDMA_READ_RESPONSE_ONLY:
 | 
			
		||||
		syn = aeth_syn(pkt);
 | 
			
		||||
 | 
			
		||||
		if ((syn & AETH_TYPE_MASK) != AETH_ACK)
 | 
			
		||||
			return COMPST_ERROR;
 | 
			
		||||
 | 
			
		||||
		/* Fall through (IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE
 | 
			
		||||
		 * doesn't have an AETH)
 | 
			
		||||
		 */
 | 
			
		||||
	case IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE:
 | 
			
		||||
		if (wqe->wr.opcode != IB_WR_RDMA_READ &&
 | 
			
		||||
		    wqe->wr.opcode != IB_WR_RDMA_READ_WITH_INV) {
 | 
			
		||||
			return COMPST_ERROR;
 | 
			
		||||
		}
 | 
			
		||||
		reset_retry_counters(qp);
 | 
			
		||||
		return COMPST_READ;
 | 
			
		||||
 | 
			
		||||
	case IB_OPCODE_RC_ATOMIC_ACKNOWLEDGE:
 | 
			
		||||
		syn = aeth_syn(pkt);
 | 
			
		||||
 | 
			
		||||
		if ((syn & AETH_TYPE_MASK) != AETH_ACK)
 | 
			
		||||
			return COMPST_ERROR;
 | 
			
		||||
 | 
			
		||||
		if (wqe->wr.opcode != IB_WR_ATOMIC_CMP_AND_SWP &&
 | 
			
		||||
		    wqe->wr.opcode != IB_WR_ATOMIC_FETCH_AND_ADD)
 | 
			
		||||
			return COMPST_ERROR;
 | 
			
		||||
		reset_retry_counters(qp);
 | 
			
		||||
		return COMPST_ATOMIC;
 | 
			
		||||
 | 
			
		||||
	case IB_OPCODE_RC_ACKNOWLEDGE:
 | 
			
		||||
		syn = aeth_syn(pkt);
 | 
			
		||||
		switch (syn & AETH_TYPE_MASK) {
 | 
			
		||||
		case AETH_ACK:
 | 
			
		||||
			reset_retry_counters(qp);
 | 
			
		||||
			return COMPST_WRITE_SEND;
 | 
			
		||||
 | 
			
		||||
		case AETH_RNR_NAK:
 | 
			
		||||
			return COMPST_RNR_RETRY;
 | 
			
		||||
 | 
			
		||||
		case AETH_NAK:
 | 
			
		||||
			switch (syn) {
 | 
			
		||||
			case AETH_NAK_PSN_SEQ_ERROR:
 | 
			
		||||
				/* a nak implicitly acks all packets with psns
 | 
			
		||||
				 * before
 | 
			
		||||
				 */
 | 
			
		||||
				if (psn_compare(pkt->psn, qp->comp.psn) > 0) {
 | 
			
		||||
					qp->comp.psn = pkt->psn;
 | 
			
		||||
					if (qp->req.wait_psn) {
 | 
			
		||||
						qp->req.wait_psn = 0;
 | 
			
		||||
						rxe_run_task(&qp->req.task, 1);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				return COMPST_ERROR_RETRY;
 | 
			
		||||
 | 
			
		||||
			case AETH_NAK_INVALID_REQ:
 | 
			
		||||
				wqe->status = IB_WC_REM_INV_REQ_ERR;
 | 
			
		||||
				return COMPST_ERROR;
 | 
			
		||||
 | 
			
		||||
			case AETH_NAK_REM_ACC_ERR:
 | 
			
		||||
				wqe->status = IB_WC_REM_ACCESS_ERR;
 | 
			
		||||
				return COMPST_ERROR;
 | 
			
		||||
 | 
			
		||||
			case AETH_NAK_REM_OP_ERR:
 | 
			
		||||
				wqe->status = IB_WC_REM_OP_ERR;
 | 
			
		||||
				return COMPST_ERROR;
 | 
			
		||||
 | 
			
		||||
			default:
 | 
			
		||||
				pr_warn("unexpected nak %x\n", syn);
 | 
			
		||||
				wqe->status = IB_WC_REM_OP_ERR;
 | 
			
		||||
				return COMPST_ERROR;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			return COMPST_ERROR;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		pr_warn("unexpected opcode\n");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return COMPST_ERROR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline enum comp_state do_read(struct rxe_qp *qp,
 | 
			
		||||
				      struct rxe_pkt_info *pkt,
 | 
			
		||||
				      struct rxe_send_wqe *wqe)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = copy_data(rxe, qp->pd, IB_ACCESS_LOCAL_WRITE,
 | 
			
		||||
			&wqe->dma, payload_addr(pkt),
 | 
			
		||||
			payload_size(pkt), to_mem_obj, NULL);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return COMPST_ERROR;
 | 
			
		||||
 | 
			
		||||
	if (wqe->dma.resid == 0 && (pkt->mask & RXE_END_MASK))
 | 
			
		||||
		return COMPST_COMP_ACK;
 | 
			
		||||
	else
 | 
			
		||||
		return COMPST_UPDATE_COMP;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline enum comp_state do_atomic(struct rxe_qp *qp,
 | 
			
		||||
					struct rxe_pkt_info *pkt,
 | 
			
		||||
					struct rxe_send_wqe *wqe)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	u64 atomic_orig = atmack_orig(pkt);
 | 
			
		||||
 | 
			
		||||
	ret = copy_data(rxe, qp->pd, IB_ACCESS_LOCAL_WRITE,
 | 
			
		||||
			&wqe->dma, &atomic_orig,
 | 
			
		||||
			sizeof(u64), to_mem_obj, NULL);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return COMPST_ERROR;
 | 
			
		||||
	else
 | 
			
		||||
		return COMPST_COMP_ACK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void make_send_cqe(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
 | 
			
		||||
			  struct rxe_cqe *cqe)
 | 
			
		||||
{
 | 
			
		||||
	memset(cqe, 0, sizeof(*cqe));
 | 
			
		||||
 | 
			
		||||
	if (!qp->is_user) {
 | 
			
		||||
		struct ib_wc		*wc	= &cqe->ibwc;
 | 
			
		||||
 | 
			
		||||
		wc->wr_id		= wqe->wr.wr_id;
 | 
			
		||||
		wc->status		= wqe->status;
 | 
			
		||||
		wc->opcode		= wr_to_wc_opcode(wqe->wr.opcode);
 | 
			
		||||
		if (wqe->wr.opcode == IB_WR_RDMA_WRITE_WITH_IMM ||
 | 
			
		||||
		    wqe->wr.opcode == IB_WR_SEND_WITH_IMM)
 | 
			
		||||
			wc->wc_flags = IB_WC_WITH_IMM;
 | 
			
		||||
		wc->byte_len		= wqe->dma.length;
 | 
			
		||||
		wc->qp			= &qp->ibqp;
 | 
			
		||||
	} else {
 | 
			
		||||
		struct ib_uverbs_wc	*uwc	= &cqe->uibwc;
 | 
			
		||||
 | 
			
		||||
		uwc->wr_id		= wqe->wr.wr_id;
 | 
			
		||||
		uwc->status		= wqe->status;
 | 
			
		||||
		uwc->opcode		= wr_to_wc_opcode(wqe->wr.opcode);
 | 
			
		||||
		if (wqe->wr.opcode == IB_WR_RDMA_WRITE_WITH_IMM ||
 | 
			
		||||
		    wqe->wr.opcode == IB_WR_SEND_WITH_IMM)
 | 
			
		||||
			uwc->wc_flags = IB_WC_WITH_IMM;
 | 
			
		||||
		uwc->byte_len		= wqe->dma.length;
 | 
			
		||||
		uwc->qp_num		= qp->ibqp.qp_num;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void do_complete(struct rxe_qp *qp, struct rxe_send_wqe *wqe)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_cqe cqe;
 | 
			
		||||
 | 
			
		||||
	if ((qp->sq_sig_type == IB_SIGNAL_ALL_WR) ||
 | 
			
		||||
	    (wqe->wr.send_flags & IB_SEND_SIGNALED) ||
 | 
			
		||||
	    (qp->req.state == QP_STATE_ERROR)) {
 | 
			
		||||
		make_send_cqe(qp, wqe, &cqe);
 | 
			
		||||
		rxe_cq_post(qp->scq, &cqe, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	advance_consumer(qp->sq.queue);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * we completed something so let req run again
 | 
			
		||||
	 * if it is trying to fence
 | 
			
		||||
	 */
 | 
			
		||||
	if (qp->req.wait_fence) {
 | 
			
		||||
		qp->req.wait_fence = 0;
 | 
			
		||||
		rxe_run_task(&qp->req.task, 1);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline enum comp_state complete_ack(struct rxe_qp *qp,
 | 
			
		||||
					   struct rxe_pkt_info *pkt,
 | 
			
		||||
					   struct rxe_send_wqe *wqe)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	if (wqe->has_rd_atomic) {
 | 
			
		||||
		wqe->has_rd_atomic = 0;
 | 
			
		||||
		atomic_inc(&qp->req.rd_atomic);
 | 
			
		||||
		if (qp->req.need_rd_atomic) {
 | 
			
		||||
			qp->comp.timeout_retry = 0;
 | 
			
		||||
			qp->req.need_rd_atomic = 0;
 | 
			
		||||
			rxe_run_task(&qp->req.task, 1);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (unlikely(qp->req.state == QP_STATE_DRAIN)) {
 | 
			
		||||
		/* state_lock used by requester & completer */
 | 
			
		||||
		spin_lock_irqsave(&qp->state_lock, flags);
 | 
			
		||||
		if ((qp->req.state == QP_STATE_DRAIN) &&
 | 
			
		||||
		    (qp->comp.psn == qp->req.psn)) {
 | 
			
		||||
			qp->req.state = QP_STATE_DRAINED;
 | 
			
		||||
			spin_unlock_irqrestore(&qp->state_lock, flags);
 | 
			
		||||
 | 
			
		||||
			if (qp->ibqp.event_handler) {
 | 
			
		||||
				struct ib_event ev;
 | 
			
		||||
 | 
			
		||||
				ev.device = qp->ibqp.device;
 | 
			
		||||
				ev.element.qp = &qp->ibqp;
 | 
			
		||||
				ev.event = IB_EVENT_SQ_DRAINED;
 | 
			
		||||
				qp->ibqp.event_handler(&ev,
 | 
			
		||||
					qp->ibqp.qp_context);
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			spin_unlock_irqrestore(&qp->state_lock, flags);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	do_complete(qp, wqe);
 | 
			
		||||
 | 
			
		||||
	if (psn_compare(pkt->psn, qp->comp.psn) >= 0)
 | 
			
		||||
		return COMPST_UPDATE_COMP;
 | 
			
		||||
	else
 | 
			
		||||
		return COMPST_DONE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline enum comp_state complete_wqe(struct rxe_qp *qp,
 | 
			
		||||
					   struct rxe_pkt_info *pkt,
 | 
			
		||||
					   struct rxe_send_wqe *wqe)
 | 
			
		||||
{
 | 
			
		||||
	qp->comp.opcode = -1;
 | 
			
		||||
 | 
			
		||||
	if (pkt) {
 | 
			
		||||
		if (psn_compare(pkt->psn, qp->comp.psn) >= 0)
 | 
			
		||||
			qp->comp.psn = (pkt->psn + 1) & BTH_PSN_MASK;
 | 
			
		||||
 | 
			
		||||
		if (qp->req.wait_psn) {
 | 
			
		||||
			qp->req.wait_psn = 0;
 | 
			
		||||
			rxe_run_task(&qp->req.task, 1);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	do_complete(qp, wqe);
 | 
			
		||||
 | 
			
		||||
	return COMPST_GET_WQE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rxe_completer(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_qp *qp = (struct rxe_qp *)arg;
 | 
			
		||||
	struct rxe_send_wqe *wqe = wqe;
 | 
			
		||||
	struct sk_buff *skb = NULL;
 | 
			
		||||
	struct rxe_pkt_info *pkt = NULL;
 | 
			
		||||
	enum comp_state state;
 | 
			
		||||
 | 
			
		||||
	if (!qp->valid) {
 | 
			
		||||
		while ((skb = skb_dequeue(&qp->resp_pkts))) {
 | 
			
		||||
			rxe_drop_ref(qp);
 | 
			
		||||
			kfree_skb(skb);
 | 
			
		||||
		}
 | 
			
		||||
		skb = NULL;
 | 
			
		||||
		pkt = NULL;
 | 
			
		||||
 | 
			
		||||
		while (queue_head(qp->sq.queue))
 | 
			
		||||
			advance_consumer(qp->sq.queue);
 | 
			
		||||
 | 
			
		||||
		goto exit;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (qp->req.state == QP_STATE_ERROR) {
 | 
			
		||||
		while ((skb = skb_dequeue(&qp->resp_pkts))) {
 | 
			
		||||
			rxe_drop_ref(qp);
 | 
			
		||||
			kfree_skb(skb);
 | 
			
		||||
		}
 | 
			
		||||
		skb = NULL;
 | 
			
		||||
		pkt = NULL;
 | 
			
		||||
 | 
			
		||||
		while ((wqe = queue_head(qp->sq.queue))) {
 | 
			
		||||
			wqe->status = IB_WC_WR_FLUSH_ERR;
 | 
			
		||||
			do_complete(qp, wqe);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		goto exit;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (qp->req.state == QP_STATE_RESET) {
 | 
			
		||||
		while ((skb = skb_dequeue(&qp->resp_pkts))) {
 | 
			
		||||
			rxe_drop_ref(qp);
 | 
			
		||||
			kfree_skb(skb);
 | 
			
		||||
		}
 | 
			
		||||
		skb = NULL;
 | 
			
		||||
		pkt = NULL;
 | 
			
		||||
 | 
			
		||||
		while (queue_head(qp->sq.queue))
 | 
			
		||||
			advance_consumer(qp->sq.queue);
 | 
			
		||||
 | 
			
		||||
		goto exit;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (qp->comp.timeout) {
 | 
			
		||||
		qp->comp.timeout_retry = 1;
 | 
			
		||||
		qp->comp.timeout = 0;
 | 
			
		||||
	} else {
 | 
			
		||||
		qp->comp.timeout_retry = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (qp->req.need_retry)
 | 
			
		||||
		goto exit;
 | 
			
		||||
 | 
			
		||||
	state = COMPST_GET_ACK;
 | 
			
		||||
 | 
			
		||||
	while (1) {
 | 
			
		||||
		pr_debug("state = %s\n", comp_state_name[state]);
 | 
			
		||||
		switch (state) {
 | 
			
		||||
		case COMPST_GET_ACK:
 | 
			
		||||
			skb = skb_dequeue(&qp->resp_pkts);
 | 
			
		||||
			if (skb) {
 | 
			
		||||
				pkt = SKB_TO_PKT(skb);
 | 
			
		||||
				qp->comp.timeout_retry = 0;
 | 
			
		||||
			}
 | 
			
		||||
			state = COMPST_GET_WQE;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case COMPST_GET_WQE:
 | 
			
		||||
			state = get_wqe(qp, pkt, &wqe);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case COMPST_CHECK_PSN:
 | 
			
		||||
			state = check_psn(qp, pkt, wqe);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case COMPST_CHECK_ACK:
 | 
			
		||||
			state = check_ack(qp, pkt, wqe);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case COMPST_READ:
 | 
			
		||||
			state = do_read(qp, pkt, wqe);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case COMPST_ATOMIC:
 | 
			
		||||
			state = do_atomic(qp, pkt, wqe);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case COMPST_WRITE_SEND:
 | 
			
		||||
			if (wqe->state == wqe_state_pending &&
 | 
			
		||||
			    wqe->last_psn == pkt->psn)
 | 
			
		||||
				state = COMPST_COMP_ACK;
 | 
			
		||||
			else
 | 
			
		||||
				state = COMPST_UPDATE_COMP;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case COMPST_COMP_ACK:
 | 
			
		||||
			state = complete_ack(qp, pkt, wqe);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case COMPST_COMP_WQE:
 | 
			
		||||
			state = complete_wqe(qp, pkt, wqe);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case COMPST_UPDATE_COMP:
 | 
			
		||||
			if (pkt->mask & RXE_END_MASK)
 | 
			
		||||
				qp->comp.opcode = -1;
 | 
			
		||||
			else
 | 
			
		||||
				qp->comp.opcode = pkt->opcode;
 | 
			
		||||
 | 
			
		||||
			if (psn_compare(pkt->psn, qp->comp.psn) >= 0)
 | 
			
		||||
				qp->comp.psn = (pkt->psn + 1) & BTH_PSN_MASK;
 | 
			
		||||
 | 
			
		||||
			if (qp->req.wait_psn) {
 | 
			
		||||
				qp->req.wait_psn = 0;
 | 
			
		||||
				rxe_run_task(&qp->req.task, 1);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			state = COMPST_DONE;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case COMPST_DONE:
 | 
			
		||||
			if (pkt) {
 | 
			
		||||
				rxe_drop_ref(pkt->qp);
 | 
			
		||||
				kfree_skb(skb);
 | 
			
		||||
			}
 | 
			
		||||
			goto done;
 | 
			
		||||
 | 
			
		||||
		case COMPST_EXIT:
 | 
			
		||||
			if (qp->comp.timeout_retry && wqe) {
 | 
			
		||||
				state = COMPST_ERROR_RETRY;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* re reset the timeout counter if
 | 
			
		||||
			 * (1) QP is type RC
 | 
			
		||||
			 * (2) the QP is alive
 | 
			
		||||
			 * (3) there is a packet sent by the requester that
 | 
			
		||||
			 *     might be acked (we still might get spurious
 | 
			
		||||
			 *     timeouts but try to keep them as few as possible)
 | 
			
		||||
			 * (4) the timeout parameter is set
 | 
			
		||||
			 */
 | 
			
		||||
			if ((qp_type(qp) == IB_QPT_RC) &&
 | 
			
		||||
			    (qp->req.state == QP_STATE_READY) &&
 | 
			
		||||
			    (psn_compare(qp->req.psn, qp->comp.psn) > 0) &&
 | 
			
		||||
			    qp->qp_timeout_jiffies)
 | 
			
		||||
				mod_timer(&qp->retrans_timer,
 | 
			
		||||
					  jiffies + qp->qp_timeout_jiffies);
 | 
			
		||||
			goto exit;
 | 
			
		||||
 | 
			
		||||
		case COMPST_ERROR_RETRY:
 | 
			
		||||
			/* we come here if the retry timer fired and we did
 | 
			
		||||
			 * not receive a response packet. try to retry the send
 | 
			
		||||
			 * queue if that makes sense and the limits have not
 | 
			
		||||
			 * been exceeded. remember that some timeouts are
 | 
			
		||||
			 * spurious since we do not reset the timer but kick
 | 
			
		||||
			 * it down the road or let it expire
 | 
			
		||||
			 */
 | 
			
		||||
 | 
			
		||||
			/* there is nothing to retry in this case */
 | 
			
		||||
			if (!wqe || (wqe->state == wqe_state_posted))
 | 
			
		||||
				goto exit;
 | 
			
		||||
 | 
			
		||||
			if (qp->comp.retry_cnt > 0) {
 | 
			
		||||
				if (qp->comp.retry_cnt != 7)
 | 
			
		||||
					qp->comp.retry_cnt--;
 | 
			
		||||
 | 
			
		||||
				/* no point in retrying if we have already
 | 
			
		||||
				 * seen the last ack that the requester could
 | 
			
		||||
				 * have caused
 | 
			
		||||
				 */
 | 
			
		||||
				if (psn_compare(qp->req.psn,
 | 
			
		||||
						qp->comp.psn) > 0) {
 | 
			
		||||
					/* tell the requester to retry the
 | 
			
		||||
					 * send send queue next time around
 | 
			
		||||
					 */
 | 
			
		||||
					qp->req.need_retry = 1;
 | 
			
		||||
					rxe_run_task(&qp->req.task, 1);
 | 
			
		||||
				}
 | 
			
		||||
				goto exit;
 | 
			
		||||
			} else {
 | 
			
		||||
				wqe->status = IB_WC_RETRY_EXC_ERR;
 | 
			
		||||
				state = COMPST_ERROR;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case COMPST_RNR_RETRY:
 | 
			
		||||
			if (qp->comp.rnr_retry > 0) {
 | 
			
		||||
				if (qp->comp.rnr_retry != 7)
 | 
			
		||||
					qp->comp.rnr_retry--;
 | 
			
		||||
 | 
			
		||||
				qp->req.need_retry = 1;
 | 
			
		||||
				pr_debug("set rnr nak timer\n");
 | 
			
		||||
				mod_timer(&qp->rnr_nak_timer,
 | 
			
		||||
					  jiffies + rnrnak_jiffies(aeth_syn(pkt)
 | 
			
		||||
						& ~AETH_TYPE_MASK));
 | 
			
		||||
				goto exit;
 | 
			
		||||
			} else {
 | 
			
		||||
				wqe->status = IB_WC_RNR_RETRY_EXC_ERR;
 | 
			
		||||
				state = COMPST_ERROR;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case COMPST_ERROR:
 | 
			
		||||
			do_complete(qp, wqe);
 | 
			
		||||
			rxe_qp_error(qp);
 | 
			
		||||
			goto exit;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
exit:
 | 
			
		||||
	/* we come here if we are done with processing and want the task to
 | 
			
		||||
	 * exit from the loop calling us
 | 
			
		||||
	 */
 | 
			
		||||
	return -EAGAIN;
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
	/* we come here if we have processed a packet we want the task to call
 | 
			
		||||
	 * us again to see if there is anything else to do
 | 
			
		||||
	 */
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										165
									
								
								drivers/infiniband/sw/rxe/rxe_cq.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								drivers/infiniband/sw/rxe/rxe_cq.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,165 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "rxe.h"
 | 
			
		||||
#include "rxe_loc.h"
 | 
			
		||||
#include "rxe_queue.h"
 | 
			
		||||
 | 
			
		||||
int rxe_cq_chk_attr(struct rxe_dev *rxe, struct rxe_cq *cq,
 | 
			
		||||
		    int cqe, int comp_vector, struct ib_udata *udata)
 | 
			
		||||
{
 | 
			
		||||
	int count;
 | 
			
		||||
 | 
			
		||||
	if (cqe <= 0) {
 | 
			
		||||
		pr_warn("cqe(%d) <= 0\n", cqe);
 | 
			
		||||
		goto err1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (cqe > rxe->attr.max_cqe) {
 | 
			
		||||
		pr_warn("cqe(%d) > max_cqe(%d)\n",
 | 
			
		||||
			cqe, rxe->attr.max_cqe);
 | 
			
		||||
		goto err1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (cq) {
 | 
			
		||||
		count = queue_count(cq->queue);
 | 
			
		||||
		if (cqe < count) {
 | 
			
		||||
			pr_warn("cqe(%d) < current # elements in queue (%d)",
 | 
			
		||||
				cqe, count);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err1:
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rxe_send_complete(unsigned long data)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_cq *cq = (struct rxe_cq *)data;
 | 
			
		||||
 | 
			
		||||
	cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rxe_cq_from_init(struct rxe_dev *rxe, struct rxe_cq *cq, int cqe,
 | 
			
		||||
		     int comp_vector, struct ib_ucontext *context,
 | 
			
		||||
		     struct ib_udata *udata)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	cq->queue = rxe_queue_init(rxe, &cqe,
 | 
			
		||||
				   sizeof(struct rxe_cqe));
 | 
			
		||||
	if (!cq->queue) {
 | 
			
		||||
		pr_warn("unable to create cq\n");
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = do_mmap_info(rxe, udata, false, context, cq->queue->buf,
 | 
			
		||||
			   cq->queue->buf_size, &cq->queue->ip);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		kvfree(cq->queue->buf);
 | 
			
		||||
		kfree(cq->queue);
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (udata)
 | 
			
		||||
		cq->is_user = 1;
 | 
			
		||||
 | 
			
		||||
	tasklet_init(&cq->comp_task, rxe_send_complete, (unsigned long)cq);
 | 
			
		||||
 | 
			
		||||
	spin_lock_init(&cq->cq_lock);
 | 
			
		||||
	cq->ibcq.cqe = cqe;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rxe_cq_resize_queue(struct rxe_cq *cq, int cqe, struct ib_udata *udata)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	err = rxe_queue_resize(cq->queue, (unsigned int *)&cqe,
 | 
			
		||||
			       sizeof(struct rxe_cqe),
 | 
			
		||||
			       cq->queue->ip ? cq->queue->ip->context : NULL,
 | 
			
		||||
			       udata, NULL, &cq->cq_lock);
 | 
			
		||||
	if (!err)
 | 
			
		||||
		cq->ibcq.cqe = cqe;
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rxe_cq_post(struct rxe_cq *cq, struct rxe_cqe *cqe, int solicited)
 | 
			
		||||
{
 | 
			
		||||
	struct ib_event ev;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&cq->cq_lock, flags);
 | 
			
		||||
 | 
			
		||||
	if (unlikely(queue_full(cq->queue))) {
 | 
			
		||||
		spin_unlock_irqrestore(&cq->cq_lock, flags);
 | 
			
		||||
		if (cq->ibcq.event_handler) {
 | 
			
		||||
			ev.device = cq->ibcq.device;
 | 
			
		||||
			ev.element.cq = &cq->ibcq;
 | 
			
		||||
			ev.event = IB_EVENT_CQ_ERR;
 | 
			
		||||
			cq->ibcq.event_handler(&ev, cq->ibcq.cq_context);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	memcpy(producer_addr(cq->queue), cqe, sizeof(*cqe));
 | 
			
		||||
 | 
			
		||||
	/* make sure all changes to the CQ are written before we update the
 | 
			
		||||
	 * producer pointer
 | 
			
		||||
	 */
 | 
			
		||||
	smp_wmb();
 | 
			
		||||
 | 
			
		||||
	advance_producer(cq->queue);
 | 
			
		||||
	spin_unlock_irqrestore(&cq->cq_lock, flags);
 | 
			
		||||
 | 
			
		||||
	if ((cq->notify == IB_CQ_NEXT_COMP) ||
 | 
			
		||||
	    (cq->notify == IB_CQ_SOLICITED && solicited)) {
 | 
			
		||||
		cq->notify = 0;
 | 
			
		||||
		tasklet_schedule(&cq->comp_task);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rxe_cq_cleanup(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_cq *cq = arg;
 | 
			
		||||
 | 
			
		||||
	if (cq->queue)
 | 
			
		||||
		rxe_queue_cleanup(cq->queue);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										166
									
								
								drivers/infiniband/sw/rxe/rxe_dma.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								drivers/infiniband/sw/rxe/rxe_dma.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,166 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "rxe.h"
 | 
			
		||||
#include "rxe_loc.h"
 | 
			
		||||
 | 
			
		||||
#define DMA_BAD_ADDER ((u64)0)
 | 
			
		||||
 | 
			
		||||
static int rxe_mapping_error(struct ib_device *dev, u64 dma_addr)
 | 
			
		||||
{
 | 
			
		||||
	return dma_addr == DMA_BAD_ADDER;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static u64 rxe_dma_map_single(struct ib_device *dev,
 | 
			
		||||
			      void *cpu_addr, size_t size,
 | 
			
		||||
			      enum dma_data_direction direction)
 | 
			
		||||
{
 | 
			
		||||
	WARN_ON(!valid_dma_direction(direction));
 | 
			
		||||
	return (uintptr_t)cpu_addr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rxe_dma_unmap_single(struct ib_device *dev,
 | 
			
		||||
				 u64 addr, size_t size,
 | 
			
		||||
				 enum dma_data_direction direction)
 | 
			
		||||
{
 | 
			
		||||
	WARN_ON(!valid_dma_direction(direction));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static u64 rxe_dma_map_page(struct ib_device *dev,
 | 
			
		||||
			    struct page *page,
 | 
			
		||||
			    unsigned long offset,
 | 
			
		||||
			    size_t size, enum dma_data_direction direction)
 | 
			
		||||
{
 | 
			
		||||
	u64 addr;
 | 
			
		||||
 | 
			
		||||
	WARN_ON(!valid_dma_direction(direction));
 | 
			
		||||
 | 
			
		||||
	if (offset + size > PAGE_SIZE) {
 | 
			
		||||
		addr = DMA_BAD_ADDER;
 | 
			
		||||
		goto done;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	addr = (uintptr_t)page_address(page);
 | 
			
		||||
	if (addr)
 | 
			
		||||
		addr += offset;
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
	return addr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rxe_dma_unmap_page(struct ib_device *dev,
 | 
			
		||||
			       u64 addr, size_t size,
 | 
			
		||||
			       enum dma_data_direction direction)
 | 
			
		||||
{
 | 
			
		||||
	WARN_ON(!valid_dma_direction(direction));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rxe_map_sg(struct ib_device *dev, struct scatterlist *sgl,
 | 
			
		||||
		      int nents, enum dma_data_direction direction)
 | 
			
		||||
{
 | 
			
		||||
	struct scatterlist *sg;
 | 
			
		||||
	u64 addr;
 | 
			
		||||
	int i;
 | 
			
		||||
	int ret = nents;
 | 
			
		||||
 | 
			
		||||
	WARN_ON(!valid_dma_direction(direction));
 | 
			
		||||
 | 
			
		||||
	for_each_sg(sgl, sg, nents, i) {
 | 
			
		||||
		addr = (uintptr_t)page_address(sg_page(sg));
 | 
			
		||||
		if (!addr) {
 | 
			
		||||
			ret = 0;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		sg->dma_address = addr + sg->offset;
 | 
			
		||||
#ifdef CONFIG_NEED_SG_DMA_LENGTH
 | 
			
		||||
		sg->dma_length = sg->length;
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rxe_unmap_sg(struct ib_device *dev,
 | 
			
		||||
			 struct scatterlist *sg, int nents,
 | 
			
		||||
			 enum dma_data_direction direction)
 | 
			
		||||
{
 | 
			
		||||
	WARN_ON(!valid_dma_direction(direction));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rxe_sync_single_for_cpu(struct ib_device *dev,
 | 
			
		||||
				    u64 addr,
 | 
			
		||||
				    size_t size, enum dma_data_direction dir)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rxe_sync_single_for_device(struct ib_device *dev,
 | 
			
		||||
				       u64 addr,
 | 
			
		||||
				       size_t size, enum dma_data_direction dir)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void *rxe_dma_alloc_coherent(struct ib_device *dev, size_t size,
 | 
			
		||||
				    u64 *dma_handle, gfp_t flag)
 | 
			
		||||
{
 | 
			
		||||
	struct page *p;
 | 
			
		||||
	void *addr = NULL;
 | 
			
		||||
 | 
			
		||||
	p = alloc_pages(flag, get_order(size));
 | 
			
		||||
	if (p)
 | 
			
		||||
		addr = page_address(p);
 | 
			
		||||
 | 
			
		||||
	if (dma_handle)
 | 
			
		||||
		*dma_handle = (uintptr_t)addr;
 | 
			
		||||
 | 
			
		||||
	return addr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rxe_dma_free_coherent(struct ib_device *dev, size_t size,
 | 
			
		||||
				  void *cpu_addr, u64 dma_handle)
 | 
			
		||||
{
 | 
			
		||||
	free_pages((unsigned long)cpu_addr, get_order(size));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct ib_dma_mapping_ops rxe_dma_mapping_ops = {
 | 
			
		||||
	.mapping_error		= rxe_mapping_error,
 | 
			
		||||
	.map_single		= rxe_dma_map_single,
 | 
			
		||||
	.unmap_single		= rxe_dma_unmap_single,
 | 
			
		||||
	.map_page		= rxe_dma_map_page,
 | 
			
		||||
	.unmap_page		= rxe_dma_unmap_page,
 | 
			
		||||
	.map_sg			= rxe_map_sg,
 | 
			
		||||
	.unmap_sg		= rxe_unmap_sg,
 | 
			
		||||
	.sync_single_for_cpu	= rxe_sync_single_for_cpu,
 | 
			
		||||
	.sync_single_for_device	= rxe_sync_single_for_device,
 | 
			
		||||
	.alloc_coherent		= rxe_dma_alloc_coherent,
 | 
			
		||||
	.free_coherent		= rxe_dma_free_coherent
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										952
									
								
								drivers/infiniband/sw/rxe/rxe_hdr.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										952
									
								
								drivers/infiniband/sw/rxe/rxe_hdr.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,952 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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 RXE_HDR_H
 | 
			
		||||
#define RXE_HDR_H
 | 
			
		||||
 | 
			
		||||
/* extracted information about a packet carried in an sk_buff struct fits in
 | 
			
		||||
 * the skbuff cb array. Must be at most 48 bytes. stored in control block of
 | 
			
		||||
 * sk_buff for received packets.
 | 
			
		||||
 */
 | 
			
		||||
struct rxe_pkt_info {
 | 
			
		||||
	struct rxe_dev		*rxe;		/* device that owns packet */
 | 
			
		||||
	struct rxe_qp		*qp;		/* qp that owns packet */
 | 
			
		||||
	struct rxe_send_wqe	*wqe;		/* send wqe */
 | 
			
		||||
	u8			*hdr;		/* points to bth */
 | 
			
		||||
	u32			mask;		/* useful info about pkt */
 | 
			
		||||
	u32			psn;		/* bth psn of packet */
 | 
			
		||||
	u16			pkey_index;	/* partition of pkt */
 | 
			
		||||
	u16			paylen;		/* length of bth - icrc */
 | 
			
		||||
	u8			port_num;	/* port pkt received on */
 | 
			
		||||
	u8			opcode;		/* bth opcode of packet */
 | 
			
		||||
	u8			offset;		/* bth offset from pkt->hdr */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Macros should be used only for received skb */
 | 
			
		||||
#define SKB_TO_PKT(skb) ((struct rxe_pkt_info *)(skb)->cb)
 | 
			
		||||
#define PKT_TO_SKB(pkt) container_of((void *)(pkt), struct sk_buff, cb)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * IBA header types and methods
 | 
			
		||||
 *
 | 
			
		||||
 * Some of these are for reference and completeness only since
 | 
			
		||||
 * rxe does not currently support RD transport
 | 
			
		||||
 * most of this could be moved into IB core. ib_pack.h has
 | 
			
		||||
 * part of this but is incomplete
 | 
			
		||||
 *
 | 
			
		||||
 * Header specific routines to insert/extract values to/from headers
 | 
			
		||||
 * the routines that are named __hhh_(set_)fff() take a pointer to a
 | 
			
		||||
 * hhh header and get(set) the fff field. The routines named
 | 
			
		||||
 * hhh_(set_)fff take a packet info struct and find the
 | 
			
		||||
 * header and field based on the opcode in the packet.
 | 
			
		||||
 * Conversion to/from network byte order from cpu order is also done.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define RXE_ICRC_SIZE		(4)
 | 
			
		||||
#define RXE_MAX_HDR_LENGTH	(80)
 | 
			
		||||
 | 
			
		||||
/******************************************************************************
 | 
			
		||||
 * Base Transport Header
 | 
			
		||||
 ******************************************************************************/
 | 
			
		||||
struct rxe_bth {
 | 
			
		||||
	u8			opcode;
 | 
			
		||||
	u8			flags;
 | 
			
		||||
	__be16			pkey;
 | 
			
		||||
	__be32			qpn;
 | 
			
		||||
	__be32			apsn;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define BTH_TVER		(0)
 | 
			
		||||
#define BTH_DEF_PKEY		(0xffff)
 | 
			
		||||
 | 
			
		||||
#define BTH_SE_MASK		(0x80)
 | 
			
		||||
#define BTH_MIG_MASK		(0x40)
 | 
			
		||||
#define BTH_PAD_MASK		(0x30)
 | 
			
		||||
#define BTH_TVER_MASK		(0x0f)
 | 
			
		||||
#define BTH_FECN_MASK		(0x80000000)
 | 
			
		||||
#define BTH_BECN_MASK		(0x40000000)
 | 
			
		||||
#define BTH_RESV6A_MASK		(0x3f000000)
 | 
			
		||||
#define BTH_QPN_MASK		(0x00ffffff)
 | 
			
		||||
#define BTH_ACK_MASK		(0x80000000)
 | 
			
		||||
#define BTH_RESV7_MASK		(0x7f000000)
 | 
			
		||||
#define BTH_PSN_MASK		(0x00ffffff)
 | 
			
		||||
 | 
			
		||||
static inline u8 __bth_opcode(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
 | 
			
		||||
	return bth->opcode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __bth_set_opcode(void *arg, u8 opcode)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
 | 
			
		||||
	bth->opcode = opcode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u8 __bth_se(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
 | 
			
		||||
	return 0 != (BTH_SE_MASK & bth->flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __bth_set_se(void *arg, int se)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
 | 
			
		||||
	if (se)
 | 
			
		||||
		bth->flags |= BTH_SE_MASK;
 | 
			
		||||
	else
 | 
			
		||||
		bth->flags &= ~BTH_SE_MASK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u8 __bth_mig(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
 | 
			
		||||
	return 0 != (BTH_MIG_MASK & bth->flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __bth_set_mig(void *arg, u8 mig)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
 | 
			
		||||
	if (mig)
 | 
			
		||||
		bth->flags |= BTH_MIG_MASK;
 | 
			
		||||
	else
 | 
			
		||||
		bth->flags &= ~BTH_MIG_MASK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u8 __bth_pad(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
 | 
			
		||||
	return (BTH_PAD_MASK & bth->flags) >> 4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __bth_set_pad(void *arg, u8 pad)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
 | 
			
		||||
	bth->flags = (BTH_PAD_MASK & (pad << 4)) |
 | 
			
		||||
			(~BTH_PAD_MASK & bth->flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u8 __bth_tver(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
 | 
			
		||||
	return BTH_TVER_MASK & bth->flags;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __bth_set_tver(void *arg, u8 tver)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
 | 
			
		||||
	bth->flags = (BTH_TVER_MASK & tver) |
 | 
			
		||||
			(~BTH_TVER_MASK & bth->flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u16 __bth_pkey(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
 | 
			
		||||
	return be16_to_cpu(bth->pkey);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __bth_set_pkey(void *arg, u16 pkey)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
 | 
			
		||||
	bth->pkey = cpu_to_be16(pkey);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 __bth_qpn(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
 | 
			
		||||
	return BTH_QPN_MASK & be32_to_cpu(bth->qpn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __bth_set_qpn(void *arg, u32 qpn)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
	u32 resvqpn = be32_to_cpu(bth->qpn);
 | 
			
		||||
 | 
			
		||||
	bth->qpn = cpu_to_be32((BTH_QPN_MASK & qpn) |
 | 
			
		||||
			       (~BTH_QPN_MASK & resvqpn));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int __bth_fecn(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
 | 
			
		||||
	return 0 != (cpu_to_be32(BTH_FECN_MASK) & bth->qpn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __bth_set_fecn(void *arg, int fecn)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
 | 
			
		||||
	if (fecn)
 | 
			
		||||
		bth->qpn |= cpu_to_be32(BTH_FECN_MASK);
 | 
			
		||||
	else
 | 
			
		||||
		bth->qpn &= ~cpu_to_be32(BTH_FECN_MASK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int __bth_becn(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
 | 
			
		||||
	return 0 != (cpu_to_be32(BTH_BECN_MASK) & bth->qpn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __bth_set_becn(void *arg, int becn)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
 | 
			
		||||
	if (becn)
 | 
			
		||||
		bth->qpn |= cpu_to_be32(BTH_BECN_MASK);
 | 
			
		||||
	else
 | 
			
		||||
		bth->qpn &= ~cpu_to_be32(BTH_BECN_MASK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u8 __bth_resv6a(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
 | 
			
		||||
	return (BTH_RESV6A_MASK & be32_to_cpu(bth->qpn)) >> 24;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __bth_set_resv6a(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
 | 
			
		||||
	bth->qpn = cpu_to_be32(~BTH_RESV6A_MASK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int __bth_ack(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
 | 
			
		||||
	return 0 != (cpu_to_be32(BTH_ACK_MASK) & bth->apsn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __bth_set_ack(void *arg, int ack)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
 | 
			
		||||
	if (ack)
 | 
			
		||||
		bth->apsn |= cpu_to_be32(BTH_ACK_MASK);
 | 
			
		||||
	else
 | 
			
		||||
		bth->apsn &= ~cpu_to_be32(BTH_ACK_MASK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __bth_set_resv7(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
 | 
			
		||||
	bth->apsn &= ~cpu_to_be32(BTH_RESV7_MASK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 __bth_psn(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
 | 
			
		||||
	return BTH_PSN_MASK & be32_to_cpu(bth->apsn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __bth_set_psn(void *arg, u32 psn)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = arg;
 | 
			
		||||
	u32 apsn = be32_to_cpu(bth->apsn);
 | 
			
		||||
 | 
			
		||||
	bth->apsn = cpu_to_be32((BTH_PSN_MASK & psn) |
 | 
			
		||||
			(~BTH_PSN_MASK & apsn));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u8 bth_opcode(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __bth_opcode(pkt->hdr + pkt->offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void bth_set_opcode(struct rxe_pkt_info *pkt, u8 opcode)
 | 
			
		||||
{
 | 
			
		||||
	__bth_set_opcode(pkt->hdr + pkt->offset, opcode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u8 bth_se(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __bth_se(pkt->hdr + pkt->offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void bth_set_se(struct rxe_pkt_info *pkt, int se)
 | 
			
		||||
{
 | 
			
		||||
	__bth_set_se(pkt->hdr + pkt->offset, se);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u8 bth_mig(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __bth_mig(pkt->hdr + pkt->offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void bth_set_mig(struct rxe_pkt_info *pkt, u8 mig)
 | 
			
		||||
{
 | 
			
		||||
	__bth_set_mig(pkt->hdr + pkt->offset, mig);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u8 bth_pad(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __bth_pad(pkt->hdr + pkt->offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void bth_set_pad(struct rxe_pkt_info *pkt, u8 pad)
 | 
			
		||||
{
 | 
			
		||||
	__bth_set_pad(pkt->hdr + pkt->offset, pad);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u8 bth_tver(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __bth_tver(pkt->hdr + pkt->offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void bth_set_tver(struct rxe_pkt_info *pkt, u8 tver)
 | 
			
		||||
{
 | 
			
		||||
	__bth_set_tver(pkt->hdr + pkt->offset, tver);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u16 bth_pkey(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __bth_pkey(pkt->hdr + pkt->offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void bth_set_pkey(struct rxe_pkt_info *pkt, u16 pkey)
 | 
			
		||||
{
 | 
			
		||||
	__bth_set_pkey(pkt->hdr + pkt->offset, pkey);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 bth_qpn(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __bth_qpn(pkt->hdr + pkt->offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void bth_set_qpn(struct rxe_pkt_info *pkt, u32 qpn)
 | 
			
		||||
{
 | 
			
		||||
	__bth_set_qpn(pkt->hdr + pkt->offset, qpn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int bth_fecn(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __bth_fecn(pkt->hdr + pkt->offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void bth_set_fecn(struct rxe_pkt_info *pkt, int fecn)
 | 
			
		||||
{
 | 
			
		||||
	__bth_set_fecn(pkt->hdr + pkt->offset, fecn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int bth_becn(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __bth_becn(pkt->hdr + pkt->offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void bth_set_becn(struct rxe_pkt_info *pkt, int becn)
 | 
			
		||||
{
 | 
			
		||||
	__bth_set_becn(pkt->hdr + pkt->offset, becn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u8 bth_resv6a(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __bth_resv6a(pkt->hdr + pkt->offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void bth_set_resv6a(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	__bth_set_resv6a(pkt->hdr + pkt->offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int bth_ack(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __bth_ack(pkt->hdr + pkt->offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void bth_set_ack(struct rxe_pkt_info *pkt, int ack)
 | 
			
		||||
{
 | 
			
		||||
	__bth_set_ack(pkt->hdr + pkt->offset, ack);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void bth_set_resv7(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	__bth_set_resv7(pkt->hdr + pkt->offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 bth_psn(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __bth_psn(pkt->hdr + pkt->offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void bth_set_psn(struct rxe_pkt_info *pkt, u32 psn)
 | 
			
		||||
{
 | 
			
		||||
	__bth_set_psn(pkt->hdr + pkt->offset, psn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void bth_init(struct rxe_pkt_info *pkt, u8 opcode, int se,
 | 
			
		||||
			    int mig, int pad, u16 pkey, u32 qpn, int ack_req,
 | 
			
		||||
			    u32 psn)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_bth *bth = (struct rxe_bth *)(pkt->hdr + pkt->offset);
 | 
			
		||||
 | 
			
		||||
	bth->opcode = opcode;
 | 
			
		||||
	bth->flags = (pad << 4) & BTH_PAD_MASK;
 | 
			
		||||
	if (se)
 | 
			
		||||
		bth->flags |= BTH_SE_MASK;
 | 
			
		||||
	if (mig)
 | 
			
		||||
		bth->flags |= BTH_MIG_MASK;
 | 
			
		||||
	bth->pkey = cpu_to_be16(pkey);
 | 
			
		||||
	bth->qpn = cpu_to_be32(qpn & BTH_QPN_MASK);
 | 
			
		||||
	psn &= BTH_PSN_MASK;
 | 
			
		||||
	if (ack_req)
 | 
			
		||||
		psn |= BTH_ACK_MASK;
 | 
			
		||||
	bth->apsn = cpu_to_be32(psn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******************************************************************************
 | 
			
		||||
 * Reliable Datagram Extended Transport Header
 | 
			
		||||
 ******************************************************************************/
 | 
			
		||||
struct rxe_rdeth {
 | 
			
		||||
	__be32			een;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define RDETH_EEN_MASK		(0x00ffffff)
 | 
			
		||||
 | 
			
		||||
static inline u8 __rdeth_een(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_rdeth *rdeth = arg;
 | 
			
		||||
 | 
			
		||||
	return RDETH_EEN_MASK & be32_to_cpu(rdeth->een);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __rdeth_set_een(void *arg, u32 een)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_rdeth *rdeth = arg;
 | 
			
		||||
 | 
			
		||||
	rdeth->een = cpu_to_be32(RDETH_EEN_MASK & een);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u8 rdeth_een(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __rdeth_een(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_RDETH]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void rdeth_set_een(struct rxe_pkt_info *pkt, u32 een)
 | 
			
		||||
{
 | 
			
		||||
	__rdeth_set_een(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_RDETH], een);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******************************************************************************
 | 
			
		||||
 * Datagram Extended Transport Header
 | 
			
		||||
 ******************************************************************************/
 | 
			
		||||
struct rxe_deth {
 | 
			
		||||
	__be32			qkey;
 | 
			
		||||
	__be32			sqp;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define GSI_QKEY		(0x80010000)
 | 
			
		||||
#define DETH_SQP_MASK		(0x00ffffff)
 | 
			
		||||
 | 
			
		||||
static inline u32 __deth_qkey(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_deth *deth = arg;
 | 
			
		||||
 | 
			
		||||
	return be32_to_cpu(deth->qkey);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __deth_set_qkey(void *arg, u32 qkey)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_deth *deth = arg;
 | 
			
		||||
 | 
			
		||||
	deth->qkey = cpu_to_be32(qkey);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 __deth_sqp(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_deth *deth = arg;
 | 
			
		||||
 | 
			
		||||
	return DETH_SQP_MASK & be32_to_cpu(deth->sqp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __deth_set_sqp(void *arg, u32 sqp)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_deth *deth = arg;
 | 
			
		||||
 | 
			
		||||
	deth->sqp = cpu_to_be32(DETH_SQP_MASK & sqp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 deth_qkey(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __deth_qkey(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_DETH]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void deth_set_qkey(struct rxe_pkt_info *pkt, u32 qkey)
 | 
			
		||||
{
 | 
			
		||||
	__deth_set_qkey(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_DETH], qkey);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 deth_sqp(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __deth_sqp(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_DETH]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void deth_set_sqp(struct rxe_pkt_info *pkt, u32 sqp)
 | 
			
		||||
{
 | 
			
		||||
	__deth_set_sqp(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_DETH], sqp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******************************************************************************
 | 
			
		||||
 * RDMA Extended Transport Header
 | 
			
		||||
 ******************************************************************************/
 | 
			
		||||
struct rxe_reth {
 | 
			
		||||
	__be64			va;
 | 
			
		||||
	__be32			rkey;
 | 
			
		||||
	__be32			len;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline u64 __reth_va(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_reth *reth = arg;
 | 
			
		||||
 | 
			
		||||
	return be64_to_cpu(reth->va);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __reth_set_va(void *arg, u64 va)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_reth *reth = arg;
 | 
			
		||||
 | 
			
		||||
	reth->va = cpu_to_be64(va);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 __reth_rkey(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_reth *reth = arg;
 | 
			
		||||
 | 
			
		||||
	return be32_to_cpu(reth->rkey);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __reth_set_rkey(void *arg, u32 rkey)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_reth *reth = arg;
 | 
			
		||||
 | 
			
		||||
	reth->rkey = cpu_to_be32(rkey);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 __reth_len(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_reth *reth = arg;
 | 
			
		||||
 | 
			
		||||
	return be32_to_cpu(reth->len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __reth_set_len(void *arg, u32 len)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_reth *reth = arg;
 | 
			
		||||
 | 
			
		||||
	reth->len = cpu_to_be32(len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u64 reth_va(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __reth_va(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_RETH]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void reth_set_va(struct rxe_pkt_info *pkt, u64 va)
 | 
			
		||||
{
 | 
			
		||||
	__reth_set_va(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_RETH], va);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 reth_rkey(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __reth_rkey(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_RETH]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void reth_set_rkey(struct rxe_pkt_info *pkt, u32 rkey)
 | 
			
		||||
{
 | 
			
		||||
	__reth_set_rkey(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_RETH], rkey);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 reth_len(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __reth_len(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_RETH]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void reth_set_len(struct rxe_pkt_info *pkt, u32 len)
 | 
			
		||||
{
 | 
			
		||||
	__reth_set_len(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_RETH], len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******************************************************************************
 | 
			
		||||
 * Atomic Extended Transport Header
 | 
			
		||||
 ******************************************************************************/
 | 
			
		||||
struct rxe_atmeth {
 | 
			
		||||
	__be64			va;
 | 
			
		||||
	__be32			rkey;
 | 
			
		||||
	__be64			swap_add;
 | 
			
		||||
	__be64			comp;
 | 
			
		||||
} __attribute__((__packed__));
 | 
			
		||||
 | 
			
		||||
static inline u64 __atmeth_va(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_atmeth *atmeth = arg;
 | 
			
		||||
 | 
			
		||||
	return be64_to_cpu(atmeth->va);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __atmeth_set_va(void *arg, u64 va)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_atmeth *atmeth = arg;
 | 
			
		||||
 | 
			
		||||
	atmeth->va = cpu_to_be64(va);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 __atmeth_rkey(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_atmeth *atmeth = arg;
 | 
			
		||||
 | 
			
		||||
	return be32_to_cpu(atmeth->rkey);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __atmeth_set_rkey(void *arg, u32 rkey)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_atmeth *atmeth = arg;
 | 
			
		||||
 | 
			
		||||
	atmeth->rkey = cpu_to_be32(rkey);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u64 __atmeth_swap_add(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_atmeth *atmeth = arg;
 | 
			
		||||
 | 
			
		||||
	return be64_to_cpu(atmeth->swap_add);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __atmeth_set_swap_add(void *arg, u64 swap_add)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_atmeth *atmeth = arg;
 | 
			
		||||
 | 
			
		||||
	atmeth->swap_add = cpu_to_be64(swap_add);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u64 __atmeth_comp(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_atmeth *atmeth = arg;
 | 
			
		||||
 | 
			
		||||
	return be64_to_cpu(atmeth->comp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __atmeth_set_comp(void *arg, u64 comp)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_atmeth *atmeth = arg;
 | 
			
		||||
 | 
			
		||||
	atmeth->comp = cpu_to_be64(comp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u64 atmeth_va(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __atmeth_va(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_ATMETH]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void atmeth_set_va(struct rxe_pkt_info *pkt, u64 va)
 | 
			
		||||
{
 | 
			
		||||
	__atmeth_set_va(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_ATMETH], va);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 atmeth_rkey(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __atmeth_rkey(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_ATMETH]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void atmeth_set_rkey(struct rxe_pkt_info *pkt, u32 rkey)
 | 
			
		||||
{
 | 
			
		||||
	__atmeth_set_rkey(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_ATMETH], rkey);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u64 atmeth_swap_add(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __atmeth_swap_add(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_ATMETH]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void atmeth_set_swap_add(struct rxe_pkt_info *pkt, u64 swap_add)
 | 
			
		||||
{
 | 
			
		||||
	__atmeth_set_swap_add(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_ATMETH], swap_add);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u64 atmeth_comp(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __atmeth_comp(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_ATMETH]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void atmeth_set_comp(struct rxe_pkt_info *pkt, u64 comp)
 | 
			
		||||
{
 | 
			
		||||
	__atmeth_set_comp(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_ATMETH], comp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******************************************************************************
 | 
			
		||||
 * Ack Extended Transport Header
 | 
			
		||||
 ******************************************************************************/
 | 
			
		||||
struct rxe_aeth {
 | 
			
		||||
	__be32			smsn;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define AETH_SYN_MASK		(0xff000000)
 | 
			
		||||
#define AETH_MSN_MASK		(0x00ffffff)
 | 
			
		||||
 | 
			
		||||
enum aeth_syndrome {
 | 
			
		||||
	AETH_TYPE_MASK		= 0xe0,
 | 
			
		||||
	AETH_ACK		= 0x00,
 | 
			
		||||
	AETH_RNR_NAK		= 0x20,
 | 
			
		||||
	AETH_RSVD		= 0x40,
 | 
			
		||||
	AETH_NAK		= 0x60,
 | 
			
		||||
	AETH_ACK_UNLIMITED	= 0x1f,
 | 
			
		||||
	AETH_NAK_PSN_SEQ_ERROR	= 0x60,
 | 
			
		||||
	AETH_NAK_INVALID_REQ	= 0x61,
 | 
			
		||||
	AETH_NAK_REM_ACC_ERR	= 0x62,
 | 
			
		||||
	AETH_NAK_REM_OP_ERR	= 0x63,
 | 
			
		||||
	AETH_NAK_INV_RD_REQ	= 0x64,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline u8 __aeth_syn(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_aeth *aeth = arg;
 | 
			
		||||
 | 
			
		||||
	return (AETH_SYN_MASK & be32_to_cpu(aeth->smsn)) >> 24;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __aeth_set_syn(void *arg, u8 syn)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_aeth *aeth = arg;
 | 
			
		||||
	u32 smsn = be32_to_cpu(aeth->smsn);
 | 
			
		||||
 | 
			
		||||
	aeth->smsn = cpu_to_be32((AETH_SYN_MASK & (syn << 24)) |
 | 
			
		||||
			 (~AETH_SYN_MASK & smsn));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 __aeth_msn(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_aeth *aeth = arg;
 | 
			
		||||
 | 
			
		||||
	return AETH_MSN_MASK & be32_to_cpu(aeth->smsn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __aeth_set_msn(void *arg, u32 msn)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_aeth *aeth = arg;
 | 
			
		||||
	u32 smsn = be32_to_cpu(aeth->smsn);
 | 
			
		||||
 | 
			
		||||
	aeth->smsn = cpu_to_be32((AETH_MSN_MASK & msn) |
 | 
			
		||||
			 (~AETH_MSN_MASK & smsn));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u8 aeth_syn(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __aeth_syn(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_AETH]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void aeth_set_syn(struct rxe_pkt_info *pkt, u8 syn)
 | 
			
		||||
{
 | 
			
		||||
	__aeth_set_syn(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_AETH], syn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 aeth_msn(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __aeth_msn(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_AETH]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void aeth_set_msn(struct rxe_pkt_info *pkt, u32 msn)
 | 
			
		||||
{
 | 
			
		||||
	__aeth_set_msn(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_AETH], msn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******************************************************************************
 | 
			
		||||
 * Atomic Ack Extended Transport Header
 | 
			
		||||
 ******************************************************************************/
 | 
			
		||||
struct rxe_atmack {
 | 
			
		||||
	__be64			orig;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline u64 __atmack_orig(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_atmack *atmack = arg;
 | 
			
		||||
 | 
			
		||||
	return be64_to_cpu(atmack->orig);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __atmack_set_orig(void *arg, u64 orig)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_atmack *atmack = arg;
 | 
			
		||||
 | 
			
		||||
	atmack->orig = cpu_to_be64(orig);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u64 atmack_orig(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __atmack_orig(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_ATMACK]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void atmack_set_orig(struct rxe_pkt_info *pkt, u64 orig)
 | 
			
		||||
{
 | 
			
		||||
	__atmack_set_orig(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_ATMACK], orig);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******************************************************************************
 | 
			
		||||
 * Immediate Extended Transport Header
 | 
			
		||||
 ******************************************************************************/
 | 
			
		||||
struct rxe_immdt {
 | 
			
		||||
	__be32			imm;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline __be32 __immdt_imm(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_immdt *immdt = arg;
 | 
			
		||||
 | 
			
		||||
	return immdt->imm;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __immdt_set_imm(void *arg, __be32 imm)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_immdt *immdt = arg;
 | 
			
		||||
 | 
			
		||||
	immdt->imm = imm;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline __be32 immdt_imm(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __immdt_imm(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_IMMDT]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void immdt_set_imm(struct rxe_pkt_info *pkt, __be32 imm)
 | 
			
		||||
{
 | 
			
		||||
	__immdt_set_imm(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_IMMDT], imm);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******************************************************************************
 | 
			
		||||
 * Invalidate Extended Transport Header
 | 
			
		||||
 ******************************************************************************/
 | 
			
		||||
struct rxe_ieth {
 | 
			
		||||
	__be32			rkey;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline u32 __ieth_rkey(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_ieth *ieth = arg;
 | 
			
		||||
 | 
			
		||||
	return be32_to_cpu(ieth->rkey);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __ieth_set_rkey(void *arg, u32 rkey)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_ieth *ieth = arg;
 | 
			
		||||
 | 
			
		||||
	ieth->rkey = cpu_to_be32(rkey);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline u32 ieth_rkey(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return __ieth_rkey(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_IETH]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void ieth_set_rkey(struct rxe_pkt_info *pkt, u32 rkey)
 | 
			
		||||
{
 | 
			
		||||
	__ieth_set_rkey(pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_IETH], rkey);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum rxe_hdr_length {
 | 
			
		||||
	RXE_BTH_BYTES		= sizeof(struct rxe_bth),
 | 
			
		||||
	RXE_DETH_BYTES		= sizeof(struct rxe_deth),
 | 
			
		||||
	RXE_IMMDT_BYTES		= sizeof(struct rxe_immdt),
 | 
			
		||||
	RXE_RETH_BYTES		= sizeof(struct rxe_reth),
 | 
			
		||||
	RXE_AETH_BYTES		= sizeof(struct rxe_aeth),
 | 
			
		||||
	RXE_ATMACK_BYTES	= sizeof(struct rxe_atmack),
 | 
			
		||||
	RXE_ATMETH_BYTES	= sizeof(struct rxe_atmeth),
 | 
			
		||||
	RXE_IETH_BYTES		= sizeof(struct rxe_ieth),
 | 
			
		||||
	RXE_RDETH_BYTES		= sizeof(struct rxe_rdeth),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline size_t header_size(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return pkt->offset + rxe_opcode[pkt->opcode].length;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void *payload_addr(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return pkt->hdr + pkt->offset
 | 
			
		||||
		+ rxe_opcode[pkt->opcode].offset[RXE_PAYLOAD];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline size_t payload_size(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	return pkt->paylen - rxe_opcode[pkt->opcode].offset[RXE_PAYLOAD]
 | 
			
		||||
		- bth_pad(pkt) - RXE_ICRC_SIZE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* RXE_HDR_H */
 | 
			
		||||
							
								
								
									
										96
									
								
								drivers/infiniband/sw/rxe/rxe_icrc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								drivers/infiniband/sw/rxe/rxe_icrc.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,96 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "rxe.h"
 | 
			
		||||
#include "rxe_loc.h"
 | 
			
		||||
 | 
			
		||||
/* Compute a partial ICRC for all the IB transport headers. */
 | 
			
		||||
u32 rxe_icrc_hdr(struct rxe_pkt_info *pkt, struct sk_buff *skb)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int bth_offset = 0;
 | 
			
		||||
	struct iphdr *ip4h = NULL;
 | 
			
		||||
	struct ipv6hdr *ip6h = NULL;
 | 
			
		||||
	struct udphdr *udph;
 | 
			
		||||
	struct rxe_bth *bth;
 | 
			
		||||
	int crc;
 | 
			
		||||
	int length;
 | 
			
		||||
	int hdr_size = sizeof(struct udphdr) +
 | 
			
		||||
		(skb->protocol == htons(ETH_P_IP) ?
 | 
			
		||||
		sizeof(struct iphdr) : sizeof(struct ipv6hdr));
 | 
			
		||||
	/* pseudo header buffer size is calculate using ipv6 header size since
 | 
			
		||||
	 * it is bigger than ipv4
 | 
			
		||||
	 */
 | 
			
		||||
	u8 pshdr[sizeof(struct udphdr) +
 | 
			
		||||
		sizeof(struct ipv6hdr) +
 | 
			
		||||
		RXE_BTH_BYTES];
 | 
			
		||||
 | 
			
		||||
	/* This seed is the result of computing a CRC with a seed of
 | 
			
		||||
	 * 0xfffffff and 8 bytes of 0xff representing a masked LRH.
 | 
			
		||||
	 */
 | 
			
		||||
	crc = 0xdebb20e3;
 | 
			
		||||
 | 
			
		||||
	if (skb->protocol == htons(ETH_P_IP)) { /* IPv4 */
 | 
			
		||||
		memcpy(pshdr, ip_hdr(skb), hdr_size);
 | 
			
		||||
		ip4h = (struct iphdr *)pshdr;
 | 
			
		||||
		udph = (struct udphdr *)(ip4h + 1);
 | 
			
		||||
 | 
			
		||||
		ip4h->ttl = 0xff;
 | 
			
		||||
		ip4h->check = CSUM_MANGLED_0;
 | 
			
		||||
		ip4h->tos = 0xff;
 | 
			
		||||
	} else {				/* IPv6 */
 | 
			
		||||
		memcpy(pshdr, ipv6_hdr(skb), hdr_size);
 | 
			
		||||
		ip6h = (struct ipv6hdr *)pshdr;
 | 
			
		||||
		udph = (struct udphdr *)(ip6h + 1);
 | 
			
		||||
 | 
			
		||||
		memset(ip6h->flow_lbl, 0xff, sizeof(ip6h->flow_lbl));
 | 
			
		||||
		ip6h->priority = 0xf;
 | 
			
		||||
		ip6h->hop_limit = 0xff;
 | 
			
		||||
	}
 | 
			
		||||
	udph->check = CSUM_MANGLED_0;
 | 
			
		||||
 | 
			
		||||
	bth_offset += hdr_size;
 | 
			
		||||
 | 
			
		||||
	memcpy(&pshdr[bth_offset], pkt->hdr, RXE_BTH_BYTES);
 | 
			
		||||
	bth = (struct rxe_bth *)&pshdr[bth_offset];
 | 
			
		||||
 | 
			
		||||
	/* exclude bth.resv8a */
 | 
			
		||||
	bth->qpn |= cpu_to_be32(~BTH_QPN_MASK);
 | 
			
		||||
 | 
			
		||||
	length = hdr_size + RXE_BTH_BYTES;
 | 
			
		||||
	crc = crc32_le(crc, pshdr, length);
 | 
			
		||||
 | 
			
		||||
	/* And finish to compute the CRC on the remainder of the headers. */
 | 
			
		||||
	crc = crc32_le(crc, pkt->hdr + RXE_BTH_BYTES,
 | 
			
		||||
		       rxe_opcode[pkt->opcode].length - RXE_BTH_BYTES);
 | 
			
		||||
	return crc;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										286
									
								
								drivers/infiniband/sw/rxe/rxe_loc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										286
									
								
								drivers/infiniband/sw/rxe/rxe_loc.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,286 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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 RXE_LOC_H
 | 
			
		||||
#define RXE_LOC_H
 | 
			
		||||
 | 
			
		||||
/* rxe_av.c */
 | 
			
		||||
 | 
			
		||||
int rxe_av_chk_attr(struct rxe_dev *rxe, struct ib_ah_attr *attr);
 | 
			
		||||
 | 
			
		||||
int rxe_av_from_attr(struct rxe_dev *rxe, u8 port_num,
 | 
			
		||||
		     struct rxe_av *av, struct ib_ah_attr *attr);
 | 
			
		||||
 | 
			
		||||
int rxe_av_to_attr(struct rxe_dev *rxe, struct rxe_av *av,
 | 
			
		||||
		   struct ib_ah_attr *attr);
 | 
			
		||||
 | 
			
		||||
int rxe_av_fill_ip_info(struct rxe_dev *rxe,
 | 
			
		||||
			struct rxe_av *av,
 | 
			
		||||
			struct ib_ah_attr *attr,
 | 
			
		||||
			struct ib_gid_attr *sgid_attr,
 | 
			
		||||
			union ib_gid *sgid);
 | 
			
		||||
 | 
			
		||||
struct rxe_av *rxe_get_av(struct rxe_pkt_info *pkt);
 | 
			
		||||
 | 
			
		||||
/* rxe_cq.c */
 | 
			
		||||
int rxe_cq_chk_attr(struct rxe_dev *rxe, struct rxe_cq *cq,
 | 
			
		||||
		    int cqe, int comp_vector, struct ib_udata *udata);
 | 
			
		||||
 | 
			
		||||
int rxe_cq_from_init(struct rxe_dev *rxe, struct rxe_cq *cq, int cqe,
 | 
			
		||||
		     int comp_vector, struct ib_ucontext *context,
 | 
			
		||||
		     struct ib_udata *udata);
 | 
			
		||||
 | 
			
		||||
int rxe_cq_resize_queue(struct rxe_cq *cq, int new_cqe, struct ib_udata *udata);
 | 
			
		||||
 | 
			
		||||
int rxe_cq_post(struct rxe_cq *cq, struct rxe_cqe *cqe, int solicited);
 | 
			
		||||
 | 
			
		||||
void rxe_cq_cleanup(void *arg);
 | 
			
		||||
 | 
			
		||||
/* rxe_mcast.c */
 | 
			
		||||
int rxe_mcast_get_grp(struct rxe_dev *rxe, union ib_gid *mgid,
 | 
			
		||||
		      struct rxe_mc_grp **grp_p);
 | 
			
		||||
 | 
			
		||||
int rxe_mcast_add_grp_elem(struct rxe_dev *rxe, struct rxe_qp *qp,
 | 
			
		||||
			   struct rxe_mc_grp *grp);
 | 
			
		||||
 | 
			
		||||
int rxe_mcast_drop_grp_elem(struct rxe_dev *rxe, struct rxe_qp *qp,
 | 
			
		||||
			    union ib_gid *mgid);
 | 
			
		||||
 | 
			
		||||
void rxe_drop_all_mcast_groups(struct rxe_qp *qp);
 | 
			
		||||
 | 
			
		||||
void rxe_mc_cleanup(void *arg);
 | 
			
		||||
 | 
			
		||||
/* rxe_mmap.c */
 | 
			
		||||
struct rxe_mmap_info {
 | 
			
		||||
	struct list_head	pending_mmaps;
 | 
			
		||||
	struct ib_ucontext	*context;
 | 
			
		||||
	struct kref		ref;
 | 
			
		||||
	void			*obj;
 | 
			
		||||
 | 
			
		||||
	struct mminfo info;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void rxe_mmap_release(struct kref *ref);
 | 
			
		||||
 | 
			
		||||
struct rxe_mmap_info *rxe_create_mmap_info(struct rxe_dev *dev,
 | 
			
		||||
					   u32 size,
 | 
			
		||||
					   struct ib_ucontext *context,
 | 
			
		||||
					   void *obj);
 | 
			
		||||
 | 
			
		||||
int rxe_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
 | 
			
		||||
 | 
			
		||||
/* rxe_mr.c */
 | 
			
		||||
enum copy_direction {
 | 
			
		||||
	to_mem_obj,
 | 
			
		||||
	from_mem_obj,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int rxe_mem_init_dma(struct rxe_dev *rxe, struct rxe_pd *pd,
 | 
			
		||||
		     int access, struct rxe_mem *mem);
 | 
			
		||||
 | 
			
		||||
int rxe_mem_init_user(struct rxe_dev *rxe, struct rxe_pd *pd, u64 start,
 | 
			
		||||
		      u64 length, u64 iova, int access, struct ib_udata *udata,
 | 
			
		||||
		      struct rxe_mem *mr);
 | 
			
		||||
 | 
			
		||||
int rxe_mem_init_fast(struct rxe_dev *rxe, struct rxe_pd *pd,
 | 
			
		||||
		      int max_pages, struct rxe_mem *mem);
 | 
			
		||||
 | 
			
		||||
int rxe_mem_copy(struct rxe_mem *mem, u64 iova, void *addr,
 | 
			
		||||
		 int length, enum copy_direction dir, u32 *crcp);
 | 
			
		||||
 | 
			
		||||
int copy_data(struct rxe_dev *rxe, struct rxe_pd *pd, int access,
 | 
			
		||||
	      struct rxe_dma_info *dma, void *addr, int length,
 | 
			
		||||
	      enum copy_direction dir, u32 *crcp);
 | 
			
		||||
 | 
			
		||||
void *iova_to_vaddr(struct rxe_mem *mem, u64 iova, int length);
 | 
			
		||||
 | 
			
		||||
enum lookup_type {
 | 
			
		||||
	lookup_local,
 | 
			
		||||
	lookup_remote,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_mem *lookup_mem(struct rxe_pd *pd, int access, u32 key,
 | 
			
		||||
			   enum lookup_type type);
 | 
			
		||||
 | 
			
		||||
int mem_check_range(struct rxe_mem *mem, u64 iova, size_t length);
 | 
			
		||||
 | 
			
		||||
int rxe_mem_map_pages(struct rxe_dev *rxe, struct rxe_mem *mem,
 | 
			
		||||
		      u64 *page, int num_pages, u64 iova);
 | 
			
		||||
 | 
			
		||||
void rxe_mem_cleanup(void *arg);
 | 
			
		||||
 | 
			
		||||
int advance_dma_data(struct rxe_dma_info *dma, unsigned int length);
 | 
			
		||||
 | 
			
		||||
/* rxe_qp.c */
 | 
			
		||||
int rxe_qp_chk_init(struct rxe_dev *rxe, struct ib_qp_init_attr *init);
 | 
			
		||||
 | 
			
		||||
int rxe_qp_from_init(struct rxe_dev *rxe, struct rxe_qp *qp, struct rxe_pd *pd,
 | 
			
		||||
		     struct ib_qp_init_attr *init, struct ib_udata *udata,
 | 
			
		||||
		     struct ib_pd *ibpd);
 | 
			
		||||
 | 
			
		||||
int rxe_qp_to_init(struct rxe_qp *qp, struct ib_qp_init_attr *init);
 | 
			
		||||
 | 
			
		||||
int rxe_qp_chk_attr(struct rxe_dev *rxe, struct rxe_qp *qp,
 | 
			
		||||
		    struct ib_qp_attr *attr, int mask);
 | 
			
		||||
 | 
			
		||||
int rxe_qp_from_attr(struct rxe_qp *qp, struct ib_qp_attr *attr,
 | 
			
		||||
		     int mask, struct ib_udata *udata);
 | 
			
		||||
 | 
			
		||||
int rxe_qp_to_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask);
 | 
			
		||||
 | 
			
		||||
void rxe_qp_error(struct rxe_qp *qp);
 | 
			
		||||
 | 
			
		||||
void rxe_qp_destroy(struct rxe_qp *qp);
 | 
			
		||||
 | 
			
		||||
void rxe_qp_cleanup(void *arg);
 | 
			
		||||
 | 
			
		||||
static inline int qp_num(struct rxe_qp *qp)
 | 
			
		||||
{
 | 
			
		||||
	return qp->ibqp.qp_num;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline enum ib_qp_type qp_type(struct rxe_qp *qp)
 | 
			
		||||
{
 | 
			
		||||
	return qp->ibqp.qp_type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline enum ib_qp_state qp_state(struct rxe_qp *qp)
 | 
			
		||||
{
 | 
			
		||||
	return qp->attr.qp_state;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int qp_mtu(struct rxe_qp *qp)
 | 
			
		||||
{
 | 
			
		||||
	if (qp->ibqp.qp_type == IB_QPT_RC || qp->ibqp.qp_type == IB_QPT_UC)
 | 
			
		||||
		return qp->attr.path_mtu;
 | 
			
		||||
	else
 | 
			
		||||
		return RXE_PORT_MAX_MTU;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int rcv_wqe_size(int max_sge)
 | 
			
		||||
{
 | 
			
		||||
	return sizeof(struct rxe_recv_wqe) +
 | 
			
		||||
		max_sge * sizeof(struct ib_sge);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void free_rd_atomic_resource(struct rxe_qp *qp, struct resp_res *res);
 | 
			
		||||
 | 
			
		||||
static inline void rxe_advance_resp_resource(struct rxe_qp *qp)
 | 
			
		||||
{
 | 
			
		||||
	qp->resp.res_head++;
 | 
			
		||||
	if (unlikely(qp->resp.res_head == qp->attr.max_rd_atomic))
 | 
			
		||||
		qp->resp.res_head = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void retransmit_timer(unsigned long data);
 | 
			
		||||
void rnr_nak_timer(unsigned long data);
 | 
			
		||||
 | 
			
		||||
void dump_qp(struct rxe_qp *qp);
 | 
			
		||||
 | 
			
		||||
/* rxe_srq.c */
 | 
			
		||||
#define IB_SRQ_INIT_MASK (~IB_SRQ_LIMIT)
 | 
			
		||||
 | 
			
		||||
int rxe_srq_chk_attr(struct rxe_dev *rxe, struct rxe_srq *srq,
 | 
			
		||||
		     struct ib_srq_attr *attr, enum ib_srq_attr_mask mask);
 | 
			
		||||
 | 
			
		||||
int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq,
 | 
			
		||||
		      struct ib_srq_init_attr *init,
 | 
			
		||||
		      struct ib_ucontext *context, struct ib_udata *udata);
 | 
			
		||||
 | 
			
		||||
int rxe_srq_from_attr(struct rxe_dev *rxe, struct rxe_srq *srq,
 | 
			
		||||
		      struct ib_srq_attr *attr, enum ib_srq_attr_mask mask,
 | 
			
		||||
		      struct ib_udata *udata);
 | 
			
		||||
 | 
			
		||||
extern struct ib_dma_mapping_ops rxe_dma_mapping_ops;
 | 
			
		||||
 | 
			
		||||
void rxe_release(struct kref *kref);
 | 
			
		||||
 | 
			
		||||
int rxe_completer(void *arg);
 | 
			
		||||
int rxe_requester(void *arg);
 | 
			
		||||
int rxe_responder(void *arg);
 | 
			
		||||
 | 
			
		||||
u32 rxe_icrc_hdr(struct rxe_pkt_info *pkt, struct sk_buff *skb);
 | 
			
		||||
 | 
			
		||||
void rxe_resp_queue_pkt(struct rxe_dev *rxe,
 | 
			
		||||
			struct rxe_qp *qp, struct sk_buff *skb);
 | 
			
		||||
 | 
			
		||||
void rxe_comp_queue_pkt(struct rxe_dev *rxe,
 | 
			
		||||
			struct rxe_qp *qp, struct sk_buff *skb);
 | 
			
		||||
 | 
			
		||||
static inline unsigned wr_opcode_mask(int opcode, struct rxe_qp *qp)
 | 
			
		||||
{
 | 
			
		||||
	return rxe_wr_opcode_info[opcode].mask[qp->ibqp.qp_type];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int rxe_xmit_packet(struct rxe_dev *rxe, struct rxe_qp *qp,
 | 
			
		||||
				  struct rxe_pkt_info *pkt, struct sk_buff *skb)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
	int is_request = pkt->mask & RXE_REQ_MASK;
 | 
			
		||||
 | 
			
		||||
	if ((is_request && (qp->req.state != QP_STATE_READY)) ||
 | 
			
		||||
	    (!is_request && (qp->resp.state != QP_STATE_READY))) {
 | 
			
		||||
		pr_info("Packet dropped. QP is not in ready state\n");
 | 
			
		||||
		goto drop;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (pkt->mask & RXE_LOOPBACK_MASK) {
 | 
			
		||||
		memcpy(SKB_TO_PKT(skb), pkt, sizeof(*pkt));
 | 
			
		||||
		err = rxe->ifc_ops->loopback(skb);
 | 
			
		||||
	} else {
 | 
			
		||||
		err = rxe->ifc_ops->send(rxe, pkt, skb);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (err) {
 | 
			
		||||
		rxe->xmit_errors++;
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	atomic_inc(&qp->skb_out);
 | 
			
		||||
 | 
			
		||||
	if ((qp_type(qp) != IB_QPT_RC) &&
 | 
			
		||||
	    (pkt->mask & RXE_END_MASK)) {
 | 
			
		||||
		pkt->wqe->state = wqe_state_done;
 | 
			
		||||
		rxe_run_task(&qp->comp.task, 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	goto done;
 | 
			
		||||
 | 
			
		||||
drop:
 | 
			
		||||
	kfree_skb(skb);
 | 
			
		||||
	err = 0;
 | 
			
		||||
done:
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* RXE_LOC_H */
 | 
			
		||||
							
								
								
									
										190
									
								
								drivers/infiniband/sw/rxe/rxe_mcast.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								drivers/infiniband/sw/rxe/rxe_mcast.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,190 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "rxe.h"
 | 
			
		||||
#include "rxe_loc.h"
 | 
			
		||||
 | 
			
		||||
int rxe_mcast_get_grp(struct rxe_dev *rxe, union ib_gid *mgid,
 | 
			
		||||
		      struct rxe_mc_grp **grp_p)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
	struct rxe_mc_grp *grp;
 | 
			
		||||
 | 
			
		||||
	if (rxe->attr.max_mcast_qp_attach == 0) {
 | 
			
		||||
		err = -EINVAL;
 | 
			
		||||
		goto err1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	grp = rxe_pool_get_key(&rxe->mc_grp_pool, mgid);
 | 
			
		||||
	if (grp)
 | 
			
		||||
		goto done;
 | 
			
		||||
 | 
			
		||||
	grp = rxe_alloc(&rxe->mc_grp_pool);
 | 
			
		||||
	if (!grp) {
 | 
			
		||||
		err = -ENOMEM;
 | 
			
		||||
		goto err1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	INIT_LIST_HEAD(&grp->qp_list);
 | 
			
		||||
	spin_lock_init(&grp->mcg_lock);
 | 
			
		||||
	grp->rxe = rxe;
 | 
			
		||||
 | 
			
		||||
	rxe_add_key(grp, mgid);
 | 
			
		||||
 | 
			
		||||
	err = rxe->ifc_ops->mcast_add(rxe, mgid);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err2;
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
	*grp_p = grp;
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err2:
 | 
			
		||||
	rxe_drop_ref(grp);
 | 
			
		||||
err1:
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rxe_mcast_add_grp_elem(struct rxe_dev *rxe, struct rxe_qp *qp,
 | 
			
		||||
			   struct rxe_mc_grp *grp)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
	struct rxe_mc_elem *elem;
 | 
			
		||||
 | 
			
		||||
	/* check to see of the qp is already a member of the group */
 | 
			
		||||
	spin_lock_bh(&qp->grp_lock);
 | 
			
		||||
	spin_lock_bh(&grp->mcg_lock);
 | 
			
		||||
	list_for_each_entry(elem, &grp->qp_list, qp_list) {
 | 
			
		||||
		if (elem->qp == qp) {
 | 
			
		||||
			err = 0;
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (grp->num_qp >= rxe->attr.max_mcast_qp_attach) {
 | 
			
		||||
		err = -ENOMEM;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	elem = rxe_alloc(&rxe->mc_elem_pool);
 | 
			
		||||
	if (!elem) {
 | 
			
		||||
		err = -ENOMEM;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* each qp holds a ref on the grp */
 | 
			
		||||
	rxe_add_ref(grp);
 | 
			
		||||
 | 
			
		||||
	grp->num_qp++;
 | 
			
		||||
	elem->qp = qp;
 | 
			
		||||
	elem->grp = grp;
 | 
			
		||||
 | 
			
		||||
	list_add(&elem->qp_list, &grp->qp_list);
 | 
			
		||||
	list_add(&elem->grp_list, &qp->grp_list);
 | 
			
		||||
 | 
			
		||||
	err = 0;
 | 
			
		||||
out:
 | 
			
		||||
	spin_unlock_bh(&grp->mcg_lock);
 | 
			
		||||
	spin_unlock_bh(&qp->grp_lock);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rxe_mcast_drop_grp_elem(struct rxe_dev *rxe, struct rxe_qp *qp,
 | 
			
		||||
			    union ib_gid *mgid)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_mc_grp *grp;
 | 
			
		||||
	struct rxe_mc_elem *elem, *tmp;
 | 
			
		||||
 | 
			
		||||
	grp = rxe_pool_get_key(&rxe->mc_grp_pool, mgid);
 | 
			
		||||
	if (!grp)
 | 
			
		||||
		goto err1;
 | 
			
		||||
 | 
			
		||||
	spin_lock_bh(&qp->grp_lock);
 | 
			
		||||
	spin_lock_bh(&grp->mcg_lock);
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry_safe(elem, tmp, &grp->qp_list, qp_list) {
 | 
			
		||||
		if (elem->qp == qp) {
 | 
			
		||||
			list_del(&elem->qp_list);
 | 
			
		||||
			list_del(&elem->grp_list);
 | 
			
		||||
			grp->num_qp--;
 | 
			
		||||
 | 
			
		||||
			spin_unlock_bh(&grp->mcg_lock);
 | 
			
		||||
			spin_unlock_bh(&qp->grp_lock);
 | 
			
		||||
			rxe_drop_ref(elem);
 | 
			
		||||
			rxe_drop_ref(grp);	/* ref held by QP */
 | 
			
		||||
			rxe_drop_ref(grp);	/* ref from get_key */
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	spin_unlock_bh(&grp->mcg_lock);
 | 
			
		||||
	spin_unlock_bh(&qp->grp_lock);
 | 
			
		||||
	rxe_drop_ref(grp);			/* ref from get_key */
 | 
			
		||||
err1:
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rxe_drop_all_mcast_groups(struct rxe_qp *qp)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_mc_grp *grp;
 | 
			
		||||
	struct rxe_mc_elem *elem;
 | 
			
		||||
 | 
			
		||||
	while (1) {
 | 
			
		||||
		spin_lock_bh(&qp->grp_lock);
 | 
			
		||||
		if (list_empty(&qp->grp_list)) {
 | 
			
		||||
			spin_unlock_bh(&qp->grp_lock);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		elem = list_first_entry(&qp->grp_list, struct rxe_mc_elem,
 | 
			
		||||
					grp_list);
 | 
			
		||||
		list_del(&elem->grp_list);
 | 
			
		||||
		spin_unlock_bh(&qp->grp_lock);
 | 
			
		||||
 | 
			
		||||
		grp = elem->grp;
 | 
			
		||||
		spin_lock_bh(&grp->mcg_lock);
 | 
			
		||||
		list_del(&elem->qp_list);
 | 
			
		||||
		grp->num_qp--;
 | 
			
		||||
		spin_unlock_bh(&grp->mcg_lock);
 | 
			
		||||
		rxe_drop_ref(grp);
 | 
			
		||||
		rxe_drop_ref(elem);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rxe_mc_cleanup(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_mc_grp *grp = arg;
 | 
			
		||||
	struct rxe_dev *rxe = grp->rxe;
 | 
			
		||||
 | 
			
		||||
	rxe_drop_key(grp);
 | 
			
		||||
	rxe->ifc_ops->mcast_delete(rxe, &grp->mgid);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										173
									
								
								drivers/infiniband/sw/rxe/rxe_mmap.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								drivers/infiniband/sw/rxe/rxe_mmap.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,173 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <linux/vmalloc.h>
 | 
			
		||||
#include <linux/mm.h>
 | 
			
		||||
#include <linux/errno.h>
 | 
			
		||||
#include <asm/pgtable.h>
 | 
			
		||||
 | 
			
		||||
#include "rxe.h"
 | 
			
		||||
#include "rxe_loc.h"
 | 
			
		||||
#include "rxe_queue.h"
 | 
			
		||||
 | 
			
		||||
void rxe_mmap_release(struct kref *ref)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_mmap_info *ip = container_of(ref,
 | 
			
		||||
					struct rxe_mmap_info, ref);
 | 
			
		||||
	struct rxe_dev *rxe = to_rdev(ip->context->device);
 | 
			
		||||
 | 
			
		||||
	spin_lock_bh(&rxe->pending_lock);
 | 
			
		||||
 | 
			
		||||
	if (!list_empty(&ip->pending_mmaps))
 | 
			
		||||
		list_del(&ip->pending_mmaps);
 | 
			
		||||
 | 
			
		||||
	spin_unlock_bh(&rxe->pending_lock);
 | 
			
		||||
 | 
			
		||||
	vfree(ip->obj);		/* buf */
 | 
			
		||||
	kfree(ip);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * open and close keep track of how many times the memory region is mapped,
 | 
			
		||||
 * to avoid releasing it.
 | 
			
		||||
 */
 | 
			
		||||
static void rxe_vma_open(struct vm_area_struct *vma)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_mmap_info *ip = vma->vm_private_data;
 | 
			
		||||
 | 
			
		||||
	kref_get(&ip->ref);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rxe_vma_close(struct vm_area_struct *vma)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_mmap_info *ip = vma->vm_private_data;
 | 
			
		||||
 | 
			
		||||
	kref_put(&ip->ref, rxe_mmap_release);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct vm_operations_struct rxe_vm_ops = {
 | 
			
		||||
	.open = rxe_vma_open,
 | 
			
		||||
	.close = rxe_vma_close,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rxe_mmap - create a new mmap region
 | 
			
		||||
 * @context: the IB user context of the process making the mmap() call
 | 
			
		||||
 * @vma: the VMA to be initialized
 | 
			
		||||
 * Return zero if the mmap is OK. Otherwise, return an errno.
 | 
			
		||||
 */
 | 
			
		||||
int rxe_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_dev *rxe = to_rdev(context->device);
 | 
			
		||||
	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
 | 
			
		||||
	unsigned long size = vma->vm_end - vma->vm_start;
 | 
			
		||||
	struct rxe_mmap_info *ip, *pp;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Search the device's list of objects waiting for a mmap call.
 | 
			
		||||
	 * Normally, this list is very short since a call to create a
 | 
			
		||||
	 * CQ, QP, or SRQ is soon followed by a call to mmap().
 | 
			
		||||
	 */
 | 
			
		||||
	spin_lock_bh(&rxe->pending_lock);
 | 
			
		||||
	list_for_each_entry_safe(ip, pp, &rxe->pending_mmaps, pending_mmaps) {
 | 
			
		||||
		if (context != ip->context || (__u64)offset != ip->info.offset)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/* Don't allow a mmap larger than the object. */
 | 
			
		||||
		if (size > ip->info.size) {
 | 
			
		||||
			pr_err("mmap region is larger than the object!\n");
 | 
			
		||||
			spin_unlock_bh(&rxe->pending_lock);
 | 
			
		||||
			ret = -EINVAL;
 | 
			
		||||
			goto done;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		goto found_it;
 | 
			
		||||
	}
 | 
			
		||||
	pr_warn("unable to find pending mmap info\n");
 | 
			
		||||
	spin_unlock_bh(&rxe->pending_lock);
 | 
			
		||||
	ret = -EINVAL;
 | 
			
		||||
	goto done;
 | 
			
		||||
 | 
			
		||||
found_it:
 | 
			
		||||
	list_del_init(&ip->pending_mmaps);
 | 
			
		||||
	spin_unlock_bh(&rxe->pending_lock);
 | 
			
		||||
 | 
			
		||||
	ret = remap_vmalloc_range(vma, ip->obj, 0);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		pr_err("rxe: err %d from remap_vmalloc_range\n", ret);
 | 
			
		||||
		goto done;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vma->vm_ops = &rxe_vm_ops;
 | 
			
		||||
	vma->vm_private_data = ip;
 | 
			
		||||
	rxe_vma_open(vma);
 | 
			
		||||
done:
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Allocate information for rxe_mmap
 | 
			
		||||
 */
 | 
			
		||||
struct rxe_mmap_info *rxe_create_mmap_info(struct rxe_dev *rxe,
 | 
			
		||||
					   u32 size,
 | 
			
		||||
					   struct ib_ucontext *context,
 | 
			
		||||
					   void *obj)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_mmap_info *ip;
 | 
			
		||||
 | 
			
		||||
	ip = kmalloc(sizeof(*ip), GFP_KERNEL);
 | 
			
		||||
	if (!ip)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	size = PAGE_ALIGN(size);
 | 
			
		||||
 | 
			
		||||
	spin_lock_bh(&rxe->mmap_offset_lock);
 | 
			
		||||
 | 
			
		||||
	if (rxe->mmap_offset == 0)
 | 
			
		||||
		rxe->mmap_offset = PAGE_SIZE;
 | 
			
		||||
 | 
			
		||||
	ip->info.offset = rxe->mmap_offset;
 | 
			
		||||
	rxe->mmap_offset += size;
 | 
			
		||||
 | 
			
		||||
	spin_unlock_bh(&rxe->mmap_offset_lock);
 | 
			
		||||
 | 
			
		||||
	INIT_LIST_HEAD(&ip->pending_mmaps);
 | 
			
		||||
	ip->info.size = size;
 | 
			
		||||
	ip->context = context;
 | 
			
		||||
	ip->obj = obj;
 | 
			
		||||
	kref_init(&ip->ref);
 | 
			
		||||
 | 
			
		||||
	return ip;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										643
									
								
								drivers/infiniband/sw/rxe/rxe_mr.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										643
									
								
								drivers/infiniband/sw/rxe/rxe_mr.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,643 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "rxe.h"
 | 
			
		||||
#include "rxe_loc.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * lfsr (linear feedback shift register) with period 255
 | 
			
		||||
 */
 | 
			
		||||
static u8 rxe_get_key(void)
 | 
			
		||||
{
 | 
			
		||||
	static unsigned key = 1;
 | 
			
		||||
 | 
			
		||||
	key = key << 1;
 | 
			
		||||
 | 
			
		||||
	key |= (0 != (key & 0x100)) ^ (0 != (key & 0x10))
 | 
			
		||||
		^ (0 != (key & 0x80)) ^ (0 != (key & 0x40));
 | 
			
		||||
 | 
			
		||||
	key &= 0xff;
 | 
			
		||||
 | 
			
		||||
	return key;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mem_check_range(struct rxe_mem *mem, u64 iova, size_t length)
 | 
			
		||||
{
 | 
			
		||||
	switch (mem->type) {
 | 
			
		||||
	case RXE_MEM_TYPE_DMA:
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	case RXE_MEM_TYPE_MR:
 | 
			
		||||
	case RXE_MEM_TYPE_FMR:
 | 
			
		||||
		return ((iova < mem->iova) ||
 | 
			
		||||
			((iova + length) > (mem->iova + mem->length))) ?
 | 
			
		||||
			-EFAULT : 0;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		return -EFAULT;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define IB_ACCESS_REMOTE	(IB_ACCESS_REMOTE_READ		\
 | 
			
		||||
				| IB_ACCESS_REMOTE_WRITE	\
 | 
			
		||||
				| IB_ACCESS_REMOTE_ATOMIC)
 | 
			
		||||
 | 
			
		||||
static void rxe_mem_init(int access, struct rxe_mem *mem)
 | 
			
		||||
{
 | 
			
		||||
	u32 lkey = mem->pelem.index << 8 | rxe_get_key();
 | 
			
		||||
	u32 rkey = (access & IB_ACCESS_REMOTE) ? lkey : 0;
 | 
			
		||||
 | 
			
		||||
	if (mem->pelem.pool->type == RXE_TYPE_MR) {
 | 
			
		||||
		mem->ibmr.lkey		= lkey;
 | 
			
		||||
		mem->ibmr.rkey		= rkey;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mem->lkey		= lkey;
 | 
			
		||||
	mem->rkey		= rkey;
 | 
			
		||||
	mem->state		= RXE_MEM_STATE_INVALID;
 | 
			
		||||
	mem->type		= RXE_MEM_TYPE_NONE;
 | 
			
		||||
	mem->map_shift		= ilog2(RXE_BUF_PER_MAP);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rxe_mem_cleanup(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_mem *mem = arg;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (mem->umem)
 | 
			
		||||
		ib_umem_release(mem->umem);
 | 
			
		||||
 | 
			
		||||
	if (mem->map) {
 | 
			
		||||
		for (i = 0; i < mem->num_map; i++)
 | 
			
		||||
			kfree(mem->map[i]);
 | 
			
		||||
 | 
			
		||||
		kfree(mem->map);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rxe_mem_alloc(struct rxe_dev *rxe, struct rxe_mem *mem, int num_buf)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	int num_map;
 | 
			
		||||
	struct rxe_map **map = mem->map;
 | 
			
		||||
 | 
			
		||||
	num_map = (num_buf + RXE_BUF_PER_MAP - 1) / RXE_BUF_PER_MAP;
 | 
			
		||||
 | 
			
		||||
	mem->map = kmalloc_array(num_map, sizeof(*map), GFP_KERNEL);
 | 
			
		||||
	if (!mem->map)
 | 
			
		||||
		goto err1;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < num_map; i++) {
 | 
			
		||||
		mem->map[i] = kmalloc(sizeof(**map), GFP_KERNEL);
 | 
			
		||||
		if (!mem->map[i])
 | 
			
		||||
			goto err2;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	WARN_ON(!is_power_of_2(RXE_BUF_PER_MAP));
 | 
			
		||||
 | 
			
		||||
	mem->map_shift	= ilog2(RXE_BUF_PER_MAP);
 | 
			
		||||
	mem->map_mask	= RXE_BUF_PER_MAP - 1;
 | 
			
		||||
 | 
			
		||||
	mem->num_buf = num_buf;
 | 
			
		||||
	mem->num_map = num_map;
 | 
			
		||||
	mem->max_buf = num_map * RXE_BUF_PER_MAP;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err2:
 | 
			
		||||
	for (i--; i >= 0; i--)
 | 
			
		||||
		kfree(mem->map[i]);
 | 
			
		||||
 | 
			
		||||
	kfree(mem->map);
 | 
			
		||||
err1:
 | 
			
		||||
	return -ENOMEM;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rxe_mem_init_dma(struct rxe_dev *rxe, struct rxe_pd *pd,
 | 
			
		||||
		     int access, struct rxe_mem *mem)
 | 
			
		||||
{
 | 
			
		||||
	rxe_mem_init(access, mem);
 | 
			
		||||
 | 
			
		||||
	mem->pd			= pd;
 | 
			
		||||
	mem->access		= access;
 | 
			
		||||
	mem->state		= RXE_MEM_STATE_VALID;
 | 
			
		||||
	mem->type		= RXE_MEM_TYPE_DMA;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rxe_mem_init_user(struct rxe_dev *rxe, struct rxe_pd *pd, u64 start,
 | 
			
		||||
		      u64 length, u64 iova, int access, struct ib_udata *udata,
 | 
			
		||||
		      struct rxe_mem *mem)
 | 
			
		||||
{
 | 
			
		||||
	int			entry;
 | 
			
		||||
	struct rxe_map		**map;
 | 
			
		||||
	struct rxe_phys_buf	*buf = NULL;
 | 
			
		||||
	struct ib_umem		*umem;
 | 
			
		||||
	struct scatterlist	*sg;
 | 
			
		||||
	int			num_buf;
 | 
			
		||||
	void			*vaddr;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	umem = ib_umem_get(pd->ibpd.uobject->context, start, length, access, 0);
 | 
			
		||||
	if (IS_ERR(umem)) {
 | 
			
		||||
		pr_warn("err %d from rxe_umem_get\n",
 | 
			
		||||
			(int)PTR_ERR(umem));
 | 
			
		||||
		err = -EINVAL;
 | 
			
		||||
		goto err1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mem->umem = umem;
 | 
			
		||||
	num_buf = umem->nmap;
 | 
			
		||||
 | 
			
		||||
	rxe_mem_init(access, mem);
 | 
			
		||||
 | 
			
		||||
	err = rxe_mem_alloc(rxe, mem, num_buf);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		pr_warn("err %d from rxe_mem_alloc\n", err);
 | 
			
		||||
		ib_umem_release(umem);
 | 
			
		||||
		goto err1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	WARN_ON(!is_power_of_2(umem->page_size));
 | 
			
		||||
 | 
			
		||||
	mem->page_shift		= ilog2(umem->page_size);
 | 
			
		||||
	mem->page_mask		= umem->page_size - 1;
 | 
			
		||||
 | 
			
		||||
	num_buf			= 0;
 | 
			
		||||
	map			= mem->map;
 | 
			
		||||
	if (length > 0) {
 | 
			
		||||
		buf = map[0]->buf;
 | 
			
		||||
 | 
			
		||||
		for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) {
 | 
			
		||||
			vaddr = page_address(sg_page(sg));
 | 
			
		||||
			if (!vaddr) {
 | 
			
		||||
				pr_warn("null vaddr\n");
 | 
			
		||||
				err = -ENOMEM;
 | 
			
		||||
				goto err1;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			buf->addr = (uintptr_t)vaddr;
 | 
			
		||||
			buf->size = umem->page_size;
 | 
			
		||||
			num_buf++;
 | 
			
		||||
			buf++;
 | 
			
		||||
 | 
			
		||||
			if (num_buf >= RXE_BUF_PER_MAP) {
 | 
			
		||||
				map++;
 | 
			
		||||
				buf = map[0]->buf;
 | 
			
		||||
				num_buf = 0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mem->pd			= pd;
 | 
			
		||||
	mem->umem		= umem;
 | 
			
		||||
	mem->access		= access;
 | 
			
		||||
	mem->length		= length;
 | 
			
		||||
	mem->iova		= iova;
 | 
			
		||||
	mem->va			= start;
 | 
			
		||||
	mem->offset		= ib_umem_offset(umem);
 | 
			
		||||
	mem->state		= RXE_MEM_STATE_VALID;
 | 
			
		||||
	mem->type		= RXE_MEM_TYPE_MR;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err1:
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rxe_mem_init_fast(struct rxe_dev *rxe, struct rxe_pd *pd,
 | 
			
		||||
		      int max_pages, struct rxe_mem *mem)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	rxe_mem_init(0, mem);
 | 
			
		||||
 | 
			
		||||
	/* In fastreg, we also set the rkey */
 | 
			
		||||
	mem->ibmr.rkey = mem->ibmr.lkey;
 | 
			
		||||
 | 
			
		||||
	err = rxe_mem_alloc(rxe, mem, max_pages);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err1;
 | 
			
		||||
 | 
			
		||||
	mem->pd			= pd;
 | 
			
		||||
	mem->max_buf		= max_pages;
 | 
			
		||||
	mem->state		= RXE_MEM_STATE_FREE;
 | 
			
		||||
	mem->type		= RXE_MEM_TYPE_MR;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err1:
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void lookup_iova(
 | 
			
		||||
	struct rxe_mem	*mem,
 | 
			
		||||
	u64			iova,
 | 
			
		||||
	int			*m_out,
 | 
			
		||||
	int			*n_out,
 | 
			
		||||
	size_t			*offset_out)
 | 
			
		||||
{
 | 
			
		||||
	size_t			offset = iova - mem->iova + mem->offset;
 | 
			
		||||
	int			map_index;
 | 
			
		||||
	int			buf_index;
 | 
			
		||||
	u64			length;
 | 
			
		||||
 | 
			
		||||
	if (likely(mem->page_shift)) {
 | 
			
		||||
		*offset_out = offset & mem->page_mask;
 | 
			
		||||
		offset >>= mem->page_shift;
 | 
			
		||||
		*n_out = offset & mem->map_mask;
 | 
			
		||||
		*m_out = offset >> mem->map_shift;
 | 
			
		||||
	} else {
 | 
			
		||||
		map_index = 0;
 | 
			
		||||
		buf_index = 0;
 | 
			
		||||
 | 
			
		||||
		length = mem->map[map_index]->buf[buf_index].size;
 | 
			
		||||
 | 
			
		||||
		while (offset >= length) {
 | 
			
		||||
			offset -= length;
 | 
			
		||||
			buf_index++;
 | 
			
		||||
 | 
			
		||||
			if (buf_index == RXE_BUF_PER_MAP) {
 | 
			
		||||
				map_index++;
 | 
			
		||||
				buf_index = 0;
 | 
			
		||||
			}
 | 
			
		||||
			length = mem->map[map_index]->buf[buf_index].size;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		*m_out = map_index;
 | 
			
		||||
		*n_out = buf_index;
 | 
			
		||||
		*offset_out = offset;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *iova_to_vaddr(struct rxe_mem *mem, u64 iova, int length)
 | 
			
		||||
{
 | 
			
		||||
	size_t offset;
 | 
			
		||||
	int m, n;
 | 
			
		||||
	void *addr;
 | 
			
		||||
 | 
			
		||||
	if (mem->state != RXE_MEM_STATE_VALID) {
 | 
			
		||||
		pr_warn("mem not in valid state\n");
 | 
			
		||||
		addr = NULL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!mem->map) {
 | 
			
		||||
		addr = (void *)(uintptr_t)iova;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mem_check_range(mem, iova, length)) {
 | 
			
		||||
		pr_warn("range violation\n");
 | 
			
		||||
		addr = NULL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lookup_iova(mem, iova, &m, &n, &offset);
 | 
			
		||||
 | 
			
		||||
	if (offset + length > mem->map[m]->buf[n].size) {
 | 
			
		||||
		pr_warn("crosses page boundary\n");
 | 
			
		||||
		addr = NULL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	addr = (void *)(uintptr_t)mem->map[m]->buf[n].addr + offset;
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	return addr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* copy data from a range (vaddr, vaddr+length-1) to or from
 | 
			
		||||
 * a mem object starting at iova. Compute incremental value of
 | 
			
		||||
 * crc32 if crcp is not zero. caller must hold a reference to mem
 | 
			
		||||
 */
 | 
			
		||||
int rxe_mem_copy(struct rxe_mem *mem, u64 iova, void *addr, int length,
 | 
			
		||||
		 enum copy_direction dir, u32 *crcp)
 | 
			
		||||
{
 | 
			
		||||
	int			err;
 | 
			
		||||
	int			bytes;
 | 
			
		||||
	u8			*va;
 | 
			
		||||
	struct rxe_map		**map;
 | 
			
		||||
	struct rxe_phys_buf	*buf;
 | 
			
		||||
	int			m;
 | 
			
		||||
	int			i;
 | 
			
		||||
	size_t			offset;
 | 
			
		||||
	u32			crc = crcp ? (*crcp) : 0;
 | 
			
		||||
 | 
			
		||||
	if (mem->type == RXE_MEM_TYPE_DMA) {
 | 
			
		||||
		u8 *src, *dest;
 | 
			
		||||
 | 
			
		||||
		src  = (dir == to_mem_obj) ?
 | 
			
		||||
			addr : ((void *)(uintptr_t)iova);
 | 
			
		||||
 | 
			
		||||
		dest = (dir == to_mem_obj) ?
 | 
			
		||||
			((void *)(uintptr_t)iova) : addr;
 | 
			
		||||
 | 
			
		||||
		if (crcp)
 | 
			
		||||
			*crcp = crc32_le(*crcp, src, length);
 | 
			
		||||
 | 
			
		||||
		memcpy(dest, src, length);
 | 
			
		||||
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	WARN_ON(!mem->map);
 | 
			
		||||
 | 
			
		||||
	err = mem_check_range(mem, iova, length);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		err = -EFAULT;
 | 
			
		||||
		goto err1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lookup_iova(mem, iova, &m, &i, &offset);
 | 
			
		||||
 | 
			
		||||
	map	= mem->map + m;
 | 
			
		||||
	buf	= map[0]->buf + i;
 | 
			
		||||
 | 
			
		||||
	while (length > 0) {
 | 
			
		||||
		u8 *src, *dest;
 | 
			
		||||
 | 
			
		||||
		va	= (u8 *)(uintptr_t)buf->addr + offset;
 | 
			
		||||
		src  = (dir == to_mem_obj) ? addr : va;
 | 
			
		||||
		dest = (dir == to_mem_obj) ? va : addr;
 | 
			
		||||
 | 
			
		||||
		bytes	= buf->size - offset;
 | 
			
		||||
 | 
			
		||||
		if (bytes > length)
 | 
			
		||||
			bytes = length;
 | 
			
		||||
 | 
			
		||||
		if (crcp)
 | 
			
		||||
			crc = crc32_le(crc, src, bytes);
 | 
			
		||||
 | 
			
		||||
		memcpy(dest, src, bytes);
 | 
			
		||||
 | 
			
		||||
		length	-= bytes;
 | 
			
		||||
		addr	+= bytes;
 | 
			
		||||
 | 
			
		||||
		offset	= 0;
 | 
			
		||||
		buf++;
 | 
			
		||||
		i++;
 | 
			
		||||
 | 
			
		||||
		if (i == RXE_BUF_PER_MAP) {
 | 
			
		||||
			i = 0;
 | 
			
		||||
			map++;
 | 
			
		||||
			buf = map[0]->buf;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (crcp)
 | 
			
		||||
		*crcp = crc;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err1:
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* copy data in or out of a wqe, i.e. sg list
 | 
			
		||||
 * under the control of a dma descriptor
 | 
			
		||||
 */
 | 
			
		||||
int copy_data(
 | 
			
		||||
	struct rxe_dev		*rxe,
 | 
			
		||||
	struct rxe_pd		*pd,
 | 
			
		||||
	int			access,
 | 
			
		||||
	struct rxe_dma_info	*dma,
 | 
			
		||||
	void			*addr,
 | 
			
		||||
	int			length,
 | 
			
		||||
	enum copy_direction	dir,
 | 
			
		||||
	u32			*crcp)
 | 
			
		||||
{
 | 
			
		||||
	int			bytes;
 | 
			
		||||
	struct rxe_sge		*sge	= &dma->sge[dma->cur_sge];
 | 
			
		||||
	int			offset	= dma->sge_offset;
 | 
			
		||||
	int			resid	= dma->resid;
 | 
			
		||||
	struct rxe_mem		*mem	= NULL;
 | 
			
		||||
	u64			iova;
 | 
			
		||||
	int			err;
 | 
			
		||||
 | 
			
		||||
	if (length == 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (length > resid) {
 | 
			
		||||
		err = -EINVAL;
 | 
			
		||||
		goto err2;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (sge->length && (offset < sge->length)) {
 | 
			
		||||
		mem = lookup_mem(pd, access, sge->lkey, lookup_local);
 | 
			
		||||
		if (!mem) {
 | 
			
		||||
			err = -EINVAL;
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while (length > 0) {
 | 
			
		||||
		bytes = length;
 | 
			
		||||
 | 
			
		||||
		if (offset >= sge->length) {
 | 
			
		||||
			if (mem) {
 | 
			
		||||
				rxe_drop_ref(mem);
 | 
			
		||||
				mem = NULL;
 | 
			
		||||
			}
 | 
			
		||||
			sge++;
 | 
			
		||||
			dma->cur_sge++;
 | 
			
		||||
			offset = 0;
 | 
			
		||||
 | 
			
		||||
			if (dma->cur_sge >= dma->num_sge) {
 | 
			
		||||
				err = -ENOSPC;
 | 
			
		||||
				goto err2;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (sge->length) {
 | 
			
		||||
				mem = lookup_mem(pd, access, sge->lkey,
 | 
			
		||||
						 lookup_local);
 | 
			
		||||
				if (!mem) {
 | 
			
		||||
					err = -EINVAL;
 | 
			
		||||
					goto err1;
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (bytes > sge->length - offset)
 | 
			
		||||
			bytes = sge->length - offset;
 | 
			
		||||
 | 
			
		||||
		if (bytes > 0) {
 | 
			
		||||
			iova = sge->addr + offset;
 | 
			
		||||
 | 
			
		||||
			err = rxe_mem_copy(mem, iova, addr, bytes, dir, crcp);
 | 
			
		||||
			if (err)
 | 
			
		||||
				goto err2;
 | 
			
		||||
 | 
			
		||||
			offset	+= bytes;
 | 
			
		||||
			resid	-= bytes;
 | 
			
		||||
			length	-= bytes;
 | 
			
		||||
			addr	+= bytes;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dma->sge_offset = offset;
 | 
			
		||||
	dma->resid	= resid;
 | 
			
		||||
 | 
			
		||||
	if (mem)
 | 
			
		||||
		rxe_drop_ref(mem);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err2:
 | 
			
		||||
	if (mem)
 | 
			
		||||
		rxe_drop_ref(mem);
 | 
			
		||||
err1:
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int advance_dma_data(struct rxe_dma_info *dma, unsigned int length)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_sge		*sge	= &dma->sge[dma->cur_sge];
 | 
			
		||||
	int			offset	= dma->sge_offset;
 | 
			
		||||
	int			resid	= dma->resid;
 | 
			
		||||
 | 
			
		||||
	while (length) {
 | 
			
		||||
		unsigned int bytes;
 | 
			
		||||
 | 
			
		||||
		if (offset >= sge->length) {
 | 
			
		||||
			sge++;
 | 
			
		||||
			dma->cur_sge++;
 | 
			
		||||
			offset = 0;
 | 
			
		||||
			if (dma->cur_sge >= dma->num_sge)
 | 
			
		||||
				return -ENOSPC;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		bytes = length;
 | 
			
		||||
 | 
			
		||||
		if (bytes > sge->length - offset)
 | 
			
		||||
			bytes = sge->length - offset;
 | 
			
		||||
 | 
			
		||||
		offset	+= bytes;
 | 
			
		||||
		resid	-= bytes;
 | 
			
		||||
		length	-= bytes;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dma->sge_offset = offset;
 | 
			
		||||
	dma->resid	= resid;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* (1) find the mem (mr or mw) corresponding to lkey/rkey
 | 
			
		||||
 *     depending on lookup_type
 | 
			
		||||
 * (2) verify that the (qp) pd matches the mem pd
 | 
			
		||||
 * (3) verify that the mem can support the requested access
 | 
			
		||||
 * (4) verify that mem state is valid
 | 
			
		||||
 */
 | 
			
		||||
struct rxe_mem *lookup_mem(struct rxe_pd *pd, int access, u32 key,
 | 
			
		||||
			   enum lookup_type type)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_mem *mem;
 | 
			
		||||
	struct rxe_dev *rxe = to_rdev(pd->ibpd.device);
 | 
			
		||||
	int index = key >> 8;
 | 
			
		||||
 | 
			
		||||
	if (index >= RXE_MIN_MR_INDEX && index <= RXE_MAX_MR_INDEX) {
 | 
			
		||||
		mem = rxe_pool_get_index(&rxe->mr_pool, index);
 | 
			
		||||
		if (!mem)
 | 
			
		||||
			goto err1;
 | 
			
		||||
	} else {
 | 
			
		||||
		goto err1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((type == lookup_local && mem->lkey != key) ||
 | 
			
		||||
	    (type == lookup_remote && mem->rkey != key))
 | 
			
		||||
		goto err2;
 | 
			
		||||
 | 
			
		||||
	if (mem->pd != pd)
 | 
			
		||||
		goto err2;
 | 
			
		||||
 | 
			
		||||
	if (access && !(access & mem->access))
 | 
			
		||||
		goto err2;
 | 
			
		||||
 | 
			
		||||
	if (mem->state != RXE_MEM_STATE_VALID)
 | 
			
		||||
		goto err2;
 | 
			
		||||
 | 
			
		||||
	return mem;
 | 
			
		||||
 | 
			
		||||
err2:
 | 
			
		||||
	rxe_drop_ref(mem);
 | 
			
		||||
err1:
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rxe_mem_map_pages(struct rxe_dev *rxe, struct rxe_mem *mem,
 | 
			
		||||
		      u64 *page, int num_pages, u64 iova)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	int num_buf;
 | 
			
		||||
	int err;
 | 
			
		||||
	struct rxe_map **map;
 | 
			
		||||
	struct rxe_phys_buf *buf;
 | 
			
		||||
	int page_size;
 | 
			
		||||
 | 
			
		||||
	if (num_pages > mem->max_buf) {
 | 
			
		||||
		err = -EINVAL;
 | 
			
		||||
		goto err1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	num_buf		= 0;
 | 
			
		||||
	page_size	= 1 << mem->page_shift;
 | 
			
		||||
	map		= mem->map;
 | 
			
		||||
	buf		= map[0]->buf;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < num_pages; i++) {
 | 
			
		||||
		buf->addr = *page++;
 | 
			
		||||
		buf->size = page_size;
 | 
			
		||||
		buf++;
 | 
			
		||||
		num_buf++;
 | 
			
		||||
 | 
			
		||||
		if (num_buf == RXE_BUF_PER_MAP) {
 | 
			
		||||
			map++;
 | 
			
		||||
			buf = map[0]->buf;
 | 
			
		||||
			num_buf = 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mem->iova	= iova;
 | 
			
		||||
	mem->va		= iova;
 | 
			
		||||
	mem->length	= num_pages << mem->page_shift;
 | 
			
		||||
	mem->state	= RXE_MEM_STATE_VALID;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err1:
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										708
									
								
								drivers/infiniband/sw/rxe/rxe_net.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										708
									
								
								drivers/infiniband/sw/rxe/rxe_net.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,708 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/skbuff.h>
 | 
			
		||||
#include <linux/if_arp.h>
 | 
			
		||||
#include <linux/netdevice.h>
 | 
			
		||||
#include <linux/if.h>
 | 
			
		||||
#include <linux/if_vlan.h>
 | 
			
		||||
#include <net/udp_tunnel.h>
 | 
			
		||||
#include <net/sch_generic.h>
 | 
			
		||||
#include <linux/netfilter.h>
 | 
			
		||||
#include <rdma/ib_addr.h>
 | 
			
		||||
 | 
			
		||||
#include "rxe.h"
 | 
			
		||||
#include "rxe_net.h"
 | 
			
		||||
#include "rxe_loc.h"
 | 
			
		||||
 | 
			
		||||
static LIST_HEAD(rxe_dev_list);
 | 
			
		||||
static spinlock_t dev_list_lock; /* spinlock for device list */
 | 
			
		||||
 | 
			
		||||
struct rxe_dev *net_to_rxe(struct net_device *ndev)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_dev *rxe;
 | 
			
		||||
	struct rxe_dev *found = NULL;
 | 
			
		||||
 | 
			
		||||
	spin_lock_bh(&dev_list_lock);
 | 
			
		||||
	list_for_each_entry(rxe, &rxe_dev_list, list) {
 | 
			
		||||
		if (rxe->ndev == ndev) {
 | 
			
		||||
			found = rxe;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	spin_unlock_bh(&dev_list_lock);
 | 
			
		||||
 | 
			
		||||
	return found;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct rxe_dev *get_rxe_by_name(const char* name)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_dev *rxe;
 | 
			
		||||
	struct rxe_dev *found = NULL;
 | 
			
		||||
 | 
			
		||||
	spin_lock_bh(&dev_list_lock);
 | 
			
		||||
	list_for_each_entry(rxe, &rxe_dev_list, list) {
 | 
			
		||||
		if (!strcmp(name, rxe->ib_dev.name)) {
 | 
			
		||||
			found = rxe;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	spin_unlock_bh(&dev_list_lock);
 | 
			
		||||
	return found;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct rxe_recv_sockets recv_sockets;
 | 
			
		||||
 | 
			
		||||
static __be64 rxe_mac_to_eui64(struct net_device *ndev)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char *mac_addr = ndev->dev_addr;
 | 
			
		||||
	__be64 eui64;
 | 
			
		||||
	unsigned char *dst = (unsigned char *)&eui64;
 | 
			
		||||
 | 
			
		||||
	dst[0] = mac_addr[0] ^ 2;
 | 
			
		||||
	dst[1] = mac_addr[1];
 | 
			
		||||
	dst[2] = mac_addr[2];
 | 
			
		||||
	dst[3] = 0xff;
 | 
			
		||||
	dst[4] = 0xfe;
 | 
			
		||||
	dst[5] = mac_addr[3];
 | 
			
		||||
	dst[6] = mac_addr[4];
 | 
			
		||||
	dst[7] = mac_addr[5];
 | 
			
		||||
 | 
			
		||||
	return eui64;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static __be64 node_guid(struct rxe_dev *rxe)
 | 
			
		||||
{
 | 
			
		||||
	return rxe_mac_to_eui64(rxe->ndev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static __be64 port_guid(struct rxe_dev *rxe)
 | 
			
		||||
{
 | 
			
		||||
	return rxe_mac_to_eui64(rxe->ndev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct device *dma_device(struct rxe_dev *rxe)
 | 
			
		||||
{
 | 
			
		||||
	struct net_device *ndev;
 | 
			
		||||
 | 
			
		||||
	ndev = rxe->ndev;
 | 
			
		||||
 | 
			
		||||
	if (ndev->priv_flags & IFF_802_1Q_VLAN)
 | 
			
		||||
		ndev = vlan_dev_real_dev(ndev);
 | 
			
		||||
 | 
			
		||||
	return ndev->dev.parent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int mcast_add(struct rxe_dev *rxe, union ib_gid *mgid)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
	unsigned char ll_addr[ETH_ALEN];
 | 
			
		||||
 | 
			
		||||
	ipv6_eth_mc_map((struct in6_addr *)mgid->raw, ll_addr);
 | 
			
		||||
	err = dev_mc_add(rxe->ndev, ll_addr);
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int mcast_delete(struct rxe_dev *rxe, union ib_gid *mgid)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
	unsigned char ll_addr[ETH_ALEN];
 | 
			
		||||
 | 
			
		||||
	ipv6_eth_mc_map((struct in6_addr *)mgid->raw, ll_addr);
 | 
			
		||||
	err = dev_mc_del(rxe->ndev, ll_addr);
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct dst_entry *rxe_find_route4(struct net_device *ndev,
 | 
			
		||||
				  struct in_addr *saddr,
 | 
			
		||||
				  struct in_addr *daddr)
 | 
			
		||||
{
 | 
			
		||||
	struct rtable *rt;
 | 
			
		||||
	struct flowi4 fl = { { 0 } };
 | 
			
		||||
 | 
			
		||||
	memset(&fl, 0, sizeof(fl));
 | 
			
		||||
	fl.flowi4_oif = ndev->ifindex;
 | 
			
		||||
	memcpy(&fl.saddr, saddr, sizeof(*saddr));
 | 
			
		||||
	memcpy(&fl.daddr, daddr, sizeof(*daddr));
 | 
			
		||||
	fl.flowi4_proto = IPPROTO_UDP;
 | 
			
		||||
 | 
			
		||||
	rt = ip_route_output_key(&init_net, &fl);
 | 
			
		||||
	if (IS_ERR(rt)) {
 | 
			
		||||
		pr_err_ratelimited("no route to %pI4\n", &daddr->s_addr);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &rt->dst;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if IS_ENABLED(CONFIG_IPV6)
 | 
			
		||||
static struct dst_entry *rxe_find_route6(struct net_device *ndev,
 | 
			
		||||
					 struct in6_addr *saddr,
 | 
			
		||||
					 struct in6_addr *daddr)
 | 
			
		||||
{
 | 
			
		||||
	struct dst_entry *ndst;
 | 
			
		||||
	struct flowi6 fl6 = { { 0 } };
 | 
			
		||||
 | 
			
		||||
	memset(&fl6, 0, sizeof(fl6));
 | 
			
		||||
	fl6.flowi6_oif = ndev->ifindex;
 | 
			
		||||
	memcpy(&fl6.saddr, saddr, sizeof(*saddr));
 | 
			
		||||
	memcpy(&fl6.daddr, daddr, sizeof(*daddr));
 | 
			
		||||
	fl6.flowi6_proto = IPPROTO_UDP;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ipv6_stub->ipv6_dst_lookup(sock_net(recv_sockets.sk6->sk),
 | 
			
		||||
						recv_sockets.sk6->sk, &ndst, &fl6))) {
 | 
			
		||||
		pr_err_ratelimited("no route to %pI6\n", daddr);
 | 
			
		||||
		goto put;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (unlikely(ndst->error)) {
 | 
			
		||||
		pr_err("no route to %pI6\n", daddr);
 | 
			
		||||
		goto put;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ndst;
 | 
			
		||||
put:
 | 
			
		||||
	dst_release(ndst);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
static struct dst_entry *rxe_find_route6(struct net_device *ndev,
 | 
			
		||||
					 struct in6_addr *saddr,
 | 
			
		||||
					 struct in6_addr *daddr)
 | 
			
		||||
{
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static int rxe_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 | 
			
		||||
{
 | 
			
		||||
	struct udphdr *udph;
 | 
			
		||||
	struct net_device *ndev = skb->dev;
 | 
			
		||||
	struct rxe_dev *rxe = net_to_rxe(ndev);
 | 
			
		||||
	struct rxe_pkt_info *pkt = SKB_TO_PKT(skb);
 | 
			
		||||
 | 
			
		||||
	if (!rxe)
 | 
			
		||||
		goto drop;
 | 
			
		||||
 | 
			
		||||
	if (skb_linearize(skb)) {
 | 
			
		||||
		pr_err("skb_linearize failed\n");
 | 
			
		||||
		goto drop;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	udph = udp_hdr(skb);
 | 
			
		||||
	pkt->rxe = rxe;
 | 
			
		||||
	pkt->port_num = 1;
 | 
			
		||||
	pkt->hdr = (u8 *)(udph + 1);
 | 
			
		||||
	pkt->mask = RXE_GRH_MASK;
 | 
			
		||||
	pkt->paylen = be16_to_cpu(udph->len) - sizeof(*udph);
 | 
			
		||||
 | 
			
		||||
	return rxe_rcv(skb);
 | 
			
		||||
drop:
 | 
			
		||||
	kfree_skb(skb);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct socket *rxe_setup_udp_tunnel(struct net *net, __be16 port,
 | 
			
		||||
					   bool ipv6)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
	struct socket *sock;
 | 
			
		||||
	struct udp_port_cfg udp_cfg;
 | 
			
		||||
	struct udp_tunnel_sock_cfg tnl_cfg;
 | 
			
		||||
 | 
			
		||||
	memset(&udp_cfg, 0, sizeof(udp_cfg));
 | 
			
		||||
 | 
			
		||||
	if (ipv6) {
 | 
			
		||||
		udp_cfg.family = AF_INET6;
 | 
			
		||||
		udp_cfg.ipv6_v6only = 1;
 | 
			
		||||
	} else {
 | 
			
		||||
		udp_cfg.family = AF_INET;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	udp_cfg.local_udp_port = port;
 | 
			
		||||
 | 
			
		||||
	/* Create UDP socket */
 | 
			
		||||
	err = udp_sock_create(net, &udp_cfg, &sock);
 | 
			
		||||
	if (err < 0) {
 | 
			
		||||
		pr_err("failed to create udp socket. err = %d\n", err);
 | 
			
		||||
		return ERR_PTR(err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tnl_cfg.sk_user_data = NULL;
 | 
			
		||||
	tnl_cfg.encap_type = 1;
 | 
			
		||||
	tnl_cfg.encap_rcv = rxe_udp_encap_recv;
 | 
			
		||||
	tnl_cfg.encap_destroy = NULL;
 | 
			
		||||
 | 
			
		||||
	/* Setup UDP tunnel */
 | 
			
		||||
	setup_udp_tunnel_sock(net, sock, &tnl_cfg);
 | 
			
		||||
 | 
			
		||||
	return sock;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rxe_release_udp_tunnel(struct socket *sk)
 | 
			
		||||
{
 | 
			
		||||
	udp_tunnel_sock_release(sk);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void prepare_udp_hdr(struct sk_buff *skb, __be16 src_port,
 | 
			
		||||
			    __be16 dst_port)
 | 
			
		||||
{
 | 
			
		||||
	struct udphdr *udph;
 | 
			
		||||
 | 
			
		||||
	__skb_push(skb, sizeof(*udph));
 | 
			
		||||
	skb_reset_transport_header(skb);
 | 
			
		||||
	udph = udp_hdr(skb);
 | 
			
		||||
 | 
			
		||||
	udph->dest = dst_port;
 | 
			
		||||
	udph->source = src_port;
 | 
			
		||||
	udph->len = htons(skb->len);
 | 
			
		||||
	udph->check = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void prepare_ipv4_hdr(struct dst_entry *dst, struct sk_buff *skb,
 | 
			
		||||
			     __be32 saddr, __be32 daddr, __u8 proto,
 | 
			
		||||
			     __u8 tos, __u8 ttl, __be16 df, bool xnet)
 | 
			
		||||
{
 | 
			
		||||
	struct iphdr *iph;
 | 
			
		||||
 | 
			
		||||
	skb_scrub_packet(skb, xnet);
 | 
			
		||||
 | 
			
		||||
	skb_clear_hash(skb);
 | 
			
		||||
	skb_dst_set(skb, dst);
 | 
			
		||||
	memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
 | 
			
		||||
 | 
			
		||||
	skb_push(skb, sizeof(struct iphdr));
 | 
			
		||||
	skb_reset_network_header(skb);
 | 
			
		||||
 | 
			
		||||
	iph = ip_hdr(skb);
 | 
			
		||||
 | 
			
		||||
	iph->version	=	IPVERSION;
 | 
			
		||||
	iph->ihl	=	sizeof(struct iphdr) >> 2;
 | 
			
		||||
	iph->frag_off	=	df;
 | 
			
		||||
	iph->protocol	=	proto;
 | 
			
		||||
	iph->tos	=	tos;
 | 
			
		||||
	iph->daddr	=	daddr;
 | 
			
		||||
	iph->saddr	=	saddr;
 | 
			
		||||
	iph->ttl	=	ttl;
 | 
			
		||||
	__ip_select_ident(dev_net(dst->dev), iph,
 | 
			
		||||
			  skb_shinfo(skb)->gso_segs ?: 1);
 | 
			
		||||
	iph->tot_len = htons(skb->len);
 | 
			
		||||
	ip_send_check(iph);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void prepare_ipv6_hdr(struct dst_entry *dst, struct sk_buff *skb,
 | 
			
		||||
			     struct in6_addr *saddr, struct in6_addr *daddr,
 | 
			
		||||
			     __u8 proto, __u8 prio, __u8 ttl)
 | 
			
		||||
{
 | 
			
		||||
	struct ipv6hdr *ip6h;
 | 
			
		||||
 | 
			
		||||
	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
 | 
			
		||||
	IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED
 | 
			
		||||
			    | IPSKB_REROUTED);
 | 
			
		||||
	skb_dst_set(skb, dst);
 | 
			
		||||
 | 
			
		||||
	__skb_push(skb, sizeof(*ip6h));
 | 
			
		||||
	skb_reset_network_header(skb);
 | 
			
		||||
	ip6h		  = ipv6_hdr(skb);
 | 
			
		||||
	ip6_flow_hdr(ip6h, prio, htonl(0));
 | 
			
		||||
	ip6h->payload_len = htons(skb->len);
 | 
			
		||||
	ip6h->nexthdr     = proto;
 | 
			
		||||
	ip6h->hop_limit   = ttl;
 | 
			
		||||
	ip6h->daddr	  = *daddr;
 | 
			
		||||
	ip6h->saddr	  = *saddr;
 | 
			
		||||
	ip6h->payload_len = htons(skb->len - sizeof(*ip6h));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int prepare4(struct rxe_dev *rxe, struct sk_buff *skb, struct rxe_av *av)
 | 
			
		||||
{
 | 
			
		||||
	struct dst_entry *dst;
 | 
			
		||||
	bool xnet = false;
 | 
			
		||||
	__be16 df = htons(IP_DF);
 | 
			
		||||
	struct in_addr *saddr = &av->sgid_addr._sockaddr_in.sin_addr;
 | 
			
		||||
	struct in_addr *daddr = &av->dgid_addr._sockaddr_in.sin_addr;
 | 
			
		||||
	struct rxe_pkt_info *pkt = SKB_TO_PKT(skb);
 | 
			
		||||
 | 
			
		||||
	dst = rxe_find_route4(rxe->ndev, saddr, daddr);
 | 
			
		||||
	if (!dst) {
 | 
			
		||||
		pr_err("Host not reachable\n");
 | 
			
		||||
		return -EHOSTUNREACH;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!memcmp(saddr, daddr, sizeof(*daddr)))
 | 
			
		||||
		pkt->mask |= RXE_LOOPBACK_MASK;
 | 
			
		||||
 | 
			
		||||
	prepare_udp_hdr(skb, htons(RXE_ROCE_V2_SPORT),
 | 
			
		||||
			htons(ROCE_V2_UDP_DPORT));
 | 
			
		||||
 | 
			
		||||
	prepare_ipv4_hdr(dst, skb, saddr->s_addr, daddr->s_addr, IPPROTO_UDP,
 | 
			
		||||
			 av->grh.traffic_class, av->grh.hop_limit, df, xnet);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int prepare6(struct rxe_dev *rxe, struct sk_buff *skb, struct rxe_av *av)
 | 
			
		||||
{
 | 
			
		||||
	struct dst_entry *dst;
 | 
			
		||||
	struct in6_addr *saddr = &av->sgid_addr._sockaddr_in6.sin6_addr;
 | 
			
		||||
	struct in6_addr *daddr = &av->dgid_addr._sockaddr_in6.sin6_addr;
 | 
			
		||||
	struct rxe_pkt_info *pkt = SKB_TO_PKT(skb);
 | 
			
		||||
 | 
			
		||||
	dst = rxe_find_route6(rxe->ndev, saddr, daddr);
 | 
			
		||||
	if (!dst) {
 | 
			
		||||
		pr_err("Host not reachable\n");
 | 
			
		||||
		return -EHOSTUNREACH;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!memcmp(saddr, daddr, sizeof(*daddr)))
 | 
			
		||||
		pkt->mask |= RXE_LOOPBACK_MASK;
 | 
			
		||||
 | 
			
		||||
	prepare_udp_hdr(skb, htons(RXE_ROCE_V2_SPORT),
 | 
			
		||||
			htons(ROCE_V2_UDP_DPORT));
 | 
			
		||||
 | 
			
		||||
	prepare_ipv6_hdr(dst, skb, saddr, daddr, IPPROTO_UDP,
 | 
			
		||||
			 av->grh.traffic_class,
 | 
			
		||||
			 av->grh.hop_limit);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int prepare(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
 | 
			
		||||
		   struct sk_buff *skb, u32 *crc)
 | 
			
		||||
{
 | 
			
		||||
	int err = 0;
 | 
			
		||||
	struct rxe_av *av = rxe_get_av(pkt);
 | 
			
		||||
 | 
			
		||||
	if (av->network_type == RDMA_NETWORK_IPV4)
 | 
			
		||||
		err = prepare4(rxe, skb, av);
 | 
			
		||||
	else if (av->network_type == RDMA_NETWORK_IPV6)
 | 
			
		||||
		err = prepare6(rxe, skb, av);
 | 
			
		||||
 | 
			
		||||
	*crc = rxe_icrc_hdr(pkt, skb);
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rxe_skb_tx_dtor(struct sk_buff *skb)
 | 
			
		||||
{
 | 
			
		||||
	struct sock *sk = skb->sk;
 | 
			
		||||
	struct rxe_qp *qp = sk->sk_user_data;
 | 
			
		||||
	int skb_out = atomic_dec_return(&qp->skb_out);
 | 
			
		||||
 | 
			
		||||
	if (unlikely(qp->need_req_skb &&
 | 
			
		||||
		     skb_out < RXE_INFLIGHT_SKBS_PER_QP_LOW))
 | 
			
		||||
		rxe_run_task(&qp->req.task, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int send(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
 | 
			
		||||
		struct sk_buff *skb)
 | 
			
		||||
{
 | 
			
		||||
	struct sk_buff *nskb;
 | 
			
		||||
	struct rxe_av *av;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	av = rxe_get_av(pkt);
 | 
			
		||||
 | 
			
		||||
	nskb = skb_clone(skb, GFP_ATOMIC);
 | 
			
		||||
	if (!nskb)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	nskb->destructor = rxe_skb_tx_dtor;
 | 
			
		||||
	nskb->sk = pkt->qp->sk->sk;
 | 
			
		||||
 | 
			
		||||
	if (av->network_type == RDMA_NETWORK_IPV4) {
 | 
			
		||||
		err = ip_local_out(dev_net(skb_dst(skb)->dev), nskb->sk, nskb);
 | 
			
		||||
	} else if (av->network_type == RDMA_NETWORK_IPV6) {
 | 
			
		||||
		err = ip6_local_out(dev_net(skb_dst(skb)->dev), nskb->sk, nskb);
 | 
			
		||||
	} else {
 | 
			
		||||
		pr_err("Unknown layer 3 protocol: %d\n", av->network_type);
 | 
			
		||||
		kfree_skb(nskb);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (unlikely(net_xmit_eval(err))) {
 | 
			
		||||
		pr_debug("error sending packet: %d\n", err);
 | 
			
		||||
		return -EAGAIN;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	kfree_skb(skb);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int loopback(struct sk_buff *skb)
 | 
			
		||||
{
 | 
			
		||||
	return rxe_rcv(skb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int addr_same(struct rxe_dev *rxe, struct rxe_av *av)
 | 
			
		||||
{
 | 
			
		||||
	return rxe->port.port_guid == av->grh.dgid.global.interface_id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct sk_buff *init_packet(struct rxe_dev *rxe, struct rxe_av *av,
 | 
			
		||||
				   int paylen, struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int hdr_len;
 | 
			
		||||
	struct sk_buff *skb;
 | 
			
		||||
 | 
			
		||||
	if (av->network_type == RDMA_NETWORK_IPV4)
 | 
			
		||||
		hdr_len = ETH_HLEN + sizeof(struct udphdr) +
 | 
			
		||||
			sizeof(struct iphdr);
 | 
			
		||||
	else
 | 
			
		||||
		hdr_len = ETH_HLEN + sizeof(struct udphdr) +
 | 
			
		||||
			sizeof(struct ipv6hdr);
 | 
			
		||||
 | 
			
		||||
	skb = alloc_skb(paylen + hdr_len + LL_RESERVED_SPACE(rxe->ndev),
 | 
			
		||||
			GFP_ATOMIC);
 | 
			
		||||
	if (unlikely(!skb))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	skb_reserve(skb, hdr_len + LL_RESERVED_SPACE(rxe->ndev));
 | 
			
		||||
 | 
			
		||||
	skb->dev	= rxe->ndev;
 | 
			
		||||
	if (av->network_type == RDMA_NETWORK_IPV4)
 | 
			
		||||
		skb->protocol = htons(ETH_P_IP);
 | 
			
		||||
	else
 | 
			
		||||
		skb->protocol = htons(ETH_P_IPV6);
 | 
			
		||||
 | 
			
		||||
	pkt->rxe	= rxe;
 | 
			
		||||
	pkt->port_num	= 1;
 | 
			
		||||
	pkt->hdr	= skb_put(skb, paylen);
 | 
			
		||||
	pkt->mask	|= RXE_GRH_MASK;
 | 
			
		||||
 | 
			
		||||
	memset(pkt->hdr, 0, paylen);
 | 
			
		||||
 | 
			
		||||
	return skb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * this is required by rxe_cfg to match rxe devices in
 | 
			
		||||
 * /sys/class/infiniband up with their underlying ethernet devices
 | 
			
		||||
 */
 | 
			
		||||
static char *parent_name(struct rxe_dev *rxe, unsigned int port_num)
 | 
			
		||||
{
 | 
			
		||||
	return rxe->ndev->name;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static enum rdma_link_layer link_layer(struct rxe_dev *rxe,
 | 
			
		||||
				       unsigned int port_num)
 | 
			
		||||
{
 | 
			
		||||
	return IB_LINK_LAYER_ETHERNET;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct rxe_ifc_ops ifc_ops = {
 | 
			
		||||
	.node_guid	= node_guid,
 | 
			
		||||
	.port_guid	= port_guid,
 | 
			
		||||
	.dma_device	= dma_device,
 | 
			
		||||
	.mcast_add	= mcast_add,
 | 
			
		||||
	.mcast_delete	= mcast_delete,
 | 
			
		||||
	.prepare	= prepare,
 | 
			
		||||
	.send		= send,
 | 
			
		||||
	.loopback	= loopback,
 | 
			
		||||
	.init_packet	= init_packet,
 | 
			
		||||
	.parent_name	= parent_name,
 | 
			
		||||
	.link_layer	= link_layer,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_dev *rxe_net_add(struct net_device *ndev)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
	struct rxe_dev *rxe = NULL;
 | 
			
		||||
 | 
			
		||||
	rxe = (struct rxe_dev *)ib_alloc_device(sizeof(*rxe));
 | 
			
		||||
	if (!rxe)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	rxe->ifc_ops = &ifc_ops;
 | 
			
		||||
	rxe->ndev = ndev;
 | 
			
		||||
 | 
			
		||||
	err = rxe_add(rxe, ndev->mtu);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		ib_dealloc_device(&rxe->ib_dev);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	spin_lock_bh(&dev_list_lock);
 | 
			
		||||
	list_add_tail(&rxe_dev_list, &rxe->list);
 | 
			
		||||
	spin_unlock_bh(&dev_list_lock);
 | 
			
		||||
	return rxe;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rxe_remove_all(void)
 | 
			
		||||
{
 | 
			
		||||
	spin_lock_bh(&dev_list_lock);
 | 
			
		||||
	while (!list_empty(&rxe_dev_list)) {
 | 
			
		||||
		struct rxe_dev *rxe =
 | 
			
		||||
			list_first_entry(&rxe_dev_list, struct rxe_dev, list);
 | 
			
		||||
 | 
			
		||||
		list_del(&rxe->list);
 | 
			
		||||
		spin_unlock_bh(&dev_list_lock);
 | 
			
		||||
		rxe_remove(rxe);
 | 
			
		||||
		spin_lock_bh(&dev_list_lock);
 | 
			
		||||
	}
 | 
			
		||||
	spin_unlock_bh(&dev_list_lock);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(rxe_remove_all);
 | 
			
		||||
 | 
			
		||||
static void rxe_port_event(struct rxe_dev *rxe,
 | 
			
		||||
			   enum ib_event_type event)
 | 
			
		||||
{
 | 
			
		||||
	struct ib_event ev;
 | 
			
		||||
 | 
			
		||||
	ev.device = &rxe->ib_dev;
 | 
			
		||||
	ev.element.port_num = 1;
 | 
			
		||||
	ev.event = event;
 | 
			
		||||
 | 
			
		||||
	ib_dispatch_event(&ev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Caller must hold net_info_lock */
 | 
			
		||||
void rxe_port_up(struct rxe_dev *rxe)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_port *port;
 | 
			
		||||
 | 
			
		||||
	port = &rxe->port;
 | 
			
		||||
	port->attr.state = IB_PORT_ACTIVE;
 | 
			
		||||
	port->attr.phys_state = IB_PHYS_STATE_LINK_UP;
 | 
			
		||||
 | 
			
		||||
	rxe_port_event(rxe, IB_EVENT_PORT_ACTIVE);
 | 
			
		||||
	pr_info("rxe: set %s active\n", rxe->ib_dev.name);
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Caller must hold net_info_lock */
 | 
			
		||||
void rxe_port_down(struct rxe_dev *rxe)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_port *port;
 | 
			
		||||
 | 
			
		||||
	port = &rxe->port;
 | 
			
		||||
	port->attr.state = IB_PORT_DOWN;
 | 
			
		||||
	port->attr.phys_state = IB_PHYS_STATE_LINK_DOWN;
 | 
			
		||||
 | 
			
		||||
	rxe_port_event(rxe, IB_EVENT_PORT_ERR);
 | 
			
		||||
	pr_info("rxe: set %s down\n", rxe->ib_dev.name);
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rxe_notify(struct notifier_block *not_blk,
 | 
			
		||||
		      unsigned long event,
 | 
			
		||||
		      void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct net_device *ndev = netdev_notifier_info_to_dev(arg);
 | 
			
		||||
	struct rxe_dev *rxe = net_to_rxe(ndev);
 | 
			
		||||
 | 
			
		||||
	if (!rxe)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	switch (event) {
 | 
			
		||||
	case NETDEV_UNREGISTER:
 | 
			
		||||
		list_del(&rxe->list);
 | 
			
		||||
		rxe_remove(rxe);
 | 
			
		||||
		break;
 | 
			
		||||
	case NETDEV_UP:
 | 
			
		||||
		rxe_port_up(rxe);
 | 
			
		||||
		break;
 | 
			
		||||
	case NETDEV_DOWN:
 | 
			
		||||
		rxe_port_down(rxe);
 | 
			
		||||
		break;
 | 
			
		||||
	case NETDEV_CHANGEMTU:
 | 
			
		||||
		pr_info("rxe: %s changed mtu to %d\n", ndev->name, ndev->mtu);
 | 
			
		||||
		rxe_set_mtu(rxe, ndev->mtu);
 | 
			
		||||
		break;
 | 
			
		||||
	case NETDEV_REBOOT:
 | 
			
		||||
	case NETDEV_CHANGE:
 | 
			
		||||
	case NETDEV_GOING_DOWN:
 | 
			
		||||
	case NETDEV_CHANGEADDR:
 | 
			
		||||
	case NETDEV_CHANGENAME:
 | 
			
		||||
	case NETDEV_FEAT_CHANGE:
 | 
			
		||||
	default:
 | 
			
		||||
		pr_info("rxe: ignoring netdev event = %ld for %s\n",
 | 
			
		||||
			event, ndev->name);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
out:
 | 
			
		||||
	return NOTIFY_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct notifier_block rxe_net_notifier = {
 | 
			
		||||
	.notifier_call = rxe_notify,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int rxe_net_init(void)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	spin_lock_init(&dev_list_lock);
 | 
			
		||||
 | 
			
		||||
	recv_sockets.sk6 = rxe_setup_udp_tunnel(&init_net,
 | 
			
		||||
			htons(ROCE_V2_UDP_DPORT), true);
 | 
			
		||||
	if (IS_ERR(recv_sockets.sk6)) {
 | 
			
		||||
		recv_sockets.sk6 = NULL;
 | 
			
		||||
		pr_err("rxe: Failed to create IPv6 UDP tunnel\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	recv_sockets.sk4 = rxe_setup_udp_tunnel(&init_net,
 | 
			
		||||
			htons(ROCE_V2_UDP_DPORT), false);
 | 
			
		||||
	if (IS_ERR(recv_sockets.sk4)) {
 | 
			
		||||
		rxe_release_udp_tunnel(recv_sockets.sk6);
 | 
			
		||||
		recv_sockets.sk4 = NULL;
 | 
			
		||||
		recv_sockets.sk6 = NULL;
 | 
			
		||||
		pr_err("rxe: Failed to create IPv4 UDP tunnel\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = register_netdevice_notifier(&rxe_net_notifier);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		rxe_release_udp_tunnel(recv_sockets.sk6);
 | 
			
		||||
		rxe_release_udp_tunnel(recv_sockets.sk4);
 | 
			
		||||
		pr_err("rxe: Failed to rigister netdev notifier\n");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rxe_net_exit(void)
 | 
			
		||||
{
 | 
			
		||||
	if (recv_sockets.sk6)
 | 
			
		||||
		rxe_release_udp_tunnel(recv_sockets.sk6);
 | 
			
		||||
 | 
			
		||||
	if (recv_sockets.sk4)
 | 
			
		||||
		rxe_release_udp_tunnel(recv_sockets.sk4);
 | 
			
		||||
 | 
			
		||||
	unregister_netdevice_notifier(&rxe_net_notifier);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										53
									
								
								drivers/infiniband/sw/rxe/rxe_net.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								drivers/infiniband/sw/rxe/rxe_net.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,53 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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 RXE_NET_H
 | 
			
		||||
#define RXE_NET_H
 | 
			
		||||
 | 
			
		||||
#include <net/sock.h>
 | 
			
		||||
#include <net/if_inet6.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
 | 
			
		||||
struct rxe_recv_sockets {
 | 
			
		||||
	struct socket *sk4;
 | 
			
		||||
	struct socket *sk6;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern struct rxe_recv_sockets recv_sockets;
 | 
			
		||||
 | 
			
		||||
struct rxe_dev *rxe_net_add(struct net_device *ndev);
 | 
			
		||||
 | 
			
		||||
int rxe_net_init(void);
 | 
			
		||||
void rxe_net_exit(void);
 | 
			
		||||
 | 
			
		||||
#endif /* RXE_NET_H */
 | 
			
		||||
							
								
								
									
										961
									
								
								drivers/infiniband/sw/rxe/rxe_opcode.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										961
									
								
								drivers/infiniband/sw/rxe/rxe_opcode.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,961 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <rdma/ib_pack.h>
 | 
			
		||||
#include "rxe_opcode.h"
 | 
			
		||||
#include "rxe_hdr.h"
 | 
			
		||||
 | 
			
		||||
/* useful information about work request opcodes and pkt opcodes in
 | 
			
		||||
 * table form
 | 
			
		||||
 */
 | 
			
		||||
struct rxe_wr_opcode_info rxe_wr_opcode_info[] = {
 | 
			
		||||
	[IB_WR_RDMA_WRITE]				= {
 | 
			
		||||
		.name	= "IB_WR_RDMA_WRITE",
 | 
			
		||||
		.mask	= {
 | 
			
		||||
			[IB_QPT_RC]	= WR_INLINE_MASK | WR_WRITE_MASK,
 | 
			
		||||
			[IB_QPT_UC]	= WR_INLINE_MASK | WR_WRITE_MASK,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	[IB_WR_RDMA_WRITE_WITH_IMM]			= {
 | 
			
		||||
		.name	= "IB_WR_RDMA_WRITE_WITH_IMM",
 | 
			
		||||
		.mask	= {
 | 
			
		||||
			[IB_QPT_RC]	= WR_INLINE_MASK | WR_WRITE_MASK,
 | 
			
		||||
			[IB_QPT_UC]	= WR_INLINE_MASK | WR_WRITE_MASK,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	[IB_WR_SEND]					= {
 | 
			
		||||
		.name	= "IB_WR_SEND",
 | 
			
		||||
		.mask	= {
 | 
			
		||||
			[IB_QPT_SMI]	= WR_INLINE_MASK | WR_SEND_MASK,
 | 
			
		||||
			[IB_QPT_GSI]	= WR_INLINE_MASK | WR_SEND_MASK,
 | 
			
		||||
			[IB_QPT_RC]	= WR_INLINE_MASK | WR_SEND_MASK,
 | 
			
		||||
			[IB_QPT_UC]	= WR_INLINE_MASK | WR_SEND_MASK,
 | 
			
		||||
			[IB_QPT_UD]	= WR_INLINE_MASK | WR_SEND_MASK,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	[IB_WR_SEND_WITH_IMM]				= {
 | 
			
		||||
		.name	= "IB_WR_SEND_WITH_IMM",
 | 
			
		||||
		.mask	= {
 | 
			
		||||
			[IB_QPT_SMI]	= WR_INLINE_MASK | WR_SEND_MASK,
 | 
			
		||||
			[IB_QPT_GSI]	= WR_INLINE_MASK | WR_SEND_MASK,
 | 
			
		||||
			[IB_QPT_RC]	= WR_INLINE_MASK | WR_SEND_MASK,
 | 
			
		||||
			[IB_QPT_UC]	= WR_INLINE_MASK | WR_SEND_MASK,
 | 
			
		||||
			[IB_QPT_UD]	= WR_INLINE_MASK | WR_SEND_MASK,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	[IB_WR_RDMA_READ]				= {
 | 
			
		||||
		.name	= "IB_WR_RDMA_READ",
 | 
			
		||||
		.mask	= {
 | 
			
		||||
			[IB_QPT_RC]	= WR_READ_MASK,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	[IB_WR_ATOMIC_CMP_AND_SWP]			= {
 | 
			
		||||
		.name	= "IB_WR_ATOMIC_CMP_AND_SWP",
 | 
			
		||||
		.mask	= {
 | 
			
		||||
			[IB_QPT_RC]	= WR_ATOMIC_MASK,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	[IB_WR_ATOMIC_FETCH_AND_ADD]			= {
 | 
			
		||||
		.name	= "IB_WR_ATOMIC_FETCH_AND_ADD",
 | 
			
		||||
		.mask	= {
 | 
			
		||||
			[IB_QPT_RC]	= WR_ATOMIC_MASK,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	[IB_WR_LSO]					= {
 | 
			
		||||
		.name	= "IB_WR_LSO",
 | 
			
		||||
		.mask	= {
 | 
			
		||||
			/* not supported */
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	[IB_WR_SEND_WITH_INV]				= {
 | 
			
		||||
		.name	= "IB_WR_SEND_WITH_INV",
 | 
			
		||||
		.mask	= {
 | 
			
		||||
			[IB_QPT_RC]	= WR_INLINE_MASK | WR_SEND_MASK,
 | 
			
		||||
			[IB_QPT_UC]	= WR_INLINE_MASK | WR_SEND_MASK,
 | 
			
		||||
			[IB_QPT_UD]	= WR_INLINE_MASK | WR_SEND_MASK,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	[IB_WR_RDMA_READ_WITH_INV]			= {
 | 
			
		||||
		.name	= "IB_WR_RDMA_READ_WITH_INV",
 | 
			
		||||
		.mask	= {
 | 
			
		||||
			[IB_QPT_RC]	= WR_READ_MASK,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	[IB_WR_LOCAL_INV]				= {
 | 
			
		||||
		.name	= "IB_WR_LOCAL_INV",
 | 
			
		||||
		.mask	= {
 | 
			
		||||
			[IB_QPT_RC]	= WR_REG_MASK,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	[IB_WR_REG_MR]					= {
 | 
			
		||||
		.name	= "IB_WR_REG_MR",
 | 
			
		||||
		.mask	= {
 | 
			
		||||
			[IB_QPT_RC]	= WR_REG_MASK,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_opcode_info rxe_opcode[RXE_NUM_OPCODE] = {
 | 
			
		||||
	[IB_OPCODE_RC_SEND_FIRST]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_RC_SEND_FIRST",
 | 
			
		||||
		.mask	= RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_RWR_MASK
 | 
			
		||||
				| RXE_SEND_MASK | RXE_START_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RC_SEND_MIDDLE]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_RC_SEND_MIDDLE]",
 | 
			
		||||
		.mask	= RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_SEND_MASK
 | 
			
		||||
				| RXE_MIDDLE_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RC_SEND_LAST]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_RC_SEND_LAST",
 | 
			
		||||
		.mask	= RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_COMP_MASK
 | 
			
		||||
				| RXE_SEND_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RC_SEND_LAST_WITH_IMMEDIATE]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_RC_SEND_LAST_WITH_IMMEDIATE",
 | 
			
		||||
		.mask	= RXE_IMMDT_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
 | 
			
		||||
				| RXE_COMP_MASK | RXE_SEND_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_IMMDT_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_IMMDT]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_IMMDT_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RC_SEND_ONLY]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_RC_SEND_ONLY",
 | 
			
		||||
		.mask	= RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_COMP_MASK
 | 
			
		||||
				| RXE_RWR_MASK | RXE_SEND_MASK
 | 
			
		||||
				| RXE_START_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RC_SEND_ONLY_WITH_IMMEDIATE]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_RC_SEND_ONLY_WITH_IMMEDIATE",
 | 
			
		||||
		.mask	= RXE_IMMDT_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
 | 
			
		||||
				| RXE_COMP_MASK | RXE_RWR_MASK | RXE_SEND_MASK
 | 
			
		||||
				| RXE_START_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_IMMDT_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_IMMDT]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_IMMDT_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RC_RDMA_WRITE_FIRST]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_RC_RDMA_WRITE_FIRST",
 | 
			
		||||
		.mask	= RXE_RETH_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
 | 
			
		||||
				| RXE_WRITE_MASK | RXE_START_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_RETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RC_RDMA_WRITE_MIDDLE]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_RC_RDMA_WRITE_MIDDLE",
 | 
			
		||||
		.mask	= RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_WRITE_MASK
 | 
			
		||||
				| RXE_MIDDLE_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RC_RDMA_WRITE_LAST]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_RC_RDMA_WRITE_LAST",
 | 
			
		||||
		.mask	= RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_WRITE_MASK
 | 
			
		||||
				| RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RC_RDMA_WRITE_LAST_WITH_IMMEDIATE]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_RC_RDMA_WRITE_LAST_WITH_IMMEDIATE",
 | 
			
		||||
		.mask	= RXE_IMMDT_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
 | 
			
		||||
				| RXE_WRITE_MASK | RXE_COMP_MASK | RXE_RWR_MASK
 | 
			
		||||
				| RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_IMMDT_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_IMMDT]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_IMMDT_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RC_RDMA_WRITE_ONLY]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_RC_RDMA_WRITE_ONLY",
 | 
			
		||||
		.mask	= RXE_RETH_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
 | 
			
		||||
				| RXE_WRITE_MASK | RXE_START_MASK
 | 
			
		||||
				| RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_RETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RC_RDMA_WRITE_ONLY_WITH_IMMEDIATE]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_RC_RDMA_WRITE_ONLY_WITH_IMMEDIATE",
 | 
			
		||||
		.mask	= RXE_RETH_MASK | RXE_IMMDT_MASK | RXE_PAYLOAD_MASK
 | 
			
		||||
				| RXE_REQ_MASK | RXE_WRITE_MASK
 | 
			
		||||
				| RXE_COMP_MASK | RXE_RWR_MASK
 | 
			
		||||
				| RXE_START_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_IMMDT_BYTES + RXE_RETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_IMMDT]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RETH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RETH_BYTES
 | 
			
		||||
						+ RXE_IMMDT_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RC_RDMA_READ_REQUEST]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_RC_RDMA_READ_REQUEST",
 | 
			
		||||
		.mask	= RXE_RETH_MASK | RXE_REQ_MASK | RXE_READ_MASK
 | 
			
		||||
				| RXE_START_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_RETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST",
 | 
			
		||||
		.mask	= RXE_AETH_MASK | RXE_PAYLOAD_MASK | RXE_ACK_MASK
 | 
			
		||||
				| RXE_START_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_AETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_AETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_AETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE",
 | 
			
		||||
		.mask	= RXE_PAYLOAD_MASK | RXE_ACK_MASK | RXE_MIDDLE_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RC_RDMA_READ_RESPONSE_LAST]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_RC_RDMA_READ_RESPONSE_LAST",
 | 
			
		||||
		.mask	= RXE_AETH_MASK | RXE_PAYLOAD_MASK | RXE_ACK_MASK
 | 
			
		||||
				| RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_AETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_AETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_AETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RC_RDMA_READ_RESPONSE_ONLY]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_RC_RDMA_READ_RESPONSE_ONLY",
 | 
			
		||||
		.mask	= RXE_AETH_MASK | RXE_PAYLOAD_MASK | RXE_ACK_MASK
 | 
			
		||||
				| RXE_START_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_AETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_AETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_AETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RC_ACKNOWLEDGE]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_RC_ACKNOWLEDGE",
 | 
			
		||||
		.mask	= RXE_AETH_MASK | RXE_ACK_MASK | RXE_START_MASK
 | 
			
		||||
				| RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_AETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_AETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_AETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RC_ATOMIC_ACKNOWLEDGE]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_RC_ATOMIC_ACKNOWLEDGE",
 | 
			
		||||
		.mask	= RXE_AETH_MASK | RXE_ATMACK_MASK | RXE_ACK_MASK
 | 
			
		||||
				| RXE_START_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_ATMACK_BYTES + RXE_AETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_AETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_ATMACK]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_AETH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
					+ RXE_ATMACK_BYTES + RXE_AETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RC_COMPARE_SWAP]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_RC_COMPARE_SWAP",
 | 
			
		||||
		.mask	= RXE_ATMETH_MASK | RXE_REQ_MASK | RXE_ATOMIC_MASK
 | 
			
		||||
				| RXE_START_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_ATMETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_ATMETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_ATMETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RC_FETCH_ADD]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_RC_FETCH_ADD",
 | 
			
		||||
		.mask	= RXE_ATMETH_MASK | RXE_REQ_MASK | RXE_ATOMIC_MASK
 | 
			
		||||
				| RXE_START_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_ATMETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_ATMETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_ATMETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RC_SEND_LAST_WITH_INVALIDATE]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_RC_SEND_LAST_WITH_INVALIDATE",
 | 
			
		||||
		.mask	= RXE_IETH_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
 | 
			
		||||
				| RXE_COMP_MASK | RXE_SEND_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_IETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_IETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_IETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RC_SEND_ONLY_WITH_INVALIDATE]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_RC_SEND_ONLY_INV",
 | 
			
		||||
		.mask	= RXE_IETH_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
 | 
			
		||||
				| RXE_COMP_MASK | RXE_RWR_MASK | RXE_SEND_MASK
 | 
			
		||||
				| RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_IETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_IETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_IETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	/* UC */
 | 
			
		||||
	[IB_OPCODE_UC_SEND_FIRST]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_UC_SEND_FIRST",
 | 
			
		||||
		.mask	= RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_RWR_MASK
 | 
			
		||||
				| RXE_SEND_MASK | RXE_START_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_UC_SEND_MIDDLE]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_UC_SEND_MIDDLE",
 | 
			
		||||
		.mask	= RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_SEND_MASK
 | 
			
		||||
				| RXE_MIDDLE_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_UC_SEND_LAST]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_UC_SEND_LAST",
 | 
			
		||||
		.mask	= RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_COMP_MASK
 | 
			
		||||
				| RXE_SEND_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_UC_SEND_LAST_WITH_IMMEDIATE]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_UC_SEND_LAST_WITH_IMMEDIATE",
 | 
			
		||||
		.mask	= RXE_IMMDT_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
 | 
			
		||||
				| RXE_COMP_MASK | RXE_SEND_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_IMMDT_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_IMMDT]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_IMMDT_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_UC_SEND_ONLY]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_UC_SEND_ONLY",
 | 
			
		||||
		.mask	= RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_COMP_MASK
 | 
			
		||||
				| RXE_RWR_MASK | RXE_SEND_MASK
 | 
			
		||||
				| RXE_START_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_UC_SEND_ONLY_WITH_IMMEDIATE]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_UC_SEND_ONLY_WITH_IMMEDIATE",
 | 
			
		||||
		.mask	= RXE_IMMDT_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
 | 
			
		||||
				| RXE_COMP_MASK | RXE_RWR_MASK | RXE_SEND_MASK
 | 
			
		||||
				| RXE_START_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_IMMDT_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_IMMDT]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_IMMDT_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_UC_RDMA_WRITE_FIRST]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_UC_RDMA_WRITE_FIRST",
 | 
			
		||||
		.mask	= RXE_RETH_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
 | 
			
		||||
				| RXE_WRITE_MASK | RXE_START_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_RETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_UC_RDMA_WRITE_MIDDLE]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_UC_RDMA_WRITE_MIDDLE",
 | 
			
		||||
		.mask	= RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_WRITE_MASK
 | 
			
		||||
				| RXE_MIDDLE_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_UC_RDMA_WRITE_LAST]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_UC_RDMA_WRITE_LAST",
 | 
			
		||||
		.mask	= RXE_PAYLOAD_MASK | RXE_REQ_MASK | RXE_WRITE_MASK
 | 
			
		||||
				| RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_UC_RDMA_WRITE_LAST_WITH_IMMEDIATE]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_UC_RDMA_WRITE_LAST_WITH_IMMEDIATE",
 | 
			
		||||
		.mask	= RXE_IMMDT_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
 | 
			
		||||
				| RXE_WRITE_MASK | RXE_COMP_MASK | RXE_RWR_MASK
 | 
			
		||||
				| RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_IMMDT_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_IMMDT]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_IMMDT_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_UC_RDMA_WRITE_ONLY]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_UC_RDMA_WRITE_ONLY",
 | 
			
		||||
		.mask	= RXE_RETH_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
 | 
			
		||||
				| RXE_WRITE_MASK | RXE_START_MASK
 | 
			
		||||
				| RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_RETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_UC_RDMA_WRITE_ONLY_WITH_IMMEDIATE]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_UC_RDMA_WRITE_ONLY_WITH_IMMEDIATE",
 | 
			
		||||
		.mask	= RXE_RETH_MASK | RXE_IMMDT_MASK | RXE_PAYLOAD_MASK
 | 
			
		||||
				| RXE_REQ_MASK | RXE_WRITE_MASK
 | 
			
		||||
				| RXE_COMP_MASK | RXE_RWR_MASK
 | 
			
		||||
				| RXE_START_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_IMMDT_BYTES + RXE_RETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_IMMDT]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RETH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RETH_BYTES
 | 
			
		||||
						+ RXE_IMMDT_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	/* RD */
 | 
			
		||||
	[IB_OPCODE_RD_SEND_FIRST]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_RD_SEND_FIRST",
 | 
			
		||||
		.mask	= RXE_RDETH_MASK | RXE_DETH_MASK | RXE_PAYLOAD_MASK
 | 
			
		||||
				| RXE_REQ_MASK | RXE_RWR_MASK | RXE_SEND_MASK
 | 
			
		||||
				| RXE_START_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_DETH_BYTES + RXE_RDETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RDETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_DETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RD_SEND_MIDDLE]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_RD_SEND_MIDDLE",
 | 
			
		||||
		.mask	= RXE_RDETH_MASK | RXE_DETH_MASK | RXE_PAYLOAD_MASK
 | 
			
		||||
				| RXE_REQ_MASK | RXE_SEND_MASK
 | 
			
		||||
				| RXE_MIDDLE_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_DETH_BYTES + RXE_RDETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RDETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_DETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RD_SEND_LAST]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_RD_SEND_LAST",
 | 
			
		||||
		.mask	= RXE_RDETH_MASK | RXE_DETH_MASK | RXE_PAYLOAD_MASK
 | 
			
		||||
				| RXE_REQ_MASK | RXE_COMP_MASK | RXE_SEND_MASK
 | 
			
		||||
				| RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_DETH_BYTES + RXE_RDETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RDETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_DETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RD_SEND_LAST_WITH_IMMEDIATE]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_RD_SEND_LAST_WITH_IMMEDIATE",
 | 
			
		||||
		.mask	= RXE_RDETH_MASK | RXE_DETH_MASK | RXE_IMMDT_MASK
 | 
			
		||||
				| RXE_PAYLOAD_MASK | RXE_REQ_MASK
 | 
			
		||||
				| RXE_COMP_MASK | RXE_SEND_MASK
 | 
			
		||||
				| RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_IMMDT_BYTES + RXE_DETH_BYTES
 | 
			
		||||
				+ RXE_RDETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RDETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_DETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES,
 | 
			
		||||
			[RXE_IMMDT]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES
 | 
			
		||||
						+ RXE_IMMDT_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RD_SEND_ONLY]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_RD_SEND_ONLY",
 | 
			
		||||
		.mask	= RXE_RDETH_MASK | RXE_DETH_MASK | RXE_PAYLOAD_MASK
 | 
			
		||||
				| RXE_REQ_MASK | RXE_COMP_MASK | RXE_RWR_MASK
 | 
			
		||||
				| RXE_SEND_MASK | RXE_START_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_DETH_BYTES + RXE_RDETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RDETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_DETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RD_SEND_ONLY_WITH_IMMEDIATE]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_RD_SEND_ONLY_WITH_IMMEDIATE",
 | 
			
		||||
		.mask	= RXE_RDETH_MASK | RXE_DETH_MASK | RXE_IMMDT_MASK
 | 
			
		||||
				| RXE_PAYLOAD_MASK | RXE_REQ_MASK
 | 
			
		||||
				| RXE_COMP_MASK | RXE_RWR_MASK | RXE_SEND_MASK
 | 
			
		||||
				| RXE_START_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_IMMDT_BYTES + RXE_DETH_BYTES
 | 
			
		||||
				+ RXE_RDETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RDETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_DETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES,
 | 
			
		||||
			[RXE_IMMDT]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES
 | 
			
		||||
						+ RXE_IMMDT_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RD_RDMA_WRITE_FIRST]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_RD_RDMA_WRITE_FIRST",
 | 
			
		||||
		.mask	= RXE_RDETH_MASK | RXE_DETH_MASK | RXE_RETH_MASK
 | 
			
		||||
				| RXE_PAYLOAD_MASK | RXE_REQ_MASK
 | 
			
		||||
				| RXE_WRITE_MASK | RXE_START_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_RETH_BYTES + RXE_DETH_BYTES
 | 
			
		||||
				+ RXE_RDETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RDETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_DETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES,
 | 
			
		||||
			[RXE_RETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES
 | 
			
		||||
						+ RXE_RETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RD_RDMA_WRITE_MIDDLE]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_RD_RDMA_WRITE_MIDDLE",
 | 
			
		||||
		.mask	= RXE_RDETH_MASK | RXE_DETH_MASK | RXE_PAYLOAD_MASK
 | 
			
		||||
				| RXE_REQ_MASK | RXE_WRITE_MASK
 | 
			
		||||
				| RXE_MIDDLE_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_DETH_BYTES + RXE_RDETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RDETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_DETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RD_RDMA_WRITE_LAST]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_RD_RDMA_WRITE_LAST",
 | 
			
		||||
		.mask	= RXE_RDETH_MASK | RXE_DETH_MASK | RXE_PAYLOAD_MASK
 | 
			
		||||
				| RXE_REQ_MASK | RXE_WRITE_MASK
 | 
			
		||||
				| RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_DETH_BYTES + RXE_RDETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RDETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_DETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RD_RDMA_WRITE_LAST_WITH_IMMEDIATE]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_RD_RDMA_WRITE_LAST_WITH_IMMEDIATE",
 | 
			
		||||
		.mask	= RXE_RDETH_MASK | RXE_DETH_MASK | RXE_IMMDT_MASK
 | 
			
		||||
				| RXE_PAYLOAD_MASK | RXE_REQ_MASK
 | 
			
		||||
				| RXE_WRITE_MASK | RXE_COMP_MASK | RXE_RWR_MASK
 | 
			
		||||
				| RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_IMMDT_BYTES + RXE_DETH_BYTES
 | 
			
		||||
				+ RXE_RDETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RDETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_DETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES,
 | 
			
		||||
			[RXE_IMMDT]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES
 | 
			
		||||
						+ RXE_IMMDT_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RD_RDMA_WRITE_ONLY]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_RD_RDMA_WRITE_ONLY",
 | 
			
		||||
		.mask	= RXE_RDETH_MASK | RXE_DETH_MASK | RXE_RETH_MASK
 | 
			
		||||
				| RXE_PAYLOAD_MASK | RXE_REQ_MASK
 | 
			
		||||
				| RXE_WRITE_MASK | RXE_START_MASK
 | 
			
		||||
				| RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_RETH_BYTES + RXE_DETH_BYTES
 | 
			
		||||
				+ RXE_RDETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RDETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_DETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES,
 | 
			
		||||
			[RXE_RETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES
 | 
			
		||||
						+ RXE_RETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RD_RDMA_WRITE_ONLY_WITH_IMMEDIATE]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_RD_RDMA_WRITE_ONLY_WITH_IMMEDIATE",
 | 
			
		||||
		.mask	= RXE_RDETH_MASK | RXE_DETH_MASK | RXE_RETH_MASK
 | 
			
		||||
				| RXE_IMMDT_MASK | RXE_PAYLOAD_MASK
 | 
			
		||||
				| RXE_REQ_MASK | RXE_WRITE_MASK
 | 
			
		||||
				| RXE_COMP_MASK | RXE_RWR_MASK
 | 
			
		||||
				| RXE_START_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_IMMDT_BYTES + RXE_RETH_BYTES
 | 
			
		||||
				+ RXE_DETH_BYTES + RXE_RDETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RDETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_DETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES,
 | 
			
		||||
			[RXE_RETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES,
 | 
			
		||||
			[RXE_IMMDT]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES
 | 
			
		||||
						+ RXE_RETH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES
 | 
			
		||||
						+ RXE_RETH_BYTES
 | 
			
		||||
						+ RXE_IMMDT_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RD_RDMA_READ_REQUEST]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_RD_RDMA_READ_REQUEST",
 | 
			
		||||
		.mask	= RXE_RDETH_MASK | RXE_DETH_MASK | RXE_RETH_MASK
 | 
			
		||||
				| RXE_REQ_MASK | RXE_READ_MASK
 | 
			
		||||
				| RXE_START_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_RETH_BYTES + RXE_DETH_BYTES
 | 
			
		||||
				+ RXE_RDETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RDETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_DETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES,
 | 
			
		||||
			[RXE_RETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RD_RDMA_READ_RESPONSE_FIRST]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_RD_RDMA_READ_RESPONSE_FIRST",
 | 
			
		||||
		.mask	= RXE_RDETH_MASK | RXE_AETH_MASK
 | 
			
		||||
				| RXE_PAYLOAD_MASK | RXE_ACK_MASK
 | 
			
		||||
				| RXE_START_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_AETH_BYTES + RXE_RDETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RDETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_AETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_AETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RD_RDMA_READ_RESPONSE_MIDDLE]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_RD_RDMA_READ_RESPONSE_MIDDLE",
 | 
			
		||||
		.mask	= RXE_RDETH_MASK | RXE_PAYLOAD_MASK | RXE_ACK_MASK
 | 
			
		||||
				| RXE_MIDDLE_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_RDETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RDETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RD_RDMA_READ_RESPONSE_LAST]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_RD_RDMA_READ_RESPONSE_LAST",
 | 
			
		||||
		.mask	= RXE_RDETH_MASK | RXE_AETH_MASK | RXE_PAYLOAD_MASK
 | 
			
		||||
				| RXE_ACK_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_AETH_BYTES + RXE_RDETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RDETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_AETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_AETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RD_RDMA_READ_RESPONSE_ONLY]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_RD_RDMA_READ_RESPONSE_ONLY",
 | 
			
		||||
		.mask	= RXE_RDETH_MASK | RXE_AETH_MASK | RXE_PAYLOAD_MASK
 | 
			
		||||
				| RXE_ACK_MASK | RXE_START_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_AETH_BYTES + RXE_RDETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RDETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_AETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_AETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RD_ACKNOWLEDGE]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_RD_ACKNOWLEDGE",
 | 
			
		||||
		.mask	= RXE_RDETH_MASK | RXE_AETH_MASK | RXE_ACK_MASK
 | 
			
		||||
				| RXE_START_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_AETH_BYTES + RXE_RDETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RDETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_AETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RD_ATOMIC_ACKNOWLEDGE]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_RD_ATOMIC_ACKNOWLEDGE",
 | 
			
		||||
		.mask	= RXE_RDETH_MASK | RXE_AETH_MASK | RXE_ATMACK_MASK
 | 
			
		||||
				| RXE_ACK_MASK | RXE_START_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_ATMACK_BYTES + RXE_AETH_BYTES
 | 
			
		||||
				+ RXE_RDETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RDETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_AETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES,
 | 
			
		||||
			[RXE_ATMACK]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_AETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RD_COMPARE_SWAP]			= {
 | 
			
		||||
		.name	= "RD_COMPARE_SWAP",
 | 
			
		||||
		.mask	= RXE_RDETH_MASK | RXE_DETH_MASK | RXE_ATMETH_MASK
 | 
			
		||||
				| RXE_REQ_MASK | RXE_ATOMIC_MASK
 | 
			
		||||
				| RXE_START_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_ATMETH_BYTES + RXE_DETH_BYTES
 | 
			
		||||
				+ RXE_RDETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RDETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_DETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES,
 | 
			
		||||
			[RXE_ATMETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES +
 | 
			
		||||
						+ RXE_ATMETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES +
 | 
			
		||||
						+ RXE_RDETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_RD_FETCH_ADD]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_RD_FETCH_ADD",
 | 
			
		||||
		.mask	= RXE_RDETH_MASK | RXE_DETH_MASK | RXE_ATMETH_MASK
 | 
			
		||||
				| RXE_REQ_MASK | RXE_ATOMIC_MASK
 | 
			
		||||
				| RXE_START_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_ATMETH_BYTES + RXE_DETH_BYTES
 | 
			
		||||
				+ RXE_RDETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_RDETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_DETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES,
 | 
			
		||||
			[RXE_ATMETH]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_RDETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES +
 | 
			
		||||
						+ RXE_ATMETH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES +
 | 
			
		||||
						+ RXE_RDETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	/* UD */
 | 
			
		||||
	[IB_OPCODE_UD_SEND_ONLY]			= {
 | 
			
		||||
		.name	= "IB_OPCODE_UD_SEND_ONLY",
 | 
			
		||||
		.mask	= RXE_DETH_MASK | RXE_PAYLOAD_MASK | RXE_REQ_MASK
 | 
			
		||||
				| RXE_COMP_MASK | RXE_RWR_MASK | RXE_SEND_MASK
 | 
			
		||||
				| RXE_START_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_DETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_DETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	[IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE]		= {
 | 
			
		||||
		.name	= "IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE",
 | 
			
		||||
		.mask	= RXE_DETH_MASK | RXE_IMMDT_MASK | RXE_PAYLOAD_MASK
 | 
			
		||||
				| RXE_REQ_MASK | RXE_COMP_MASK | RXE_RWR_MASK
 | 
			
		||||
				| RXE_SEND_MASK | RXE_START_MASK | RXE_END_MASK,
 | 
			
		||||
		.length = RXE_BTH_BYTES + RXE_IMMDT_BYTES + RXE_DETH_BYTES,
 | 
			
		||||
		.offset = {
 | 
			
		||||
			[RXE_BTH]	= 0,
 | 
			
		||||
			[RXE_DETH]	= RXE_BTH_BYTES,
 | 
			
		||||
			[RXE_IMMDT]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES,
 | 
			
		||||
			[RXE_PAYLOAD]	= RXE_BTH_BYTES
 | 
			
		||||
						+ RXE_DETH_BYTES
 | 
			
		||||
						+ RXE_IMMDT_BYTES,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										129
									
								
								drivers/infiniband/sw/rxe/rxe_opcode.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								drivers/infiniband/sw/rxe/rxe_opcode.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,129 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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 RXE_OPCODE_H
 | 
			
		||||
#define RXE_OPCODE_H
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * contains header bit mask definitions and header lengths
 | 
			
		||||
 * declaration of the rxe_opcode_info struct and
 | 
			
		||||
 * rxe_wr_opcode_info struct
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
enum rxe_wr_mask {
 | 
			
		||||
	WR_INLINE_MASK			= BIT(0),
 | 
			
		||||
	WR_ATOMIC_MASK			= BIT(1),
 | 
			
		||||
	WR_SEND_MASK			= BIT(2),
 | 
			
		||||
	WR_READ_MASK			= BIT(3),
 | 
			
		||||
	WR_WRITE_MASK			= BIT(4),
 | 
			
		||||
	WR_LOCAL_MASK			= BIT(5),
 | 
			
		||||
	WR_REG_MASK			= BIT(6),
 | 
			
		||||
 | 
			
		||||
	WR_READ_OR_WRITE_MASK		= WR_READ_MASK | WR_WRITE_MASK,
 | 
			
		||||
	WR_READ_WRITE_OR_SEND_MASK	= WR_READ_OR_WRITE_MASK | WR_SEND_MASK,
 | 
			
		||||
	WR_WRITE_OR_SEND_MASK		= WR_WRITE_MASK | WR_SEND_MASK,
 | 
			
		||||
	WR_ATOMIC_OR_READ_MASK		= WR_ATOMIC_MASK | WR_READ_MASK,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define WR_MAX_QPT		(8)
 | 
			
		||||
 | 
			
		||||
struct rxe_wr_opcode_info {
 | 
			
		||||
	char			*name;
 | 
			
		||||
	enum rxe_wr_mask	mask[WR_MAX_QPT];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern struct rxe_wr_opcode_info rxe_wr_opcode_info[];
 | 
			
		||||
 | 
			
		||||
enum rxe_hdr_type {
 | 
			
		||||
	RXE_LRH,
 | 
			
		||||
	RXE_GRH,
 | 
			
		||||
	RXE_BTH,
 | 
			
		||||
	RXE_RETH,
 | 
			
		||||
	RXE_AETH,
 | 
			
		||||
	RXE_ATMETH,
 | 
			
		||||
	RXE_ATMACK,
 | 
			
		||||
	RXE_IETH,
 | 
			
		||||
	RXE_RDETH,
 | 
			
		||||
	RXE_DETH,
 | 
			
		||||
	RXE_IMMDT,
 | 
			
		||||
	RXE_PAYLOAD,
 | 
			
		||||
	NUM_HDR_TYPES
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum rxe_hdr_mask {
 | 
			
		||||
	RXE_LRH_MASK		= BIT(RXE_LRH),
 | 
			
		||||
	RXE_GRH_MASK		= BIT(RXE_GRH),
 | 
			
		||||
	RXE_BTH_MASK		= BIT(RXE_BTH),
 | 
			
		||||
	RXE_IMMDT_MASK		= BIT(RXE_IMMDT),
 | 
			
		||||
	RXE_RETH_MASK		= BIT(RXE_RETH),
 | 
			
		||||
	RXE_AETH_MASK		= BIT(RXE_AETH),
 | 
			
		||||
	RXE_ATMETH_MASK		= BIT(RXE_ATMETH),
 | 
			
		||||
	RXE_ATMACK_MASK		= BIT(RXE_ATMACK),
 | 
			
		||||
	RXE_IETH_MASK		= BIT(RXE_IETH),
 | 
			
		||||
	RXE_RDETH_MASK		= BIT(RXE_RDETH),
 | 
			
		||||
	RXE_DETH_MASK		= BIT(RXE_DETH),
 | 
			
		||||
	RXE_PAYLOAD_MASK	= BIT(RXE_PAYLOAD),
 | 
			
		||||
 | 
			
		||||
	RXE_REQ_MASK		= BIT(NUM_HDR_TYPES + 0),
 | 
			
		||||
	RXE_ACK_MASK		= BIT(NUM_HDR_TYPES + 1),
 | 
			
		||||
	RXE_SEND_MASK		= BIT(NUM_HDR_TYPES + 2),
 | 
			
		||||
	RXE_WRITE_MASK		= BIT(NUM_HDR_TYPES + 3),
 | 
			
		||||
	RXE_READ_MASK		= BIT(NUM_HDR_TYPES + 4),
 | 
			
		||||
	RXE_ATOMIC_MASK		= BIT(NUM_HDR_TYPES + 5),
 | 
			
		||||
 | 
			
		||||
	RXE_RWR_MASK		= BIT(NUM_HDR_TYPES + 6),
 | 
			
		||||
	RXE_COMP_MASK		= BIT(NUM_HDR_TYPES + 7),
 | 
			
		||||
 | 
			
		||||
	RXE_START_MASK		= BIT(NUM_HDR_TYPES + 8),
 | 
			
		||||
	RXE_MIDDLE_MASK		= BIT(NUM_HDR_TYPES + 9),
 | 
			
		||||
	RXE_END_MASK		= BIT(NUM_HDR_TYPES + 10),
 | 
			
		||||
 | 
			
		||||
	RXE_LOOPBACK_MASK	= BIT(NUM_HDR_TYPES + 12),
 | 
			
		||||
 | 
			
		||||
	RXE_READ_OR_ATOMIC	= (RXE_READ_MASK | RXE_ATOMIC_MASK),
 | 
			
		||||
	RXE_WRITE_OR_SEND	= (RXE_WRITE_MASK | RXE_SEND_MASK),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define OPCODE_NONE		(-1)
 | 
			
		||||
#define RXE_NUM_OPCODE		256
 | 
			
		||||
 | 
			
		||||
struct rxe_opcode_info {
 | 
			
		||||
	char			*name;
 | 
			
		||||
	enum rxe_hdr_mask	mask;
 | 
			
		||||
	int			length;
 | 
			
		||||
	int			offset[NUM_HDR_TYPES];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern struct rxe_opcode_info rxe_opcode[RXE_NUM_OPCODE];
 | 
			
		||||
 | 
			
		||||
#endif /* RXE_OPCODE_H */
 | 
			
		||||
							
								
								
									
										172
									
								
								drivers/infiniband/sw/rxe/rxe_param.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								drivers/infiniband/sw/rxe/rxe_param.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,172 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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 RXE_PARAM_H
 | 
			
		||||
#define RXE_PARAM_H
 | 
			
		||||
 | 
			
		||||
static inline enum ib_mtu rxe_mtu_int_to_enum(int mtu)
 | 
			
		||||
{
 | 
			
		||||
	if (mtu < 256)
 | 
			
		||||
		return 0;
 | 
			
		||||
	else if (mtu < 512)
 | 
			
		||||
		return IB_MTU_256;
 | 
			
		||||
	else if (mtu < 1024)
 | 
			
		||||
		return IB_MTU_512;
 | 
			
		||||
	else if (mtu < 2048)
 | 
			
		||||
		return IB_MTU_1024;
 | 
			
		||||
	else if (mtu < 4096)
 | 
			
		||||
		return IB_MTU_2048;
 | 
			
		||||
	else
 | 
			
		||||
		return IB_MTU_4096;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Find the IB mtu for a given network MTU. */
 | 
			
		||||
static inline enum ib_mtu eth_mtu_int_to_enum(int mtu)
 | 
			
		||||
{
 | 
			
		||||
	mtu -= RXE_MAX_HDR_LENGTH;
 | 
			
		||||
 | 
			
		||||
	return rxe_mtu_int_to_enum(mtu);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* default/initial rxe device parameter settings */
 | 
			
		||||
enum rxe_device_param {
 | 
			
		||||
	RXE_FW_VER			= 0,
 | 
			
		||||
	RXE_MAX_MR_SIZE			= -1ull,
 | 
			
		||||
	RXE_PAGE_SIZE_CAP		= 0xfffff000,
 | 
			
		||||
	RXE_VENDOR_ID			= 0,
 | 
			
		||||
	RXE_VENDOR_PART_ID		= 0,
 | 
			
		||||
	RXE_HW_VER			= 0,
 | 
			
		||||
	RXE_MAX_QP			= 0x10000,
 | 
			
		||||
	RXE_MAX_QP_WR			= 0x4000,
 | 
			
		||||
	RXE_MAX_INLINE_DATA		= 400,
 | 
			
		||||
	RXE_DEVICE_CAP_FLAGS		= IB_DEVICE_BAD_PKEY_CNTR
 | 
			
		||||
					| IB_DEVICE_BAD_QKEY_CNTR
 | 
			
		||||
					| IB_DEVICE_AUTO_PATH_MIG
 | 
			
		||||
					| IB_DEVICE_CHANGE_PHY_PORT
 | 
			
		||||
					| IB_DEVICE_UD_AV_PORT_ENFORCE
 | 
			
		||||
					| IB_DEVICE_PORT_ACTIVE_EVENT
 | 
			
		||||
					| IB_DEVICE_SYS_IMAGE_GUID
 | 
			
		||||
					| IB_DEVICE_RC_RNR_NAK_GEN
 | 
			
		||||
					| IB_DEVICE_SRQ_RESIZE
 | 
			
		||||
					| IB_DEVICE_MEM_MGT_EXTENSIONS,
 | 
			
		||||
	RXE_MAX_SGE			= 32,
 | 
			
		||||
	RXE_MAX_SGE_RD			= 32,
 | 
			
		||||
	RXE_MAX_CQ			= 16384,
 | 
			
		||||
	RXE_MAX_LOG_CQE			= 13,
 | 
			
		||||
	RXE_MAX_MR			= 2 * 1024,
 | 
			
		||||
	RXE_MAX_PD			= 0x7ffc,
 | 
			
		||||
	RXE_MAX_QP_RD_ATOM		= 128,
 | 
			
		||||
	RXE_MAX_EE_RD_ATOM		= 0,
 | 
			
		||||
	RXE_MAX_RES_RD_ATOM		= 0x3f000,
 | 
			
		||||
	RXE_MAX_QP_INIT_RD_ATOM		= 128,
 | 
			
		||||
	RXE_MAX_EE_INIT_RD_ATOM		= 0,
 | 
			
		||||
	RXE_ATOMIC_CAP			= 1,
 | 
			
		||||
	RXE_MAX_EE			= 0,
 | 
			
		||||
	RXE_MAX_RDD			= 0,
 | 
			
		||||
	RXE_MAX_MW			= 0,
 | 
			
		||||
	RXE_MAX_RAW_IPV6_QP		= 0,
 | 
			
		||||
	RXE_MAX_RAW_ETHY_QP		= 0,
 | 
			
		||||
	RXE_MAX_MCAST_GRP		= 8192,
 | 
			
		||||
	RXE_MAX_MCAST_QP_ATTACH		= 56,
 | 
			
		||||
	RXE_MAX_TOT_MCAST_QP_ATTACH	= 0x70000,
 | 
			
		||||
	RXE_MAX_AH			= 100,
 | 
			
		||||
	RXE_MAX_FMR			= 0,
 | 
			
		||||
	RXE_MAX_MAP_PER_FMR		= 0,
 | 
			
		||||
	RXE_MAX_SRQ			= 960,
 | 
			
		||||
	RXE_MAX_SRQ_WR			= 0x4000,
 | 
			
		||||
	RXE_MIN_SRQ_WR			= 1,
 | 
			
		||||
	RXE_MAX_SRQ_SGE			= 27,
 | 
			
		||||
	RXE_MIN_SRQ_SGE			= 1,
 | 
			
		||||
	RXE_MAX_FMR_PAGE_LIST_LEN	= 512,
 | 
			
		||||
	RXE_MAX_PKEYS			= 64,
 | 
			
		||||
	RXE_LOCAL_CA_ACK_DELAY		= 15,
 | 
			
		||||
 | 
			
		||||
	RXE_MAX_UCONTEXT		= 512,
 | 
			
		||||
 | 
			
		||||
	RXE_NUM_PORT			= 1,
 | 
			
		||||
	RXE_NUM_COMP_VECTORS		= 1,
 | 
			
		||||
 | 
			
		||||
	RXE_MIN_QP_INDEX		= 16,
 | 
			
		||||
	RXE_MAX_QP_INDEX		= 0x00020000,
 | 
			
		||||
 | 
			
		||||
	RXE_MIN_SRQ_INDEX		= 0x00020001,
 | 
			
		||||
	RXE_MAX_SRQ_INDEX		= 0x00040000,
 | 
			
		||||
 | 
			
		||||
	RXE_MIN_MR_INDEX		= 0x00000001,
 | 
			
		||||
	RXE_MAX_MR_INDEX		= 0x00040000,
 | 
			
		||||
	RXE_MIN_MW_INDEX		= 0x00040001,
 | 
			
		||||
	RXE_MAX_MW_INDEX		= 0x00060000,
 | 
			
		||||
	RXE_MAX_PKT_PER_ACK		= 64,
 | 
			
		||||
 | 
			
		||||
	RXE_MAX_UNACKED_PSNS		= 128,
 | 
			
		||||
 | 
			
		||||
	/* Max inflight SKBs per queue pair */
 | 
			
		||||
	RXE_INFLIGHT_SKBS_PER_QP_HIGH	= 64,
 | 
			
		||||
	RXE_INFLIGHT_SKBS_PER_QP_LOW	= 16,
 | 
			
		||||
 | 
			
		||||
	/* Delay before calling arbiter timer */
 | 
			
		||||
	RXE_NSEC_ARB_TIMER_DELAY	= 200,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* default/initial rxe port parameters */
 | 
			
		||||
enum rxe_port_param {
 | 
			
		||||
	RXE_PORT_STATE			= IB_PORT_DOWN,
 | 
			
		||||
	RXE_PORT_MAX_MTU		= IB_MTU_4096,
 | 
			
		||||
	RXE_PORT_ACTIVE_MTU		= IB_MTU_256,
 | 
			
		||||
	RXE_PORT_GID_TBL_LEN		= 1024,
 | 
			
		||||
	RXE_PORT_PORT_CAP_FLAGS		= RDMA_CORE_CAP_PROT_ROCE_UDP_ENCAP,
 | 
			
		||||
	RXE_PORT_MAX_MSG_SZ		= 0x800000,
 | 
			
		||||
	RXE_PORT_BAD_PKEY_CNTR		= 0,
 | 
			
		||||
	RXE_PORT_QKEY_VIOL_CNTR		= 0,
 | 
			
		||||
	RXE_PORT_LID			= 0,
 | 
			
		||||
	RXE_PORT_SM_LID			= 0,
 | 
			
		||||
	RXE_PORT_SM_SL			= 0,
 | 
			
		||||
	RXE_PORT_LMC			= 0,
 | 
			
		||||
	RXE_PORT_MAX_VL_NUM		= 1,
 | 
			
		||||
	RXE_PORT_SUBNET_TIMEOUT		= 0,
 | 
			
		||||
	RXE_PORT_INIT_TYPE_REPLY	= 0,
 | 
			
		||||
	RXE_PORT_ACTIVE_WIDTH		= IB_WIDTH_1X,
 | 
			
		||||
	RXE_PORT_ACTIVE_SPEED		= 1,
 | 
			
		||||
	RXE_PORT_PKEY_TBL_LEN		= 64,
 | 
			
		||||
	RXE_PORT_PHYS_STATE		= 2,
 | 
			
		||||
	RXE_PORT_SUBNET_PREFIX		= 0xfe80000000000000ULL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* default/initial port info parameters */
 | 
			
		||||
enum rxe_port_info_param {
 | 
			
		||||
	RXE_PORT_INFO_VL_CAP		= 4,	/* 1-8 */
 | 
			
		||||
	RXE_PORT_INFO_MTU_CAP		= 5,	/* 4096 */
 | 
			
		||||
	RXE_PORT_INFO_OPER_VL		= 1,	/* 1 */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif /* RXE_PARAM_H */
 | 
			
		||||
							
								
								
									
										502
									
								
								drivers/infiniband/sw/rxe/rxe_pool.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										502
									
								
								drivers/infiniband/sw/rxe/rxe_pool.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,502 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "rxe.h"
 | 
			
		||||
#include "rxe_loc.h"
 | 
			
		||||
 | 
			
		||||
/* info about object pools
 | 
			
		||||
 * note that mr and mw share a single index space
 | 
			
		||||
 * so that one can map an lkey to the correct type of object
 | 
			
		||||
 */
 | 
			
		||||
struct rxe_type_info rxe_type_info[RXE_NUM_TYPES] = {
 | 
			
		||||
	[RXE_TYPE_UC] = {
 | 
			
		||||
		.name		= "rxe-uc",
 | 
			
		||||
		.size		= sizeof(struct rxe_ucontext),
 | 
			
		||||
	},
 | 
			
		||||
	[RXE_TYPE_PD] = {
 | 
			
		||||
		.name		= "rxe-pd",
 | 
			
		||||
		.size		= sizeof(struct rxe_pd),
 | 
			
		||||
	},
 | 
			
		||||
	[RXE_TYPE_AH] = {
 | 
			
		||||
		.name		= "rxe-ah",
 | 
			
		||||
		.size		= sizeof(struct rxe_ah),
 | 
			
		||||
		.flags		= RXE_POOL_ATOMIC,
 | 
			
		||||
	},
 | 
			
		||||
	[RXE_TYPE_SRQ] = {
 | 
			
		||||
		.name		= "rxe-srq",
 | 
			
		||||
		.size		= sizeof(struct rxe_srq),
 | 
			
		||||
		.flags		= RXE_POOL_INDEX,
 | 
			
		||||
		.min_index	= RXE_MIN_SRQ_INDEX,
 | 
			
		||||
		.max_index	= RXE_MAX_SRQ_INDEX,
 | 
			
		||||
	},
 | 
			
		||||
	[RXE_TYPE_QP] = {
 | 
			
		||||
		.name		= "rxe-qp",
 | 
			
		||||
		.size		= sizeof(struct rxe_qp),
 | 
			
		||||
		.cleanup	= rxe_qp_cleanup,
 | 
			
		||||
		.flags		= RXE_POOL_INDEX,
 | 
			
		||||
		.min_index	= RXE_MIN_QP_INDEX,
 | 
			
		||||
		.max_index	= RXE_MAX_QP_INDEX,
 | 
			
		||||
	},
 | 
			
		||||
	[RXE_TYPE_CQ] = {
 | 
			
		||||
		.name		= "rxe-cq",
 | 
			
		||||
		.size		= sizeof(struct rxe_cq),
 | 
			
		||||
		.cleanup	= rxe_cq_cleanup,
 | 
			
		||||
	},
 | 
			
		||||
	[RXE_TYPE_MR] = {
 | 
			
		||||
		.name		= "rxe-mr",
 | 
			
		||||
		.size		= sizeof(struct rxe_mem),
 | 
			
		||||
		.cleanup	= rxe_mem_cleanup,
 | 
			
		||||
		.flags		= RXE_POOL_INDEX,
 | 
			
		||||
		.max_index	= RXE_MAX_MR_INDEX,
 | 
			
		||||
		.min_index	= RXE_MIN_MR_INDEX,
 | 
			
		||||
	},
 | 
			
		||||
	[RXE_TYPE_MW] = {
 | 
			
		||||
		.name		= "rxe-mw",
 | 
			
		||||
		.size		= sizeof(struct rxe_mem),
 | 
			
		||||
		.flags		= RXE_POOL_INDEX,
 | 
			
		||||
		.max_index	= RXE_MAX_MW_INDEX,
 | 
			
		||||
		.min_index	= RXE_MIN_MW_INDEX,
 | 
			
		||||
	},
 | 
			
		||||
	[RXE_TYPE_MC_GRP] = {
 | 
			
		||||
		.name		= "rxe-mc_grp",
 | 
			
		||||
		.size		= sizeof(struct rxe_mc_grp),
 | 
			
		||||
		.cleanup	= rxe_mc_cleanup,
 | 
			
		||||
		.flags		= RXE_POOL_KEY,
 | 
			
		||||
		.key_offset	= offsetof(struct rxe_mc_grp, mgid),
 | 
			
		||||
		.key_size	= sizeof(union ib_gid),
 | 
			
		||||
	},
 | 
			
		||||
	[RXE_TYPE_MC_ELEM] = {
 | 
			
		||||
		.name		= "rxe-mc_elem",
 | 
			
		||||
		.size		= sizeof(struct rxe_mc_elem),
 | 
			
		||||
		.flags		= RXE_POOL_ATOMIC,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline char *pool_name(struct rxe_pool *pool)
 | 
			
		||||
{
 | 
			
		||||
	return rxe_type_info[pool->type].name;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline struct kmem_cache *pool_cache(struct rxe_pool *pool)
 | 
			
		||||
{
 | 
			
		||||
	return rxe_type_info[pool->type].cache;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline enum rxe_elem_type rxe_type(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_pool_entry *elem = arg;
 | 
			
		||||
 | 
			
		||||
	return elem->pool->type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rxe_cache_init(void)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
	int i;
 | 
			
		||||
	size_t size;
 | 
			
		||||
	struct rxe_type_info *type;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < RXE_NUM_TYPES; i++) {
 | 
			
		||||
		type = &rxe_type_info[i];
 | 
			
		||||
		size = ALIGN(type->size, RXE_POOL_ALIGN);
 | 
			
		||||
		type->cache = kmem_cache_create(type->name, size,
 | 
			
		||||
				RXE_POOL_ALIGN,
 | 
			
		||||
				RXE_POOL_CACHE_FLAGS, NULL);
 | 
			
		||||
		if (!type->cache) {
 | 
			
		||||
			pr_err("Unable to init kmem cache for %s\n",
 | 
			
		||||
			       type->name);
 | 
			
		||||
			err = -ENOMEM;
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err1:
 | 
			
		||||
	while (--i >= 0) {
 | 
			
		||||
		kmem_cache_destroy(type->cache);
 | 
			
		||||
		type->cache = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rxe_cache_exit(void)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	struct rxe_type_info *type;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < RXE_NUM_TYPES; i++) {
 | 
			
		||||
		type = &rxe_type_info[i];
 | 
			
		||||
		kmem_cache_destroy(type->cache);
 | 
			
		||||
		type->cache = NULL;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rxe_pool_init_index(struct rxe_pool *pool, u32 max, u32 min)
 | 
			
		||||
{
 | 
			
		||||
	int err = 0;
 | 
			
		||||
	size_t size;
 | 
			
		||||
 | 
			
		||||
	if ((max - min + 1) < pool->max_elem) {
 | 
			
		||||
		pr_warn("not enough indices for max_elem\n");
 | 
			
		||||
		err = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pool->max_index = max;
 | 
			
		||||
	pool->min_index = min;
 | 
			
		||||
 | 
			
		||||
	size = BITS_TO_LONGS(max - min + 1) * sizeof(long);
 | 
			
		||||
	pool->table = kmalloc(size, GFP_KERNEL);
 | 
			
		||||
	if (!pool->table) {
 | 
			
		||||
		pr_warn("no memory for bit table\n");
 | 
			
		||||
		err = -ENOMEM;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pool->table_size = size;
 | 
			
		||||
	bitmap_zero(pool->table, max - min + 1);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rxe_pool_init(
 | 
			
		||||
	struct rxe_dev		*rxe,
 | 
			
		||||
	struct rxe_pool		*pool,
 | 
			
		||||
	enum rxe_elem_type	type,
 | 
			
		||||
	unsigned		max_elem)
 | 
			
		||||
{
 | 
			
		||||
	int			err = 0;
 | 
			
		||||
	size_t			size = rxe_type_info[type].size;
 | 
			
		||||
 | 
			
		||||
	memset(pool, 0, sizeof(*pool));
 | 
			
		||||
 | 
			
		||||
	pool->rxe		= rxe;
 | 
			
		||||
	pool->type		= type;
 | 
			
		||||
	pool->max_elem		= max_elem;
 | 
			
		||||
	pool->elem_size		= ALIGN(size, RXE_POOL_ALIGN);
 | 
			
		||||
	pool->flags		= rxe_type_info[type].flags;
 | 
			
		||||
	pool->tree		= RB_ROOT;
 | 
			
		||||
	pool->cleanup		= rxe_type_info[type].cleanup;
 | 
			
		||||
 | 
			
		||||
	atomic_set(&pool->num_elem, 0);
 | 
			
		||||
 | 
			
		||||
	kref_init(&pool->ref_cnt);
 | 
			
		||||
 | 
			
		||||
	spin_lock_init(&pool->pool_lock);
 | 
			
		||||
 | 
			
		||||
	if (rxe_type_info[type].flags & RXE_POOL_INDEX) {
 | 
			
		||||
		err = rxe_pool_init_index(pool,
 | 
			
		||||
					  rxe_type_info[type].max_index,
 | 
			
		||||
					  rxe_type_info[type].min_index);
 | 
			
		||||
		if (err)
 | 
			
		||||
			goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (rxe_type_info[type].flags & RXE_POOL_KEY) {
 | 
			
		||||
		pool->key_offset = rxe_type_info[type].key_offset;
 | 
			
		||||
		pool->key_size = rxe_type_info[type].key_size;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pool->state = rxe_pool_valid;
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rxe_pool_release(struct kref *kref)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_pool *pool = container_of(kref, struct rxe_pool, ref_cnt);
 | 
			
		||||
 | 
			
		||||
	pool->state = rxe_pool_invalid;
 | 
			
		||||
	kfree(pool->table);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rxe_pool_put(struct rxe_pool *pool)
 | 
			
		||||
{
 | 
			
		||||
	kref_put(&pool->ref_cnt, rxe_pool_release);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rxe_pool_cleanup(struct rxe_pool *pool)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&pool->pool_lock, flags);
 | 
			
		||||
	pool->state = rxe_pool_invalid;
 | 
			
		||||
	if (atomic_read(&pool->num_elem) > 0)
 | 
			
		||||
		pr_warn("%s pool destroyed with unfree'd elem\n",
 | 
			
		||||
			pool_name(pool));
 | 
			
		||||
	spin_unlock_irqrestore(&pool->pool_lock, flags);
 | 
			
		||||
 | 
			
		||||
	rxe_pool_put(pool);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static u32 alloc_index(struct rxe_pool *pool)
 | 
			
		||||
{
 | 
			
		||||
	u32 index;
 | 
			
		||||
	u32 range = pool->max_index - pool->min_index + 1;
 | 
			
		||||
 | 
			
		||||
	index = find_next_zero_bit(pool->table, range, pool->last);
 | 
			
		||||
	if (index >= range)
 | 
			
		||||
		index = find_first_zero_bit(pool->table, range);
 | 
			
		||||
 | 
			
		||||
	set_bit(index, pool->table);
 | 
			
		||||
	pool->last = index;
 | 
			
		||||
	return index + pool->min_index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void insert_index(struct rxe_pool *pool, struct rxe_pool_entry *new)
 | 
			
		||||
{
 | 
			
		||||
	struct rb_node **link = &pool->tree.rb_node;
 | 
			
		||||
	struct rb_node *parent = NULL;
 | 
			
		||||
	struct rxe_pool_entry *elem;
 | 
			
		||||
 | 
			
		||||
	while (*link) {
 | 
			
		||||
		parent = *link;
 | 
			
		||||
		elem = rb_entry(parent, struct rxe_pool_entry, node);
 | 
			
		||||
 | 
			
		||||
		if (elem->index == new->index) {
 | 
			
		||||
			pr_warn("element already exists!\n");
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (elem->index > new->index)
 | 
			
		||||
			link = &(*link)->rb_left;
 | 
			
		||||
		else
 | 
			
		||||
			link = &(*link)->rb_right;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rb_link_node(&new->node, parent, link);
 | 
			
		||||
	rb_insert_color(&new->node, &pool->tree);
 | 
			
		||||
out:
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void insert_key(struct rxe_pool *pool, struct rxe_pool_entry *new)
 | 
			
		||||
{
 | 
			
		||||
	struct rb_node **link = &pool->tree.rb_node;
 | 
			
		||||
	struct rb_node *parent = NULL;
 | 
			
		||||
	struct rxe_pool_entry *elem;
 | 
			
		||||
	int cmp;
 | 
			
		||||
 | 
			
		||||
	while (*link) {
 | 
			
		||||
		parent = *link;
 | 
			
		||||
		elem = rb_entry(parent, struct rxe_pool_entry, node);
 | 
			
		||||
 | 
			
		||||
		cmp = memcmp((u8 *)elem + pool->key_offset,
 | 
			
		||||
			     (u8 *)new + pool->key_offset, pool->key_size);
 | 
			
		||||
 | 
			
		||||
		if (cmp == 0) {
 | 
			
		||||
			pr_warn("key already exists!\n");
 | 
			
		||||
			goto out;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (cmp > 0)
 | 
			
		||||
			link = &(*link)->rb_left;
 | 
			
		||||
		else
 | 
			
		||||
			link = &(*link)->rb_right;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rb_link_node(&new->node, parent, link);
 | 
			
		||||
	rb_insert_color(&new->node, &pool->tree);
 | 
			
		||||
out:
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rxe_add_key(void *arg, void *key)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_pool_entry *elem = arg;
 | 
			
		||||
	struct rxe_pool *pool = elem->pool;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&pool->pool_lock, flags);
 | 
			
		||||
	memcpy((u8 *)elem + pool->key_offset, key, pool->key_size);
 | 
			
		||||
	insert_key(pool, elem);
 | 
			
		||||
	spin_unlock_irqrestore(&pool->pool_lock, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rxe_drop_key(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_pool_entry *elem = arg;
 | 
			
		||||
	struct rxe_pool *pool = elem->pool;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&pool->pool_lock, flags);
 | 
			
		||||
	rb_erase(&elem->node, &pool->tree);
 | 
			
		||||
	spin_unlock_irqrestore(&pool->pool_lock, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rxe_add_index(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_pool_entry *elem = arg;
 | 
			
		||||
	struct rxe_pool *pool = elem->pool;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&pool->pool_lock, flags);
 | 
			
		||||
	elem->index = alloc_index(pool);
 | 
			
		||||
	insert_index(pool, elem);
 | 
			
		||||
	spin_unlock_irqrestore(&pool->pool_lock, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rxe_drop_index(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_pool_entry *elem = arg;
 | 
			
		||||
	struct rxe_pool *pool = elem->pool;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&pool->pool_lock, flags);
 | 
			
		||||
	clear_bit(elem->index - pool->min_index, pool->table);
 | 
			
		||||
	rb_erase(&elem->node, &pool->tree);
 | 
			
		||||
	spin_unlock_irqrestore(&pool->pool_lock, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *rxe_alloc(struct rxe_pool *pool)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_pool_entry *elem;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	might_sleep_if(!(pool->flags & RXE_POOL_ATOMIC));
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&pool->pool_lock, flags);
 | 
			
		||||
	if (pool->state != rxe_pool_valid) {
 | 
			
		||||
		spin_unlock_irqrestore(&pool->pool_lock, flags);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	kref_get(&pool->ref_cnt);
 | 
			
		||||
	spin_unlock_irqrestore(&pool->pool_lock, flags);
 | 
			
		||||
 | 
			
		||||
	kref_get(&pool->rxe->ref_cnt);
 | 
			
		||||
 | 
			
		||||
	if (atomic_inc_return(&pool->num_elem) > pool->max_elem) {
 | 
			
		||||
		atomic_dec(&pool->num_elem);
 | 
			
		||||
		rxe_dev_put(pool->rxe);
 | 
			
		||||
		rxe_pool_put(pool);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	elem = kmem_cache_zalloc(pool_cache(pool),
 | 
			
		||||
				 (pool->flags & RXE_POOL_ATOMIC) ?
 | 
			
		||||
				 GFP_ATOMIC : GFP_KERNEL);
 | 
			
		||||
 | 
			
		||||
	elem->pool = pool;
 | 
			
		||||
	kref_init(&elem->ref_cnt);
 | 
			
		||||
 | 
			
		||||
	return elem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rxe_elem_release(struct kref *kref)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_pool_entry *elem =
 | 
			
		||||
		container_of(kref, struct rxe_pool_entry, ref_cnt);
 | 
			
		||||
	struct rxe_pool *pool = elem->pool;
 | 
			
		||||
 | 
			
		||||
	if (pool->cleanup)
 | 
			
		||||
		pool->cleanup(elem);
 | 
			
		||||
 | 
			
		||||
	kmem_cache_free(pool_cache(pool), elem);
 | 
			
		||||
	atomic_dec(&pool->num_elem);
 | 
			
		||||
	rxe_dev_put(pool->rxe);
 | 
			
		||||
	rxe_pool_put(pool);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *rxe_pool_get_index(struct rxe_pool *pool, u32 index)
 | 
			
		||||
{
 | 
			
		||||
	struct rb_node *node = NULL;
 | 
			
		||||
	struct rxe_pool_entry *elem = NULL;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&pool->pool_lock, flags);
 | 
			
		||||
 | 
			
		||||
	if (pool->state != rxe_pool_valid)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	node = pool->tree.rb_node;
 | 
			
		||||
 | 
			
		||||
	while (node) {
 | 
			
		||||
		elem = rb_entry(node, struct rxe_pool_entry, node);
 | 
			
		||||
 | 
			
		||||
		if (elem->index > index)
 | 
			
		||||
			node = node->rb_left;
 | 
			
		||||
		else if (elem->index < index)
 | 
			
		||||
			node = node->rb_right;
 | 
			
		||||
		else
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (node)
 | 
			
		||||
		kref_get(&elem->ref_cnt);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	spin_unlock_irqrestore(&pool->pool_lock, flags);
 | 
			
		||||
	return node ? (void *)elem : NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *rxe_pool_get_key(struct rxe_pool *pool, void *key)
 | 
			
		||||
{
 | 
			
		||||
	struct rb_node *node = NULL;
 | 
			
		||||
	struct rxe_pool_entry *elem = NULL;
 | 
			
		||||
	int cmp;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&pool->pool_lock, flags);
 | 
			
		||||
 | 
			
		||||
	if (pool->state != rxe_pool_valid)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	node = pool->tree.rb_node;
 | 
			
		||||
 | 
			
		||||
	while (node) {
 | 
			
		||||
		elem = rb_entry(node, struct rxe_pool_entry, node);
 | 
			
		||||
 | 
			
		||||
		cmp = memcmp((u8 *)elem + pool->key_offset,
 | 
			
		||||
			     key, pool->key_size);
 | 
			
		||||
 | 
			
		||||
		if (cmp > 0)
 | 
			
		||||
			node = node->rb_left;
 | 
			
		||||
		else if (cmp < 0)
 | 
			
		||||
			node = node->rb_right;
 | 
			
		||||
		else
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (node)
 | 
			
		||||
		kref_get(&elem->ref_cnt);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	spin_unlock_irqrestore(&pool->pool_lock, flags);
 | 
			
		||||
	return node ? ((void *)elem) : NULL;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										163
									
								
								drivers/infiniband/sw/rxe/rxe_pool.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								drivers/infiniband/sw/rxe/rxe_pool.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,163 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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 RXE_POOL_H
 | 
			
		||||
#define RXE_POOL_H
 | 
			
		||||
 | 
			
		||||
#define RXE_POOL_ALIGN		(16)
 | 
			
		||||
#define RXE_POOL_CACHE_FLAGS	(0)
 | 
			
		||||
 | 
			
		||||
enum rxe_pool_flags {
 | 
			
		||||
	RXE_POOL_ATOMIC		= BIT(0),
 | 
			
		||||
	RXE_POOL_INDEX		= BIT(1),
 | 
			
		||||
	RXE_POOL_KEY		= BIT(2),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum rxe_elem_type {
 | 
			
		||||
	RXE_TYPE_UC,
 | 
			
		||||
	RXE_TYPE_PD,
 | 
			
		||||
	RXE_TYPE_AH,
 | 
			
		||||
	RXE_TYPE_SRQ,
 | 
			
		||||
	RXE_TYPE_QP,
 | 
			
		||||
	RXE_TYPE_CQ,
 | 
			
		||||
	RXE_TYPE_MR,
 | 
			
		||||
	RXE_TYPE_MW,
 | 
			
		||||
	RXE_TYPE_MC_GRP,
 | 
			
		||||
	RXE_TYPE_MC_ELEM,
 | 
			
		||||
	RXE_NUM_TYPES,		/* keep me last */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_type_info {
 | 
			
		||||
	char			*name;
 | 
			
		||||
	size_t			size;
 | 
			
		||||
	void			(*cleanup)(void *obj);
 | 
			
		||||
	enum rxe_pool_flags	flags;
 | 
			
		||||
	u32			max_index;
 | 
			
		||||
	u32			min_index;
 | 
			
		||||
	size_t			key_offset;
 | 
			
		||||
	size_t			key_size;
 | 
			
		||||
	struct kmem_cache	*cache;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern struct rxe_type_info rxe_type_info[];
 | 
			
		||||
 | 
			
		||||
enum rxe_pool_state {
 | 
			
		||||
	rxe_pool_invalid,
 | 
			
		||||
	rxe_pool_valid,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_pool_entry {
 | 
			
		||||
	struct rxe_pool		*pool;
 | 
			
		||||
	struct kref		ref_cnt;
 | 
			
		||||
	struct list_head	list;
 | 
			
		||||
 | 
			
		||||
	/* only used if indexed or keyed */
 | 
			
		||||
	struct rb_node		node;
 | 
			
		||||
	u32			index;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_pool {
 | 
			
		||||
	struct rxe_dev		*rxe;
 | 
			
		||||
	spinlock_t              pool_lock; /* pool spinlock */
 | 
			
		||||
	size_t			elem_size;
 | 
			
		||||
	struct kref		ref_cnt;
 | 
			
		||||
	void			(*cleanup)(void *obj);
 | 
			
		||||
	enum rxe_pool_state	state;
 | 
			
		||||
	enum rxe_pool_flags	flags;
 | 
			
		||||
	enum rxe_elem_type	type;
 | 
			
		||||
 | 
			
		||||
	unsigned int		max_elem;
 | 
			
		||||
	atomic_t		num_elem;
 | 
			
		||||
 | 
			
		||||
	/* only used if indexed or keyed */
 | 
			
		||||
	struct rb_root		tree;
 | 
			
		||||
	unsigned long		*table;
 | 
			
		||||
	size_t			table_size;
 | 
			
		||||
	u32			max_index;
 | 
			
		||||
	u32			min_index;
 | 
			
		||||
	u32			last;
 | 
			
		||||
	size_t			key_offset;
 | 
			
		||||
	size_t			key_size;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* initialize slab caches for managed objects */
 | 
			
		||||
int rxe_cache_init(void);
 | 
			
		||||
 | 
			
		||||
/* cleanup slab caches for managed objects */
 | 
			
		||||
void rxe_cache_exit(void);
 | 
			
		||||
 | 
			
		||||
/* initialize a pool of objects with given limit on
 | 
			
		||||
 * number of elements. gets parameters from rxe_type_info
 | 
			
		||||
 * pool elements will be allocated out of a slab cache
 | 
			
		||||
 */
 | 
			
		||||
int rxe_pool_init(struct rxe_dev *rxe, struct rxe_pool *pool,
 | 
			
		||||
		  enum rxe_elem_type type, u32 max_elem);
 | 
			
		||||
 | 
			
		||||
/* free resources from object pool */
 | 
			
		||||
int rxe_pool_cleanup(struct rxe_pool *pool);
 | 
			
		||||
 | 
			
		||||
/* allocate an object from pool */
 | 
			
		||||
void *rxe_alloc(struct rxe_pool *pool);
 | 
			
		||||
 | 
			
		||||
/* assign an index to an indexed object and insert object into
 | 
			
		||||
 *  pool's rb tree
 | 
			
		||||
 */
 | 
			
		||||
void rxe_add_index(void *elem);
 | 
			
		||||
 | 
			
		||||
/* drop an index and remove object from rb tree */
 | 
			
		||||
void rxe_drop_index(void *elem);
 | 
			
		||||
 | 
			
		||||
/* assign a key to a keyed object and insert object into
 | 
			
		||||
 *  pool's rb tree
 | 
			
		||||
 */
 | 
			
		||||
void rxe_add_key(void *elem, void *key);
 | 
			
		||||
 | 
			
		||||
/* remove elem from rb tree */
 | 
			
		||||
void rxe_drop_key(void *elem);
 | 
			
		||||
 | 
			
		||||
/* lookup an indexed object from index. takes a reference on object */
 | 
			
		||||
void *rxe_pool_get_index(struct rxe_pool *pool, u32 index);
 | 
			
		||||
 | 
			
		||||
/* lookup keyed object from key. takes a reference on the object */
 | 
			
		||||
void *rxe_pool_get_key(struct rxe_pool *pool, void *key);
 | 
			
		||||
 | 
			
		||||
/* cleanup an object when all references are dropped */
 | 
			
		||||
void rxe_elem_release(struct kref *kref);
 | 
			
		||||
 | 
			
		||||
/* take a reference on an object */
 | 
			
		||||
#define rxe_add_ref(elem) kref_get(&(elem)->pelem.ref_cnt)
 | 
			
		||||
 | 
			
		||||
/* drop a reference on an object */
 | 
			
		||||
#define rxe_drop_ref(elem) kref_put(&(elem)->pelem.ref_cnt, rxe_elem_release)
 | 
			
		||||
 | 
			
		||||
#endif /* RXE_POOL_H */
 | 
			
		||||
							
								
								
									
										851
									
								
								drivers/infiniband/sw/rxe/rxe_qp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										851
									
								
								drivers/infiniband/sw/rxe/rxe_qp.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,851 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/skbuff.h>
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
#include <linux/sched.h>
 | 
			
		||||
 | 
			
		||||
#include "rxe.h"
 | 
			
		||||
#include "rxe_loc.h"
 | 
			
		||||
#include "rxe_queue.h"
 | 
			
		||||
#include "rxe_task.h"
 | 
			
		||||
 | 
			
		||||
char *rxe_qp_state_name[] = {
 | 
			
		||||
	[QP_STATE_RESET]	= "RESET",
 | 
			
		||||
	[QP_STATE_INIT]		= "INIT",
 | 
			
		||||
	[QP_STATE_READY]	= "READY",
 | 
			
		||||
	[QP_STATE_DRAIN]	= "DRAIN",
 | 
			
		||||
	[QP_STATE_DRAINED]	= "DRAINED",
 | 
			
		||||
	[QP_STATE_ERROR]	= "ERROR",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int rxe_qp_chk_cap(struct rxe_dev *rxe, struct ib_qp_cap *cap,
 | 
			
		||||
			  int has_srq)
 | 
			
		||||
{
 | 
			
		||||
	if (cap->max_send_wr > rxe->attr.max_qp_wr) {
 | 
			
		||||
		pr_warn("invalid send wr = %d > %d\n",
 | 
			
		||||
			cap->max_send_wr, rxe->attr.max_qp_wr);
 | 
			
		||||
		goto err1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (cap->max_send_sge > rxe->attr.max_sge) {
 | 
			
		||||
		pr_warn("invalid send sge = %d > %d\n",
 | 
			
		||||
			cap->max_send_sge, rxe->attr.max_sge);
 | 
			
		||||
		goto err1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!has_srq) {
 | 
			
		||||
		if (cap->max_recv_wr > rxe->attr.max_qp_wr) {
 | 
			
		||||
			pr_warn("invalid recv wr = %d > %d\n",
 | 
			
		||||
				cap->max_recv_wr, rxe->attr.max_qp_wr);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (cap->max_recv_sge > rxe->attr.max_sge) {
 | 
			
		||||
			pr_warn("invalid recv sge = %d > %d\n",
 | 
			
		||||
				cap->max_recv_sge, rxe->attr.max_sge);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (cap->max_inline_data > rxe->max_inline_data) {
 | 
			
		||||
		pr_warn("invalid max inline data = %d > %d\n",
 | 
			
		||||
			cap->max_inline_data, rxe->max_inline_data);
 | 
			
		||||
		goto err1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err1:
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rxe_qp_chk_init(struct rxe_dev *rxe, struct ib_qp_init_attr *init)
 | 
			
		||||
{
 | 
			
		||||
	struct ib_qp_cap *cap = &init->cap;
 | 
			
		||||
	struct rxe_port *port;
 | 
			
		||||
	int port_num = init->port_num;
 | 
			
		||||
 | 
			
		||||
	if (!init->recv_cq || !init->send_cq) {
 | 
			
		||||
		pr_warn("missing cq\n");
 | 
			
		||||
		goto err1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (rxe_qp_chk_cap(rxe, cap, !!init->srq))
 | 
			
		||||
		goto err1;
 | 
			
		||||
 | 
			
		||||
	if (init->qp_type == IB_QPT_SMI || init->qp_type == IB_QPT_GSI) {
 | 
			
		||||
		if (port_num != 1) {
 | 
			
		||||
			pr_warn("invalid port = %d\n", port_num);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		port = &rxe->port;
 | 
			
		||||
 | 
			
		||||
		if (init->qp_type == IB_QPT_SMI && port->qp_smi_index) {
 | 
			
		||||
			pr_warn("SMI QP exists for port %d\n", port_num);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (init->qp_type == IB_QPT_GSI && port->qp_gsi_index) {
 | 
			
		||||
			pr_warn("GSI QP exists for port %d\n", port_num);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err1:
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int alloc_rd_atomic_resources(struct rxe_qp *qp, unsigned int n)
 | 
			
		||||
{
 | 
			
		||||
	qp->resp.res_head = 0;
 | 
			
		||||
	qp->resp.res_tail = 0;
 | 
			
		||||
	qp->resp.resources = kcalloc(n, sizeof(struct resp_res), GFP_KERNEL);
 | 
			
		||||
 | 
			
		||||
	if (!qp->resp.resources)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void free_rd_atomic_resources(struct rxe_qp *qp)
 | 
			
		||||
{
 | 
			
		||||
	if (qp->resp.resources) {
 | 
			
		||||
		int i;
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < qp->attr.max_rd_atomic; i++) {
 | 
			
		||||
			struct resp_res *res = &qp->resp.resources[i];
 | 
			
		||||
 | 
			
		||||
			free_rd_atomic_resource(qp, res);
 | 
			
		||||
		}
 | 
			
		||||
		kfree(qp->resp.resources);
 | 
			
		||||
		qp->resp.resources = NULL;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void free_rd_atomic_resource(struct rxe_qp *qp, struct resp_res *res)
 | 
			
		||||
{
 | 
			
		||||
	if (res->type == RXE_ATOMIC_MASK) {
 | 
			
		||||
		rxe_drop_ref(qp);
 | 
			
		||||
		kfree_skb(res->atomic.skb);
 | 
			
		||||
	} else if (res->type == RXE_READ_MASK) {
 | 
			
		||||
		if (res->read.mr)
 | 
			
		||||
			rxe_drop_ref(res->read.mr);
 | 
			
		||||
	}
 | 
			
		||||
	res->type = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void cleanup_rd_atomic_resources(struct rxe_qp *qp)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	struct resp_res *res;
 | 
			
		||||
 | 
			
		||||
	if (qp->resp.resources) {
 | 
			
		||||
		for (i = 0; i < qp->attr.max_rd_atomic; i++) {
 | 
			
		||||
			res = &qp->resp.resources[i];
 | 
			
		||||
			free_rd_atomic_resource(qp, res);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rxe_qp_init_misc(struct rxe_dev *rxe, struct rxe_qp *qp,
 | 
			
		||||
			     struct ib_qp_init_attr *init)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_port *port;
 | 
			
		||||
	u32 qpn;
 | 
			
		||||
 | 
			
		||||
	qp->sq_sig_type		= init->sq_sig_type;
 | 
			
		||||
	qp->attr.path_mtu	= 1;
 | 
			
		||||
	qp->mtu			= ib_mtu_enum_to_int(qp->attr.path_mtu);
 | 
			
		||||
 | 
			
		||||
	qpn			= qp->pelem.index;
 | 
			
		||||
	port			= &rxe->port;
 | 
			
		||||
 | 
			
		||||
	switch (init->qp_type) {
 | 
			
		||||
	case IB_QPT_SMI:
 | 
			
		||||
		qp->ibqp.qp_num		= 0;
 | 
			
		||||
		port->qp_smi_index	= qpn;
 | 
			
		||||
		qp->attr.port_num	= init->port_num;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case IB_QPT_GSI:
 | 
			
		||||
		qp->ibqp.qp_num		= 1;
 | 
			
		||||
		port->qp_gsi_index	= qpn;
 | 
			
		||||
		qp->attr.port_num	= init->port_num;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		qp->ibqp.qp_num		= qpn;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	INIT_LIST_HEAD(&qp->grp_list);
 | 
			
		||||
 | 
			
		||||
	skb_queue_head_init(&qp->send_pkts);
 | 
			
		||||
 | 
			
		||||
	spin_lock_init(&qp->grp_lock);
 | 
			
		||||
	spin_lock_init(&qp->state_lock);
 | 
			
		||||
 | 
			
		||||
	atomic_set(&qp->ssn, 0);
 | 
			
		||||
	atomic_set(&qp->skb_out, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rxe_qp_init_req(struct rxe_dev *rxe, struct rxe_qp *qp,
 | 
			
		||||
			   struct ib_qp_init_attr *init,
 | 
			
		||||
			   struct ib_ucontext *context, struct ib_udata *udata)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
	int wqe_size;
 | 
			
		||||
 | 
			
		||||
	err = sock_create_kern(&init_net, AF_INET, SOCK_DGRAM, 0, &qp->sk);
 | 
			
		||||
	if (err < 0)
 | 
			
		||||
		return err;
 | 
			
		||||
	qp->sk->sk->sk_user_data = qp;
 | 
			
		||||
 | 
			
		||||
	qp->sq.max_wr		= init->cap.max_send_wr;
 | 
			
		||||
	qp->sq.max_sge		= init->cap.max_send_sge;
 | 
			
		||||
	qp->sq.max_inline	= init->cap.max_inline_data;
 | 
			
		||||
 | 
			
		||||
	wqe_size = max_t(int, sizeof(struct rxe_send_wqe) +
 | 
			
		||||
			 qp->sq.max_sge * sizeof(struct ib_sge),
 | 
			
		||||
			 sizeof(struct rxe_send_wqe) +
 | 
			
		||||
			 qp->sq.max_inline);
 | 
			
		||||
 | 
			
		||||
	qp->sq.queue = rxe_queue_init(rxe,
 | 
			
		||||
				      &qp->sq.max_wr,
 | 
			
		||||
				      wqe_size);
 | 
			
		||||
	if (!qp->sq.queue)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	err = do_mmap_info(rxe, udata, true,
 | 
			
		||||
			   context, qp->sq.queue->buf,
 | 
			
		||||
			   qp->sq.queue->buf_size, &qp->sq.queue->ip);
 | 
			
		||||
 | 
			
		||||
	if (err) {
 | 
			
		||||
		kvfree(qp->sq.queue->buf);
 | 
			
		||||
		kfree(qp->sq.queue);
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	qp->req.wqe_index	= producer_index(qp->sq.queue);
 | 
			
		||||
	qp->req.state		= QP_STATE_RESET;
 | 
			
		||||
	qp->req.opcode		= -1;
 | 
			
		||||
	qp->comp.opcode		= -1;
 | 
			
		||||
 | 
			
		||||
	spin_lock_init(&qp->sq.sq_lock);
 | 
			
		||||
	skb_queue_head_init(&qp->req_pkts);
 | 
			
		||||
 | 
			
		||||
	rxe_init_task(rxe, &qp->req.task, qp,
 | 
			
		||||
		      rxe_requester, "req");
 | 
			
		||||
	rxe_init_task(rxe, &qp->comp.task, qp,
 | 
			
		||||
		      rxe_completer, "comp");
 | 
			
		||||
 | 
			
		||||
	init_timer(&qp->rnr_nak_timer);
 | 
			
		||||
	qp->rnr_nak_timer.function = rnr_nak_timer;
 | 
			
		||||
	qp->rnr_nak_timer.data = (unsigned long)qp;
 | 
			
		||||
 | 
			
		||||
	init_timer(&qp->retrans_timer);
 | 
			
		||||
	qp->retrans_timer.function = retransmit_timer;
 | 
			
		||||
	qp->retrans_timer.data = (unsigned long)qp;
 | 
			
		||||
	qp->qp_timeout_jiffies = 0; /* Can't be set for UD/UC in modify_qp */
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rxe_qp_init_resp(struct rxe_dev *rxe, struct rxe_qp *qp,
 | 
			
		||||
			    struct ib_qp_init_attr *init,
 | 
			
		||||
			    struct ib_ucontext *context, struct ib_udata *udata)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
	int wqe_size;
 | 
			
		||||
 | 
			
		||||
	if (!qp->srq) {
 | 
			
		||||
		qp->rq.max_wr		= init->cap.max_recv_wr;
 | 
			
		||||
		qp->rq.max_sge		= init->cap.max_recv_sge;
 | 
			
		||||
 | 
			
		||||
		wqe_size = rcv_wqe_size(qp->rq.max_sge);
 | 
			
		||||
 | 
			
		||||
		pr_debug("max_wr = %d, max_sge = %d, wqe_size = %d\n",
 | 
			
		||||
			 qp->rq.max_wr, qp->rq.max_sge, wqe_size);
 | 
			
		||||
 | 
			
		||||
		qp->rq.queue = rxe_queue_init(rxe,
 | 
			
		||||
					      &qp->rq.max_wr,
 | 
			
		||||
					      wqe_size);
 | 
			
		||||
		if (!qp->rq.queue)
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
		err = do_mmap_info(rxe, udata, false, context,
 | 
			
		||||
				   qp->rq.queue->buf,
 | 
			
		||||
				   qp->rq.queue->buf_size,
 | 
			
		||||
				   &qp->rq.queue->ip);
 | 
			
		||||
		if (err) {
 | 
			
		||||
			kvfree(qp->rq.queue->buf);
 | 
			
		||||
			kfree(qp->rq.queue);
 | 
			
		||||
			return err;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	spin_lock_init(&qp->rq.producer_lock);
 | 
			
		||||
	spin_lock_init(&qp->rq.consumer_lock);
 | 
			
		||||
 | 
			
		||||
	skb_queue_head_init(&qp->resp_pkts);
 | 
			
		||||
 | 
			
		||||
	rxe_init_task(rxe, &qp->resp.task, qp,
 | 
			
		||||
		      rxe_responder, "resp");
 | 
			
		||||
 | 
			
		||||
	qp->resp.opcode		= OPCODE_NONE;
 | 
			
		||||
	qp->resp.msn		= 0;
 | 
			
		||||
	qp->resp.state		= QP_STATE_RESET;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* called by the create qp verb */
 | 
			
		||||
int rxe_qp_from_init(struct rxe_dev *rxe, struct rxe_qp *qp, struct rxe_pd *pd,
 | 
			
		||||
		     struct ib_qp_init_attr *init, struct ib_udata *udata,
 | 
			
		||||
		     struct ib_pd *ibpd)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
	struct rxe_cq *rcq = to_rcq(init->recv_cq);
 | 
			
		||||
	struct rxe_cq *scq = to_rcq(init->send_cq);
 | 
			
		||||
	struct rxe_srq *srq = init->srq ? to_rsrq(init->srq) : NULL;
 | 
			
		||||
	struct ib_ucontext *context = udata ? ibpd->uobject->context : NULL;
 | 
			
		||||
 | 
			
		||||
	rxe_add_ref(pd);
 | 
			
		||||
	rxe_add_ref(rcq);
 | 
			
		||||
	rxe_add_ref(scq);
 | 
			
		||||
	if (srq)
 | 
			
		||||
		rxe_add_ref(srq);
 | 
			
		||||
 | 
			
		||||
	qp->pd			= pd;
 | 
			
		||||
	qp->rcq			= rcq;
 | 
			
		||||
	qp->scq			= scq;
 | 
			
		||||
	qp->srq			= srq;
 | 
			
		||||
 | 
			
		||||
	rxe_qp_init_misc(rxe, qp, init);
 | 
			
		||||
 | 
			
		||||
	err = rxe_qp_init_req(rxe, qp, init, context, udata);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err1;
 | 
			
		||||
 | 
			
		||||
	err = rxe_qp_init_resp(rxe, qp, init, context, udata);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err2;
 | 
			
		||||
 | 
			
		||||
	qp->attr.qp_state = IB_QPS_RESET;
 | 
			
		||||
	qp->valid = 1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err2:
 | 
			
		||||
	rxe_queue_cleanup(qp->sq.queue);
 | 
			
		||||
err1:
 | 
			
		||||
	if (srq)
 | 
			
		||||
		rxe_drop_ref(srq);
 | 
			
		||||
	rxe_drop_ref(scq);
 | 
			
		||||
	rxe_drop_ref(rcq);
 | 
			
		||||
	rxe_drop_ref(pd);
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* called by the query qp verb */
 | 
			
		||||
int rxe_qp_to_init(struct rxe_qp *qp, struct ib_qp_init_attr *init)
 | 
			
		||||
{
 | 
			
		||||
	init->event_handler		= qp->ibqp.event_handler;
 | 
			
		||||
	init->qp_context		= qp->ibqp.qp_context;
 | 
			
		||||
	init->send_cq			= qp->ibqp.send_cq;
 | 
			
		||||
	init->recv_cq			= qp->ibqp.recv_cq;
 | 
			
		||||
	init->srq			= qp->ibqp.srq;
 | 
			
		||||
 | 
			
		||||
	init->cap.max_send_wr		= qp->sq.max_wr;
 | 
			
		||||
	init->cap.max_send_sge		= qp->sq.max_sge;
 | 
			
		||||
	init->cap.max_inline_data	= qp->sq.max_inline;
 | 
			
		||||
 | 
			
		||||
	if (!qp->srq) {
 | 
			
		||||
		init->cap.max_recv_wr		= qp->rq.max_wr;
 | 
			
		||||
		init->cap.max_recv_sge		= qp->rq.max_sge;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	init->sq_sig_type		= qp->sq_sig_type;
 | 
			
		||||
 | 
			
		||||
	init->qp_type			= qp->ibqp.qp_type;
 | 
			
		||||
	init->port_num			= 1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* called by the modify qp verb, this routine checks all the parameters before
 | 
			
		||||
 * making any changes
 | 
			
		||||
 */
 | 
			
		||||
int rxe_qp_chk_attr(struct rxe_dev *rxe, struct rxe_qp *qp,
 | 
			
		||||
		    struct ib_qp_attr *attr, int mask)
 | 
			
		||||
{
 | 
			
		||||
	enum ib_qp_state cur_state = (mask & IB_QP_CUR_STATE) ?
 | 
			
		||||
					attr->cur_qp_state : qp->attr.qp_state;
 | 
			
		||||
	enum ib_qp_state new_state = (mask & IB_QP_STATE) ?
 | 
			
		||||
					attr->qp_state : cur_state;
 | 
			
		||||
 | 
			
		||||
	if (!ib_modify_qp_is_ok(cur_state, new_state, qp_type(qp), mask,
 | 
			
		||||
				IB_LINK_LAYER_ETHERNET)) {
 | 
			
		||||
		pr_warn("invalid mask or state for qp\n");
 | 
			
		||||
		goto err1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_STATE) {
 | 
			
		||||
		if (cur_state == IB_QPS_SQD) {
 | 
			
		||||
			if (qp->req.state == QP_STATE_DRAIN &&
 | 
			
		||||
			    new_state != IB_QPS_ERR)
 | 
			
		||||
				goto err1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_PORT) {
 | 
			
		||||
		if (attr->port_num != 1) {
 | 
			
		||||
			pr_warn("invalid port %d\n", attr->port_num);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_CAP && rxe_qp_chk_cap(rxe, &attr->cap, !!qp->srq))
 | 
			
		||||
		goto err1;
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_AV && rxe_av_chk_attr(rxe, &attr->ah_attr))
 | 
			
		||||
		goto err1;
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_ALT_PATH) {
 | 
			
		||||
		if (rxe_av_chk_attr(rxe, &attr->alt_ah_attr))
 | 
			
		||||
			goto err1;
 | 
			
		||||
		if (attr->alt_port_num != 1) {
 | 
			
		||||
			pr_warn("invalid alt port %d\n", attr->alt_port_num);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
		if (attr->alt_timeout > 31) {
 | 
			
		||||
			pr_warn("invalid QP alt timeout %d > 31\n",
 | 
			
		||||
				attr->alt_timeout);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_PATH_MTU) {
 | 
			
		||||
		struct rxe_port *port = &rxe->port;
 | 
			
		||||
 | 
			
		||||
		enum ib_mtu max_mtu = port->attr.max_mtu;
 | 
			
		||||
		enum ib_mtu mtu = attr->path_mtu;
 | 
			
		||||
 | 
			
		||||
		if (mtu > max_mtu) {
 | 
			
		||||
			pr_debug("invalid mtu (%d) > (%d)\n",
 | 
			
		||||
				 ib_mtu_enum_to_int(mtu),
 | 
			
		||||
				 ib_mtu_enum_to_int(max_mtu));
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_MAX_QP_RD_ATOMIC) {
 | 
			
		||||
		if (attr->max_rd_atomic > rxe->attr.max_qp_rd_atom) {
 | 
			
		||||
			pr_warn("invalid max_rd_atomic %d > %d\n",
 | 
			
		||||
				attr->max_rd_atomic,
 | 
			
		||||
				rxe->attr.max_qp_rd_atom);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_TIMEOUT) {
 | 
			
		||||
		if (attr->timeout > 31) {
 | 
			
		||||
			pr_warn("invalid QP timeout %d > 31\n",
 | 
			
		||||
				attr->timeout);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err1:
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* move the qp to the reset state */
 | 
			
		||||
static void rxe_qp_reset(struct rxe_qp *qp)
 | 
			
		||||
{
 | 
			
		||||
	/* stop tasks from running */
 | 
			
		||||
	rxe_disable_task(&qp->resp.task);
 | 
			
		||||
 | 
			
		||||
	/* stop request/comp */
 | 
			
		||||
	if (qp->sq.queue) {
 | 
			
		||||
		if (qp_type(qp) == IB_QPT_RC)
 | 
			
		||||
			rxe_disable_task(&qp->comp.task);
 | 
			
		||||
		rxe_disable_task(&qp->req.task);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* move qp to the reset state */
 | 
			
		||||
	qp->req.state = QP_STATE_RESET;
 | 
			
		||||
	qp->resp.state = QP_STATE_RESET;
 | 
			
		||||
 | 
			
		||||
	/* let state machines reset themselves drain work and packet queues
 | 
			
		||||
	 * etc.
 | 
			
		||||
	 */
 | 
			
		||||
	__rxe_do_task(&qp->resp.task);
 | 
			
		||||
 | 
			
		||||
	if (qp->sq.queue) {
 | 
			
		||||
		__rxe_do_task(&qp->comp.task);
 | 
			
		||||
		__rxe_do_task(&qp->req.task);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* cleanup attributes */
 | 
			
		||||
	atomic_set(&qp->ssn, 0);
 | 
			
		||||
	qp->req.opcode = -1;
 | 
			
		||||
	qp->req.need_retry = 0;
 | 
			
		||||
	qp->req.noack_pkts = 0;
 | 
			
		||||
	qp->resp.msn = 0;
 | 
			
		||||
	qp->resp.opcode = -1;
 | 
			
		||||
	qp->resp.drop_msg = 0;
 | 
			
		||||
	qp->resp.goto_error = 0;
 | 
			
		||||
	qp->resp.sent_psn_nak = 0;
 | 
			
		||||
 | 
			
		||||
	if (qp->resp.mr) {
 | 
			
		||||
		rxe_drop_ref(qp->resp.mr);
 | 
			
		||||
		qp->resp.mr = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cleanup_rd_atomic_resources(qp);
 | 
			
		||||
 | 
			
		||||
	/* reenable tasks */
 | 
			
		||||
	rxe_enable_task(&qp->resp.task);
 | 
			
		||||
 | 
			
		||||
	if (qp->sq.queue) {
 | 
			
		||||
		if (qp_type(qp) == IB_QPT_RC)
 | 
			
		||||
			rxe_enable_task(&qp->comp.task);
 | 
			
		||||
 | 
			
		||||
		rxe_enable_task(&qp->req.task);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* drain the send queue */
 | 
			
		||||
static void rxe_qp_drain(struct rxe_qp *qp)
 | 
			
		||||
{
 | 
			
		||||
	if (qp->sq.queue) {
 | 
			
		||||
		if (qp->req.state != QP_STATE_DRAINED) {
 | 
			
		||||
			qp->req.state = QP_STATE_DRAIN;
 | 
			
		||||
			if (qp_type(qp) == IB_QPT_RC)
 | 
			
		||||
				rxe_run_task(&qp->comp.task, 1);
 | 
			
		||||
			else
 | 
			
		||||
				__rxe_do_task(&qp->comp.task);
 | 
			
		||||
			rxe_run_task(&qp->req.task, 1);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* move the qp to the error state */
 | 
			
		||||
void rxe_qp_error(struct rxe_qp *qp)
 | 
			
		||||
{
 | 
			
		||||
	qp->req.state = QP_STATE_ERROR;
 | 
			
		||||
	qp->resp.state = QP_STATE_ERROR;
 | 
			
		||||
 | 
			
		||||
	/* drain work and packet queues */
 | 
			
		||||
	rxe_run_task(&qp->resp.task, 1);
 | 
			
		||||
 | 
			
		||||
	if (qp_type(qp) == IB_QPT_RC)
 | 
			
		||||
		rxe_run_task(&qp->comp.task, 1);
 | 
			
		||||
	else
 | 
			
		||||
		__rxe_do_task(&qp->comp.task);
 | 
			
		||||
	rxe_run_task(&qp->req.task, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* called by the modify qp verb */
 | 
			
		||||
int rxe_qp_from_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask,
 | 
			
		||||
		     struct ib_udata *udata)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
	struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
 | 
			
		||||
	union ib_gid sgid;
 | 
			
		||||
	struct ib_gid_attr sgid_attr;
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_MAX_QP_RD_ATOMIC) {
 | 
			
		||||
		int max_rd_atomic = __roundup_pow_of_two(attr->max_rd_atomic);
 | 
			
		||||
 | 
			
		||||
		free_rd_atomic_resources(qp);
 | 
			
		||||
 | 
			
		||||
		err = alloc_rd_atomic_resources(qp, max_rd_atomic);
 | 
			
		||||
		if (err)
 | 
			
		||||
			return err;
 | 
			
		||||
 | 
			
		||||
		qp->attr.max_rd_atomic = max_rd_atomic;
 | 
			
		||||
		atomic_set(&qp->req.rd_atomic, max_rd_atomic);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_CUR_STATE)
 | 
			
		||||
		qp->attr.cur_qp_state = attr->qp_state;
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_EN_SQD_ASYNC_NOTIFY)
 | 
			
		||||
		qp->attr.en_sqd_async_notify = attr->en_sqd_async_notify;
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_ACCESS_FLAGS)
 | 
			
		||||
		qp->attr.qp_access_flags = attr->qp_access_flags;
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_PKEY_INDEX)
 | 
			
		||||
		qp->attr.pkey_index = attr->pkey_index;
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_PORT)
 | 
			
		||||
		qp->attr.port_num = attr->port_num;
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_QKEY)
 | 
			
		||||
		qp->attr.qkey = attr->qkey;
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_AV) {
 | 
			
		||||
		ib_get_cached_gid(&rxe->ib_dev, 1,
 | 
			
		||||
				  attr->ah_attr.grh.sgid_index, &sgid,
 | 
			
		||||
				  &sgid_attr);
 | 
			
		||||
		rxe_av_from_attr(rxe, attr->port_num, &qp->pri_av,
 | 
			
		||||
				 &attr->ah_attr);
 | 
			
		||||
		rxe_av_fill_ip_info(rxe, &qp->pri_av, &attr->ah_attr,
 | 
			
		||||
				    &sgid_attr, &sgid);
 | 
			
		||||
		if (sgid_attr.ndev)
 | 
			
		||||
			dev_put(sgid_attr.ndev);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_ALT_PATH) {
 | 
			
		||||
		ib_get_cached_gid(&rxe->ib_dev, 1,
 | 
			
		||||
				  attr->alt_ah_attr.grh.sgid_index, &sgid,
 | 
			
		||||
				  &sgid_attr);
 | 
			
		||||
 | 
			
		||||
		rxe_av_from_attr(rxe, attr->alt_port_num, &qp->alt_av,
 | 
			
		||||
				 &attr->alt_ah_attr);
 | 
			
		||||
		rxe_av_fill_ip_info(rxe, &qp->alt_av, &attr->alt_ah_attr,
 | 
			
		||||
				    &sgid_attr, &sgid);
 | 
			
		||||
		if (sgid_attr.ndev)
 | 
			
		||||
			dev_put(sgid_attr.ndev);
 | 
			
		||||
 | 
			
		||||
		qp->attr.alt_port_num = attr->alt_port_num;
 | 
			
		||||
		qp->attr.alt_pkey_index = attr->alt_pkey_index;
 | 
			
		||||
		qp->attr.alt_timeout = attr->alt_timeout;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_PATH_MTU) {
 | 
			
		||||
		qp->attr.path_mtu = attr->path_mtu;
 | 
			
		||||
		qp->mtu = ib_mtu_enum_to_int(attr->path_mtu);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_TIMEOUT) {
 | 
			
		||||
		qp->attr.timeout = attr->timeout;
 | 
			
		||||
		if (attr->timeout == 0) {
 | 
			
		||||
			qp->qp_timeout_jiffies = 0;
 | 
			
		||||
		} else {
 | 
			
		||||
			/* According to the spec, timeout = 4.096 * 2 ^ attr->timeout [us] */
 | 
			
		||||
			int j = nsecs_to_jiffies(4096ULL << attr->timeout);
 | 
			
		||||
 | 
			
		||||
			qp->qp_timeout_jiffies = j ? j : 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_RETRY_CNT) {
 | 
			
		||||
		qp->attr.retry_cnt = attr->retry_cnt;
 | 
			
		||||
		qp->comp.retry_cnt = attr->retry_cnt;
 | 
			
		||||
		pr_debug("set retry count = %d\n", attr->retry_cnt);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_RNR_RETRY) {
 | 
			
		||||
		qp->attr.rnr_retry = attr->rnr_retry;
 | 
			
		||||
		qp->comp.rnr_retry = attr->rnr_retry;
 | 
			
		||||
		pr_debug("set rnr retry count = %d\n", attr->rnr_retry);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_RQ_PSN) {
 | 
			
		||||
		qp->attr.rq_psn = (attr->rq_psn & BTH_PSN_MASK);
 | 
			
		||||
		qp->resp.psn = qp->attr.rq_psn;
 | 
			
		||||
		pr_debug("set resp psn = 0x%x\n", qp->resp.psn);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_MIN_RNR_TIMER) {
 | 
			
		||||
		qp->attr.min_rnr_timer = attr->min_rnr_timer;
 | 
			
		||||
		pr_debug("set min rnr timer = 0x%x\n",
 | 
			
		||||
			 attr->min_rnr_timer);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_SQ_PSN) {
 | 
			
		||||
		qp->attr.sq_psn = (attr->sq_psn & BTH_PSN_MASK);
 | 
			
		||||
		qp->req.psn = qp->attr.sq_psn;
 | 
			
		||||
		qp->comp.psn = qp->attr.sq_psn;
 | 
			
		||||
		pr_debug("set req psn = 0x%x\n", qp->req.psn);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_MAX_DEST_RD_ATOMIC) {
 | 
			
		||||
		qp->attr.max_dest_rd_atomic =
 | 
			
		||||
			__roundup_pow_of_two(attr->max_dest_rd_atomic);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_PATH_MIG_STATE)
 | 
			
		||||
		qp->attr.path_mig_state = attr->path_mig_state;
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_DEST_QPN)
 | 
			
		||||
		qp->attr.dest_qp_num = attr->dest_qp_num;
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_QP_STATE) {
 | 
			
		||||
		qp->attr.qp_state = attr->qp_state;
 | 
			
		||||
 | 
			
		||||
		switch (attr->qp_state) {
 | 
			
		||||
		case IB_QPS_RESET:
 | 
			
		||||
			pr_debug("qp state -> RESET\n");
 | 
			
		||||
			rxe_qp_reset(qp);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case IB_QPS_INIT:
 | 
			
		||||
			pr_debug("qp state -> INIT\n");
 | 
			
		||||
			qp->req.state = QP_STATE_INIT;
 | 
			
		||||
			qp->resp.state = QP_STATE_INIT;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case IB_QPS_RTR:
 | 
			
		||||
			pr_debug("qp state -> RTR\n");
 | 
			
		||||
			qp->resp.state = QP_STATE_READY;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case IB_QPS_RTS:
 | 
			
		||||
			pr_debug("qp state -> RTS\n");
 | 
			
		||||
			qp->req.state = QP_STATE_READY;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case IB_QPS_SQD:
 | 
			
		||||
			pr_debug("qp state -> SQD\n");
 | 
			
		||||
			rxe_qp_drain(qp);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case IB_QPS_SQE:
 | 
			
		||||
			pr_warn("qp state -> SQE !!?\n");
 | 
			
		||||
			/* Not possible from modify_qp. */
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case IB_QPS_ERR:
 | 
			
		||||
			pr_debug("qp state -> ERR\n");
 | 
			
		||||
			rxe_qp_error(qp);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* called by the query qp verb */
 | 
			
		||||
int rxe_qp_to_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
 | 
			
		||||
 | 
			
		||||
	*attr = qp->attr;
 | 
			
		||||
 | 
			
		||||
	attr->rq_psn				= qp->resp.psn;
 | 
			
		||||
	attr->sq_psn				= qp->req.psn;
 | 
			
		||||
 | 
			
		||||
	attr->cap.max_send_wr			= qp->sq.max_wr;
 | 
			
		||||
	attr->cap.max_send_sge			= qp->sq.max_sge;
 | 
			
		||||
	attr->cap.max_inline_data		= qp->sq.max_inline;
 | 
			
		||||
 | 
			
		||||
	if (!qp->srq) {
 | 
			
		||||
		attr->cap.max_recv_wr		= qp->rq.max_wr;
 | 
			
		||||
		attr->cap.max_recv_sge		= qp->rq.max_sge;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rxe_av_to_attr(rxe, &qp->pri_av, &attr->ah_attr);
 | 
			
		||||
	rxe_av_to_attr(rxe, &qp->alt_av, &attr->alt_ah_attr);
 | 
			
		||||
 | 
			
		||||
	if (qp->req.state == QP_STATE_DRAIN) {
 | 
			
		||||
		attr->sq_draining = 1;
 | 
			
		||||
		/* applications that get this state
 | 
			
		||||
		 * typically spin on it. yield the
 | 
			
		||||
		 * processor
 | 
			
		||||
		 */
 | 
			
		||||
		cond_resched();
 | 
			
		||||
	} else {
 | 
			
		||||
		attr->sq_draining = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pr_debug("attr->sq_draining = %d\n", attr->sq_draining);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* called by the destroy qp verb */
 | 
			
		||||
void rxe_qp_destroy(struct rxe_qp *qp)
 | 
			
		||||
{
 | 
			
		||||
	qp->valid = 0;
 | 
			
		||||
	qp->qp_timeout_jiffies = 0;
 | 
			
		||||
	rxe_cleanup_task(&qp->resp.task);
 | 
			
		||||
 | 
			
		||||
	del_timer_sync(&qp->retrans_timer);
 | 
			
		||||
	del_timer_sync(&qp->rnr_nak_timer);
 | 
			
		||||
 | 
			
		||||
	rxe_cleanup_task(&qp->req.task);
 | 
			
		||||
	if (qp_type(qp) == IB_QPT_RC)
 | 
			
		||||
		rxe_cleanup_task(&qp->comp.task);
 | 
			
		||||
 | 
			
		||||
	/* flush out any receive wr's or pending requests */
 | 
			
		||||
	__rxe_do_task(&qp->req.task);
 | 
			
		||||
	if (qp->sq.queue) {
 | 
			
		||||
		__rxe_do_task(&qp->comp.task);
 | 
			
		||||
		__rxe_do_task(&qp->req.task);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* called when the last reference to the qp is dropped */
 | 
			
		||||
void rxe_qp_cleanup(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_qp *qp = arg;
 | 
			
		||||
 | 
			
		||||
	rxe_drop_all_mcast_groups(qp);
 | 
			
		||||
 | 
			
		||||
	if (qp->sq.queue)
 | 
			
		||||
		rxe_queue_cleanup(qp->sq.queue);
 | 
			
		||||
 | 
			
		||||
	if (qp->srq)
 | 
			
		||||
		rxe_drop_ref(qp->srq);
 | 
			
		||||
 | 
			
		||||
	if (qp->rq.queue)
 | 
			
		||||
		rxe_queue_cleanup(qp->rq.queue);
 | 
			
		||||
 | 
			
		||||
	if (qp->scq)
 | 
			
		||||
		rxe_drop_ref(qp->scq);
 | 
			
		||||
	if (qp->rcq)
 | 
			
		||||
		rxe_drop_ref(qp->rcq);
 | 
			
		||||
	if (qp->pd)
 | 
			
		||||
		rxe_drop_ref(qp->pd);
 | 
			
		||||
 | 
			
		||||
	if (qp->resp.mr) {
 | 
			
		||||
		rxe_drop_ref(qp->resp.mr);
 | 
			
		||||
		qp->resp.mr = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	free_rd_atomic_resources(qp);
 | 
			
		||||
 | 
			
		||||
	kernel_sock_shutdown(qp->sk, SHUT_RDWR);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										217
									
								
								drivers/infiniband/sw/rxe/rxe_queue.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								drivers/infiniband/sw/rxe/rxe_queue.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,217 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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 retailuce the above
 | 
			
		||||
 *	  copyright notice, this list of conditions and the following
 | 
			
		||||
 *	  disclaimer in the documentation and/or other materials
 | 
			
		||||
 *	  provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/vmalloc.h>
 | 
			
		||||
#include "rxe.h"
 | 
			
		||||
#include "rxe_loc.h"
 | 
			
		||||
#include "rxe_queue.h"
 | 
			
		||||
 | 
			
		||||
int do_mmap_info(struct rxe_dev *rxe,
 | 
			
		||||
		 struct ib_udata *udata,
 | 
			
		||||
		 bool is_req,
 | 
			
		||||
		 struct ib_ucontext *context,
 | 
			
		||||
		 struct rxe_queue_buf *buf,
 | 
			
		||||
		 size_t buf_size,
 | 
			
		||||
		 struct rxe_mmap_info **ip_p)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
	u32 len, offset;
 | 
			
		||||
	struct rxe_mmap_info *ip = NULL;
 | 
			
		||||
 | 
			
		||||
	if (udata) {
 | 
			
		||||
		if (is_req) {
 | 
			
		||||
			len = udata->outlen - sizeof(struct mminfo);
 | 
			
		||||
			offset = sizeof(struct mminfo);
 | 
			
		||||
		} else {
 | 
			
		||||
			len = udata->outlen;
 | 
			
		||||
			offset = 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (len < sizeof(ip->info))
 | 
			
		||||
			goto err1;
 | 
			
		||||
 | 
			
		||||
		ip = rxe_create_mmap_info(rxe, buf_size, context, buf);
 | 
			
		||||
		if (!ip)
 | 
			
		||||
			goto err1;
 | 
			
		||||
 | 
			
		||||
		err = copy_to_user(udata->outbuf + offset, &ip->info,
 | 
			
		||||
				   sizeof(ip->info));
 | 
			
		||||
		if (err)
 | 
			
		||||
			goto err2;
 | 
			
		||||
 | 
			
		||||
		spin_lock_bh(&rxe->pending_lock);
 | 
			
		||||
		list_add(&ip->pending_mmaps, &rxe->pending_mmaps);
 | 
			
		||||
		spin_unlock_bh(&rxe->pending_lock);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*ip_p = ip;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err2:
 | 
			
		||||
	kfree(ip);
 | 
			
		||||
err1:
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct rxe_queue *rxe_queue_init(struct rxe_dev *rxe,
 | 
			
		||||
				 int *num_elem,
 | 
			
		||||
				 unsigned int elem_size)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_queue *q;
 | 
			
		||||
	size_t buf_size;
 | 
			
		||||
	unsigned int num_slots;
 | 
			
		||||
 | 
			
		||||
	/* num_elem == 0 is allowed, but uninteresting */
 | 
			
		||||
	if (*num_elem < 0)
 | 
			
		||||
		goto err1;
 | 
			
		||||
 | 
			
		||||
	q = kmalloc(sizeof(*q), GFP_KERNEL);
 | 
			
		||||
	if (!q)
 | 
			
		||||
		goto err1;
 | 
			
		||||
 | 
			
		||||
	q->rxe = rxe;
 | 
			
		||||
 | 
			
		||||
	/* used in resize, only need to copy used part of queue */
 | 
			
		||||
	q->elem_size = elem_size;
 | 
			
		||||
 | 
			
		||||
	/* pad element up to at least a cacheline and always a power of 2 */
 | 
			
		||||
	if (elem_size < cache_line_size())
 | 
			
		||||
		elem_size = cache_line_size();
 | 
			
		||||
	elem_size = roundup_pow_of_two(elem_size);
 | 
			
		||||
 | 
			
		||||
	q->log2_elem_size = order_base_2(elem_size);
 | 
			
		||||
 | 
			
		||||
	num_slots = *num_elem + 1;
 | 
			
		||||
	num_slots = roundup_pow_of_two(num_slots);
 | 
			
		||||
	q->index_mask = num_slots - 1;
 | 
			
		||||
 | 
			
		||||
	buf_size = sizeof(struct rxe_queue_buf) + num_slots * elem_size;
 | 
			
		||||
 | 
			
		||||
	q->buf = vmalloc_user(buf_size);
 | 
			
		||||
	if (!q->buf)
 | 
			
		||||
		goto err2;
 | 
			
		||||
 | 
			
		||||
	q->buf->log2_elem_size = q->log2_elem_size;
 | 
			
		||||
	q->buf->index_mask = q->index_mask;
 | 
			
		||||
 | 
			
		||||
	q->buf_size = buf_size;
 | 
			
		||||
 | 
			
		||||
	*num_elem = num_slots - 1;
 | 
			
		||||
	return q;
 | 
			
		||||
 | 
			
		||||
err2:
 | 
			
		||||
	kfree(q);
 | 
			
		||||
err1:
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* copies elements from original q to new q and then swaps the contents of the
 | 
			
		||||
 * two q headers. This is so that if anyone is holding a pointer to q it will
 | 
			
		||||
 * still work
 | 
			
		||||
 */
 | 
			
		||||
static int resize_finish(struct rxe_queue *q, struct rxe_queue *new_q,
 | 
			
		||||
			 unsigned int num_elem)
 | 
			
		||||
{
 | 
			
		||||
	if (!queue_empty(q) && (num_elem < queue_count(q)))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	while (!queue_empty(q)) {
 | 
			
		||||
		memcpy(producer_addr(new_q), consumer_addr(q),
 | 
			
		||||
		       new_q->elem_size);
 | 
			
		||||
		advance_producer(new_q);
 | 
			
		||||
		advance_consumer(q);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	swap(*q, *new_q);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rxe_queue_resize(struct rxe_queue *q,
 | 
			
		||||
		     unsigned int *num_elem_p,
 | 
			
		||||
		     unsigned int elem_size,
 | 
			
		||||
		     struct ib_ucontext *context,
 | 
			
		||||
		     struct ib_udata *udata,
 | 
			
		||||
		     spinlock_t *producer_lock,
 | 
			
		||||
		     spinlock_t *consumer_lock)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_queue *new_q;
 | 
			
		||||
	unsigned int num_elem = *num_elem_p;
 | 
			
		||||
	int err;
 | 
			
		||||
	unsigned long flags = 0, flags1;
 | 
			
		||||
 | 
			
		||||
	new_q = rxe_queue_init(q->rxe, &num_elem, elem_size);
 | 
			
		||||
	if (!new_q)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	err = do_mmap_info(new_q->rxe, udata, false, context, new_q->buf,
 | 
			
		||||
			   new_q->buf_size, &new_q->ip);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		vfree(new_q->buf);
 | 
			
		||||
		kfree(new_q);
 | 
			
		||||
		goto err1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(consumer_lock, flags1);
 | 
			
		||||
 | 
			
		||||
	if (producer_lock) {
 | 
			
		||||
		spin_lock_irqsave(producer_lock, flags);
 | 
			
		||||
		err = resize_finish(q, new_q, num_elem);
 | 
			
		||||
		spin_unlock_irqrestore(producer_lock, flags);
 | 
			
		||||
	} else {
 | 
			
		||||
		err = resize_finish(q, new_q, num_elem);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	spin_unlock_irqrestore(consumer_lock, flags1);
 | 
			
		||||
 | 
			
		||||
	rxe_queue_cleanup(new_q);	/* new/old dep on err */
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto err1;
 | 
			
		||||
 | 
			
		||||
	*num_elem_p = num_elem;
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err1:
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rxe_queue_cleanup(struct rxe_queue *q)
 | 
			
		||||
{
 | 
			
		||||
	if (q->ip)
 | 
			
		||||
		kref_put(&q->ip->ref, rxe_mmap_release);
 | 
			
		||||
	else
 | 
			
		||||
		vfree(q->buf);
 | 
			
		||||
 | 
			
		||||
	kfree(q);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										178
									
								
								drivers/infiniband/sw/rxe/rxe_queue.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								drivers/infiniband/sw/rxe/rxe_queue.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,178 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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 RXE_QUEUE_H
 | 
			
		||||
#define RXE_QUEUE_H
 | 
			
		||||
 | 
			
		||||
/* implements a simple circular buffer that can optionally be
 | 
			
		||||
 * shared between user space and the kernel and can be resized
 | 
			
		||||
 | 
			
		||||
 * the requested element size is rounded up to a power of 2
 | 
			
		||||
 * and the number of elements in the buffer is also rounded
 | 
			
		||||
 * up to a power of 2. Since the queue is empty when the
 | 
			
		||||
 * producer and consumer indices match the maximum capacity
 | 
			
		||||
 * of the queue is one less than the number of element slots
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* this data structure is shared between user space and kernel
 | 
			
		||||
 * space for those cases where the queue is shared. It contains
 | 
			
		||||
 * the producer and consumer indices. Is also contains a copy
 | 
			
		||||
 * of the queue size parameters for user space to use but the
 | 
			
		||||
 * kernel must use the parameters in the rxe_queue struct
 | 
			
		||||
 * this MUST MATCH the corresponding librxe struct
 | 
			
		||||
 * for performance reasons arrange to have producer and consumer
 | 
			
		||||
 * pointers in separate cache lines
 | 
			
		||||
 * the kernel should always mask the indices to avoid accessing
 | 
			
		||||
 * memory outside of the data area
 | 
			
		||||
 */
 | 
			
		||||
struct rxe_queue_buf {
 | 
			
		||||
	__u32			log2_elem_size;
 | 
			
		||||
	__u32			index_mask;
 | 
			
		||||
	__u32			pad_1[30];
 | 
			
		||||
	__u32			producer_index;
 | 
			
		||||
	__u32			pad_2[31];
 | 
			
		||||
	__u32			consumer_index;
 | 
			
		||||
	__u32			pad_3[31];
 | 
			
		||||
	__u8			data[0];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_queue {
 | 
			
		||||
	struct rxe_dev		*rxe;
 | 
			
		||||
	struct rxe_queue_buf	*buf;
 | 
			
		||||
	struct rxe_mmap_info	*ip;
 | 
			
		||||
	size_t			buf_size;
 | 
			
		||||
	size_t			elem_size;
 | 
			
		||||
	unsigned int		log2_elem_size;
 | 
			
		||||
	unsigned int		index_mask;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int do_mmap_info(struct rxe_dev *rxe,
 | 
			
		||||
		 struct ib_udata *udata,
 | 
			
		||||
		 bool is_req,
 | 
			
		||||
		 struct ib_ucontext *context,
 | 
			
		||||
		 struct rxe_queue_buf *buf,
 | 
			
		||||
		 size_t buf_size,
 | 
			
		||||
		 struct rxe_mmap_info **ip_p);
 | 
			
		||||
 | 
			
		||||
struct rxe_queue *rxe_queue_init(struct rxe_dev *rxe,
 | 
			
		||||
				 int *num_elem,
 | 
			
		||||
				 unsigned int elem_size);
 | 
			
		||||
 | 
			
		||||
int rxe_queue_resize(struct rxe_queue *q,
 | 
			
		||||
		     unsigned int *num_elem_p,
 | 
			
		||||
		     unsigned int elem_size,
 | 
			
		||||
		     struct ib_ucontext *context,
 | 
			
		||||
		     struct ib_udata *udata,
 | 
			
		||||
		     /* Protect producers while resizing queue */
 | 
			
		||||
		     spinlock_t *producer_lock,
 | 
			
		||||
		     /* Protect consumers while resizing queue */
 | 
			
		||||
		     spinlock_t *consumer_lock);
 | 
			
		||||
 | 
			
		||||
void rxe_queue_cleanup(struct rxe_queue *queue);
 | 
			
		||||
 | 
			
		||||
static inline int next_index(struct rxe_queue *q, int index)
 | 
			
		||||
{
 | 
			
		||||
	return (index + 1) & q->buf->index_mask;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int queue_empty(struct rxe_queue *q)
 | 
			
		||||
{
 | 
			
		||||
	return ((q->buf->producer_index - q->buf->consumer_index)
 | 
			
		||||
			& q->index_mask) == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int queue_full(struct rxe_queue *q)
 | 
			
		||||
{
 | 
			
		||||
	return ((q->buf->producer_index + 1 - q->buf->consumer_index)
 | 
			
		||||
			& q->index_mask) == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void advance_producer(struct rxe_queue *q)
 | 
			
		||||
{
 | 
			
		||||
	q->buf->producer_index = (q->buf->producer_index + 1)
 | 
			
		||||
			& q->index_mask;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void advance_consumer(struct rxe_queue *q)
 | 
			
		||||
{
 | 
			
		||||
	q->buf->consumer_index = (q->buf->consumer_index + 1)
 | 
			
		||||
			& q->index_mask;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void *producer_addr(struct rxe_queue *q)
 | 
			
		||||
{
 | 
			
		||||
	return q->buf->data + ((q->buf->producer_index & q->index_mask)
 | 
			
		||||
				<< q->log2_elem_size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void *consumer_addr(struct rxe_queue *q)
 | 
			
		||||
{
 | 
			
		||||
	return q->buf->data + ((q->buf->consumer_index & q->index_mask)
 | 
			
		||||
				<< q->log2_elem_size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline unsigned int producer_index(struct rxe_queue *q)
 | 
			
		||||
{
 | 
			
		||||
	return q->buf->producer_index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline unsigned int consumer_index(struct rxe_queue *q)
 | 
			
		||||
{
 | 
			
		||||
	return q->buf->consumer_index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void *addr_from_index(struct rxe_queue *q, unsigned int index)
 | 
			
		||||
{
 | 
			
		||||
	return q->buf->data + ((index & q->index_mask)
 | 
			
		||||
				<< q->buf->log2_elem_size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline unsigned int index_from_addr(const struct rxe_queue *q,
 | 
			
		||||
					   const void *addr)
 | 
			
		||||
{
 | 
			
		||||
	return (((u8 *)addr - q->buf->data) >> q->log2_elem_size)
 | 
			
		||||
		& q->index_mask;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline unsigned int queue_count(const struct rxe_queue *q)
 | 
			
		||||
{
 | 
			
		||||
	return (q->buf->producer_index - q->buf->consumer_index)
 | 
			
		||||
		& q->index_mask;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void *queue_head(struct rxe_queue *q)
 | 
			
		||||
{
 | 
			
		||||
	return queue_empty(q) ? NULL : consumer_addr(q);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* RXE_QUEUE_H */
 | 
			
		||||
							
								
								
									
										420
									
								
								drivers/infiniband/sw/rxe/rxe_recv.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										420
									
								
								drivers/infiniband/sw/rxe/rxe_recv.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,420 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/skbuff.h>
 | 
			
		||||
 | 
			
		||||
#include "rxe.h"
 | 
			
		||||
#include "rxe_loc.h"
 | 
			
		||||
 | 
			
		||||
static int check_type_state(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
 | 
			
		||||
			    struct rxe_qp *qp)
 | 
			
		||||
{
 | 
			
		||||
	if (unlikely(!qp->valid))
 | 
			
		||||
		goto err1;
 | 
			
		||||
 | 
			
		||||
	switch (qp_type(qp)) {
 | 
			
		||||
	case IB_QPT_RC:
 | 
			
		||||
		if (unlikely((pkt->opcode & IB_OPCODE_RC) != 0)) {
 | 
			
		||||
			pr_warn_ratelimited("bad qp type\n");
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case IB_QPT_UC:
 | 
			
		||||
		if (unlikely(!(pkt->opcode & IB_OPCODE_UC))) {
 | 
			
		||||
			pr_warn_ratelimited("bad qp type\n");
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case IB_QPT_UD:
 | 
			
		||||
	case IB_QPT_SMI:
 | 
			
		||||
	case IB_QPT_GSI:
 | 
			
		||||
		if (unlikely(!(pkt->opcode & IB_OPCODE_UD))) {
 | 
			
		||||
			pr_warn_ratelimited("bad qp type\n");
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		pr_warn_ratelimited("unsupported qp type\n");
 | 
			
		||||
		goto err1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (pkt->mask & RXE_REQ_MASK) {
 | 
			
		||||
		if (unlikely(qp->resp.state != QP_STATE_READY))
 | 
			
		||||
			goto err1;
 | 
			
		||||
	} else if (unlikely(qp->req.state < QP_STATE_READY ||
 | 
			
		||||
				qp->req.state > QP_STATE_DRAINED)) {
 | 
			
		||||
		goto err1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err1:
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void set_bad_pkey_cntr(struct rxe_port *port)
 | 
			
		||||
{
 | 
			
		||||
	spin_lock_bh(&port->port_lock);
 | 
			
		||||
	port->attr.bad_pkey_cntr = min((u32)0xffff,
 | 
			
		||||
				       port->attr.bad_pkey_cntr + 1);
 | 
			
		||||
	spin_unlock_bh(&port->port_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void set_qkey_viol_cntr(struct rxe_port *port)
 | 
			
		||||
{
 | 
			
		||||
	spin_lock_bh(&port->port_lock);
 | 
			
		||||
	port->attr.qkey_viol_cntr = min((u32)0xffff,
 | 
			
		||||
					port->attr.qkey_viol_cntr + 1);
 | 
			
		||||
	spin_unlock_bh(&port->port_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int check_keys(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
 | 
			
		||||
		      u32 qpn, struct rxe_qp *qp)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	int found_pkey = 0;
 | 
			
		||||
	struct rxe_port *port = &rxe->port;
 | 
			
		||||
	u16 pkey = bth_pkey(pkt);
 | 
			
		||||
 | 
			
		||||
	pkt->pkey_index = 0;
 | 
			
		||||
 | 
			
		||||
	if (qpn == 1) {
 | 
			
		||||
		for (i = 0; i < port->attr.pkey_tbl_len; i++) {
 | 
			
		||||
			if (pkey_match(pkey, port->pkey_tbl[i])) {
 | 
			
		||||
				pkt->pkey_index = i;
 | 
			
		||||
				found_pkey = 1;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!found_pkey) {
 | 
			
		||||
			pr_warn_ratelimited("bad pkey = 0x%x\n", pkey);
 | 
			
		||||
			set_bad_pkey_cntr(port);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
	} else if (qpn != 0) {
 | 
			
		||||
		if (unlikely(!pkey_match(pkey,
 | 
			
		||||
					 port->pkey_tbl[qp->attr.pkey_index]
 | 
			
		||||
					))) {
 | 
			
		||||
			pr_warn_ratelimited("bad pkey = 0x%0x\n", pkey);
 | 
			
		||||
			set_bad_pkey_cntr(port);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
		pkt->pkey_index = qp->attr.pkey_index;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((qp_type(qp) == IB_QPT_UD || qp_type(qp) == IB_QPT_GSI) &&
 | 
			
		||||
	    qpn != 0 && pkt->mask) {
 | 
			
		||||
		u32 qkey = (qpn == 1) ? GSI_QKEY : qp->attr.qkey;
 | 
			
		||||
 | 
			
		||||
		if (unlikely(deth_qkey(pkt) != qkey)) {
 | 
			
		||||
			pr_warn_ratelimited("bad qkey, got 0x%x expected 0x%x for qpn 0x%x\n",
 | 
			
		||||
					    deth_qkey(pkt), qkey, qpn);
 | 
			
		||||
			set_qkey_viol_cntr(port);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err1:
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int check_addr(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
 | 
			
		||||
		      struct rxe_qp *qp)
 | 
			
		||||
{
 | 
			
		||||
	struct sk_buff *skb = PKT_TO_SKB(pkt);
 | 
			
		||||
 | 
			
		||||
	if (qp_type(qp) != IB_QPT_RC && qp_type(qp) != IB_QPT_UC)
 | 
			
		||||
		goto done;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(pkt->port_num != qp->attr.port_num)) {
 | 
			
		||||
		pr_warn_ratelimited("port %d != qp port %d\n",
 | 
			
		||||
				    pkt->port_num, qp->attr.port_num);
 | 
			
		||||
		goto err1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (skb->protocol == htons(ETH_P_IP)) {
 | 
			
		||||
		struct in_addr *saddr =
 | 
			
		||||
			&qp->pri_av.sgid_addr._sockaddr_in.sin_addr;
 | 
			
		||||
		struct in_addr *daddr =
 | 
			
		||||
			&qp->pri_av.dgid_addr._sockaddr_in.sin_addr;
 | 
			
		||||
 | 
			
		||||
		if (ip_hdr(skb)->daddr != saddr->s_addr) {
 | 
			
		||||
			pr_warn_ratelimited("dst addr %pI4 != qp source addr %pI4\n",
 | 
			
		||||
					    &ip_hdr(skb)->daddr,
 | 
			
		||||
					    &saddr->s_addr);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (ip_hdr(skb)->saddr != daddr->s_addr) {
 | 
			
		||||
			pr_warn_ratelimited("source addr %pI4 != qp dst addr %pI4\n",
 | 
			
		||||
					    &ip_hdr(skb)->saddr,
 | 
			
		||||
					    &daddr->s_addr);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	} else if (skb->protocol == htons(ETH_P_IPV6)) {
 | 
			
		||||
		struct in6_addr *saddr =
 | 
			
		||||
			&qp->pri_av.sgid_addr._sockaddr_in6.sin6_addr;
 | 
			
		||||
		struct in6_addr *daddr =
 | 
			
		||||
			&qp->pri_av.dgid_addr._sockaddr_in6.sin6_addr;
 | 
			
		||||
 | 
			
		||||
		if (memcmp(&ipv6_hdr(skb)->daddr, saddr, sizeof(*saddr))) {
 | 
			
		||||
			pr_warn_ratelimited("dst addr %pI6 != qp source addr %pI6\n",
 | 
			
		||||
					    &ipv6_hdr(skb)->daddr, saddr);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (memcmp(&ipv6_hdr(skb)->saddr, daddr, sizeof(*daddr))) {
 | 
			
		||||
			pr_warn_ratelimited("source addr %pI6 != qp dst addr %pI6\n",
 | 
			
		||||
					    &ipv6_hdr(skb)->saddr, daddr);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err1:
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int hdr_check(struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_dev *rxe = pkt->rxe;
 | 
			
		||||
	struct rxe_port *port = &rxe->port;
 | 
			
		||||
	struct rxe_qp *qp = NULL;
 | 
			
		||||
	u32 qpn = bth_qpn(pkt);
 | 
			
		||||
	int index;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(bth_tver(pkt) != BTH_TVER)) {
 | 
			
		||||
		pr_warn_ratelimited("bad tver\n");
 | 
			
		||||
		goto err1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (qpn != IB_MULTICAST_QPN) {
 | 
			
		||||
		index = (qpn == 0) ? port->qp_smi_index :
 | 
			
		||||
			((qpn == 1) ? port->qp_gsi_index : qpn);
 | 
			
		||||
		qp = rxe_pool_get_index(&rxe->qp_pool, index);
 | 
			
		||||
		if (unlikely(!qp)) {
 | 
			
		||||
			pr_warn_ratelimited("no qp matches qpn 0x%x\n", qpn);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		err = check_type_state(rxe, pkt, qp);
 | 
			
		||||
		if (unlikely(err))
 | 
			
		||||
			goto err2;
 | 
			
		||||
 | 
			
		||||
		err = check_addr(rxe, pkt, qp);
 | 
			
		||||
		if (unlikely(err))
 | 
			
		||||
			goto err2;
 | 
			
		||||
 | 
			
		||||
		err = check_keys(rxe, pkt, qpn, qp);
 | 
			
		||||
		if (unlikely(err))
 | 
			
		||||
			goto err2;
 | 
			
		||||
	} else {
 | 
			
		||||
		if (unlikely((pkt->mask & RXE_GRH_MASK) == 0)) {
 | 
			
		||||
			pr_warn_ratelimited("no grh for mcast qpn\n");
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pkt->qp = qp;
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err2:
 | 
			
		||||
	if (qp)
 | 
			
		||||
		rxe_drop_ref(qp);
 | 
			
		||||
err1:
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void rxe_rcv_pkt(struct rxe_dev *rxe,
 | 
			
		||||
			       struct rxe_pkt_info *pkt,
 | 
			
		||||
			       struct sk_buff *skb)
 | 
			
		||||
{
 | 
			
		||||
	if (pkt->mask & RXE_REQ_MASK)
 | 
			
		||||
		rxe_resp_queue_pkt(rxe, pkt->qp, skb);
 | 
			
		||||
	else
 | 
			
		||||
		rxe_comp_queue_pkt(rxe, pkt->qp, skb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rxe_rcv_mcast_pkt(struct rxe_dev *rxe, struct sk_buff *skb)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_pkt_info *pkt = SKB_TO_PKT(skb);
 | 
			
		||||
	struct rxe_mc_grp *mcg;
 | 
			
		||||
	struct sk_buff *skb_copy;
 | 
			
		||||
	struct rxe_mc_elem *mce;
 | 
			
		||||
	struct rxe_qp *qp;
 | 
			
		||||
	union ib_gid dgid;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	if (skb->protocol == htons(ETH_P_IP))
 | 
			
		||||
		ipv6_addr_set_v4mapped(ip_hdr(skb)->daddr,
 | 
			
		||||
				       (struct in6_addr *)&dgid);
 | 
			
		||||
	else if (skb->protocol == htons(ETH_P_IPV6))
 | 
			
		||||
		memcpy(&dgid, &ipv6_hdr(skb)->daddr, sizeof(dgid));
 | 
			
		||||
 | 
			
		||||
	/* lookup mcast group corresponding to mgid, takes a ref */
 | 
			
		||||
	mcg = rxe_pool_get_key(&rxe->mc_grp_pool, &dgid);
 | 
			
		||||
	if (!mcg)
 | 
			
		||||
		goto err1;	/* mcast group not registered */
 | 
			
		||||
 | 
			
		||||
	spin_lock_bh(&mcg->mcg_lock);
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry(mce, &mcg->qp_list, qp_list) {
 | 
			
		||||
		qp = mce->qp;
 | 
			
		||||
		pkt = SKB_TO_PKT(skb);
 | 
			
		||||
 | 
			
		||||
		/* validate qp for incoming packet */
 | 
			
		||||
		err = check_type_state(rxe, pkt, qp);
 | 
			
		||||
		if (err)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		err = check_keys(rxe, pkt, bth_qpn(pkt), qp);
 | 
			
		||||
		if (err)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/* if *not* the last qp in the list
 | 
			
		||||
		 * make a copy of the skb to post to the next qp
 | 
			
		||||
		 */
 | 
			
		||||
		skb_copy = (mce->qp_list.next != &mcg->qp_list) ?
 | 
			
		||||
				skb_clone(skb, GFP_KERNEL) : NULL;
 | 
			
		||||
 | 
			
		||||
		pkt->qp = qp;
 | 
			
		||||
		rxe_add_ref(qp);
 | 
			
		||||
		rxe_rcv_pkt(rxe, pkt, skb);
 | 
			
		||||
 | 
			
		||||
		skb = skb_copy;
 | 
			
		||||
		if (!skb)
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	spin_unlock_bh(&mcg->mcg_lock);
 | 
			
		||||
 | 
			
		||||
	rxe_drop_ref(mcg);	/* drop ref from rxe_pool_get_key. */
 | 
			
		||||
 | 
			
		||||
err1:
 | 
			
		||||
	if (skb)
 | 
			
		||||
		kfree_skb(skb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rxe_match_dgid(struct rxe_dev *rxe, struct sk_buff *skb)
 | 
			
		||||
{
 | 
			
		||||
	union ib_gid dgid;
 | 
			
		||||
	union ib_gid *pdgid;
 | 
			
		||||
	u16 index;
 | 
			
		||||
 | 
			
		||||
	if (skb->protocol == htons(ETH_P_IP)) {
 | 
			
		||||
		ipv6_addr_set_v4mapped(ip_hdr(skb)->daddr,
 | 
			
		||||
				       (struct in6_addr *)&dgid);
 | 
			
		||||
		pdgid = &dgid;
 | 
			
		||||
	} else {
 | 
			
		||||
		pdgid = (union ib_gid *)&ipv6_hdr(skb)->daddr;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ib_find_cached_gid_by_port(&rxe->ib_dev, pdgid,
 | 
			
		||||
					  IB_GID_TYPE_ROCE_UDP_ENCAP,
 | 
			
		||||
					  1, rxe->ndev, &index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* rxe_rcv is called from the interface driver */
 | 
			
		||||
int rxe_rcv(struct sk_buff *skb)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
	struct rxe_pkt_info *pkt = SKB_TO_PKT(skb);
 | 
			
		||||
	struct rxe_dev *rxe = pkt->rxe;
 | 
			
		||||
	__be32 *icrcp;
 | 
			
		||||
	u32 calc_icrc, pack_icrc;
 | 
			
		||||
 | 
			
		||||
	pkt->offset = 0;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(skb->len < pkt->offset + RXE_BTH_BYTES))
 | 
			
		||||
		goto drop;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(rxe_match_dgid(rxe, skb) < 0)) {
 | 
			
		||||
		pr_warn_ratelimited("failed matching dgid\n");
 | 
			
		||||
		goto drop;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pkt->opcode = bth_opcode(pkt);
 | 
			
		||||
	pkt->psn = bth_psn(pkt);
 | 
			
		||||
	pkt->qp = NULL;
 | 
			
		||||
	pkt->mask |= rxe_opcode[pkt->opcode].mask;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(skb->len < header_size(pkt)))
 | 
			
		||||
		goto drop;
 | 
			
		||||
 | 
			
		||||
	err = hdr_check(pkt);
 | 
			
		||||
	if (unlikely(err))
 | 
			
		||||
		goto drop;
 | 
			
		||||
 | 
			
		||||
	/* Verify ICRC */
 | 
			
		||||
	icrcp = (__be32 *)(pkt->hdr + pkt->paylen - RXE_ICRC_SIZE);
 | 
			
		||||
	pack_icrc = be32_to_cpu(*icrcp);
 | 
			
		||||
 | 
			
		||||
	calc_icrc = rxe_icrc_hdr(pkt, skb);
 | 
			
		||||
	calc_icrc = crc32_le(calc_icrc, (u8 *)payload_addr(pkt), payload_size(pkt));
 | 
			
		||||
	calc_icrc = cpu_to_be32(~calc_icrc);
 | 
			
		||||
	if (unlikely(calc_icrc != pack_icrc)) {
 | 
			
		||||
		char saddr[sizeof(struct in6_addr)];
 | 
			
		||||
 | 
			
		||||
		if (skb->protocol == htons(ETH_P_IPV6))
 | 
			
		||||
			sprintf(saddr, "%pI6", &ipv6_hdr(skb)->saddr);
 | 
			
		||||
		else if (skb->protocol == htons(ETH_P_IP))
 | 
			
		||||
			sprintf(saddr, "%pI4", &ip_hdr(skb)->saddr);
 | 
			
		||||
		else
 | 
			
		||||
			sprintf(saddr, "unknown");
 | 
			
		||||
 | 
			
		||||
		pr_warn_ratelimited("bad ICRC from %s\n", saddr);
 | 
			
		||||
		goto drop;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (unlikely(bth_qpn(pkt) == IB_MULTICAST_QPN))
 | 
			
		||||
		rxe_rcv_mcast_pkt(rxe, skb);
 | 
			
		||||
	else
 | 
			
		||||
		rxe_rcv_pkt(rxe, pkt, skb);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
drop:
 | 
			
		||||
	if (pkt->qp)
 | 
			
		||||
		rxe_drop_ref(pkt->qp);
 | 
			
		||||
 | 
			
		||||
	kfree_skb(skb);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(rxe_rcv);
 | 
			
		||||
							
								
								
									
										726
									
								
								drivers/infiniband/sw/rxe/rxe_req.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										726
									
								
								drivers/infiniband/sw/rxe/rxe_req.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,726 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/skbuff.h>
 | 
			
		||||
 | 
			
		||||
#include "rxe.h"
 | 
			
		||||
#include "rxe_loc.h"
 | 
			
		||||
#include "rxe_queue.h"
 | 
			
		||||
 | 
			
		||||
static int next_opcode(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
 | 
			
		||||
		       unsigned opcode);
 | 
			
		||||
 | 
			
		||||
static inline void retry_first_write_send(struct rxe_qp *qp,
 | 
			
		||||
					  struct rxe_send_wqe *wqe,
 | 
			
		||||
					  unsigned mask, int npsn)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < npsn; i++) {
 | 
			
		||||
		int to_send = (wqe->dma.resid > qp->mtu) ?
 | 
			
		||||
				qp->mtu : wqe->dma.resid;
 | 
			
		||||
 | 
			
		||||
		qp->req.opcode = next_opcode(qp, wqe,
 | 
			
		||||
					     wqe->wr.opcode);
 | 
			
		||||
 | 
			
		||||
		if (wqe->wr.send_flags & IB_SEND_INLINE) {
 | 
			
		||||
			wqe->dma.resid -= to_send;
 | 
			
		||||
			wqe->dma.sge_offset += to_send;
 | 
			
		||||
		} else {
 | 
			
		||||
			advance_dma_data(&wqe->dma, to_send);
 | 
			
		||||
		}
 | 
			
		||||
		if (mask & WR_WRITE_MASK)
 | 
			
		||||
			wqe->iova += qp->mtu;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void req_retry(struct rxe_qp *qp)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_send_wqe *wqe;
 | 
			
		||||
	unsigned int wqe_index;
 | 
			
		||||
	unsigned int mask;
 | 
			
		||||
	int npsn;
 | 
			
		||||
	int first = 1;
 | 
			
		||||
 | 
			
		||||
	wqe = queue_head(qp->sq.queue);
 | 
			
		||||
	npsn = (qp->comp.psn - wqe->first_psn) & BTH_PSN_MASK;
 | 
			
		||||
 | 
			
		||||
	qp->req.wqe_index	= consumer_index(qp->sq.queue);
 | 
			
		||||
	qp->req.psn		= qp->comp.psn;
 | 
			
		||||
	qp->req.opcode		= -1;
 | 
			
		||||
 | 
			
		||||
	for (wqe_index = consumer_index(qp->sq.queue);
 | 
			
		||||
		wqe_index != producer_index(qp->sq.queue);
 | 
			
		||||
		wqe_index = next_index(qp->sq.queue, wqe_index)) {
 | 
			
		||||
		wqe = addr_from_index(qp->sq.queue, wqe_index);
 | 
			
		||||
		mask = wr_opcode_mask(wqe->wr.opcode, qp);
 | 
			
		||||
 | 
			
		||||
		if (wqe->state == wqe_state_posted)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		if (wqe->state == wqe_state_done)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		wqe->iova = (mask & WR_ATOMIC_MASK) ?
 | 
			
		||||
			     wqe->wr.wr.atomic.remote_addr :
 | 
			
		||||
			     (mask & WR_READ_OR_WRITE_MASK) ?
 | 
			
		||||
			     wqe->wr.wr.rdma.remote_addr :
 | 
			
		||||
			     0;
 | 
			
		||||
 | 
			
		||||
		if (!first || (mask & WR_READ_MASK) == 0) {
 | 
			
		||||
			wqe->dma.resid = wqe->dma.length;
 | 
			
		||||
			wqe->dma.cur_sge = 0;
 | 
			
		||||
			wqe->dma.sge_offset = 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (first) {
 | 
			
		||||
			first = 0;
 | 
			
		||||
 | 
			
		||||
			if (mask & WR_WRITE_OR_SEND_MASK)
 | 
			
		||||
				retry_first_write_send(qp, wqe, mask, npsn);
 | 
			
		||||
 | 
			
		||||
			if (mask & WR_READ_MASK)
 | 
			
		||||
				wqe->iova += npsn * qp->mtu;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		wqe->state = wqe_state_posted;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rnr_nak_timer(unsigned long data)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_qp *qp = (struct rxe_qp *)data;
 | 
			
		||||
 | 
			
		||||
	pr_debug("rnr nak timer fired\n");
 | 
			
		||||
	rxe_run_task(&qp->req.task, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct rxe_send_wqe *req_next_wqe(struct rxe_qp *qp)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_send_wqe *wqe = queue_head(qp->sq.queue);
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(qp->req.state == QP_STATE_DRAIN)) {
 | 
			
		||||
		/* check to see if we are drained;
 | 
			
		||||
		 * state_lock used by requester and completer
 | 
			
		||||
		 */
 | 
			
		||||
		spin_lock_irqsave(&qp->state_lock, flags);
 | 
			
		||||
		do {
 | 
			
		||||
			if (qp->req.state != QP_STATE_DRAIN) {
 | 
			
		||||
				/* comp just finished */
 | 
			
		||||
				spin_unlock_irqrestore(&qp->state_lock,
 | 
			
		||||
						       flags);
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (wqe && ((qp->req.wqe_index !=
 | 
			
		||||
				consumer_index(qp->sq.queue)) ||
 | 
			
		||||
				(wqe->state != wqe_state_posted))) {
 | 
			
		||||
				/* comp not done yet */
 | 
			
		||||
				spin_unlock_irqrestore(&qp->state_lock,
 | 
			
		||||
						       flags);
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			qp->req.state = QP_STATE_DRAINED;
 | 
			
		||||
			spin_unlock_irqrestore(&qp->state_lock, flags);
 | 
			
		||||
 | 
			
		||||
			if (qp->ibqp.event_handler) {
 | 
			
		||||
				struct ib_event ev;
 | 
			
		||||
 | 
			
		||||
				ev.device = qp->ibqp.device;
 | 
			
		||||
				ev.element.qp = &qp->ibqp;
 | 
			
		||||
				ev.event = IB_EVENT_SQ_DRAINED;
 | 
			
		||||
				qp->ibqp.event_handler(&ev,
 | 
			
		||||
					qp->ibqp.qp_context);
 | 
			
		||||
			}
 | 
			
		||||
		} while (0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (qp->req.wqe_index == producer_index(qp->sq.queue))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	wqe = addr_from_index(qp->sq.queue, qp->req.wqe_index);
 | 
			
		||||
 | 
			
		||||
	if (unlikely((qp->req.state == QP_STATE_DRAIN ||
 | 
			
		||||
		      qp->req.state == QP_STATE_DRAINED) &&
 | 
			
		||||
		     (wqe->state != wqe_state_processing)))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	if (unlikely((wqe->wr.send_flags & IB_SEND_FENCE) &&
 | 
			
		||||
		     (qp->req.wqe_index != consumer_index(qp->sq.queue)))) {
 | 
			
		||||
		qp->req.wait_fence = 1;
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wqe->mask = wr_opcode_mask(wqe->wr.opcode, qp);
 | 
			
		||||
	return wqe;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int next_opcode_rc(struct rxe_qp *qp, unsigned opcode, int fits)
 | 
			
		||||
{
 | 
			
		||||
	switch (opcode) {
 | 
			
		||||
	case IB_WR_RDMA_WRITE:
 | 
			
		||||
		if (qp->req.opcode == IB_OPCODE_RC_RDMA_WRITE_FIRST ||
 | 
			
		||||
		    qp->req.opcode == IB_OPCODE_RC_RDMA_WRITE_MIDDLE)
 | 
			
		||||
			return fits ?
 | 
			
		||||
				IB_OPCODE_RC_RDMA_WRITE_LAST :
 | 
			
		||||
				IB_OPCODE_RC_RDMA_WRITE_MIDDLE;
 | 
			
		||||
		else
 | 
			
		||||
			return fits ?
 | 
			
		||||
				IB_OPCODE_RC_RDMA_WRITE_ONLY :
 | 
			
		||||
				IB_OPCODE_RC_RDMA_WRITE_FIRST;
 | 
			
		||||
 | 
			
		||||
	case IB_WR_RDMA_WRITE_WITH_IMM:
 | 
			
		||||
		if (qp->req.opcode == IB_OPCODE_RC_RDMA_WRITE_FIRST ||
 | 
			
		||||
		    qp->req.opcode == IB_OPCODE_RC_RDMA_WRITE_MIDDLE)
 | 
			
		||||
			return fits ?
 | 
			
		||||
				IB_OPCODE_RC_RDMA_WRITE_LAST_WITH_IMMEDIATE :
 | 
			
		||||
				IB_OPCODE_RC_RDMA_WRITE_MIDDLE;
 | 
			
		||||
		else
 | 
			
		||||
			return fits ?
 | 
			
		||||
				IB_OPCODE_RC_RDMA_WRITE_ONLY_WITH_IMMEDIATE :
 | 
			
		||||
				IB_OPCODE_RC_RDMA_WRITE_FIRST;
 | 
			
		||||
 | 
			
		||||
	case IB_WR_SEND:
 | 
			
		||||
		if (qp->req.opcode == IB_OPCODE_RC_SEND_FIRST ||
 | 
			
		||||
		    qp->req.opcode == IB_OPCODE_RC_SEND_MIDDLE)
 | 
			
		||||
			return fits ?
 | 
			
		||||
				IB_OPCODE_RC_SEND_LAST :
 | 
			
		||||
				IB_OPCODE_RC_SEND_MIDDLE;
 | 
			
		||||
		else
 | 
			
		||||
			return fits ?
 | 
			
		||||
				IB_OPCODE_RC_SEND_ONLY :
 | 
			
		||||
				IB_OPCODE_RC_SEND_FIRST;
 | 
			
		||||
 | 
			
		||||
	case IB_WR_SEND_WITH_IMM:
 | 
			
		||||
		if (qp->req.opcode == IB_OPCODE_RC_SEND_FIRST ||
 | 
			
		||||
		    qp->req.opcode == IB_OPCODE_RC_SEND_MIDDLE)
 | 
			
		||||
			return fits ?
 | 
			
		||||
				IB_OPCODE_RC_SEND_LAST_WITH_IMMEDIATE :
 | 
			
		||||
				IB_OPCODE_RC_SEND_MIDDLE;
 | 
			
		||||
		else
 | 
			
		||||
			return fits ?
 | 
			
		||||
				IB_OPCODE_RC_SEND_ONLY_WITH_IMMEDIATE :
 | 
			
		||||
				IB_OPCODE_RC_SEND_FIRST;
 | 
			
		||||
 | 
			
		||||
	case IB_WR_RDMA_READ:
 | 
			
		||||
		return IB_OPCODE_RC_RDMA_READ_REQUEST;
 | 
			
		||||
 | 
			
		||||
	case IB_WR_ATOMIC_CMP_AND_SWP:
 | 
			
		||||
		return IB_OPCODE_RC_COMPARE_SWAP;
 | 
			
		||||
 | 
			
		||||
	case IB_WR_ATOMIC_FETCH_AND_ADD:
 | 
			
		||||
		return IB_OPCODE_RC_FETCH_ADD;
 | 
			
		||||
 | 
			
		||||
	case IB_WR_SEND_WITH_INV:
 | 
			
		||||
		if (qp->req.opcode == IB_OPCODE_RC_SEND_FIRST ||
 | 
			
		||||
		    qp->req.opcode == IB_OPCODE_RC_SEND_MIDDLE)
 | 
			
		||||
			return fits ? IB_OPCODE_RC_SEND_LAST_WITH_INVALIDATE :
 | 
			
		||||
				IB_OPCODE_RC_SEND_MIDDLE;
 | 
			
		||||
		else
 | 
			
		||||
			return fits ? IB_OPCODE_RC_SEND_ONLY_WITH_INVALIDATE :
 | 
			
		||||
				IB_OPCODE_RC_SEND_FIRST;
 | 
			
		||||
	case IB_WR_REG_MR:
 | 
			
		||||
	case IB_WR_LOCAL_INV:
 | 
			
		||||
		return opcode;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int next_opcode_uc(struct rxe_qp *qp, unsigned opcode, int fits)
 | 
			
		||||
{
 | 
			
		||||
	switch (opcode) {
 | 
			
		||||
	case IB_WR_RDMA_WRITE:
 | 
			
		||||
		if (qp->req.opcode == IB_OPCODE_UC_RDMA_WRITE_FIRST ||
 | 
			
		||||
		    qp->req.opcode == IB_OPCODE_UC_RDMA_WRITE_MIDDLE)
 | 
			
		||||
			return fits ?
 | 
			
		||||
				IB_OPCODE_UC_RDMA_WRITE_LAST :
 | 
			
		||||
				IB_OPCODE_UC_RDMA_WRITE_MIDDLE;
 | 
			
		||||
		else
 | 
			
		||||
			return fits ?
 | 
			
		||||
				IB_OPCODE_UC_RDMA_WRITE_ONLY :
 | 
			
		||||
				IB_OPCODE_UC_RDMA_WRITE_FIRST;
 | 
			
		||||
 | 
			
		||||
	case IB_WR_RDMA_WRITE_WITH_IMM:
 | 
			
		||||
		if (qp->req.opcode == IB_OPCODE_UC_RDMA_WRITE_FIRST ||
 | 
			
		||||
		    qp->req.opcode == IB_OPCODE_UC_RDMA_WRITE_MIDDLE)
 | 
			
		||||
			return fits ?
 | 
			
		||||
				IB_OPCODE_UC_RDMA_WRITE_LAST_WITH_IMMEDIATE :
 | 
			
		||||
				IB_OPCODE_UC_RDMA_WRITE_MIDDLE;
 | 
			
		||||
		else
 | 
			
		||||
			return fits ?
 | 
			
		||||
				IB_OPCODE_UC_RDMA_WRITE_ONLY_WITH_IMMEDIATE :
 | 
			
		||||
				IB_OPCODE_UC_RDMA_WRITE_FIRST;
 | 
			
		||||
 | 
			
		||||
	case IB_WR_SEND:
 | 
			
		||||
		if (qp->req.opcode == IB_OPCODE_UC_SEND_FIRST ||
 | 
			
		||||
		    qp->req.opcode == IB_OPCODE_UC_SEND_MIDDLE)
 | 
			
		||||
			return fits ?
 | 
			
		||||
				IB_OPCODE_UC_SEND_LAST :
 | 
			
		||||
				IB_OPCODE_UC_SEND_MIDDLE;
 | 
			
		||||
		else
 | 
			
		||||
			return fits ?
 | 
			
		||||
				IB_OPCODE_UC_SEND_ONLY :
 | 
			
		||||
				IB_OPCODE_UC_SEND_FIRST;
 | 
			
		||||
 | 
			
		||||
	case IB_WR_SEND_WITH_IMM:
 | 
			
		||||
		if (qp->req.opcode == IB_OPCODE_UC_SEND_FIRST ||
 | 
			
		||||
		    qp->req.opcode == IB_OPCODE_UC_SEND_MIDDLE)
 | 
			
		||||
			return fits ?
 | 
			
		||||
				IB_OPCODE_UC_SEND_LAST_WITH_IMMEDIATE :
 | 
			
		||||
				IB_OPCODE_UC_SEND_MIDDLE;
 | 
			
		||||
		else
 | 
			
		||||
			return fits ?
 | 
			
		||||
				IB_OPCODE_UC_SEND_ONLY_WITH_IMMEDIATE :
 | 
			
		||||
				IB_OPCODE_UC_SEND_FIRST;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int next_opcode(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
 | 
			
		||||
		       unsigned opcode)
 | 
			
		||||
{
 | 
			
		||||
	int fits = (wqe->dma.resid <= qp->mtu);
 | 
			
		||||
 | 
			
		||||
	switch (qp_type(qp)) {
 | 
			
		||||
	case IB_QPT_RC:
 | 
			
		||||
		return next_opcode_rc(qp, opcode, fits);
 | 
			
		||||
 | 
			
		||||
	case IB_QPT_UC:
 | 
			
		||||
		return next_opcode_uc(qp, opcode, fits);
 | 
			
		||||
 | 
			
		||||
	case IB_QPT_SMI:
 | 
			
		||||
	case IB_QPT_UD:
 | 
			
		||||
	case IB_QPT_GSI:
 | 
			
		||||
		switch (opcode) {
 | 
			
		||||
		case IB_WR_SEND:
 | 
			
		||||
			return IB_OPCODE_UD_SEND_ONLY;
 | 
			
		||||
 | 
			
		||||
		case IB_WR_SEND_WITH_IMM:
 | 
			
		||||
			return IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE;
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int check_init_depth(struct rxe_qp *qp, struct rxe_send_wqe *wqe)
 | 
			
		||||
{
 | 
			
		||||
	int depth;
 | 
			
		||||
 | 
			
		||||
	if (wqe->has_rd_atomic)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	qp->req.need_rd_atomic = 1;
 | 
			
		||||
	depth = atomic_dec_return(&qp->req.rd_atomic);
 | 
			
		||||
 | 
			
		||||
	if (depth >= 0) {
 | 
			
		||||
		qp->req.need_rd_atomic = 0;
 | 
			
		||||
		wqe->has_rd_atomic = 1;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	atomic_inc(&qp->req.rd_atomic);
 | 
			
		||||
	return -EAGAIN;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int get_mtu(struct rxe_qp *qp, struct rxe_send_wqe *wqe)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
 | 
			
		||||
	struct rxe_port *port;
 | 
			
		||||
	struct rxe_av *av;
 | 
			
		||||
 | 
			
		||||
	if ((qp_type(qp) == IB_QPT_RC) || (qp_type(qp) == IB_QPT_UC))
 | 
			
		||||
		return qp->mtu;
 | 
			
		||||
 | 
			
		||||
	av = &wqe->av;
 | 
			
		||||
	port = &rxe->port;
 | 
			
		||||
 | 
			
		||||
	return port->mtu_cap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct sk_buff *init_req_packet(struct rxe_qp *qp,
 | 
			
		||||
				       struct rxe_send_wqe *wqe,
 | 
			
		||||
				       int opcode, int payload,
 | 
			
		||||
				       struct rxe_pkt_info *pkt)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_dev		*rxe = to_rdev(qp->ibqp.device);
 | 
			
		||||
	struct rxe_port		*port = &rxe->port;
 | 
			
		||||
	struct sk_buff		*skb;
 | 
			
		||||
	struct rxe_send_wr	*ibwr = &wqe->wr;
 | 
			
		||||
	struct rxe_av		*av;
 | 
			
		||||
	int			pad = (-payload) & 0x3;
 | 
			
		||||
	int			paylen;
 | 
			
		||||
	int			solicited;
 | 
			
		||||
	u16			pkey;
 | 
			
		||||
	u32			qp_num;
 | 
			
		||||
	int			ack_req;
 | 
			
		||||
 | 
			
		||||
	/* length from start of bth to end of icrc */
 | 
			
		||||
	paylen = rxe_opcode[opcode].length + payload + pad + RXE_ICRC_SIZE;
 | 
			
		||||
 | 
			
		||||
	/* pkt->hdr, rxe, port_num and mask are initialized in ifc
 | 
			
		||||
	 * layer
 | 
			
		||||
	 */
 | 
			
		||||
	pkt->opcode	= opcode;
 | 
			
		||||
	pkt->qp		= qp;
 | 
			
		||||
	pkt->psn	= qp->req.psn;
 | 
			
		||||
	pkt->mask	= rxe_opcode[opcode].mask;
 | 
			
		||||
	pkt->paylen	= paylen;
 | 
			
		||||
	pkt->offset	= 0;
 | 
			
		||||
	pkt->wqe	= wqe;
 | 
			
		||||
 | 
			
		||||
	/* init skb */
 | 
			
		||||
	av = rxe_get_av(pkt);
 | 
			
		||||
	skb = rxe->ifc_ops->init_packet(rxe, av, paylen, pkt);
 | 
			
		||||
	if (unlikely(!skb))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	/* init bth */
 | 
			
		||||
	solicited = (ibwr->send_flags & IB_SEND_SOLICITED) &&
 | 
			
		||||
			(pkt->mask & RXE_END_MASK) &&
 | 
			
		||||
			((pkt->mask & (RXE_SEND_MASK)) ||
 | 
			
		||||
			(pkt->mask & (RXE_WRITE_MASK | RXE_IMMDT_MASK)) ==
 | 
			
		||||
			(RXE_WRITE_MASK | RXE_IMMDT_MASK));
 | 
			
		||||
 | 
			
		||||
	pkey = (qp_type(qp) == IB_QPT_GSI) ?
 | 
			
		||||
		 port->pkey_tbl[ibwr->wr.ud.pkey_index] :
 | 
			
		||||
		 port->pkey_tbl[qp->attr.pkey_index];
 | 
			
		||||
 | 
			
		||||
	qp_num = (pkt->mask & RXE_DETH_MASK) ? ibwr->wr.ud.remote_qpn :
 | 
			
		||||
					 qp->attr.dest_qp_num;
 | 
			
		||||
 | 
			
		||||
	ack_req = ((pkt->mask & RXE_END_MASK) ||
 | 
			
		||||
		(qp->req.noack_pkts++ > RXE_MAX_PKT_PER_ACK));
 | 
			
		||||
	if (ack_req)
 | 
			
		||||
		qp->req.noack_pkts = 0;
 | 
			
		||||
 | 
			
		||||
	bth_init(pkt, pkt->opcode, solicited, 0, pad, pkey, qp_num,
 | 
			
		||||
		 ack_req, pkt->psn);
 | 
			
		||||
 | 
			
		||||
	/* init optional headers */
 | 
			
		||||
	if (pkt->mask & RXE_RETH_MASK) {
 | 
			
		||||
		reth_set_rkey(pkt, ibwr->wr.rdma.rkey);
 | 
			
		||||
		reth_set_va(pkt, wqe->iova);
 | 
			
		||||
		reth_set_len(pkt, wqe->dma.length);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (pkt->mask & RXE_IMMDT_MASK)
 | 
			
		||||
		immdt_set_imm(pkt, ibwr->ex.imm_data);
 | 
			
		||||
 | 
			
		||||
	if (pkt->mask & RXE_IETH_MASK)
 | 
			
		||||
		ieth_set_rkey(pkt, ibwr->ex.invalidate_rkey);
 | 
			
		||||
 | 
			
		||||
	if (pkt->mask & RXE_ATMETH_MASK) {
 | 
			
		||||
		atmeth_set_va(pkt, wqe->iova);
 | 
			
		||||
		if (opcode == IB_OPCODE_RC_COMPARE_SWAP ||
 | 
			
		||||
		    opcode == IB_OPCODE_RD_COMPARE_SWAP) {
 | 
			
		||||
			atmeth_set_swap_add(pkt, ibwr->wr.atomic.swap);
 | 
			
		||||
			atmeth_set_comp(pkt, ibwr->wr.atomic.compare_add);
 | 
			
		||||
		} else {
 | 
			
		||||
			atmeth_set_swap_add(pkt, ibwr->wr.atomic.compare_add);
 | 
			
		||||
		}
 | 
			
		||||
		atmeth_set_rkey(pkt, ibwr->wr.atomic.rkey);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (pkt->mask & RXE_DETH_MASK) {
 | 
			
		||||
		if (qp->ibqp.qp_num == 1)
 | 
			
		||||
			deth_set_qkey(pkt, GSI_QKEY);
 | 
			
		||||
		else
 | 
			
		||||
			deth_set_qkey(pkt, ibwr->wr.ud.remote_qkey);
 | 
			
		||||
		deth_set_sqp(pkt, qp->ibqp.qp_num);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return skb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int fill_packet(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
 | 
			
		||||
		       struct rxe_pkt_info *pkt, struct sk_buff *skb,
 | 
			
		||||
		       int paylen)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
 | 
			
		||||
	u32 crc = 0;
 | 
			
		||||
	u32 *p;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	err = rxe->ifc_ops->prepare(rxe, pkt, skb, &crc);
 | 
			
		||||
	if (err)
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
	if (pkt->mask & RXE_WRITE_OR_SEND) {
 | 
			
		||||
		if (wqe->wr.send_flags & IB_SEND_INLINE) {
 | 
			
		||||
			u8 *tmp = &wqe->dma.inline_data[wqe->dma.sge_offset];
 | 
			
		||||
 | 
			
		||||
			crc = crc32_le(crc, tmp, paylen);
 | 
			
		||||
 | 
			
		||||
			memcpy(payload_addr(pkt), tmp, paylen);
 | 
			
		||||
 | 
			
		||||
			wqe->dma.resid -= paylen;
 | 
			
		||||
			wqe->dma.sge_offset += paylen;
 | 
			
		||||
		} else {
 | 
			
		||||
			err = copy_data(rxe, qp->pd, 0, &wqe->dma,
 | 
			
		||||
					payload_addr(pkt), paylen,
 | 
			
		||||
					from_mem_obj,
 | 
			
		||||
					&crc);
 | 
			
		||||
			if (err)
 | 
			
		||||
				return err;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	p = payload_addr(pkt) + paylen + bth_pad(pkt);
 | 
			
		||||
 | 
			
		||||
	*p = ~crc;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void update_wqe_state(struct rxe_qp *qp,
 | 
			
		||||
			     struct rxe_send_wqe *wqe,
 | 
			
		||||
			     struct rxe_pkt_info *pkt,
 | 
			
		||||
			     enum wqe_state *prev_state)
 | 
			
		||||
{
 | 
			
		||||
	enum wqe_state prev_state_ = wqe->state;
 | 
			
		||||
 | 
			
		||||
	if (pkt->mask & RXE_END_MASK) {
 | 
			
		||||
		if (qp_type(qp) == IB_QPT_RC)
 | 
			
		||||
			wqe->state = wqe_state_pending;
 | 
			
		||||
	} else {
 | 
			
		||||
		wqe->state = wqe_state_processing;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*prev_state = prev_state_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void update_state(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
 | 
			
		||||
			 struct rxe_pkt_info *pkt, int payload)
 | 
			
		||||
{
 | 
			
		||||
	/* number of packets left to send including current one */
 | 
			
		||||
	int num_pkt = (wqe->dma.resid + payload + qp->mtu - 1) / qp->mtu;
 | 
			
		||||
 | 
			
		||||
	/* handle zero length packet case */
 | 
			
		||||
	if (num_pkt == 0)
 | 
			
		||||
		num_pkt = 1;
 | 
			
		||||
 | 
			
		||||
	if (pkt->mask & RXE_START_MASK) {
 | 
			
		||||
		wqe->first_psn = qp->req.psn;
 | 
			
		||||
		wqe->last_psn = (qp->req.psn + num_pkt - 1) & BTH_PSN_MASK;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (pkt->mask & RXE_READ_MASK)
 | 
			
		||||
		qp->req.psn = (wqe->first_psn + num_pkt) & BTH_PSN_MASK;
 | 
			
		||||
	else
 | 
			
		||||
		qp->req.psn = (qp->req.psn + 1) & BTH_PSN_MASK;
 | 
			
		||||
 | 
			
		||||
	qp->req.opcode = pkt->opcode;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	if (pkt->mask & RXE_END_MASK)
 | 
			
		||||
		qp->req.wqe_index = next_index(qp->sq.queue, qp->req.wqe_index);
 | 
			
		||||
 | 
			
		||||
	qp->need_req_skb = 0;
 | 
			
		||||
 | 
			
		||||
	if (qp->qp_timeout_jiffies && !timer_pending(&qp->retrans_timer))
 | 
			
		||||
		mod_timer(&qp->retrans_timer,
 | 
			
		||||
			  jiffies + qp->qp_timeout_jiffies);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rxe_requester(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_qp *qp = (struct rxe_qp *)arg;
 | 
			
		||||
	struct rxe_pkt_info pkt;
 | 
			
		||||
	struct sk_buff *skb;
 | 
			
		||||
	struct rxe_send_wqe *wqe;
 | 
			
		||||
	unsigned mask;
 | 
			
		||||
	int payload;
 | 
			
		||||
	int mtu;
 | 
			
		||||
	int opcode;
 | 
			
		||||
	int ret;
 | 
			
		||||
	enum wqe_state prev_state;
 | 
			
		||||
 | 
			
		||||
next_wqe:
 | 
			
		||||
	if (unlikely(!qp->valid || qp->req.state == QP_STATE_ERROR))
 | 
			
		||||
		goto exit;
 | 
			
		||||
 | 
			
		||||
	if (unlikely(qp->req.state == QP_STATE_RESET)) {
 | 
			
		||||
		qp->req.wqe_index = consumer_index(qp->sq.queue);
 | 
			
		||||
		qp->req.opcode = -1;
 | 
			
		||||
		qp->req.need_rd_atomic = 0;
 | 
			
		||||
		qp->req.wait_psn = 0;
 | 
			
		||||
		qp->req.need_retry = 0;
 | 
			
		||||
		goto exit;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (unlikely(qp->req.need_retry)) {
 | 
			
		||||
		req_retry(qp);
 | 
			
		||||
		qp->req.need_retry = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wqe = req_next_wqe(qp);
 | 
			
		||||
	if (unlikely(!wqe))
 | 
			
		||||
		goto exit;
 | 
			
		||||
 | 
			
		||||
	if (wqe->mask & WR_REG_MASK) {
 | 
			
		||||
		if (wqe->wr.opcode == IB_WR_LOCAL_INV) {
 | 
			
		||||
			struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
 | 
			
		||||
			struct rxe_mem *rmr;
 | 
			
		||||
 | 
			
		||||
			rmr = rxe_pool_get_index(&rxe->mr_pool,
 | 
			
		||||
						 wqe->wr.ex.invalidate_rkey >> 8);
 | 
			
		||||
			if (!rmr) {
 | 
			
		||||
				pr_err("No mr for key %#x\n", wqe->wr.ex.invalidate_rkey);
 | 
			
		||||
				wqe->state = wqe_state_error;
 | 
			
		||||
				wqe->status = IB_WC_MW_BIND_ERR;
 | 
			
		||||
				goto exit;
 | 
			
		||||
			}
 | 
			
		||||
			rmr->state = RXE_MEM_STATE_FREE;
 | 
			
		||||
			wqe->state = wqe_state_done;
 | 
			
		||||
			wqe->status = IB_WC_SUCCESS;
 | 
			
		||||
		} else if (wqe->wr.opcode == IB_WR_REG_MR) {
 | 
			
		||||
			struct rxe_mem *rmr = to_rmr(wqe->wr.wr.reg.mr);
 | 
			
		||||
 | 
			
		||||
			rmr->state = RXE_MEM_STATE_VALID;
 | 
			
		||||
			rmr->access = wqe->wr.wr.reg.access;
 | 
			
		||||
			rmr->lkey = wqe->wr.wr.reg.key;
 | 
			
		||||
			rmr->rkey = wqe->wr.wr.reg.key;
 | 
			
		||||
			wqe->state = wqe_state_done;
 | 
			
		||||
			wqe->status = IB_WC_SUCCESS;
 | 
			
		||||
		} else {
 | 
			
		||||
			goto exit;
 | 
			
		||||
		}
 | 
			
		||||
		qp->req.wqe_index = next_index(qp->sq.queue,
 | 
			
		||||
						qp->req.wqe_index);
 | 
			
		||||
		goto next_wqe;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (unlikely(qp_type(qp) == IB_QPT_RC &&
 | 
			
		||||
		     qp->req.psn > (qp->comp.psn + RXE_MAX_UNACKED_PSNS))) {
 | 
			
		||||
		qp->req.wait_psn = 1;
 | 
			
		||||
		goto exit;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Limit the number of inflight SKBs per QP */
 | 
			
		||||
	if (unlikely(atomic_read(&qp->skb_out) >
 | 
			
		||||
		     RXE_INFLIGHT_SKBS_PER_QP_HIGH)) {
 | 
			
		||||
		qp->need_req_skb = 1;
 | 
			
		||||
		goto exit;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	opcode = next_opcode(qp, wqe, wqe->wr.opcode);
 | 
			
		||||
	if (unlikely(opcode < 0)) {
 | 
			
		||||
		wqe->status = IB_WC_LOC_QP_OP_ERR;
 | 
			
		||||
		goto exit;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mask = rxe_opcode[opcode].mask;
 | 
			
		||||
	if (unlikely(mask & RXE_READ_OR_ATOMIC)) {
 | 
			
		||||
		if (check_init_depth(qp, wqe))
 | 
			
		||||
			goto exit;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mtu = get_mtu(qp, wqe);
 | 
			
		||||
	payload = (mask & RXE_WRITE_OR_SEND) ? wqe->dma.resid : 0;
 | 
			
		||||
	if (payload > mtu) {
 | 
			
		||||
		if (qp_type(qp) == IB_QPT_UD) {
 | 
			
		||||
			/* C10-93.1.1: If the total sum of all the buffer lengths specified for a
 | 
			
		||||
			 * UD message exceeds the MTU of the port as returned by QueryHCA, the CI
 | 
			
		||||
			 * shall not emit any packets for this message. Further, the CI shall not
 | 
			
		||||
			 * generate an error due to this condition.
 | 
			
		||||
			 */
 | 
			
		||||
 | 
			
		||||
			/* fake a successful UD send */
 | 
			
		||||
			wqe->first_psn = qp->req.psn;
 | 
			
		||||
			wqe->last_psn = qp->req.psn;
 | 
			
		||||
			qp->req.psn = (qp->req.psn + 1) & BTH_PSN_MASK;
 | 
			
		||||
			qp->req.opcode = IB_OPCODE_UD_SEND_ONLY;
 | 
			
		||||
			qp->req.wqe_index = next_index(qp->sq.queue,
 | 
			
		||||
						       qp->req.wqe_index);
 | 
			
		||||
			wqe->state = wqe_state_done;
 | 
			
		||||
			wqe->status = IB_WC_SUCCESS;
 | 
			
		||||
			goto complete;
 | 
			
		||||
		}
 | 
			
		||||
		payload = mtu;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	skb = init_req_packet(qp, wqe, opcode, payload, &pkt);
 | 
			
		||||
	if (unlikely(!skb)) {
 | 
			
		||||
		pr_err("Failed allocating skb\n");
 | 
			
		||||
		goto err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (fill_packet(qp, wqe, &pkt, skb, payload)) {
 | 
			
		||||
		pr_debug("Error during fill packet\n");
 | 
			
		||||
		goto err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	update_wqe_state(qp, wqe, &pkt, &prev_state);
 | 
			
		||||
	ret = rxe_xmit_packet(to_rdev(qp->ibqp.device), qp, &pkt, skb);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		qp->need_req_skb = 1;
 | 
			
		||||
		kfree_skb(skb);
 | 
			
		||||
 | 
			
		||||
		wqe->state = prev_state;
 | 
			
		||||
 | 
			
		||||
		if (ret == -EAGAIN) {
 | 
			
		||||
			rxe_run_task(&qp->req.task, 1);
 | 
			
		||||
			goto exit;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		goto err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	update_state(qp, wqe, &pkt, payload);
 | 
			
		||||
 | 
			
		||||
	goto next_wqe;
 | 
			
		||||
 | 
			
		||||
err:
 | 
			
		||||
	kfree_skb(skb);
 | 
			
		||||
	wqe->status = IB_WC_LOC_PROT_ERR;
 | 
			
		||||
	wqe->state = wqe_state_error;
 | 
			
		||||
 | 
			
		||||
complete:
 | 
			
		||||
	if (qp_type(qp) != IB_QPT_RC) {
 | 
			
		||||
		while (rxe_completer(qp) == 0)
 | 
			
		||||
			;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
exit:
 | 
			
		||||
	return -EAGAIN;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1380
									
								
								drivers/infiniband/sw/rxe/rxe_resp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1380
									
								
								drivers/infiniband/sw/rxe/rxe_resp.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										193
									
								
								drivers/infiniband/sw/rxe/rxe_srq.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								drivers/infiniband/sw/rxe/rxe_srq.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,193 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "rxe.h"
 | 
			
		||||
#include "rxe_loc.h"
 | 
			
		||||
#include "rxe_queue.h"
 | 
			
		||||
 | 
			
		||||
int rxe_srq_chk_attr(struct rxe_dev *rxe, struct rxe_srq *srq,
 | 
			
		||||
		     struct ib_srq_attr *attr, enum ib_srq_attr_mask mask)
 | 
			
		||||
{
 | 
			
		||||
	if (srq && srq->error) {
 | 
			
		||||
		pr_warn("srq in error state\n");
 | 
			
		||||
		goto err1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_SRQ_MAX_WR) {
 | 
			
		||||
		if (attr->max_wr > rxe->attr.max_srq_wr) {
 | 
			
		||||
			pr_warn("max_wr(%d) > max_srq_wr(%d)\n",
 | 
			
		||||
				attr->max_wr, rxe->attr.max_srq_wr);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (attr->max_wr <= 0) {
 | 
			
		||||
			pr_warn("max_wr(%d) <= 0\n", attr->max_wr);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (srq && srq->limit && (attr->max_wr < srq->limit)) {
 | 
			
		||||
			pr_warn("max_wr (%d) < srq->limit (%d)\n",
 | 
			
		||||
				attr->max_wr, srq->limit);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (attr->max_wr < RXE_MIN_SRQ_WR)
 | 
			
		||||
			attr->max_wr = RXE_MIN_SRQ_WR;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_SRQ_LIMIT) {
 | 
			
		||||
		if (attr->srq_limit > rxe->attr.max_srq_wr) {
 | 
			
		||||
			pr_warn("srq_limit(%d) > max_srq_wr(%d)\n",
 | 
			
		||||
				attr->srq_limit, rxe->attr.max_srq_wr);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (srq && (attr->srq_limit > srq->rq.queue->buf->index_mask)) {
 | 
			
		||||
			pr_warn("srq_limit (%d) > cur limit(%d)\n",
 | 
			
		||||
				attr->srq_limit,
 | 
			
		||||
				 srq->rq.queue->buf->index_mask);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mask == IB_SRQ_INIT_MASK) {
 | 
			
		||||
		if (attr->max_sge > rxe->attr.max_srq_sge) {
 | 
			
		||||
			pr_warn("max_sge(%d) > max_srq_sge(%d)\n",
 | 
			
		||||
				attr->max_sge, rxe->attr.max_srq_sge);
 | 
			
		||||
			goto err1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (attr->max_sge < RXE_MIN_SRQ_SGE)
 | 
			
		||||
			attr->max_sge = RXE_MIN_SRQ_SGE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err1:
 | 
			
		||||
	return -EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rxe_srq_from_init(struct rxe_dev *rxe, struct rxe_srq *srq,
 | 
			
		||||
		      struct ib_srq_init_attr *init,
 | 
			
		||||
		      struct ib_ucontext *context, struct ib_udata *udata)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
	int srq_wqe_size;
 | 
			
		||||
	struct rxe_queue *q;
 | 
			
		||||
 | 
			
		||||
	srq->ibsrq.event_handler	= init->event_handler;
 | 
			
		||||
	srq->ibsrq.srq_context		= init->srq_context;
 | 
			
		||||
	srq->limit		= init->attr.srq_limit;
 | 
			
		||||
	srq->srq_num		= srq->pelem.index;
 | 
			
		||||
	srq->rq.max_wr		= init->attr.max_wr;
 | 
			
		||||
	srq->rq.max_sge		= init->attr.max_sge;
 | 
			
		||||
 | 
			
		||||
	srq_wqe_size		= rcv_wqe_size(srq->rq.max_sge);
 | 
			
		||||
 | 
			
		||||
	spin_lock_init(&srq->rq.producer_lock);
 | 
			
		||||
	spin_lock_init(&srq->rq.consumer_lock);
 | 
			
		||||
 | 
			
		||||
	q = rxe_queue_init(rxe, &srq->rq.max_wr,
 | 
			
		||||
			   srq_wqe_size);
 | 
			
		||||
	if (!q) {
 | 
			
		||||
		pr_warn("unable to allocate queue for srq\n");
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	srq->rq.queue = q;
 | 
			
		||||
 | 
			
		||||
	err = do_mmap_info(rxe, udata, false, context, q->buf,
 | 
			
		||||
			   q->buf_size, &q->ip);
 | 
			
		||||
	if (err)
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
	if (udata && udata->outlen >= sizeof(struct mminfo) + sizeof(u32)) {
 | 
			
		||||
		if (copy_to_user(udata->outbuf + sizeof(struct mminfo),
 | 
			
		||||
				 &srq->srq_num, sizeof(u32)))
 | 
			
		||||
			return -EFAULT;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rxe_srq_from_attr(struct rxe_dev *rxe, struct rxe_srq *srq,
 | 
			
		||||
		      struct ib_srq_attr *attr, enum ib_srq_attr_mask mask,
 | 
			
		||||
		      struct ib_udata *udata)
 | 
			
		||||
{
 | 
			
		||||
	int err;
 | 
			
		||||
	struct rxe_queue *q = srq->rq.queue;
 | 
			
		||||
	struct mminfo mi = { .offset = 1, .size = 0};
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_SRQ_MAX_WR) {
 | 
			
		||||
		/* Check that we can write the mminfo struct to user space */
 | 
			
		||||
		if (udata && udata->inlen >= sizeof(__u64)) {
 | 
			
		||||
			__u64 mi_addr;
 | 
			
		||||
 | 
			
		||||
			/* Get address of user space mminfo struct */
 | 
			
		||||
			err = ib_copy_from_udata(&mi_addr, udata,
 | 
			
		||||
						 sizeof(mi_addr));
 | 
			
		||||
			if (err)
 | 
			
		||||
				goto err1;
 | 
			
		||||
 | 
			
		||||
			udata->outbuf = (void __user *)(unsigned long)mi_addr;
 | 
			
		||||
			udata->outlen = sizeof(mi);
 | 
			
		||||
 | 
			
		||||
			if (!access_ok(VERIFY_WRITE,
 | 
			
		||||
				       (void __user *)udata->outbuf,
 | 
			
		||||
					udata->outlen)) {
 | 
			
		||||
				err = -EFAULT;
 | 
			
		||||
				goto err1;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		err = rxe_queue_resize(q, (unsigned int *)&attr->max_wr,
 | 
			
		||||
				       rcv_wqe_size(srq->rq.max_sge),
 | 
			
		||||
				       srq->rq.queue->ip ?
 | 
			
		||||
						srq->rq.queue->ip->context :
 | 
			
		||||
						NULL,
 | 
			
		||||
				       udata, &srq->rq.producer_lock,
 | 
			
		||||
				       &srq->rq.consumer_lock);
 | 
			
		||||
		if (err)
 | 
			
		||||
			goto err2;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (mask & IB_SRQ_LIMIT)
 | 
			
		||||
		srq->limit = attr->srq_limit;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err2:
 | 
			
		||||
	rxe_queue_cleanup(q);
 | 
			
		||||
	srq->rq.queue = NULL;
 | 
			
		||||
err1:
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										157
									
								
								drivers/infiniband/sw/rxe/rxe_sysfs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								drivers/infiniband/sw/rxe/rxe_sysfs.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,157 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "rxe.h"
 | 
			
		||||
#include "rxe_net.h"
 | 
			
		||||
 | 
			
		||||
/* Copy argument and remove trailing CR. Return the new length. */
 | 
			
		||||
static int sanitize_arg(const char *val, char *intf, int intf_len)
 | 
			
		||||
{
 | 
			
		||||
	int len;
 | 
			
		||||
 | 
			
		||||
	if (!val)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	/* Remove newline. */
 | 
			
		||||
	for (len = 0; len < intf_len - 1 && val[len] && val[len] != '\n'; len++)
 | 
			
		||||
		intf[len] = val[len];
 | 
			
		||||
	intf[len] = 0;
 | 
			
		||||
 | 
			
		||||
	if (len == 0 || (val[len] != 0 && val[len] != '\n'))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rxe_set_port_state(struct net_device *ndev)
 | 
			
		||||
{
 | 
			
		||||
	struct rxe_dev *rxe = net_to_rxe(ndev);
 | 
			
		||||
	bool is_up = netif_running(ndev) && netif_carrier_ok(ndev);
 | 
			
		||||
 | 
			
		||||
	if (!rxe)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	if (is_up)
 | 
			
		||||
		rxe_port_up(rxe);
 | 
			
		||||
	else
 | 
			
		||||
		rxe_port_down(rxe); /* down for unknown state */
 | 
			
		||||
out:
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rxe_param_set_add(const char *val, const struct kernel_param *kp)
 | 
			
		||||
{
 | 
			
		||||
	int len;
 | 
			
		||||
	int err = 0;
 | 
			
		||||
	char intf[32];
 | 
			
		||||
	struct net_device *ndev = NULL;
 | 
			
		||||
	struct rxe_dev *rxe;
 | 
			
		||||
 | 
			
		||||
	len = sanitize_arg(val, intf, sizeof(intf));
 | 
			
		||||
	if (!len) {
 | 
			
		||||
		pr_err("rxe: add: invalid interface name\n");
 | 
			
		||||
		err = -EINVAL;
 | 
			
		||||
		goto err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ndev = dev_get_by_name(&init_net, intf);
 | 
			
		||||
	if (!ndev) {
 | 
			
		||||
		pr_err("interface %s not found\n", intf);
 | 
			
		||||
		err = -EINVAL;
 | 
			
		||||
		goto err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (net_to_rxe(ndev)) {
 | 
			
		||||
		pr_err("rxe: already configured on %s\n", intf);
 | 
			
		||||
		err = -EINVAL;
 | 
			
		||||
		goto err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rxe = rxe_net_add(ndev);
 | 
			
		||||
	if (!rxe) {
 | 
			
		||||
		pr_err("rxe: failed to add %s\n", intf);
 | 
			
		||||
		err = -EINVAL;
 | 
			
		||||
		goto err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rxe_set_port_state(ndev);
 | 
			
		||||
	pr_info("rxe: added %s to %s\n", rxe->ib_dev.name, intf);
 | 
			
		||||
err:
 | 
			
		||||
	if (ndev)
 | 
			
		||||
		dev_put(ndev);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rxe_param_set_remove(const char *val, const struct kernel_param *kp)
 | 
			
		||||
{
 | 
			
		||||
	int len;
 | 
			
		||||
	char intf[32];
 | 
			
		||||
	struct rxe_dev *rxe;
 | 
			
		||||
 | 
			
		||||
	len = sanitize_arg(val, intf, sizeof(intf));
 | 
			
		||||
	if (!len) {
 | 
			
		||||
		pr_err("rxe: add: invalid interface name\n");
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (strncmp("all", intf, len) == 0) {
 | 
			
		||||
		pr_info("rxe_sys: remove all");
 | 
			
		||||
		rxe_remove_all();
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rxe = get_rxe_by_name(intf);
 | 
			
		||||
 | 
			
		||||
	if (!rxe) {
 | 
			
		||||
		pr_err("rxe: not configured on %s\n", intf);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	list_del(&rxe->list);
 | 
			
		||||
	rxe_remove(rxe);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct kernel_param_ops rxe_add_ops = {
 | 
			
		||||
	.set = rxe_param_set_add,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct kernel_param_ops rxe_remove_ops = {
 | 
			
		||||
	.set = rxe_param_set_remove,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module_param_cb(add, &rxe_add_ops, NULL, 0200);
 | 
			
		||||
MODULE_PARM_DESC(add, "Create RXE device over network interface");
 | 
			
		||||
module_param_cb(remove, &rxe_remove_ops, NULL, 0200);
 | 
			
		||||
MODULE_PARM_DESC(remove, "Remove RXE device over network interface");
 | 
			
		||||
							
								
								
									
										154
									
								
								drivers/infiniband/sw/rxe/rxe_task.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								drivers/infiniband/sw/rxe/rxe_task.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,154 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/kernel.h>
 | 
			
		||||
#include <linux/interrupt.h>
 | 
			
		||||
#include <linux/hardirq.h>
 | 
			
		||||
 | 
			
		||||
#include "rxe_task.h"
 | 
			
		||||
 | 
			
		||||
int __rxe_do_task(struct rxe_task *task)
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	while ((ret = task->func(task->arg)) == 0)
 | 
			
		||||
		;
 | 
			
		||||
 | 
			
		||||
	task->ret = ret;
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * this locking is due to a potential race where
 | 
			
		||||
 * a second caller finds the task already running
 | 
			
		||||
 * but looks just after the last call to func
 | 
			
		||||
 */
 | 
			
		||||
void rxe_do_task(unsigned long data)
 | 
			
		||||
{
 | 
			
		||||
	int cont;
 | 
			
		||||
	int ret;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	struct rxe_task *task = (struct rxe_task *)data;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&task->state_lock, flags);
 | 
			
		||||
	switch (task->state) {
 | 
			
		||||
	case TASK_STATE_START:
 | 
			
		||||
		task->state = TASK_STATE_BUSY;
 | 
			
		||||
		spin_unlock_irqrestore(&task->state_lock, flags);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case TASK_STATE_BUSY:
 | 
			
		||||
		task->state = TASK_STATE_ARMED;
 | 
			
		||||
		/* fall through to */
 | 
			
		||||
	case TASK_STATE_ARMED:
 | 
			
		||||
		spin_unlock_irqrestore(&task->state_lock, flags);
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		spin_unlock_irqrestore(&task->state_lock, flags);
 | 
			
		||||
		pr_warn("bad state = %d in rxe_do_task\n", task->state);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		cont = 0;
 | 
			
		||||
		ret = task->func(task->arg);
 | 
			
		||||
 | 
			
		||||
		spin_lock_irqsave(&task->state_lock, flags);
 | 
			
		||||
		switch (task->state) {
 | 
			
		||||
		case TASK_STATE_BUSY:
 | 
			
		||||
			if (ret)
 | 
			
		||||
				task->state = TASK_STATE_START;
 | 
			
		||||
			else
 | 
			
		||||
				cont = 1;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		/* soneone tried to run the task since the last time we called
 | 
			
		||||
		 * func, so we will call one more time regardless of the
 | 
			
		||||
		 * return value
 | 
			
		||||
		 */
 | 
			
		||||
		case TASK_STATE_ARMED:
 | 
			
		||||
			task->state = TASK_STATE_BUSY;
 | 
			
		||||
			cont = 1;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			pr_warn("bad state = %d in rxe_do_task\n",
 | 
			
		||||
				task->state);
 | 
			
		||||
		}
 | 
			
		||||
		spin_unlock_irqrestore(&task->state_lock, flags);
 | 
			
		||||
	} while (cont);
 | 
			
		||||
 | 
			
		||||
	task->ret = ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rxe_init_task(void *obj, struct rxe_task *task,
 | 
			
		||||
		  void *arg, int (*func)(void *), char *name)
 | 
			
		||||
{
 | 
			
		||||
	task->obj	= obj;
 | 
			
		||||
	task->arg	= arg;
 | 
			
		||||
	task->func	= func;
 | 
			
		||||
	snprintf(task->name, sizeof(task->name), "%s", name);
 | 
			
		||||
 | 
			
		||||
	tasklet_init(&task->tasklet, rxe_do_task, (unsigned long)task);
 | 
			
		||||
 | 
			
		||||
	task->state = TASK_STATE_START;
 | 
			
		||||
	spin_lock_init(&task->state_lock);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rxe_cleanup_task(struct rxe_task *task)
 | 
			
		||||
{
 | 
			
		||||
	tasklet_kill(&task->tasklet);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rxe_run_task(struct rxe_task *task, int sched)
 | 
			
		||||
{
 | 
			
		||||
	if (sched)
 | 
			
		||||
		tasklet_schedule(&task->tasklet);
 | 
			
		||||
	else
 | 
			
		||||
		rxe_do_task((unsigned long)task);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rxe_disable_task(struct rxe_task *task)
 | 
			
		||||
{
 | 
			
		||||
	tasklet_disable(&task->tasklet);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rxe_enable_task(struct rxe_task *task)
 | 
			
		||||
{
 | 
			
		||||
	tasklet_enable(&task->tasklet);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										95
									
								
								drivers/infiniband/sw/rxe/rxe_task.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								drivers/infiniband/sw/rxe/rxe_task.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,95 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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 RXE_TASK_H
 | 
			
		||||
#define RXE_TASK_H
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	TASK_STATE_START	= 0,
 | 
			
		||||
	TASK_STATE_BUSY		= 1,
 | 
			
		||||
	TASK_STATE_ARMED	= 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * data structure to describe a 'task' which is a short
 | 
			
		||||
 * function that returns 0 as long as it needs to be
 | 
			
		||||
 * called again.
 | 
			
		||||
 */
 | 
			
		||||
struct rxe_task {
 | 
			
		||||
	void			*obj;
 | 
			
		||||
	struct tasklet_struct	tasklet;
 | 
			
		||||
	int			state;
 | 
			
		||||
	spinlock_t		state_lock; /* spinlock for task state */
 | 
			
		||||
	void			*arg;
 | 
			
		||||
	int			(*func)(void *arg);
 | 
			
		||||
	int			ret;
 | 
			
		||||
	char			name[16];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * init rxe_task structure
 | 
			
		||||
 *	arg  => parameter to pass to fcn
 | 
			
		||||
 *	fcn  => function to call until it returns != 0
 | 
			
		||||
 */
 | 
			
		||||
int rxe_init_task(void *obj, struct rxe_task *task,
 | 
			
		||||
		  void *arg, int (*func)(void *), char *name);
 | 
			
		||||
 | 
			
		||||
/* cleanup task */
 | 
			
		||||
void rxe_cleanup_task(struct rxe_task *task);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * raw call to func in loop without any checking
 | 
			
		||||
 * can call when tasklets are disabled
 | 
			
		||||
 */
 | 
			
		||||
int __rxe_do_task(struct rxe_task *task);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * common function called by any of the main tasklets
 | 
			
		||||
 * If there is any chance that there is additional
 | 
			
		||||
 * work to do someone must reschedule the task before
 | 
			
		||||
 * leaving
 | 
			
		||||
 */
 | 
			
		||||
void rxe_do_task(unsigned long data);
 | 
			
		||||
 | 
			
		||||
/* run a task, else schedule it to run as a tasklet, The decision
 | 
			
		||||
 * to run or schedule tasklet is based on the parameter sched.
 | 
			
		||||
 */
 | 
			
		||||
void rxe_run_task(struct rxe_task *task, int sched);
 | 
			
		||||
 | 
			
		||||
/* keep a task from scheduling */
 | 
			
		||||
void rxe_disable_task(struct rxe_task *task);
 | 
			
		||||
 | 
			
		||||
/* allow task to run */
 | 
			
		||||
void rxe_enable_task(struct rxe_task *task);
 | 
			
		||||
 | 
			
		||||
#endif /* RXE_TASK_H */
 | 
			
		||||
							
								
								
									
										1330
									
								
								drivers/infiniband/sw/rxe/rxe_verbs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1330
									
								
								drivers/infiniband/sw/rxe/rxe_verbs.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										480
									
								
								drivers/infiniband/sw/rxe/rxe_verbs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										480
									
								
								drivers/infiniband/sw/rxe/rxe_verbs.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,480 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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 RXE_VERBS_H
 | 
			
		||||
#define RXE_VERBS_H
 | 
			
		||||
 | 
			
		||||
#include <linux/interrupt.h>
 | 
			
		||||
#include <rdma/rdma_user_rxe.h>
 | 
			
		||||
#include "rxe_pool.h"
 | 
			
		||||
#include "rxe_task.h"
 | 
			
		||||
 | 
			
		||||
static inline int pkey_match(u16 key1, u16 key2)
 | 
			
		||||
{
 | 
			
		||||
	return (((key1 & 0x7fff) != 0) &&
 | 
			
		||||
		((key1 & 0x7fff) == (key2 & 0x7fff)) &&
 | 
			
		||||
		((key1 & 0x8000) || (key2 & 0x8000))) ? 1 : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Return >0 if psn_a > psn_b
 | 
			
		||||
 *	   0 if psn_a == psn_b
 | 
			
		||||
 *	  <0 if psn_a < psn_b
 | 
			
		||||
 */
 | 
			
		||||
static inline int psn_compare(u32 psn_a, u32 psn_b)
 | 
			
		||||
{
 | 
			
		||||
	s32 diff;
 | 
			
		||||
 | 
			
		||||
	diff = (psn_a - psn_b) << 8;
 | 
			
		||||
	return diff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct rxe_ucontext {
 | 
			
		||||
	struct rxe_pool_entry	pelem;
 | 
			
		||||
	struct ib_ucontext	ibuc;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_pd {
 | 
			
		||||
	struct rxe_pool_entry	pelem;
 | 
			
		||||
	struct ib_pd		ibpd;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_ah {
 | 
			
		||||
	struct rxe_pool_entry	pelem;
 | 
			
		||||
	struct ib_ah		ibah;
 | 
			
		||||
	struct rxe_pd		*pd;
 | 
			
		||||
	struct rxe_av		av;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_cqe {
 | 
			
		||||
	union {
 | 
			
		||||
		struct ib_wc		ibwc;
 | 
			
		||||
		struct ib_uverbs_wc	uibwc;
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_cq {
 | 
			
		||||
	struct rxe_pool_entry	pelem;
 | 
			
		||||
	struct ib_cq		ibcq;
 | 
			
		||||
	struct rxe_queue	*queue;
 | 
			
		||||
	spinlock_t		cq_lock;
 | 
			
		||||
	u8			notify;
 | 
			
		||||
	int			is_user;
 | 
			
		||||
	struct tasklet_struct	comp_task;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum wqe_state {
 | 
			
		||||
	wqe_state_posted,
 | 
			
		||||
	wqe_state_processing,
 | 
			
		||||
	wqe_state_pending,
 | 
			
		||||
	wqe_state_done,
 | 
			
		||||
	wqe_state_error,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_sq {
 | 
			
		||||
	int			max_wr;
 | 
			
		||||
	int			max_sge;
 | 
			
		||||
	int			max_inline;
 | 
			
		||||
	spinlock_t		sq_lock; /* guard queue */
 | 
			
		||||
	struct rxe_queue	*queue;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_rq {
 | 
			
		||||
	int			max_wr;
 | 
			
		||||
	int			max_sge;
 | 
			
		||||
	spinlock_t		producer_lock; /* guard queue producer */
 | 
			
		||||
	spinlock_t		consumer_lock; /* guard queue consumer */
 | 
			
		||||
	struct rxe_queue	*queue;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_srq {
 | 
			
		||||
	struct rxe_pool_entry	pelem;
 | 
			
		||||
	struct ib_srq		ibsrq;
 | 
			
		||||
	struct rxe_pd		*pd;
 | 
			
		||||
	struct rxe_rq		rq;
 | 
			
		||||
	u32			srq_num;
 | 
			
		||||
 | 
			
		||||
	int			limit;
 | 
			
		||||
	int			error;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum rxe_qp_state {
 | 
			
		||||
	QP_STATE_RESET,
 | 
			
		||||
	QP_STATE_INIT,
 | 
			
		||||
	QP_STATE_READY,
 | 
			
		||||
	QP_STATE_DRAIN,		/* req only */
 | 
			
		||||
	QP_STATE_DRAINED,	/* req only */
 | 
			
		||||
	QP_STATE_ERROR
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern char *rxe_qp_state_name[];
 | 
			
		||||
 | 
			
		||||
struct rxe_req_info {
 | 
			
		||||
	enum rxe_qp_state	state;
 | 
			
		||||
	int			wqe_index;
 | 
			
		||||
	u32			psn;
 | 
			
		||||
	int			opcode;
 | 
			
		||||
	atomic_t		rd_atomic;
 | 
			
		||||
	int			wait_fence;
 | 
			
		||||
	int			need_rd_atomic;
 | 
			
		||||
	int			wait_psn;
 | 
			
		||||
	int			need_retry;
 | 
			
		||||
	int			noack_pkts;
 | 
			
		||||
	struct rxe_task		task;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_comp_info {
 | 
			
		||||
	u32			psn;
 | 
			
		||||
	int			opcode;
 | 
			
		||||
	int			timeout;
 | 
			
		||||
	int			timeout_retry;
 | 
			
		||||
	u32			retry_cnt;
 | 
			
		||||
	u32			rnr_retry;
 | 
			
		||||
	struct rxe_task		task;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum rdatm_res_state {
 | 
			
		||||
	rdatm_res_state_next,
 | 
			
		||||
	rdatm_res_state_new,
 | 
			
		||||
	rdatm_res_state_replay,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct resp_res {
 | 
			
		||||
	int			type;
 | 
			
		||||
	u32			first_psn;
 | 
			
		||||
	u32			last_psn;
 | 
			
		||||
	u32			cur_psn;
 | 
			
		||||
	enum rdatm_res_state	state;
 | 
			
		||||
 | 
			
		||||
	union {
 | 
			
		||||
		struct {
 | 
			
		||||
			struct sk_buff	*skb;
 | 
			
		||||
		} atomic;
 | 
			
		||||
		struct {
 | 
			
		||||
			struct rxe_mem	*mr;
 | 
			
		||||
			u64		va_org;
 | 
			
		||||
			u32		rkey;
 | 
			
		||||
			u32		length;
 | 
			
		||||
			u64		va;
 | 
			
		||||
			u32		resid;
 | 
			
		||||
		} read;
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_resp_info {
 | 
			
		||||
	enum rxe_qp_state	state;
 | 
			
		||||
	u32			msn;
 | 
			
		||||
	u32			psn;
 | 
			
		||||
	int			opcode;
 | 
			
		||||
	int			drop_msg;
 | 
			
		||||
	int			goto_error;
 | 
			
		||||
	int			sent_psn_nak;
 | 
			
		||||
	enum ib_wc_status	status;
 | 
			
		||||
	u8			aeth_syndrome;
 | 
			
		||||
 | 
			
		||||
	/* Receive only */
 | 
			
		||||
	struct rxe_recv_wqe	*wqe;
 | 
			
		||||
 | 
			
		||||
	/* RDMA read / atomic only */
 | 
			
		||||
	u64			va;
 | 
			
		||||
	struct rxe_mem		*mr;
 | 
			
		||||
	u32			resid;
 | 
			
		||||
	u32			rkey;
 | 
			
		||||
	u64			atomic_orig;
 | 
			
		||||
 | 
			
		||||
	/* SRQ only */
 | 
			
		||||
	struct {
 | 
			
		||||
		struct rxe_recv_wqe	wqe;
 | 
			
		||||
		struct ib_sge		sge[RXE_MAX_SGE];
 | 
			
		||||
	} srq_wqe;
 | 
			
		||||
 | 
			
		||||
	/* Responder resources. It's a circular list where the oldest
 | 
			
		||||
	 * resource is dropped first.
 | 
			
		||||
	 */
 | 
			
		||||
	struct resp_res		*resources;
 | 
			
		||||
	unsigned int		res_head;
 | 
			
		||||
	unsigned int		res_tail;
 | 
			
		||||
	struct resp_res		*res;
 | 
			
		||||
	struct rxe_task		task;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_qp {
 | 
			
		||||
	struct rxe_pool_entry	pelem;
 | 
			
		||||
	struct ib_qp		ibqp;
 | 
			
		||||
	struct ib_qp_attr	attr;
 | 
			
		||||
	unsigned int		valid;
 | 
			
		||||
	unsigned int		mtu;
 | 
			
		||||
	int			is_user;
 | 
			
		||||
 | 
			
		||||
	struct rxe_pd		*pd;
 | 
			
		||||
	struct rxe_srq		*srq;
 | 
			
		||||
	struct rxe_cq		*scq;
 | 
			
		||||
	struct rxe_cq		*rcq;
 | 
			
		||||
 | 
			
		||||
	enum ib_sig_type	sq_sig_type;
 | 
			
		||||
 | 
			
		||||
	struct rxe_sq		sq;
 | 
			
		||||
	struct rxe_rq		rq;
 | 
			
		||||
 | 
			
		||||
	struct socket		*sk;
 | 
			
		||||
 | 
			
		||||
	struct rxe_av		pri_av;
 | 
			
		||||
	struct rxe_av		alt_av;
 | 
			
		||||
 | 
			
		||||
	/* list of mcast groups qp has joined (for cleanup) */
 | 
			
		||||
	struct list_head	grp_list;
 | 
			
		||||
	spinlock_t		grp_lock; /* guard grp_list */
 | 
			
		||||
 | 
			
		||||
	struct sk_buff_head	req_pkts;
 | 
			
		||||
	struct sk_buff_head	resp_pkts;
 | 
			
		||||
	struct sk_buff_head	send_pkts;
 | 
			
		||||
 | 
			
		||||
	struct rxe_req_info	req;
 | 
			
		||||
	struct rxe_comp_info	comp;
 | 
			
		||||
	struct rxe_resp_info	resp;
 | 
			
		||||
 | 
			
		||||
	atomic_t		ssn;
 | 
			
		||||
	atomic_t		skb_out;
 | 
			
		||||
	int			need_req_skb;
 | 
			
		||||
 | 
			
		||||
	/* Timer for retranmitting packet when ACKs have been lost. RC
 | 
			
		||||
	 * only. The requester sets it when it is not already
 | 
			
		||||
	 * started. The responder resets it whenever an ack is
 | 
			
		||||
	 * received.
 | 
			
		||||
	 */
 | 
			
		||||
	struct timer_list retrans_timer;
 | 
			
		||||
	u64 qp_timeout_jiffies;
 | 
			
		||||
 | 
			
		||||
	/* Timer for handling RNR NAKS. */
 | 
			
		||||
	struct timer_list rnr_nak_timer;
 | 
			
		||||
 | 
			
		||||
	spinlock_t		state_lock; /* guard requester and completer */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum rxe_mem_state {
 | 
			
		||||
	RXE_MEM_STATE_ZOMBIE,
 | 
			
		||||
	RXE_MEM_STATE_INVALID,
 | 
			
		||||
	RXE_MEM_STATE_FREE,
 | 
			
		||||
	RXE_MEM_STATE_VALID,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum rxe_mem_type {
 | 
			
		||||
	RXE_MEM_TYPE_NONE,
 | 
			
		||||
	RXE_MEM_TYPE_DMA,
 | 
			
		||||
	RXE_MEM_TYPE_MR,
 | 
			
		||||
	RXE_MEM_TYPE_FMR,
 | 
			
		||||
	RXE_MEM_TYPE_MW,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define RXE_BUF_PER_MAP		(PAGE_SIZE / sizeof(struct rxe_phys_buf))
 | 
			
		||||
 | 
			
		||||
struct rxe_phys_buf {
 | 
			
		||||
	u64      addr;
 | 
			
		||||
	u64      size;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_map {
 | 
			
		||||
	struct rxe_phys_buf	buf[RXE_BUF_PER_MAP];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_mem {
 | 
			
		||||
	struct rxe_pool_entry	pelem;
 | 
			
		||||
	union {
 | 
			
		||||
		struct ib_mr		ibmr;
 | 
			
		||||
		struct ib_mw		ibmw;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct rxe_pd		*pd;
 | 
			
		||||
	struct ib_umem		*umem;
 | 
			
		||||
 | 
			
		||||
	u32			lkey;
 | 
			
		||||
	u32			rkey;
 | 
			
		||||
 | 
			
		||||
	enum rxe_mem_state	state;
 | 
			
		||||
	enum rxe_mem_type	type;
 | 
			
		||||
	u64			va;
 | 
			
		||||
	u64			iova;
 | 
			
		||||
	size_t			length;
 | 
			
		||||
	u32			offset;
 | 
			
		||||
	int			access;
 | 
			
		||||
 | 
			
		||||
	int			page_shift;
 | 
			
		||||
	int			page_mask;
 | 
			
		||||
	int			map_shift;
 | 
			
		||||
	int			map_mask;
 | 
			
		||||
 | 
			
		||||
	u32			num_buf;
 | 
			
		||||
	u32			nbuf;
 | 
			
		||||
 | 
			
		||||
	u32			max_buf;
 | 
			
		||||
	u32			num_map;
 | 
			
		||||
 | 
			
		||||
	struct rxe_map		**map;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_mc_grp {
 | 
			
		||||
	struct rxe_pool_entry	pelem;
 | 
			
		||||
	spinlock_t		mcg_lock; /* guard group */
 | 
			
		||||
	struct rxe_dev		*rxe;
 | 
			
		||||
	struct list_head	qp_list;
 | 
			
		||||
	union ib_gid		mgid;
 | 
			
		||||
	int			num_qp;
 | 
			
		||||
	u32			qkey;
 | 
			
		||||
	u16			pkey;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_mc_elem {
 | 
			
		||||
	struct rxe_pool_entry	pelem;
 | 
			
		||||
	struct list_head	qp_list;
 | 
			
		||||
	struct list_head	grp_list;
 | 
			
		||||
	struct rxe_qp		*qp;
 | 
			
		||||
	struct rxe_mc_grp	*grp;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_port {
 | 
			
		||||
	struct ib_port_attr	attr;
 | 
			
		||||
	u16			*pkey_tbl;
 | 
			
		||||
	__be64			port_guid;
 | 
			
		||||
	__be64			subnet_prefix;
 | 
			
		||||
	spinlock_t		port_lock; /* guard port */
 | 
			
		||||
	unsigned int		mtu_cap;
 | 
			
		||||
	/* special QPs */
 | 
			
		||||
	u32			qp_smi_index;
 | 
			
		||||
	u32			qp_gsi_index;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* callbacks from rdma_rxe to network interface layer */
 | 
			
		||||
struct rxe_ifc_ops {
 | 
			
		||||
	void (*release)(struct rxe_dev *rxe);
 | 
			
		||||
	__be64 (*node_guid)(struct rxe_dev *rxe);
 | 
			
		||||
	__be64 (*port_guid)(struct rxe_dev *rxe);
 | 
			
		||||
	struct device *(*dma_device)(struct rxe_dev *rxe);
 | 
			
		||||
	int (*mcast_add)(struct rxe_dev *rxe, union ib_gid *mgid);
 | 
			
		||||
	int (*mcast_delete)(struct rxe_dev *rxe, union ib_gid *mgid);
 | 
			
		||||
	int (*prepare)(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
 | 
			
		||||
		       struct sk_buff *skb, u32 *crc);
 | 
			
		||||
	int (*send)(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
 | 
			
		||||
		    struct sk_buff *skb);
 | 
			
		||||
	int (*loopback)(struct sk_buff *skb);
 | 
			
		||||
	struct sk_buff *(*init_packet)(struct rxe_dev *rxe, struct rxe_av *av,
 | 
			
		||||
				       int paylen, struct rxe_pkt_info *pkt);
 | 
			
		||||
	char *(*parent_name)(struct rxe_dev *rxe, unsigned int port_num);
 | 
			
		||||
	enum rdma_link_layer (*link_layer)(struct rxe_dev *rxe,
 | 
			
		||||
					   unsigned int port_num);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_dev {
 | 
			
		||||
	struct ib_device	ib_dev;
 | 
			
		||||
	struct ib_device_attr	attr;
 | 
			
		||||
	int			max_ucontext;
 | 
			
		||||
	int			max_inline_data;
 | 
			
		||||
	struct kref		ref_cnt;
 | 
			
		||||
	struct mutex	usdev_lock;
 | 
			
		||||
 | 
			
		||||
	struct rxe_ifc_ops	*ifc_ops;
 | 
			
		||||
 | 
			
		||||
	struct net_device	*ndev;
 | 
			
		||||
 | 
			
		||||
	int			xmit_errors;
 | 
			
		||||
 | 
			
		||||
	struct rxe_pool		uc_pool;
 | 
			
		||||
	struct rxe_pool		pd_pool;
 | 
			
		||||
	struct rxe_pool		ah_pool;
 | 
			
		||||
	struct rxe_pool		srq_pool;
 | 
			
		||||
	struct rxe_pool		qp_pool;
 | 
			
		||||
	struct rxe_pool		cq_pool;
 | 
			
		||||
	struct rxe_pool		mr_pool;
 | 
			
		||||
	struct rxe_pool		mw_pool;
 | 
			
		||||
	struct rxe_pool		mc_grp_pool;
 | 
			
		||||
	struct rxe_pool		mc_elem_pool;
 | 
			
		||||
 | 
			
		||||
	spinlock_t		pending_lock; /* guard pending_mmaps */
 | 
			
		||||
	struct list_head	pending_mmaps;
 | 
			
		||||
 | 
			
		||||
	spinlock_t		mmap_offset_lock; /* guard mmap_offset */
 | 
			
		||||
	int			mmap_offset;
 | 
			
		||||
 | 
			
		||||
	struct rxe_port		port;
 | 
			
		||||
	struct list_head	list;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline struct rxe_dev *to_rdev(struct ib_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	return dev ? container_of(dev, struct rxe_dev, ib_dev) : NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline struct rxe_ucontext *to_ruc(struct ib_ucontext *uc)
 | 
			
		||||
{
 | 
			
		||||
	return uc ? container_of(uc, struct rxe_ucontext, ibuc) : NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline struct rxe_pd *to_rpd(struct ib_pd *pd)
 | 
			
		||||
{
 | 
			
		||||
	return pd ? container_of(pd, struct rxe_pd, ibpd) : NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline struct rxe_ah *to_rah(struct ib_ah *ah)
 | 
			
		||||
{
 | 
			
		||||
	return ah ? container_of(ah, struct rxe_ah, ibah) : NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline struct rxe_srq *to_rsrq(struct ib_srq *srq)
 | 
			
		||||
{
 | 
			
		||||
	return srq ? container_of(srq, struct rxe_srq, ibsrq) : NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline struct rxe_qp *to_rqp(struct ib_qp *qp)
 | 
			
		||||
{
 | 
			
		||||
	return qp ? container_of(qp, struct rxe_qp, ibqp) : NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline struct rxe_cq *to_rcq(struct ib_cq *cq)
 | 
			
		||||
{
 | 
			
		||||
	return cq ? container_of(cq, struct rxe_cq, ibcq) : NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline struct rxe_mem *to_rmr(struct ib_mr *mr)
 | 
			
		||||
{
 | 
			
		||||
	return mr ? container_of(mr, struct rxe_mem, ibmr) : NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline struct rxe_mem *to_rmw(struct ib_mw *mw)
 | 
			
		||||
{
 | 
			
		||||
	return mw ? container_of(mw, struct rxe_mem, ibmw) : NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rxe_register_device(struct rxe_dev *rxe);
 | 
			
		||||
int rxe_unregister_device(struct rxe_dev *rxe);
 | 
			
		||||
 | 
			
		||||
void rxe_mc_cleanup(void *arg);
 | 
			
		||||
 | 
			
		||||
#endif /* RXE_VERBS_H */
 | 
			
		||||
| 
						 | 
				
			
			@ -6,3 +6,4 @@ header-y += ib_user_verbs.h
 | 
			
		|||
header-y += rdma_netlink.h
 | 
			
		||||
header-y += rdma_user_cm.h
 | 
			
		||||
header-y += hfi/
 | 
			
		||||
header-y += rdma_user_rxe.h
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										144
									
								
								include/uapi/rdma/rdma_user_rxe.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								include/uapi/rdma/rdma_user_rxe.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,144 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
 * OpenIB.org 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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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 RDMA_USER_RXE_H
 | 
			
		||||
#define RDMA_USER_RXE_H
 | 
			
		||||
 | 
			
		||||
#include <linux/types.h>
 | 
			
		||||
 | 
			
		||||
union rxe_gid {
 | 
			
		||||
	__u8	raw[16];
 | 
			
		||||
	struct {
 | 
			
		||||
		__be64	subnet_prefix;
 | 
			
		||||
		__be64	interface_id;
 | 
			
		||||
	} global;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_global_route {
 | 
			
		||||
	union rxe_gid	dgid;
 | 
			
		||||
	__u32		flow_label;
 | 
			
		||||
	__u8		sgid_index;
 | 
			
		||||
	__u8		hop_limit;
 | 
			
		||||
	__u8		traffic_class;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_av {
 | 
			
		||||
	__u8			port_num;
 | 
			
		||||
	__u8			network_type;
 | 
			
		||||
	struct rxe_global_route	grh;
 | 
			
		||||
	union {
 | 
			
		||||
		struct sockaddr		_sockaddr;
 | 
			
		||||
		struct sockaddr_in	_sockaddr_in;
 | 
			
		||||
		struct sockaddr_in6	_sockaddr_in6;
 | 
			
		||||
	} sgid_addr, dgid_addr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_send_wr {
 | 
			
		||||
	__u64			wr_id;
 | 
			
		||||
	__u32			num_sge;
 | 
			
		||||
	__u32			opcode;
 | 
			
		||||
	__u32			send_flags;
 | 
			
		||||
	union {
 | 
			
		||||
		__be32		imm_data;
 | 
			
		||||
		__u32		invalidate_rkey;
 | 
			
		||||
	} ex;
 | 
			
		||||
	union {
 | 
			
		||||
		struct {
 | 
			
		||||
			__u64	remote_addr;
 | 
			
		||||
			__u32	rkey;
 | 
			
		||||
		} rdma;
 | 
			
		||||
		struct {
 | 
			
		||||
			__u64	remote_addr;
 | 
			
		||||
			__u64	compare_add;
 | 
			
		||||
			__u64	swap;
 | 
			
		||||
			__u32	rkey;
 | 
			
		||||
		} atomic;
 | 
			
		||||
		struct {
 | 
			
		||||
			__u32	remote_qpn;
 | 
			
		||||
			__u32	remote_qkey;
 | 
			
		||||
			__u16	pkey_index;
 | 
			
		||||
		} ud;
 | 
			
		||||
		struct {
 | 
			
		||||
			struct ib_mr *mr;
 | 
			
		||||
			__u32        key;
 | 
			
		||||
			int          access;
 | 
			
		||||
		} reg;
 | 
			
		||||
	} wr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_sge {
 | 
			
		||||
	__u64	addr;
 | 
			
		||||
	__u32	length;
 | 
			
		||||
	__u32	lkey;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct mminfo {
 | 
			
		||||
	__u64			offset;
 | 
			
		||||
	__u32			size;
 | 
			
		||||
	__u32			pad;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_dma_info {
 | 
			
		||||
	__u32			length;
 | 
			
		||||
	__u32			resid;
 | 
			
		||||
	__u32			cur_sge;
 | 
			
		||||
	__u32			num_sge;
 | 
			
		||||
	__u32			sge_offset;
 | 
			
		||||
	union {
 | 
			
		||||
		__u8		inline_data[0];
 | 
			
		||||
		struct rxe_sge	sge[0];
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_send_wqe {
 | 
			
		||||
	struct rxe_send_wr	wr;
 | 
			
		||||
	struct rxe_av		av;
 | 
			
		||||
	__u32			status;
 | 
			
		||||
	__u32			state;
 | 
			
		||||
	__u64			iova;
 | 
			
		||||
	__u32			mask;
 | 
			
		||||
	__u32			first_psn;
 | 
			
		||||
	__u32			last_psn;
 | 
			
		||||
	__u32			ack_length;
 | 
			
		||||
	__u32			ssn;
 | 
			
		||||
	__u32			has_rd_atomic;
 | 
			
		||||
	struct rxe_dma_info	dma;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rxe_recv_wqe {
 | 
			
		||||
	__u64			wr_id;
 | 
			
		||||
	__u32			num_sge;
 | 
			
		||||
	__u32			padding;
 | 
			
		||||
	struct rxe_dma_info	dma;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif /* RDMA_USER_RXE_H */
 | 
			
		||||
		Loading…
	
		Reference in a new issue