mirror of https://gitee.com/openkylin/linux.git
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
|
@ -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/
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
};
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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,
|
||||
}
|
||||
},
|
||||
|
||||
};
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
|
@ -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");
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
|
|
|
@ -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 New Issue