Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,11 @@
# SPDX-License-Identifier: GPL-2.0-only
config INFINIBAND_QEDR
tristate "QLogic RoCE driver"
depends on 64BIT && QEDE
depends on PCI
select QED_LL2
select QED_OOO
select QED_RDMA
help
This driver provides low-level InfiniBand over Ethernet
support for QLogic QED host channel adapters (HCAs).
@@ -0,0 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_INFINIBAND_QEDR) := qedr.o
qedr-y := main.o verbs.o qedr_roce_cm.o qedr_iw_cm.o
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,622 @@
/* QLogic qedr NIC Driver
* Copyright (c) 2015-2016 QLogic Corporation
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* 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 __QEDR_H__
#define __QEDR_H__
#include <linux/pci.h>
#include <linux/xarray.h>
#include <rdma/ib_addr.h>
#include <linux/qed/qed_if.h>
#include <linux/qed/qed_chain.h>
#include <linux/qed/qed_rdma_if.h>
#include <linux/qed/qede_rdma.h>
#include <linux/qed/roce_common.h>
#include <linux/completion.h>
#include "qedr_hsi_rdma.h"
#define QEDR_NODE_DESC "QLogic 579xx RoCE HCA"
#define DP_NAME(_dev) dev_name(&(_dev)->ibdev.dev)
#define IS_IWARP(_dev) ((_dev)->rdma_type == QED_RDMA_TYPE_IWARP)
#define IS_ROCE(_dev) ((_dev)->rdma_type == QED_RDMA_TYPE_ROCE)
#define DP_DEBUG(dev, module, fmt, ...) \
pr_debug("(%s) " module ": " fmt, \
DP_NAME(dev) ? DP_NAME(dev) : "", ## __VA_ARGS__)
#define QEDR_MSG_INIT "INIT"
#define QEDR_MSG_CQ " CQ"
#define QEDR_MSG_MR " MR"
#define QEDR_MSG_QP " QP"
#define QEDR_MSG_SRQ " SRQ"
#define QEDR_MSG_GSI " GSI"
#define QEDR_MSG_IWARP " IW"
#define QEDR_CQ_MAGIC_NUMBER (0x11223344)
#define FW_PAGE_SHIFT (12)
struct qedr_dev;
struct qedr_cnq {
struct qedr_dev *dev;
struct qed_chain pbl;
struct qed_sb_info *sb;
char name[32];
u64 n_comp;
__le16 *hw_cons_ptr;
u8 index;
};
#define QEDR_MAX_SGID 128
struct qedr_device_attr {
u32 vendor_id;
u32 vendor_part_id;
u32 hw_ver;
u64 fw_ver;
u64 node_guid;
u64 sys_image_guid;
u8 max_cnq;
u8 max_sge;
u16 max_inline;
u32 max_sqe;
u32 max_rqe;
u8 max_qp_resp_rd_atomic_resc;
u8 max_qp_req_rd_atomic_resc;
u64 max_dev_resp_rd_atomic_resc;
u32 max_cq;
u32 max_qp;
u32 max_mr;
u64 max_mr_size;
u32 max_cqe;
u32 max_mw;
u32 max_mr_mw_fmr_pbl;
u64 max_mr_mw_fmr_size;
u32 max_pd;
u32 max_ah;
u8 max_pkey;
u32 max_srq;
u32 max_srq_wr;
u8 max_srq_sge;
u8 max_stats_queues;
u32 dev_caps;
u64 page_size_caps;
u8 dev_ack_delay;
u32 reserved_lkey;
u32 bad_pkey_counter;
struct qed_rdma_events events;
};
#define QEDR_ENET_STATE_BIT (0)
struct qedr_dev {
struct ib_device ibdev;
struct qed_dev *cdev;
struct pci_dev *pdev;
struct net_device *ndev;
enum ib_atomic_cap atomic_cap;
void *rdma_ctx;
struct qedr_device_attr attr;
const struct qed_rdma_ops *ops;
struct qed_int_info int_info;
struct qed_sb_info *sb_array;
struct qedr_cnq *cnq_array;
int num_cnq;
int sb_start;
void __iomem *db_addr;
u64 db_phys_addr;
u32 db_size;
u16 dpi;
union ib_gid *sgid_tbl;
/* Lock for sgid table */
spinlock_t sgid_lock;
u64 guid;
u32 dp_module;
u8 dp_level;
u8 num_hwfns;
#define QEDR_IS_CMT(dev) ((dev)->num_hwfns > 1)
u8 affin_hwfn_idx;
u8 gsi_ll2_handle;
uint wq_multiplier;
u8 gsi_ll2_mac_address[ETH_ALEN];
int gsi_qp_created;
struct qedr_cq *gsi_sqcq;
struct qedr_cq *gsi_rqcq;
struct qedr_qp *gsi_qp;
enum qed_rdma_type rdma_type;
struct xarray qps;
struct xarray srqs;
struct workqueue_struct *iwarp_wq;
u16 iwarp_max_mtu;
unsigned long enet_state;
u8 user_dpm_enabled;
};
#define QEDR_MAX_SQ_PBL_ENTRIES (0x10000 / sizeof(void *))
#define QEDR_SQE_ELEMENT_SIZE (sizeof(struct rdma_sq_sge))
#define QEDR_MAX_SQE_ELEMENTS_PER_SQE (ROCE_REQ_MAX_SINGLE_SQ_WQE_SIZE / \
QEDR_SQE_ELEMENT_SIZE)
#define QEDR_MAX_SQE ((QEDR_MAX_SQ_PBL_ENTRIES) *\
(RDMA_RING_PAGE_SIZE) / \
(QEDR_SQE_ELEMENT_SIZE) /\
(QEDR_MAX_SQE_ELEMENTS_PER_SQE))
/* RQ */
#define QEDR_MAX_RQ_PBL_ENTRIES (0x10000 / sizeof(void *))
#define QEDR_RQE_ELEMENT_SIZE (sizeof(struct rdma_rq_sge))
#define QEDR_MAX_RQE_ELEMENTS_PER_RQE (RDMA_MAX_SGE_PER_RQ_WQE)
#define QEDR_MAX_RQE ((QEDR_MAX_RQ_PBL_ENTRIES) *\
(RDMA_RING_PAGE_SIZE) / \
(QEDR_RQE_ELEMENT_SIZE) /\
(QEDR_MAX_RQE_ELEMENTS_PER_RQE))
#define QEDR_CQE_SIZE (sizeof(union rdma_cqe))
#define QEDR_MAX_CQE_PBL_SIZE (512 * 1024)
#define QEDR_MAX_CQE_PBL_ENTRIES (((QEDR_MAX_CQE_PBL_SIZE) / \
sizeof(u64)) - 1)
#define QEDR_MAX_CQES ((u32)((QEDR_MAX_CQE_PBL_ENTRIES) * \
(QED_CHAIN_PAGE_SIZE) / QEDR_CQE_SIZE))
#define QEDR_ROCE_MAX_CNQ_SIZE (0x4000)
#define QEDR_PORT (1)
#define QEDR_ROCE_PKEY_TABLE_LEN 1
#define QEDR_ROCE_PKEY_DEFAULT 0xffff
struct qedr_pbl {
struct list_head list_entry;
void *va;
dma_addr_t pa;
};
struct qedr_ucontext {
struct ib_ucontext ibucontext;
struct qedr_dev *dev;
struct qedr_pd *pd;
void __iomem *dpi_addr;
struct rdma_user_mmap_entry *db_mmap_entry;
u64 dpi_phys_addr;
u32 dpi_size;
u16 dpi;
bool db_rec;
u8 edpm_mode;
};
union db_prod32 {
struct rdma_pwm_val16_data data;
u32 raw;
};
union db_prod64 {
struct rdma_pwm_val32_data data;
u64 raw;
};
enum qedr_cq_type {
QEDR_CQ_TYPE_GSI,
QEDR_CQ_TYPE_KERNEL,
QEDR_CQ_TYPE_USER,
};
struct qedr_pbl_info {
u32 num_pbls;
u32 num_pbes;
u32 pbl_size;
u32 pbe_size;
bool two_layered;
};
struct qedr_userq {
struct ib_umem *umem;
struct qedr_pbl_info pbl_info;
struct qedr_pbl *pbl_tbl;
u64 buf_addr;
size_t buf_len;
/* doorbell recovery */
void __iomem *db_addr;
struct qedr_user_db_rec *db_rec_data;
struct rdma_user_mmap_entry *db_mmap_entry;
void __iomem *db_rec_db2_addr;
union db_prod32 db_rec_db2_data;
};
struct qedr_cq {
struct ib_cq ibcq;
enum qedr_cq_type cq_type;
u32 sig;
u16 icid;
/* Lock to protect multiplem CQ's */
spinlock_t cq_lock;
u8 arm_flags;
struct qed_chain pbl;
void __iomem *db_addr;
union db_prod64 db;
u8 pbl_toggle;
union rdma_cqe *latest_cqe;
union rdma_cqe *toggle_cqe;
u32 cq_cons;
struct qedr_userq q;
u8 destroyed;
u16 cnq_notif;
};
struct qedr_pd {
struct ib_pd ibpd;
u32 pd_id;
struct qedr_ucontext *uctx;
};
struct qedr_xrcd {
struct ib_xrcd ibxrcd;
u16 xrcd_id;
};
struct qedr_qp_hwq_info {
/* WQE Elements */
struct qed_chain pbl;
u64 p_phys_addr_tbl;
u32 max_sges;
/* WQE */
u16 prod;
u16 cons;
u16 wqe_cons;
u16 gsi_cons;
u16 max_wr;
/* DB */
void __iomem *db;
union db_prod32 db_data;
void __iomem *iwarp_db2;
union db_prod32 iwarp_db2_data;
};
struct qedr_srq_hwq_info {
u32 max_sges;
u32 max_wr;
struct qed_chain pbl;
u64 p_phys_addr_tbl;
u32 wqe_prod;
u32 sge_prod;
u32 wr_prod_cnt;
atomic_t wr_cons_cnt;
u32 num_elems;
struct rdma_srq_producers *virt_prod_pair_addr;
dma_addr_t phy_prod_pair_addr;
};
struct qedr_srq {
struct ib_srq ibsrq;
struct qedr_dev *dev;
struct qedr_userq usrq;
struct qedr_srq_hwq_info hw_srq;
struct ib_umem *prod_umem;
u16 srq_id;
u32 srq_limit;
bool is_xrc;
/* lock to protect srq recv post */
spinlock_t lock;
};
enum qedr_qp_err_bitmap {
QEDR_QP_ERR_SQ_FULL = 1,
QEDR_QP_ERR_RQ_FULL = 2,
QEDR_QP_ERR_BAD_SR = 4,
QEDR_QP_ERR_BAD_RR = 8,
QEDR_QP_ERR_SQ_PBL_FULL = 16,
QEDR_QP_ERR_RQ_PBL_FULL = 32,
};
enum qedr_qp_create_type {
QEDR_QP_CREATE_NONE,
QEDR_QP_CREATE_USER,
QEDR_QP_CREATE_KERNEL,
};
enum qedr_iwarp_cm_flags {
QEDR_IWARP_CM_WAIT_FOR_CONNECT = BIT(0),
QEDR_IWARP_CM_WAIT_FOR_DISCONNECT = BIT(1),
};
struct qedr_qp {
struct ib_qp ibqp; /* must be first */
struct qedr_dev *dev;
struct qedr_qp_hwq_info sq;
struct qedr_qp_hwq_info rq;
u32 max_inline_data;
/* Lock for QP's */
spinlock_t q_lock;
struct qedr_cq *sq_cq;
struct qedr_cq *rq_cq;
struct qedr_srq *srq;
enum qed_roce_qp_state state;
u32 id;
struct qedr_pd *pd;
enum ib_qp_type qp_type;
enum qedr_qp_create_type create_type;
struct qed_rdma_qp *qed_qp;
u32 qp_id;
u16 icid;
u16 mtu;
int sgid_idx;
u32 rq_psn;
u32 sq_psn;
u32 qkey;
u32 dest_qp_num;
u8 timeout;
/* Relevant to qps created from kernel space only (ULPs) */
u8 prev_wqe_size;
u16 wqe_cons;
u32 err_bitmap;
bool signaled;
/* SQ shadow */
struct {
u64 wr_id;
enum ib_wc_opcode opcode;
u32 bytes_len;
u8 wqe_size;
bool signaled;
dma_addr_t icrc_mapping;
u32 *icrc;
struct qedr_mr *mr;
} *wqe_wr_id;
/* RQ shadow */
struct {
u64 wr_id;
struct ib_sge sg_list[RDMA_MAX_SGE_PER_RQ_WQE];
u8 wqe_size;
u8 smac[ETH_ALEN];
u16 vlan;
int rc;
} *rqe_wr_id;
/* Relevant to qps created from user space only (applications) */
struct qedr_userq usq;
struct qedr_userq urq;
/* synchronization objects used with iwarp ep */
struct kref refcnt;
struct completion iwarp_cm_comp;
struct completion qp_rel_comp;
unsigned long iwarp_cm_flags; /* enum iwarp_cm_flags */
};
struct qedr_ah {
struct ib_ah ibah;
struct rdma_ah_attr attr;
};
enum qedr_mr_type {
QEDR_MR_USER,
QEDR_MR_KERNEL,
QEDR_MR_DMA,
QEDR_MR_FRMR,
};
struct mr_info {
struct qedr_pbl *pbl_table;
struct qedr_pbl_info pbl_info;
struct list_head free_pbl_list;
struct list_head inuse_pbl_list;
u32 completed;
u32 completed_handled;
};
struct qedr_mr {
struct ib_mr ibmr;
struct ib_umem *umem;
struct qed_rdma_register_tid_in_params hw_mr;
enum qedr_mr_type type;
struct qedr_dev *dev;
struct mr_info info;
u64 *pages;
u32 npages;
};
struct qedr_user_mmap_entry {
struct rdma_user_mmap_entry rdma_entry;
struct qedr_dev *dev;
union {
u64 io_address;
void *address;
};
size_t length;
u16 dpi;
u8 mmap_flag;
};
#define SET_FIELD2(value, name, flag) ((value) |= ((flag) << (name ## _SHIFT)))
#define QEDR_RESP_IMM (RDMA_CQE_RESPONDER_IMM_FLG_MASK << \
RDMA_CQE_RESPONDER_IMM_FLG_SHIFT)
#define QEDR_RESP_RDMA (RDMA_CQE_RESPONDER_RDMA_FLG_MASK << \
RDMA_CQE_RESPONDER_RDMA_FLG_SHIFT)
#define QEDR_RESP_INV (RDMA_CQE_RESPONDER_INV_FLG_MASK << \
RDMA_CQE_RESPONDER_INV_FLG_SHIFT)
static inline void qedr_inc_sw_cons(struct qedr_qp_hwq_info *info)
{
info->cons = (info->cons + 1) % info->max_wr;
info->wqe_cons++;
}
static inline void qedr_inc_sw_prod(struct qedr_qp_hwq_info *info)
{
info->prod = (info->prod + 1) % info->max_wr;
}
static inline int qedr_get_dmac(struct qedr_dev *dev,
struct rdma_ah_attr *ah_attr, u8 *mac_addr)
{
union ib_gid zero_sgid = { { 0 } };
struct in6_addr in6;
const struct ib_global_route *grh = rdma_ah_read_grh(ah_attr);
u8 *dmac;
if (!memcmp(&grh->dgid, &zero_sgid, sizeof(union ib_gid))) {
DP_ERR(dev, "Local port GID not supported\n");
eth_zero_addr(mac_addr);
return -EINVAL;
}
memcpy(&in6, grh->dgid.raw, sizeof(in6));
dmac = rdma_ah_retrieve_dmac(ah_attr);
if (!dmac)
return -EINVAL;
ether_addr_copy(mac_addr, dmac);
return 0;
}
struct qedr_iw_listener {
struct qedr_dev *dev;
struct iw_cm_id *cm_id;
int backlog;
void *qed_handle;
};
struct qedr_iw_ep {
struct qedr_dev *dev;
struct iw_cm_id *cm_id;
struct qedr_qp *qp;
void *qed_context;
struct kref refcnt;
};
static inline
struct qedr_ucontext *get_qedr_ucontext(struct ib_ucontext *ibucontext)
{
return container_of(ibucontext, struct qedr_ucontext, ibucontext);
}
static inline struct qedr_dev *get_qedr_dev(struct ib_device *ibdev)
{
return container_of(ibdev, struct qedr_dev, ibdev);
}
static inline struct qedr_pd *get_qedr_pd(struct ib_pd *ibpd)
{
return container_of(ibpd, struct qedr_pd, ibpd);
}
static inline struct qedr_xrcd *get_qedr_xrcd(struct ib_xrcd *ibxrcd)
{
return container_of(ibxrcd, struct qedr_xrcd, ibxrcd);
}
static inline struct qedr_cq *get_qedr_cq(struct ib_cq *ibcq)
{
return container_of(ibcq, struct qedr_cq, ibcq);
}
static inline struct qedr_qp *get_qedr_qp(struct ib_qp *ibqp)
{
return container_of(ibqp, struct qedr_qp, ibqp);
}
static inline struct qedr_ah *get_qedr_ah(struct ib_ah *ibah)
{
return container_of(ibah, struct qedr_ah, ibah);
}
static inline struct qedr_mr *get_qedr_mr(struct ib_mr *ibmr)
{
return container_of(ibmr, struct qedr_mr, ibmr);
}
static inline struct qedr_srq *get_qedr_srq(struct ib_srq *ibsrq)
{
return container_of(ibsrq, struct qedr_srq, ibsrq);
}
static inline bool qedr_qp_has_srq(struct qedr_qp *qp)
{
return qp->srq;
}
static inline bool qedr_qp_has_sq(struct qedr_qp *qp)
{
if (qp->qp_type == IB_QPT_GSI || qp->qp_type == IB_QPT_XRC_TGT)
return false;
return true;
}
static inline bool qedr_qp_has_rq(struct qedr_qp *qp)
{
if (qp->qp_type == IB_QPT_GSI || qp->qp_type == IB_QPT_XRC_INI ||
qp->qp_type == IB_QPT_XRC_TGT || qedr_qp_has_srq(qp))
return false;
return true;
}
static inline struct qedr_user_mmap_entry *
get_qedr_mmap_entry(struct rdma_user_mmap_entry *rdma_entry)
{
return container_of(rdma_entry, struct qedr_user_mmap_entry,
rdma_entry);
}
#endif
@@ -0,0 +1,751 @@
/* QLogic qedr NIC Driver
* Copyright (c) 2015-2016 QLogic Corporation
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* 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 __QED_HSI_RDMA__
#define __QED_HSI_RDMA__
#include <linux/qed/rdma_common.h>
/* rdma completion notification queue element */
struct rdma_cnqe {
struct regpair cq_handle;
};
struct rdma_cqe_responder {
struct regpair srq_wr_id;
struct regpair qp_handle;
__le32 imm_data_or_inv_r_Key;
__le32 length;
__le32 imm_data_hi;
__le16 rq_cons_or_srq_id;
u8 flags;
#define RDMA_CQE_RESPONDER_TOGGLE_BIT_MASK 0x1
#define RDMA_CQE_RESPONDER_TOGGLE_BIT_SHIFT 0
#define RDMA_CQE_RESPONDER_TYPE_MASK 0x3
#define RDMA_CQE_RESPONDER_TYPE_SHIFT 1
#define RDMA_CQE_RESPONDER_INV_FLG_MASK 0x1
#define RDMA_CQE_RESPONDER_INV_FLG_SHIFT 3
#define RDMA_CQE_RESPONDER_IMM_FLG_MASK 0x1
#define RDMA_CQE_RESPONDER_IMM_FLG_SHIFT 4
#define RDMA_CQE_RESPONDER_RDMA_FLG_MASK 0x1
#define RDMA_CQE_RESPONDER_RDMA_FLG_SHIFT 5
#define RDMA_CQE_RESPONDER_RESERVED2_MASK 0x3
#define RDMA_CQE_RESPONDER_RESERVED2_SHIFT 6
u8 status;
};
struct rdma_cqe_requester {
__le16 sq_cons;
__le16 reserved0;
__le32 reserved1;
struct regpair qp_handle;
struct regpair reserved2;
__le32 reserved3;
__le16 reserved4;
u8 flags;
#define RDMA_CQE_REQUESTER_TOGGLE_BIT_MASK 0x1
#define RDMA_CQE_REQUESTER_TOGGLE_BIT_SHIFT 0
#define RDMA_CQE_REQUESTER_TYPE_MASK 0x3
#define RDMA_CQE_REQUESTER_TYPE_SHIFT 1
#define RDMA_CQE_REQUESTER_RESERVED5_MASK 0x1F
#define RDMA_CQE_REQUESTER_RESERVED5_SHIFT 3
u8 status;
};
struct rdma_cqe_common {
struct regpair reserved0;
struct regpair qp_handle;
__le16 reserved1[7];
u8 flags;
#define RDMA_CQE_COMMON_TOGGLE_BIT_MASK 0x1
#define RDMA_CQE_COMMON_TOGGLE_BIT_SHIFT 0
#define RDMA_CQE_COMMON_TYPE_MASK 0x3
#define RDMA_CQE_COMMON_TYPE_SHIFT 1
#define RDMA_CQE_COMMON_RESERVED2_MASK 0x1F
#define RDMA_CQE_COMMON_RESERVED2_SHIFT 3
u8 status;
};
/* rdma completion queue element */
union rdma_cqe {
struct rdma_cqe_responder resp;
struct rdma_cqe_requester req;
struct rdma_cqe_common cmn;
};
/* * CQE requester status enumeration */
enum rdma_cqe_requester_status_enum {
RDMA_CQE_REQ_STS_OK,
RDMA_CQE_REQ_STS_BAD_RESPONSE_ERR,
RDMA_CQE_REQ_STS_LOCAL_LENGTH_ERR,
RDMA_CQE_REQ_STS_LOCAL_QP_OPERATION_ERR,
RDMA_CQE_REQ_STS_LOCAL_PROTECTION_ERR,
RDMA_CQE_REQ_STS_MEMORY_MGT_OPERATION_ERR,
RDMA_CQE_REQ_STS_REMOTE_INVALID_REQUEST_ERR,
RDMA_CQE_REQ_STS_REMOTE_ACCESS_ERR,
RDMA_CQE_REQ_STS_REMOTE_OPERATION_ERR,
RDMA_CQE_REQ_STS_RNR_NAK_RETRY_CNT_ERR,
RDMA_CQE_REQ_STS_TRANSPORT_RETRY_CNT_ERR,
RDMA_CQE_REQ_STS_WORK_REQUEST_FLUSHED_ERR,
RDMA_CQE_REQ_STS_XRC_VOILATION_ERR,
RDMA_CQE_REQ_STS_SIG_ERR,
MAX_RDMA_CQE_REQUESTER_STATUS_ENUM
};
/* CQE responder status enumeration */
enum rdma_cqe_responder_status_enum {
RDMA_CQE_RESP_STS_OK,
RDMA_CQE_RESP_STS_LOCAL_ACCESS_ERR,
RDMA_CQE_RESP_STS_LOCAL_LENGTH_ERR,
RDMA_CQE_RESP_STS_LOCAL_QP_OPERATION_ERR,
RDMA_CQE_RESP_STS_LOCAL_PROTECTION_ERR,
RDMA_CQE_RESP_STS_MEMORY_MGT_OPERATION_ERR,
RDMA_CQE_RESP_STS_REMOTE_INVALID_REQUEST_ERR,
RDMA_CQE_RESP_STS_WORK_REQUEST_FLUSHED_ERR,
MAX_RDMA_CQE_RESPONDER_STATUS_ENUM
};
/* CQE type enumeration */
enum rdma_cqe_type {
RDMA_CQE_TYPE_REQUESTER,
RDMA_CQE_TYPE_RESPONDER_RQ,
RDMA_CQE_TYPE_RESPONDER_SRQ,
RDMA_CQE_TYPE_RESPONDER_XRC_SRQ,
RDMA_CQE_TYPE_INVALID,
MAX_RDMA_CQE_TYPE
};
struct rdma_sq_sge {
__le32 length;
struct regpair addr;
__le32 l_key;
};
struct rdma_rq_sge {
struct regpair addr;
__le32 length;
__le32 flags;
#define RDMA_RQ_SGE_L_KEY_LO_MASK 0x3FFFFFF
#define RDMA_RQ_SGE_L_KEY_LO_SHIFT 0
#define RDMA_RQ_SGE_NUM_SGES_MASK 0x7
#define RDMA_RQ_SGE_NUM_SGES_SHIFT 26
#define RDMA_RQ_SGE_L_KEY_HI_MASK 0x7
#define RDMA_RQ_SGE_L_KEY_HI_SHIFT 29
};
struct rdma_srq_wqe_header {
struct regpair wr_id;
u8 num_sges /* number of SGEs in WQE */;
u8 reserved2[7];
};
struct rdma_srq_sge {
struct regpair addr;
__le32 length;
__le32 l_key;
};
union rdma_srq_elm {
struct rdma_srq_wqe_header header;
struct rdma_srq_sge sge;
};
/* Rdma doorbell data for flags update */
struct rdma_pwm_flags_data {
__le16 icid; /* internal CID */
u8 agg_flags; /* aggregative flags */
u8 reserved;
};
/* Rdma doorbell data for SQ and RQ */
struct rdma_pwm_val16_data {
__le16 icid;
__le16 value;
};
union rdma_pwm_val16_data_union {
struct rdma_pwm_val16_data as_struct;
__le32 as_dword;
};
/* Rdma doorbell data for CQ */
struct rdma_pwm_val32_data {
__le16 icid;
u8 agg_flags;
u8 params;
#define RDMA_PWM_VAL32_DATA_AGG_CMD_MASK 0x3
#define RDMA_PWM_VAL32_DATA_AGG_CMD_SHIFT 0
#define RDMA_PWM_VAL32_DATA_BYPASS_EN_MASK 0x1
#define RDMA_PWM_VAL32_DATA_BYPASS_EN_SHIFT 2
#define RDMA_PWM_VAL32_DATA_CONN_TYPE_IS_IWARP_MASK 0x1
#define RDMA_PWM_VAL32_DATA_CONN_TYPE_IS_IWARP_SHIFT 3
#define RDMA_PWM_VAL32_DATA_SET_16B_VAL_MASK 0x1
#define RDMA_PWM_VAL32_DATA_SET_16B_VAL_SHIFT 4
#define RDMA_PWM_VAL32_DATA_RESERVED_MASK 0x7
#define RDMA_PWM_VAL32_DATA_RESERVED_SHIFT 5
__le32 value;
};
/* DIF Block size options */
enum rdma_dif_block_size {
RDMA_DIF_BLOCK_512 = 0,
RDMA_DIF_BLOCK_4096 = 1,
MAX_RDMA_DIF_BLOCK_SIZE
};
/* DIF CRC initial value */
enum rdma_dif_crc_seed {
RDMA_DIF_CRC_SEED_0000 = 0,
RDMA_DIF_CRC_SEED_FFFF = 1,
MAX_RDMA_DIF_CRC_SEED
};
/* RDMA DIF Error Result Structure */
struct rdma_dif_error_result {
__le32 error_intervals;
__le32 dif_error_1st_interval;
u8 flags;
#define RDMA_DIF_ERROR_RESULT_DIF_ERROR_TYPE_CRC_MASK 0x1
#define RDMA_DIF_ERROR_RESULT_DIF_ERROR_TYPE_CRC_SHIFT 0
#define RDMA_DIF_ERROR_RESULT_DIF_ERROR_TYPE_APP_TAG_MASK 0x1
#define RDMA_DIF_ERROR_RESULT_DIF_ERROR_TYPE_APP_TAG_SHIFT 1
#define RDMA_DIF_ERROR_RESULT_DIF_ERROR_TYPE_REF_TAG_MASK 0x1
#define RDMA_DIF_ERROR_RESULT_DIF_ERROR_TYPE_REF_TAG_SHIFT 2
#define RDMA_DIF_ERROR_RESULT_RESERVED0_MASK 0xF
#define RDMA_DIF_ERROR_RESULT_RESERVED0_SHIFT 3
#define RDMA_DIF_ERROR_RESULT_TOGGLE_BIT_MASK 0x1
#define RDMA_DIF_ERROR_RESULT_TOGGLE_BIT_SHIFT 7
u8 reserved1[55];
};
/* DIF IO direction */
enum rdma_dif_io_direction_flg {
RDMA_DIF_DIR_RX = 0,
RDMA_DIF_DIR_TX = 1,
MAX_RDMA_DIF_IO_DIRECTION_FLG
};
struct rdma_dif_params {
__le32 base_ref_tag;
__le16 app_tag;
__le16 app_tag_mask;
__le16 runt_crc_value;
__le16 flags;
#define RDMA_DIF_PARAMS_IO_DIRECTION_FLG_MASK 0x1
#define RDMA_DIF_PARAMS_IO_DIRECTION_FLG_SHIFT 0
#define RDMA_DIF_PARAMS_BLOCK_SIZE_MASK 0x1
#define RDMA_DIF_PARAMS_BLOCK_SIZE_SHIFT 1
#define RDMA_DIF_PARAMS_RUNT_VALID_FLG_MASK 0x1
#define RDMA_DIF_PARAMS_RUNT_VALID_FLG_SHIFT 2
#define RDMA_DIF_PARAMS_VALIDATE_CRC_GUARD_MASK 0x1
#define RDMA_DIF_PARAMS_VALIDATE_CRC_GUARD_SHIFT 3
#define RDMA_DIF_PARAMS_VALIDATE_REF_TAG_MASK 0x1
#define RDMA_DIF_PARAMS_VALIDATE_REF_TAG_SHIFT 4
#define RDMA_DIF_PARAMS_VALIDATE_APP_TAG_MASK 0x1
#define RDMA_DIF_PARAMS_VALIDATE_APP_TAG_SHIFT 5
#define RDMA_DIF_PARAMS_CRC_SEED_MASK 0x1
#define RDMA_DIF_PARAMS_CRC_SEED_SHIFT 6
#define RDMA_DIF_PARAMS_RX_REF_TAG_CONST_MASK 0x1
#define RDMA_DIF_PARAMS_RX_REF_TAG_CONST_SHIFT 7
#define RDMA_DIF_PARAMS_BLOCK_GUARD_TYPE_MASK 0x1
#define RDMA_DIF_PARAMS_BLOCK_GUARD_TYPE_SHIFT 8
#define RDMA_DIF_PARAMS_APP_ESCAPE_MASK 0x1
#define RDMA_DIF_PARAMS_APP_ESCAPE_SHIFT 9
#define RDMA_DIF_PARAMS_REF_ESCAPE_MASK 0x1
#define RDMA_DIF_PARAMS_REF_ESCAPE_SHIFT 10
#define RDMA_DIF_PARAMS_RESERVED4_MASK 0x1F
#define RDMA_DIF_PARAMS_RESERVED4_SHIFT 11
__le32 reserved5;
};
struct rdma_sq_atomic_wqe {
__le32 reserved1;
__le32 length;
__le32 xrc_srq;
u8 req_type;
u8 flags;
#define RDMA_SQ_ATOMIC_WQE_COMP_FLG_MASK 0x1
#define RDMA_SQ_ATOMIC_WQE_COMP_FLG_SHIFT 0
#define RDMA_SQ_ATOMIC_WQE_RD_FENCE_FLG_MASK 0x1
#define RDMA_SQ_ATOMIC_WQE_RD_FENCE_FLG_SHIFT 1
#define RDMA_SQ_ATOMIC_WQE_INV_FENCE_FLG_MASK 0x1
#define RDMA_SQ_ATOMIC_WQE_INV_FENCE_FLG_SHIFT 2
#define RDMA_SQ_ATOMIC_WQE_SE_FLG_MASK 0x1
#define RDMA_SQ_ATOMIC_WQE_SE_FLG_SHIFT 3
#define RDMA_SQ_ATOMIC_WQE_INLINE_FLG_MASK 0x1
#define RDMA_SQ_ATOMIC_WQE_INLINE_FLG_SHIFT 4
#define RDMA_SQ_ATOMIC_WQE_DIF_ON_HOST_FLG_MASK 0x1
#define RDMA_SQ_ATOMIC_WQE_DIF_ON_HOST_FLG_SHIFT 5
#define RDMA_SQ_ATOMIC_WQE_RESERVED0_MASK 0x3
#define RDMA_SQ_ATOMIC_WQE_RESERVED0_SHIFT 6
u8 wqe_size;
u8 prev_wqe_size;
struct regpair remote_va;
__le32 r_key;
__le32 reserved2;
struct regpair cmp_data;
struct regpair swap_data;
};
/* First element (16 bytes) of atomic wqe */
struct rdma_sq_atomic_wqe_1st {
__le32 reserved1;
__le32 length;
__le32 xrc_srq;
u8 req_type;
u8 flags;
#define RDMA_SQ_ATOMIC_WQE_1ST_COMP_FLG_MASK 0x1
#define RDMA_SQ_ATOMIC_WQE_1ST_COMP_FLG_SHIFT 0
#define RDMA_SQ_ATOMIC_WQE_1ST_RD_FENCE_FLG_MASK 0x1
#define RDMA_SQ_ATOMIC_WQE_1ST_RD_FENCE_FLG_SHIFT 1
#define RDMA_SQ_ATOMIC_WQE_1ST_INV_FENCE_FLG_MASK 0x1
#define RDMA_SQ_ATOMIC_WQE_1ST_INV_FENCE_FLG_SHIFT 2
#define RDMA_SQ_ATOMIC_WQE_1ST_SE_FLG_MASK 0x1
#define RDMA_SQ_ATOMIC_WQE_1ST_SE_FLG_SHIFT 3
#define RDMA_SQ_ATOMIC_WQE_1ST_INLINE_FLG_MASK 0x1
#define RDMA_SQ_ATOMIC_WQE_1ST_INLINE_FLG_SHIFT 4
#define RDMA_SQ_ATOMIC_WQE_1ST_RESERVED0_MASK 0x7
#define RDMA_SQ_ATOMIC_WQE_1ST_RESERVED0_SHIFT 5
u8 wqe_size;
u8 prev_wqe_size;
};
/* Second element (16 bytes) of atomic wqe */
struct rdma_sq_atomic_wqe_2nd {
struct regpair remote_va;
__le32 r_key;
__le32 reserved2;
};
/* Third element (16 bytes) of atomic wqe */
struct rdma_sq_atomic_wqe_3rd {
struct regpair cmp_data;
struct regpair swap_data;
};
struct rdma_sq_bind_wqe {
struct regpair addr;
__le32 l_key;
u8 req_type;
u8 flags;
#define RDMA_SQ_BIND_WQE_COMP_FLG_MASK 0x1
#define RDMA_SQ_BIND_WQE_COMP_FLG_SHIFT 0
#define RDMA_SQ_BIND_WQE_RD_FENCE_FLG_MASK 0x1
#define RDMA_SQ_BIND_WQE_RD_FENCE_FLG_SHIFT 1
#define RDMA_SQ_BIND_WQE_INV_FENCE_FLG_MASK 0x1
#define RDMA_SQ_BIND_WQE_INV_FENCE_FLG_SHIFT 2
#define RDMA_SQ_BIND_WQE_SE_FLG_MASK 0x1
#define RDMA_SQ_BIND_WQE_SE_FLG_SHIFT 3
#define RDMA_SQ_BIND_WQE_INLINE_FLG_MASK 0x1
#define RDMA_SQ_BIND_WQE_INLINE_FLG_SHIFT 4
#define RDMA_SQ_BIND_WQE_DIF_ON_HOST_FLG_MASK 0x1
#define RDMA_SQ_BIND_WQE_DIF_ON_HOST_FLG_SHIFT 5
#define RDMA_SQ_BIND_WQE_RESERVED0_MASK 0x3
#define RDMA_SQ_BIND_WQE_RESERVED0_SHIFT 6
u8 wqe_size;
u8 prev_wqe_size;
u8 bind_ctrl;
#define RDMA_SQ_BIND_WQE_ZERO_BASED_MASK 0x1
#define RDMA_SQ_BIND_WQE_ZERO_BASED_SHIFT 0
#define RDMA_SQ_BIND_WQE_RESERVED1_MASK 0x7F
#define RDMA_SQ_BIND_WQE_RESERVED1_SHIFT 1
u8 access_ctrl;
#define RDMA_SQ_BIND_WQE_REMOTE_READ_MASK 0x1
#define RDMA_SQ_BIND_WQE_REMOTE_READ_SHIFT 0
#define RDMA_SQ_BIND_WQE_REMOTE_WRITE_MASK 0x1
#define RDMA_SQ_BIND_WQE_REMOTE_WRITE_SHIFT 1
#define RDMA_SQ_BIND_WQE_ENABLE_ATOMIC_MASK 0x1
#define RDMA_SQ_BIND_WQE_ENABLE_ATOMIC_SHIFT 2
#define RDMA_SQ_BIND_WQE_LOCAL_READ_MASK 0x1
#define RDMA_SQ_BIND_WQE_LOCAL_READ_SHIFT 3
#define RDMA_SQ_BIND_WQE_LOCAL_WRITE_MASK 0x1
#define RDMA_SQ_BIND_WQE_LOCAL_WRITE_SHIFT 4
#define RDMA_SQ_BIND_WQE_RESERVED2_MASK 0x7
#define RDMA_SQ_BIND_WQE_RESERVED2_SHIFT 5
u8 reserved3;
u8 length_hi;
__le32 length_lo;
__le32 parent_l_key;
__le32 reserved4;
struct rdma_dif_params dif_params;
};
/* First element (16 bytes) of bind wqe */
struct rdma_sq_bind_wqe_1st {
struct regpair addr;
__le32 l_key;
u8 req_type;
u8 flags;
#define RDMA_SQ_BIND_WQE_1ST_COMP_FLG_MASK 0x1
#define RDMA_SQ_BIND_WQE_1ST_COMP_FLG_SHIFT 0
#define RDMA_SQ_BIND_WQE_1ST_RD_FENCE_FLG_MASK 0x1
#define RDMA_SQ_BIND_WQE_1ST_RD_FENCE_FLG_SHIFT 1
#define RDMA_SQ_BIND_WQE_1ST_INV_FENCE_FLG_MASK 0x1
#define RDMA_SQ_BIND_WQE_1ST_INV_FENCE_FLG_SHIFT 2
#define RDMA_SQ_BIND_WQE_1ST_SE_FLG_MASK 0x1
#define RDMA_SQ_BIND_WQE_1ST_SE_FLG_SHIFT 3
#define RDMA_SQ_BIND_WQE_1ST_INLINE_FLG_MASK 0x1
#define RDMA_SQ_BIND_WQE_1ST_INLINE_FLG_SHIFT 4
#define RDMA_SQ_BIND_WQE_1ST_RESERVED0_MASK 0x7
#define RDMA_SQ_BIND_WQE_1ST_RESERVED0_SHIFT 5
u8 wqe_size;
u8 prev_wqe_size;
};
/* Second element (16 bytes) of bind wqe */
struct rdma_sq_bind_wqe_2nd {
u8 bind_ctrl;
#define RDMA_SQ_BIND_WQE_2ND_ZERO_BASED_MASK 0x1
#define RDMA_SQ_BIND_WQE_2ND_ZERO_BASED_SHIFT 0
#define RDMA_SQ_BIND_WQE_2ND_RESERVED1_MASK 0x7F
#define RDMA_SQ_BIND_WQE_2ND_RESERVED1_SHIFT 1
u8 access_ctrl;
#define RDMA_SQ_BIND_WQE_2ND_REMOTE_READ_MASK 0x1
#define RDMA_SQ_BIND_WQE_2ND_REMOTE_READ_SHIFT 0
#define RDMA_SQ_BIND_WQE_2ND_REMOTE_WRITE_MASK 0x1
#define RDMA_SQ_BIND_WQE_2ND_REMOTE_WRITE_SHIFT 1
#define RDMA_SQ_BIND_WQE_2ND_ENABLE_ATOMIC_MASK 0x1
#define RDMA_SQ_BIND_WQE_2ND_ENABLE_ATOMIC_SHIFT 2
#define RDMA_SQ_BIND_WQE_2ND_LOCAL_READ_MASK 0x1
#define RDMA_SQ_BIND_WQE_2ND_LOCAL_READ_SHIFT 3
#define RDMA_SQ_BIND_WQE_2ND_LOCAL_WRITE_MASK 0x1
#define RDMA_SQ_BIND_WQE_2ND_LOCAL_WRITE_SHIFT 4
#define RDMA_SQ_BIND_WQE_2ND_RESERVED2_MASK 0x7
#define RDMA_SQ_BIND_WQE_2ND_RESERVED2_SHIFT 5
u8 reserved3;
u8 length_hi;
__le32 length_lo;
__le32 parent_l_key;
__le32 reserved4;
};
/* Third element (16 bytes) of bind wqe */
struct rdma_sq_bind_wqe_3rd {
struct rdma_dif_params dif_params;
};
/* Structure with only the SQ WQE common
* fields. Size is of one SQ element (16B)
*/
struct rdma_sq_common_wqe {
__le32 reserved1[3];
u8 req_type;
u8 flags;
#define RDMA_SQ_COMMON_WQE_COMP_FLG_MASK 0x1
#define RDMA_SQ_COMMON_WQE_COMP_FLG_SHIFT 0
#define RDMA_SQ_COMMON_WQE_RD_FENCE_FLG_MASK 0x1
#define RDMA_SQ_COMMON_WQE_RD_FENCE_FLG_SHIFT 1
#define RDMA_SQ_COMMON_WQE_INV_FENCE_FLG_MASK 0x1
#define RDMA_SQ_COMMON_WQE_INV_FENCE_FLG_SHIFT 2
#define RDMA_SQ_COMMON_WQE_SE_FLG_MASK 0x1
#define RDMA_SQ_COMMON_WQE_SE_FLG_SHIFT 3
#define RDMA_SQ_COMMON_WQE_INLINE_FLG_MASK 0x1
#define RDMA_SQ_COMMON_WQE_INLINE_FLG_SHIFT 4
#define RDMA_SQ_COMMON_WQE_RESERVED0_MASK 0x7
#define RDMA_SQ_COMMON_WQE_RESERVED0_SHIFT 5
u8 wqe_size;
u8 prev_wqe_size;
};
struct rdma_sq_fmr_wqe {
struct regpair addr;
__le32 l_key;
u8 req_type;
u8 flags;
#define RDMA_SQ_FMR_WQE_COMP_FLG_MASK 0x1
#define RDMA_SQ_FMR_WQE_COMP_FLG_SHIFT 0
#define RDMA_SQ_FMR_WQE_RD_FENCE_FLG_MASK 0x1
#define RDMA_SQ_FMR_WQE_RD_FENCE_FLG_SHIFT 1
#define RDMA_SQ_FMR_WQE_INV_FENCE_FLG_MASK 0x1
#define RDMA_SQ_FMR_WQE_INV_FENCE_FLG_SHIFT 2
#define RDMA_SQ_FMR_WQE_SE_FLG_MASK 0x1
#define RDMA_SQ_FMR_WQE_SE_FLG_SHIFT 3
#define RDMA_SQ_FMR_WQE_INLINE_FLG_MASK 0x1
#define RDMA_SQ_FMR_WQE_INLINE_FLG_SHIFT 4
#define RDMA_SQ_FMR_WQE_DIF_ON_HOST_FLG_MASK 0x1
#define RDMA_SQ_FMR_WQE_DIF_ON_HOST_FLG_SHIFT 5
#define RDMA_SQ_FMR_WQE_RESERVED0_MASK 0x3
#define RDMA_SQ_FMR_WQE_RESERVED0_SHIFT 6
u8 wqe_size;
u8 prev_wqe_size;
u8 fmr_ctrl;
#define RDMA_SQ_FMR_WQE_PAGE_SIZE_LOG_MASK 0x1F
#define RDMA_SQ_FMR_WQE_PAGE_SIZE_LOG_SHIFT 0
#define RDMA_SQ_FMR_WQE_ZERO_BASED_MASK 0x1
#define RDMA_SQ_FMR_WQE_ZERO_BASED_SHIFT 5
#define RDMA_SQ_FMR_WQE_BIND_EN_MASK 0x1
#define RDMA_SQ_FMR_WQE_BIND_EN_SHIFT 6
#define RDMA_SQ_FMR_WQE_RESERVED1_MASK 0x1
#define RDMA_SQ_FMR_WQE_RESERVED1_SHIFT 7
u8 access_ctrl;
#define RDMA_SQ_FMR_WQE_REMOTE_READ_MASK 0x1
#define RDMA_SQ_FMR_WQE_REMOTE_READ_SHIFT 0
#define RDMA_SQ_FMR_WQE_REMOTE_WRITE_MASK 0x1
#define RDMA_SQ_FMR_WQE_REMOTE_WRITE_SHIFT 1
#define RDMA_SQ_FMR_WQE_ENABLE_ATOMIC_MASK 0x1
#define RDMA_SQ_FMR_WQE_ENABLE_ATOMIC_SHIFT 2
#define RDMA_SQ_FMR_WQE_LOCAL_READ_MASK 0x1
#define RDMA_SQ_FMR_WQE_LOCAL_READ_SHIFT 3
#define RDMA_SQ_FMR_WQE_LOCAL_WRITE_MASK 0x1
#define RDMA_SQ_FMR_WQE_LOCAL_WRITE_SHIFT 4
#define RDMA_SQ_FMR_WQE_RESERVED2_MASK 0x7
#define RDMA_SQ_FMR_WQE_RESERVED2_SHIFT 5
u8 reserved3;
u8 length_hi;
__le32 length_lo;
struct regpair pbl_addr;
};
/* First element (16 bytes) of fmr wqe */
struct rdma_sq_fmr_wqe_1st {
struct regpair addr;
__le32 l_key;
u8 req_type;
u8 flags;
#define RDMA_SQ_FMR_WQE_1ST_COMP_FLG_MASK 0x1
#define RDMA_SQ_FMR_WQE_1ST_COMP_FLG_SHIFT 0
#define RDMA_SQ_FMR_WQE_1ST_RD_FENCE_FLG_MASK 0x1
#define RDMA_SQ_FMR_WQE_1ST_RD_FENCE_FLG_SHIFT 1
#define RDMA_SQ_FMR_WQE_1ST_INV_FENCE_FLG_MASK 0x1
#define RDMA_SQ_FMR_WQE_1ST_INV_FENCE_FLG_SHIFT 2
#define RDMA_SQ_FMR_WQE_1ST_SE_FLG_MASK 0x1
#define RDMA_SQ_FMR_WQE_1ST_SE_FLG_SHIFT 3
#define RDMA_SQ_FMR_WQE_1ST_INLINE_FLG_MASK 0x1
#define RDMA_SQ_FMR_WQE_1ST_INLINE_FLG_SHIFT 4
#define RDMA_SQ_FMR_WQE_1ST_DIF_ON_HOST_FLG_MASK 0x1
#define RDMA_SQ_FMR_WQE_1ST_DIF_ON_HOST_FLG_SHIFT 5
#define RDMA_SQ_FMR_WQE_1ST_RESERVED0_MASK 0x3
#define RDMA_SQ_FMR_WQE_1ST_RESERVED0_SHIFT 6
u8 wqe_size;
u8 prev_wqe_size;
};
/* Second element (16 bytes) of fmr wqe */
struct rdma_sq_fmr_wqe_2nd {
u8 fmr_ctrl;
#define RDMA_SQ_FMR_WQE_2ND_PAGE_SIZE_LOG_MASK 0x1F
#define RDMA_SQ_FMR_WQE_2ND_PAGE_SIZE_LOG_SHIFT 0
#define RDMA_SQ_FMR_WQE_2ND_ZERO_BASED_MASK 0x1
#define RDMA_SQ_FMR_WQE_2ND_ZERO_BASED_SHIFT 5
#define RDMA_SQ_FMR_WQE_2ND_BIND_EN_MASK 0x1
#define RDMA_SQ_FMR_WQE_2ND_BIND_EN_SHIFT 6
#define RDMA_SQ_FMR_WQE_2ND_RESERVED1_MASK 0x1
#define RDMA_SQ_FMR_WQE_2ND_RESERVED1_SHIFT 7
u8 access_ctrl;
#define RDMA_SQ_FMR_WQE_2ND_REMOTE_READ_MASK 0x1
#define RDMA_SQ_FMR_WQE_2ND_REMOTE_READ_SHIFT 0
#define RDMA_SQ_FMR_WQE_2ND_REMOTE_WRITE_MASK 0x1
#define RDMA_SQ_FMR_WQE_2ND_REMOTE_WRITE_SHIFT 1
#define RDMA_SQ_FMR_WQE_2ND_ENABLE_ATOMIC_MASK 0x1
#define RDMA_SQ_FMR_WQE_2ND_ENABLE_ATOMIC_SHIFT 2
#define RDMA_SQ_FMR_WQE_2ND_LOCAL_READ_MASK 0x1
#define RDMA_SQ_FMR_WQE_2ND_LOCAL_READ_SHIFT 3
#define RDMA_SQ_FMR_WQE_2ND_LOCAL_WRITE_MASK 0x1
#define RDMA_SQ_FMR_WQE_2ND_LOCAL_WRITE_SHIFT 4
#define RDMA_SQ_FMR_WQE_2ND_RESERVED2_MASK 0x7
#define RDMA_SQ_FMR_WQE_2ND_RESERVED2_SHIFT 5
u8 reserved3;
u8 length_hi;
__le32 length_lo;
struct regpair pbl_addr;
};
struct rdma_sq_local_inv_wqe {
struct regpair reserved;
__le32 inv_l_key;
u8 req_type;
u8 flags;
#define RDMA_SQ_LOCAL_INV_WQE_COMP_FLG_MASK 0x1
#define RDMA_SQ_LOCAL_INV_WQE_COMP_FLG_SHIFT 0
#define RDMA_SQ_LOCAL_INV_WQE_RD_FENCE_FLG_MASK 0x1
#define RDMA_SQ_LOCAL_INV_WQE_RD_FENCE_FLG_SHIFT 1
#define RDMA_SQ_LOCAL_INV_WQE_INV_FENCE_FLG_MASK 0x1
#define RDMA_SQ_LOCAL_INV_WQE_INV_FENCE_FLG_SHIFT 2
#define RDMA_SQ_LOCAL_INV_WQE_SE_FLG_MASK 0x1
#define RDMA_SQ_LOCAL_INV_WQE_SE_FLG_SHIFT 3
#define RDMA_SQ_LOCAL_INV_WQE_INLINE_FLG_MASK 0x1
#define RDMA_SQ_LOCAL_INV_WQE_INLINE_FLG_SHIFT 4
#define RDMA_SQ_LOCAL_INV_WQE_DIF_ON_HOST_FLG_MASK 0x1
#define RDMA_SQ_LOCAL_INV_WQE_DIF_ON_HOST_FLG_SHIFT 5
#define RDMA_SQ_LOCAL_INV_WQE_RESERVED0_MASK 0x3
#define RDMA_SQ_LOCAL_INV_WQE_RESERVED0_SHIFT 6
u8 wqe_size;
u8 prev_wqe_size;
};
struct rdma_sq_rdma_wqe {
__le32 imm_data;
__le32 length;
__le32 xrc_srq;
u8 req_type;
u8 flags;
#define RDMA_SQ_RDMA_WQE_COMP_FLG_MASK 0x1
#define RDMA_SQ_RDMA_WQE_COMP_FLG_SHIFT 0
#define RDMA_SQ_RDMA_WQE_RD_FENCE_FLG_MASK 0x1
#define RDMA_SQ_RDMA_WQE_RD_FENCE_FLG_SHIFT 1
#define RDMA_SQ_RDMA_WQE_INV_FENCE_FLG_MASK 0x1
#define RDMA_SQ_RDMA_WQE_INV_FENCE_FLG_SHIFT 2
#define RDMA_SQ_RDMA_WQE_SE_FLG_MASK 0x1
#define RDMA_SQ_RDMA_WQE_SE_FLG_SHIFT 3
#define RDMA_SQ_RDMA_WQE_INLINE_FLG_MASK 0x1
#define RDMA_SQ_RDMA_WQE_INLINE_FLG_SHIFT 4
#define RDMA_SQ_RDMA_WQE_DIF_ON_HOST_FLG_MASK 0x1
#define RDMA_SQ_RDMA_WQE_DIF_ON_HOST_FLG_SHIFT 5
#define RDMA_SQ_RDMA_WQE_READ_INV_FLG_MASK 0x1
#define RDMA_SQ_RDMA_WQE_READ_INV_FLG_SHIFT 6
#define RDMA_SQ_RDMA_WQE_RESERVED1_MASK 0x1
#define RDMA_SQ_RDMA_WQE_RESERVED1_SHIFT 7
u8 wqe_size;
u8 prev_wqe_size;
struct regpair remote_va;
__le32 r_key;
u8 dif_flags;
#define RDMA_SQ_RDMA_WQE_DIF_BLOCK_SIZE_MASK 0x1
#define RDMA_SQ_RDMA_WQE_DIF_BLOCK_SIZE_SHIFT 0
#define RDMA_SQ_RDMA_WQE_RESERVED2_MASK 0x7F
#define RDMA_SQ_RDMA_WQE_RESERVED2_SHIFT 1
u8 reserved3[3];
};
/* First element (16 bytes) of rdma wqe */
struct rdma_sq_rdma_wqe_1st {
__le32 imm_data;
__le32 length;
__le32 xrc_srq;
u8 req_type;
u8 flags;
#define RDMA_SQ_RDMA_WQE_1ST_COMP_FLG_MASK 0x1
#define RDMA_SQ_RDMA_WQE_1ST_COMP_FLG_SHIFT 0
#define RDMA_SQ_RDMA_WQE_1ST_RD_FENCE_FLG_MASK 0x1
#define RDMA_SQ_RDMA_WQE_1ST_RD_FENCE_FLG_SHIFT 1
#define RDMA_SQ_RDMA_WQE_1ST_INV_FENCE_FLG_MASK 0x1
#define RDMA_SQ_RDMA_WQE_1ST_INV_FENCE_FLG_SHIFT 2
#define RDMA_SQ_RDMA_WQE_1ST_SE_FLG_MASK 0x1
#define RDMA_SQ_RDMA_WQE_1ST_SE_FLG_SHIFT 3
#define RDMA_SQ_RDMA_WQE_1ST_INLINE_FLG_MASK 0x1
#define RDMA_SQ_RDMA_WQE_1ST_INLINE_FLG_SHIFT 4
#define RDMA_SQ_RDMA_WQE_1ST_DIF_ON_HOST_FLG_MASK 0x1
#define RDMA_SQ_RDMA_WQE_1ST_DIF_ON_HOST_FLG_SHIFT 5
#define RDMA_SQ_RDMA_WQE_1ST_READ_INV_FLG_MASK 0x1
#define RDMA_SQ_RDMA_WQE_1ST_READ_INV_FLG_SHIFT 6
#define RDMA_SQ_RDMA_WQE_1ST_RESERVED0_MASK 0x1
#define RDMA_SQ_RDMA_WQE_1ST_RESERVED0_SHIFT 7
u8 wqe_size;
u8 prev_wqe_size;
};
/* Second element (16 bytes) of rdma wqe */
struct rdma_sq_rdma_wqe_2nd {
struct regpair remote_va;
__le32 r_key;
u8 dif_flags;
#define RDMA_SQ_RDMA_WQE_2ND_DIF_BLOCK_SIZE_MASK 0x1
#define RDMA_SQ_RDMA_WQE_2ND_DIF_BLOCK_SIZE_SHIFT 0
#define RDMA_SQ_RDMA_WQE_2ND_DIF_FIRST_SEGMENT_FLG_MASK 0x1
#define RDMA_SQ_RDMA_WQE_2ND_DIF_FIRST_SEGMENT_FLG_SHIFT 1
#define RDMA_SQ_RDMA_WQE_2ND_DIF_LAST_SEGMENT_FLG_MASK 0x1
#define RDMA_SQ_RDMA_WQE_2ND_DIF_LAST_SEGMENT_FLG_SHIFT 2
#define RDMA_SQ_RDMA_WQE_2ND_RESERVED1_MASK 0x1F
#define RDMA_SQ_RDMA_WQE_2ND_RESERVED1_SHIFT 3
u8 reserved2[3];
};
/* SQ WQE req type enumeration */
enum rdma_sq_req_type {
RDMA_SQ_REQ_TYPE_SEND,
RDMA_SQ_REQ_TYPE_SEND_WITH_IMM,
RDMA_SQ_REQ_TYPE_SEND_WITH_INVALIDATE,
RDMA_SQ_REQ_TYPE_RDMA_WR,
RDMA_SQ_REQ_TYPE_RDMA_WR_WITH_IMM,
RDMA_SQ_REQ_TYPE_RDMA_RD,
RDMA_SQ_REQ_TYPE_ATOMIC_CMP_AND_SWAP,
RDMA_SQ_REQ_TYPE_ATOMIC_ADD,
RDMA_SQ_REQ_TYPE_LOCAL_INVALIDATE,
RDMA_SQ_REQ_TYPE_FAST_MR,
RDMA_SQ_REQ_TYPE_BIND,
RDMA_SQ_REQ_TYPE_INVALID,
MAX_RDMA_SQ_REQ_TYPE
};
struct rdma_sq_send_wqe {
__le32 inv_key_or_imm_data;
__le32 length;
__le32 xrc_srq;
u8 req_type;
u8 flags;
#define RDMA_SQ_SEND_WQE_COMP_FLG_MASK 0x1
#define RDMA_SQ_SEND_WQE_COMP_FLG_SHIFT 0
#define RDMA_SQ_SEND_WQE_RD_FENCE_FLG_MASK 0x1
#define RDMA_SQ_SEND_WQE_RD_FENCE_FLG_SHIFT 1
#define RDMA_SQ_SEND_WQE_INV_FENCE_FLG_MASK 0x1
#define RDMA_SQ_SEND_WQE_INV_FENCE_FLG_SHIFT 2
#define RDMA_SQ_SEND_WQE_SE_FLG_MASK 0x1
#define RDMA_SQ_SEND_WQE_SE_FLG_SHIFT 3
#define RDMA_SQ_SEND_WQE_INLINE_FLG_MASK 0x1
#define RDMA_SQ_SEND_WQE_INLINE_FLG_SHIFT 4
#define RDMA_SQ_SEND_WQE_DIF_ON_HOST_FLG_MASK 0x1
#define RDMA_SQ_SEND_WQE_DIF_ON_HOST_FLG_SHIFT 5
#define RDMA_SQ_SEND_WQE_RESERVED0_MASK 0x3
#define RDMA_SQ_SEND_WQE_RESERVED0_SHIFT 6
u8 wqe_size;
u8 prev_wqe_size;
__le32 reserved1[4];
};
struct rdma_sq_send_wqe_1st {
__le32 inv_key_or_imm_data;
__le32 length;
__le32 xrc_srq;
u8 req_type;
u8 flags;
#define RDMA_SQ_SEND_WQE_1ST_COMP_FLG_MASK 0x1
#define RDMA_SQ_SEND_WQE_1ST_COMP_FLG_SHIFT 0
#define RDMA_SQ_SEND_WQE_1ST_RD_FENCE_FLG_MASK 0x1
#define RDMA_SQ_SEND_WQE_1ST_RD_FENCE_FLG_SHIFT 1
#define RDMA_SQ_SEND_WQE_1ST_INV_FENCE_FLG_MASK 0x1
#define RDMA_SQ_SEND_WQE_1ST_INV_FENCE_FLG_SHIFT 2
#define RDMA_SQ_SEND_WQE_1ST_SE_FLG_MASK 0x1
#define RDMA_SQ_SEND_WQE_1ST_SE_FLG_SHIFT 3
#define RDMA_SQ_SEND_WQE_1ST_INLINE_FLG_MASK 0x1
#define RDMA_SQ_SEND_WQE_1ST_INLINE_FLG_SHIFT 4
#define RDMA_SQ_SEND_WQE_1ST_RESERVED0_MASK 0x7
#define RDMA_SQ_SEND_WQE_1ST_RESERVED0_SHIFT 5
u8 wqe_size;
u8 prev_wqe_size;
};
struct rdma_sq_send_wqe_2st {
__le32 reserved1[4];
};
#endif /* __QED_HSI_RDMA__ */
@@ -0,0 +1,819 @@
/* QLogic qedr NIC Driver
* Copyright (c) 2015-2017 QLogic Corporation
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* 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 <net/ip.h>
#include <net/ipv6.h>
#include <net/udp.h>
#include <net/addrconf.h>
#include <net/route.h>
#include <net/ip6_route.h>
#include <net/flow.h>
#include "qedr.h"
#include "qedr_iw_cm.h"
static inline void
qedr_fill_sockaddr4(const struct qed_iwarp_cm_info *cm_info,
struct iw_cm_event *event)
{
struct sockaddr_in *laddr = (struct sockaddr_in *)&event->local_addr;
struct sockaddr_in *raddr = (struct sockaddr_in *)&event->remote_addr;
laddr->sin_family = AF_INET;
raddr->sin_family = AF_INET;
laddr->sin_port = htons(cm_info->local_port);
raddr->sin_port = htons(cm_info->remote_port);
laddr->sin_addr.s_addr = htonl(cm_info->local_ip[0]);
raddr->sin_addr.s_addr = htonl(cm_info->remote_ip[0]);
}
static inline void
qedr_fill_sockaddr6(const struct qed_iwarp_cm_info *cm_info,
struct iw_cm_event *event)
{
struct sockaddr_in6 *laddr6 = (struct sockaddr_in6 *)&event->local_addr;
struct sockaddr_in6 *raddr6 =
(struct sockaddr_in6 *)&event->remote_addr;
int i;
laddr6->sin6_family = AF_INET6;
raddr6->sin6_family = AF_INET6;
laddr6->sin6_port = htons(cm_info->local_port);
raddr6->sin6_port = htons(cm_info->remote_port);
for (i = 0; i < 4; i++) {
laddr6->sin6_addr.in6_u.u6_addr32[i] =
htonl(cm_info->local_ip[i]);
raddr6->sin6_addr.in6_u.u6_addr32[i] =
htonl(cm_info->remote_ip[i]);
}
}
static void qedr_iw_free_qp(struct kref *ref)
{
struct qedr_qp *qp = container_of(ref, struct qedr_qp, refcnt);
complete(&qp->qp_rel_comp);
}
static void
qedr_iw_free_ep(struct kref *ref)
{
struct qedr_iw_ep *ep = container_of(ref, struct qedr_iw_ep, refcnt);
if (ep->qp)
kref_put(&ep->qp->refcnt, qedr_iw_free_qp);
if (ep->cm_id)
ep->cm_id->rem_ref(ep->cm_id);
kfree(ep);
}
static void
qedr_iw_mpa_request(void *context, struct qed_iwarp_cm_event_params *params)
{
struct qedr_iw_listener *listener = (struct qedr_iw_listener *)context;
struct qedr_dev *dev = listener->dev;
struct iw_cm_event event;
struct qedr_iw_ep *ep;
ep = kzalloc_obj(*ep, GFP_ATOMIC);
if (!ep)
return;
ep->dev = dev;
ep->qed_context = params->ep_context;
kref_init(&ep->refcnt);
memset(&event, 0, sizeof(event));
event.event = IW_CM_EVENT_CONNECT_REQUEST;
event.status = params->status;
if (!IS_ENABLED(CONFIG_IPV6) ||
params->cm_info->ip_version == QED_TCP_IPV4)
qedr_fill_sockaddr4(params->cm_info, &event);
else
qedr_fill_sockaddr6(params->cm_info, &event);
event.provider_data = (void *)ep;
event.private_data = (void *)params->cm_info->private_data;
event.private_data_len = (u8)params->cm_info->private_data_len;
event.ord = params->cm_info->ord;
event.ird = params->cm_info->ird;
listener->cm_id->event_handler(listener->cm_id, &event);
}
static void
qedr_iw_issue_event(void *context,
struct qed_iwarp_cm_event_params *params,
enum iw_cm_event_type event_type)
{
struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;
struct iw_cm_event event;
memset(&event, 0, sizeof(event));
event.status = params->status;
event.event = event_type;
if (params->cm_info) {
event.ird = params->cm_info->ird;
event.ord = params->cm_info->ord;
/* Only connect_request and reply have valid private data
* the rest of the events this may be left overs from
* connection establishment. CONNECT_REQUEST is issued via
* qedr_iw_mpa_request
*/
if (event_type == IW_CM_EVENT_CONNECT_REPLY) {
event.private_data_len =
params->cm_info->private_data_len;
event.private_data =
(void *)params->cm_info->private_data;
}
}
if (ep->cm_id)
ep->cm_id->event_handler(ep->cm_id, &event);
}
static void
qedr_iw_close_event(void *context, struct qed_iwarp_cm_event_params *params)
{
struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;
if (ep->cm_id)
qedr_iw_issue_event(context, params, IW_CM_EVENT_CLOSE);
kref_put(&ep->refcnt, qedr_iw_free_ep);
}
static void
qedr_iw_qp_event(void *context,
struct qed_iwarp_cm_event_params *params,
enum ib_event_type ib_event, char *str)
{
struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;
struct qedr_dev *dev = ep->dev;
struct ib_qp *ibqp = &ep->qp->ibqp;
struct ib_event event;
DP_NOTICE(dev, "QP error received: %s\n", str);
if (ibqp->event_handler) {
event.event = ib_event;
event.device = ibqp->device;
event.element.qp = ibqp;
ibqp->event_handler(&event, ibqp->qp_context);
}
}
struct qedr_discon_work {
struct work_struct work;
struct qedr_iw_ep *ep;
enum qed_iwarp_event_type event;
int status;
};
static void qedr_iw_disconnect_worker(struct work_struct *work)
{
struct qedr_discon_work *dwork =
container_of(work, struct qedr_discon_work, work);
struct qed_rdma_modify_qp_in_params qp_params = { 0 };
struct qedr_iw_ep *ep = dwork->ep;
struct qedr_dev *dev = ep->dev;
struct qedr_qp *qp = ep->qp;
struct iw_cm_event event;
/* The qp won't be released until we release the ep.
* the ep's refcnt was increased before calling this
* function, therefore it is safe to access qp
*/
if (test_and_set_bit(QEDR_IWARP_CM_WAIT_FOR_DISCONNECT,
&qp->iwarp_cm_flags))
goto out;
memset(&event, 0, sizeof(event));
event.status = dwork->status;
event.event = IW_CM_EVENT_DISCONNECT;
/* Success means graceful disconnect was requested. modifying
* to SQD is translated to graceful disconnect. O/w reset is sent
*/
if (dwork->status)
qp_params.new_state = QED_ROCE_QP_STATE_ERR;
else
qp_params.new_state = QED_ROCE_QP_STATE_SQD;
if (ep->cm_id)
ep->cm_id->event_handler(ep->cm_id, &event);
SET_FIELD(qp_params.modify_flags,
QED_RDMA_MODIFY_QP_VALID_NEW_STATE, 1);
dev->ops->rdma_modify_qp(dev->rdma_ctx, qp->qed_qp, &qp_params);
complete(&ep->qp->iwarp_cm_comp);
out:
kfree(dwork);
kref_put(&ep->refcnt, qedr_iw_free_ep);
}
static void
qedr_iw_disconnect_event(void *context,
struct qed_iwarp_cm_event_params *params)
{
struct qedr_discon_work *work;
struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;
struct qedr_dev *dev = ep->dev;
work = kzalloc_obj(*work, GFP_ATOMIC);
if (!work)
return;
/* We can't get a close event before disconnect, but since
* we're scheduling a work queue we need to make sure close
* won't delete the ep, so we increase the refcnt
*/
kref_get(&ep->refcnt);
work->ep = ep;
work->event = params->event;
work->status = params->status;
INIT_WORK(&work->work, qedr_iw_disconnect_worker);
queue_work(dev->iwarp_wq, &work->work);
}
static void
qedr_iw_passive_complete(void *context,
struct qed_iwarp_cm_event_params *params)
{
struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;
struct qedr_dev *dev = ep->dev;
/* We will only reach the following state if MPA_REJECT was called on
* passive. In this case there will be no associated QP.
*/
if ((params->status == -ECONNREFUSED) && (!ep->qp)) {
DP_DEBUG(dev, QEDR_MSG_IWARP,
"PASSIVE connection refused releasing ep...\n");
kref_put(&ep->refcnt, qedr_iw_free_ep);
return;
}
complete(&ep->qp->iwarp_cm_comp);
qedr_iw_issue_event(context, params, IW_CM_EVENT_ESTABLISHED);
if (params->status < 0)
qedr_iw_close_event(context, params);
}
static void
qedr_iw_active_complete(void *context,
struct qed_iwarp_cm_event_params *params)
{
struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;
complete(&ep->qp->iwarp_cm_comp);
qedr_iw_issue_event(context, params, IW_CM_EVENT_CONNECT_REPLY);
if (params->status < 0)
kref_put(&ep->refcnt, qedr_iw_free_ep);
}
static int
qedr_iw_mpa_reply(void *context, struct qed_iwarp_cm_event_params *params)
{
struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;
struct qedr_dev *dev = ep->dev;
struct qed_iwarp_send_rtr_in rtr_in;
rtr_in.ep_context = params->ep_context;
return dev->ops->iwarp_send_rtr(dev->rdma_ctx, &rtr_in);
}
static int
qedr_iw_event_handler(void *context, struct qed_iwarp_cm_event_params *params)
{
struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context;
struct qedr_dev *dev = ep->dev;
switch (params->event) {
case QED_IWARP_EVENT_MPA_REQUEST:
qedr_iw_mpa_request(context, params);
break;
case QED_IWARP_EVENT_ACTIVE_MPA_REPLY:
qedr_iw_mpa_reply(context, params);
break;
case QED_IWARP_EVENT_PASSIVE_COMPLETE:
qedr_iw_passive_complete(context, params);
break;
case QED_IWARP_EVENT_ACTIVE_COMPLETE:
qedr_iw_active_complete(context, params);
break;
case QED_IWARP_EVENT_DISCONNECT:
qedr_iw_disconnect_event(context, params);
break;
case QED_IWARP_EVENT_CLOSE:
qedr_iw_close_event(context, params);
break;
case QED_IWARP_EVENT_RQ_EMPTY:
qedr_iw_qp_event(context, params, IB_EVENT_QP_FATAL,
"QED_IWARP_EVENT_RQ_EMPTY");
break;
case QED_IWARP_EVENT_IRQ_FULL:
qedr_iw_qp_event(context, params, IB_EVENT_QP_FATAL,
"QED_IWARP_EVENT_IRQ_FULL");
break;
case QED_IWARP_EVENT_LLP_TIMEOUT:
qedr_iw_qp_event(context, params, IB_EVENT_QP_FATAL,
"QED_IWARP_EVENT_LLP_TIMEOUT");
break;
case QED_IWARP_EVENT_REMOTE_PROTECTION_ERROR:
qedr_iw_qp_event(context, params, IB_EVENT_QP_ACCESS_ERR,
"QED_IWARP_EVENT_REMOTE_PROTECTION_ERROR");
break;
case QED_IWARP_EVENT_CQ_OVERFLOW:
qedr_iw_qp_event(context, params, IB_EVENT_QP_FATAL,
"QED_IWARP_EVENT_CQ_OVERFLOW");
break;
case QED_IWARP_EVENT_QP_CATASTROPHIC:
qedr_iw_qp_event(context, params, IB_EVENT_QP_FATAL,
"QED_IWARP_EVENT_QP_CATASTROPHIC");
break;
case QED_IWARP_EVENT_LOCAL_ACCESS_ERROR:
qedr_iw_qp_event(context, params, IB_EVENT_QP_ACCESS_ERR,
"QED_IWARP_EVENT_LOCAL_ACCESS_ERROR");
break;
case QED_IWARP_EVENT_REMOTE_OPERATION_ERROR:
qedr_iw_qp_event(context, params, IB_EVENT_QP_FATAL,
"QED_IWARP_EVENT_REMOTE_OPERATION_ERROR");
break;
case QED_IWARP_EVENT_TERMINATE_RECEIVED:
DP_NOTICE(dev, "Got terminate message\n");
break;
default:
DP_NOTICE(dev, "Unknown event received %d\n", params->event);
break;
}
return 0;
}
static u16 qedr_iw_get_vlan_ipv4(struct qedr_dev *dev, u32 *addr)
{
struct net_device *ndev;
u16 vlan_id = 0;
ndev = ip_dev_find(&init_net, htonl(addr[0]));
if (ndev) {
vlan_id = rdma_vlan_dev_vlan_id(ndev);
dev_put(ndev);
}
if (vlan_id == 0xffff)
vlan_id = 0;
return vlan_id;
}
static u16 qedr_iw_get_vlan_ipv6(u32 *addr)
{
struct net_device *ndev = NULL;
struct in6_addr laddr6;
u16 vlan_id = 0;
int i;
if (!IS_ENABLED(CONFIG_IPV6))
return vlan_id;
for (i = 0; i < 4; i++)
laddr6.in6_u.u6_addr32[i] = htonl(addr[i]);
rcu_read_lock();
for_each_netdev_rcu(&init_net, ndev) {
if (ipv6_chk_addr(&init_net, &laddr6, ndev, 1)) {
vlan_id = rdma_vlan_dev_vlan_id(ndev);
break;
}
}
rcu_read_unlock();
if (vlan_id == 0xffff)
vlan_id = 0;
return vlan_id;
}
static int
qedr_addr4_resolve(struct qedr_dev *dev,
struct sockaddr_in *src_in,
struct sockaddr_in *dst_in, u8 *dst_mac)
{
__be32 src_ip = src_in->sin_addr.s_addr;
__be32 dst_ip = dst_in->sin_addr.s_addr;
struct neighbour *neigh = NULL;
struct rtable *rt = NULL;
int rc = 0;
rt = ip_route_output(&init_net, dst_ip, src_ip, 0, 0,
RT_SCOPE_UNIVERSE);
if (IS_ERR(rt)) {
DP_ERR(dev, "ip_route_output returned error\n");
return -EINVAL;
}
neigh = dst_neigh_lookup(&rt->dst, &dst_ip);
if (neigh) {
rcu_read_lock();
if (neigh->nud_state & NUD_VALID) {
ether_addr_copy(dst_mac, neigh->ha);
DP_DEBUG(dev, QEDR_MSG_QP, "mac_addr=[%pM]\n", dst_mac);
} else {
neigh_event_send(neigh, NULL);
}
rcu_read_unlock();
neigh_release(neigh);
}
ip_rt_put(rt);
return rc;
}
static int
qedr_addr6_resolve(struct qedr_dev *dev,
struct sockaddr_in6 *src_in,
struct sockaddr_in6 *dst_in, u8 *dst_mac)
{
struct neighbour *neigh = NULL;
struct dst_entry *dst;
struct flowi6 fl6;
int rc = 0;
memset(&fl6, 0, sizeof(fl6));
fl6.daddr = dst_in->sin6_addr;
fl6.saddr = src_in->sin6_addr;
dst = ip6_route_output(&init_net, NULL, &fl6);
if ((!dst) || dst->error) {
if (dst) {
DP_ERR(dev,
"ip6_route_output returned dst->error = %d\n",
dst->error);
dst_release(dst);
}
return -EINVAL;
}
neigh = dst_neigh_lookup(dst, &fl6.daddr);
if (neigh) {
rcu_read_lock();
if (neigh->nud_state & NUD_VALID) {
ether_addr_copy(dst_mac, neigh->ha);
DP_DEBUG(dev, QEDR_MSG_QP, "mac_addr=[%pM]\n", dst_mac);
} else {
neigh_event_send(neigh, NULL);
}
rcu_read_unlock();
neigh_release(neigh);
}
dst_release(dst);
return rc;
}
static struct qedr_qp *qedr_iw_load_qp(struct qedr_dev *dev, u32 qpn)
{
struct qedr_qp *qp;
xa_lock(&dev->qps);
qp = xa_load(&dev->qps, qpn);
if (qp)
kref_get(&qp->refcnt);
xa_unlock(&dev->qps);
return qp;
}
int qedr_iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
{
struct qedr_dev *dev = get_qedr_dev(cm_id->device);
struct qed_iwarp_connect_out out_params;
struct qed_iwarp_connect_in in_params;
struct qed_iwarp_cm_info *cm_info;
struct sockaddr_in6 *laddr6;
struct sockaddr_in6 *raddr6;
struct sockaddr_in *laddr;
struct sockaddr_in *raddr;
struct qedr_iw_ep *ep;
struct qedr_qp *qp;
int rc = 0;
int i;
laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
raddr = (struct sockaddr_in *)&cm_id->m_remote_addr;
laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr;
raddr6 = (struct sockaddr_in6 *)&cm_id->m_remote_addr;
DP_DEBUG(dev, QEDR_MSG_IWARP, "MAPPED %d %d\n",
ntohs(((struct sockaddr_in *)&cm_id->remote_addr)->sin_port),
ntohs(raddr->sin_port));
DP_DEBUG(dev, QEDR_MSG_IWARP,
"Connect source address: %pISpc, remote address: %pISpc\n",
&cm_id->local_addr, &cm_id->remote_addr);
if (!laddr->sin_port || !raddr->sin_port)
return -EINVAL;
ep = kzalloc_obj(*ep);
if (!ep)
return -ENOMEM;
ep->dev = dev;
kref_init(&ep->refcnt);
qp = qedr_iw_load_qp(dev, conn_param->qpn);
if (!qp) {
rc = -EINVAL;
goto err;
}
ep->qp = qp;
cm_id->add_ref(cm_id);
ep->cm_id = cm_id;
in_params.event_cb = qedr_iw_event_handler;
in_params.cb_context = ep;
cm_info = &in_params.cm_info;
memset(cm_info->local_ip, 0, sizeof(cm_info->local_ip));
memset(cm_info->remote_ip, 0, sizeof(cm_info->remote_ip));
if (!IS_ENABLED(CONFIG_IPV6) ||
cm_id->remote_addr.ss_family == AF_INET) {
cm_info->ip_version = QED_TCP_IPV4;
cm_info->remote_ip[0] = ntohl(raddr->sin_addr.s_addr);
cm_info->local_ip[0] = ntohl(laddr->sin_addr.s_addr);
cm_info->remote_port = ntohs(raddr->sin_port);
cm_info->local_port = ntohs(laddr->sin_port);
cm_info->vlan = qedr_iw_get_vlan_ipv4(dev, cm_info->local_ip);
rc = qedr_addr4_resolve(dev, laddr, raddr,
(u8 *)in_params.remote_mac_addr);
in_params.mss = dev->iwarp_max_mtu -
(sizeof(struct iphdr) + sizeof(struct tcphdr));
} else {
in_params.cm_info.ip_version = QED_TCP_IPV6;
for (i = 0; i < 4; i++) {
cm_info->remote_ip[i] =
ntohl(raddr6->sin6_addr.in6_u.u6_addr32[i]);
cm_info->local_ip[i] =
ntohl(laddr6->sin6_addr.in6_u.u6_addr32[i]);
}
cm_info->local_port = ntohs(laddr6->sin6_port);
cm_info->remote_port = ntohs(raddr6->sin6_port);
in_params.mss = dev->iwarp_max_mtu -
(sizeof(struct ipv6hdr) + sizeof(struct tcphdr));
cm_info->vlan = qedr_iw_get_vlan_ipv6(cm_info->local_ip);
rc = qedr_addr6_resolve(dev, laddr6, raddr6,
(u8 *)in_params.remote_mac_addr);
}
if (rc)
goto err;
DP_DEBUG(dev, QEDR_MSG_IWARP,
"ord = %d ird=%d private_data=%p private_data_len=%d rq_psn=%d\n",
conn_param->ord, conn_param->ird, conn_param->private_data,
conn_param->private_data_len, qp->rq_psn);
cm_info->ord = conn_param->ord;
cm_info->ird = conn_param->ird;
cm_info->private_data = conn_param->private_data;
cm_info->private_data_len = conn_param->private_data_len;
in_params.qp = qp->qed_qp;
memcpy(in_params.local_mac_addr, dev->ndev->dev_addr, ETH_ALEN);
if (test_and_set_bit(QEDR_IWARP_CM_WAIT_FOR_CONNECT,
&qp->iwarp_cm_flags)) {
rc = -ENODEV;
goto err; /* QP already being destroyed */
}
rc = dev->ops->iwarp_connect(dev->rdma_ctx, &in_params, &out_params);
if (rc) {
complete(&qp->iwarp_cm_comp);
goto err;
}
return rc;
err:
kref_put(&ep->refcnt, qedr_iw_free_ep);
return rc;
}
int qedr_iw_create_listen(struct iw_cm_id *cm_id, int backlog)
{
struct qedr_dev *dev = get_qedr_dev(cm_id->device);
struct qedr_iw_listener *listener;
struct qed_iwarp_listen_in iparams;
struct qed_iwarp_listen_out oparams;
struct sockaddr_in *laddr;
struct sockaddr_in6 *laddr6;
int rc;
int i;
laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr;
DP_DEBUG(dev, QEDR_MSG_IWARP,
"Create Listener address: %pISpc\n", &cm_id->local_addr);
listener = kzalloc_obj(*listener);
if (!listener)
return -ENOMEM;
listener->dev = dev;
cm_id->add_ref(cm_id);
listener->cm_id = cm_id;
listener->backlog = backlog;
iparams.cb_context = listener;
iparams.event_cb = qedr_iw_event_handler;
iparams.max_backlog = backlog;
if (!IS_ENABLED(CONFIG_IPV6) ||
cm_id->local_addr.ss_family == AF_INET) {
iparams.ip_version = QED_TCP_IPV4;
memset(iparams.ip_addr, 0, sizeof(iparams.ip_addr));
iparams.ip_addr[0] = ntohl(laddr->sin_addr.s_addr);
iparams.port = ntohs(laddr->sin_port);
iparams.vlan = qedr_iw_get_vlan_ipv4(dev, iparams.ip_addr);
} else {
iparams.ip_version = QED_TCP_IPV6;
for (i = 0; i < 4; i++) {
iparams.ip_addr[i] =
ntohl(laddr6->sin6_addr.in6_u.u6_addr32[i]);
}
iparams.port = ntohs(laddr6->sin6_port);
iparams.vlan = qedr_iw_get_vlan_ipv6(iparams.ip_addr);
}
rc = dev->ops->iwarp_create_listen(dev->rdma_ctx, &iparams, &oparams);
if (rc)
goto err;
listener->qed_handle = oparams.handle;
cm_id->provider_data = listener;
return rc;
err:
cm_id->rem_ref(cm_id);
kfree(listener);
return rc;
}
int qedr_iw_destroy_listen(struct iw_cm_id *cm_id)
{
struct qedr_iw_listener *listener = cm_id->provider_data;
struct qedr_dev *dev = get_qedr_dev(cm_id->device);
int rc = 0;
if (listener->qed_handle)
rc = dev->ops->iwarp_destroy_listen(dev->rdma_ctx,
listener->qed_handle);
cm_id->rem_ref(cm_id);
kfree(listener);
return rc;
}
int qedr_iw_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
{
struct qedr_iw_ep *ep = (struct qedr_iw_ep *)cm_id->provider_data;
struct qedr_dev *dev = ep->dev;
struct qedr_qp *qp;
struct qed_iwarp_accept_in params;
int rc;
DP_DEBUG(dev, QEDR_MSG_IWARP, "Accept on qpid=%d\n", conn_param->qpn);
qp = qedr_iw_load_qp(dev, conn_param->qpn);
if (!qp) {
DP_ERR(dev, "Invalid QP number %d\n", conn_param->qpn);
return -EINVAL;
}
ep->qp = qp;
cm_id->add_ref(cm_id);
ep->cm_id = cm_id;
params.ep_context = ep->qed_context;
params.cb_context = ep;
params.qp = ep->qp->qed_qp;
params.private_data = conn_param->private_data;
params.private_data_len = conn_param->private_data_len;
params.ird = conn_param->ird;
params.ord = conn_param->ord;
if (test_and_set_bit(QEDR_IWARP_CM_WAIT_FOR_CONNECT,
&qp->iwarp_cm_flags)) {
rc = -EINVAL;
goto err; /* QP already destroyed */
}
rc = dev->ops->iwarp_accept(dev->rdma_ctx, &params);
if (rc) {
complete(&qp->iwarp_cm_comp);
goto err;
}
return rc;
err:
kref_put(&ep->refcnt, qedr_iw_free_ep);
return rc;
}
int qedr_iw_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
{
struct qedr_iw_ep *ep = (struct qedr_iw_ep *)cm_id->provider_data;
struct qedr_dev *dev = ep->dev;
struct qed_iwarp_reject_in params;
params.ep_context = ep->qed_context;
params.cb_context = ep;
params.private_data = pdata;
params.private_data_len = pdata_len;
ep->qp = NULL;
return dev->ops->iwarp_reject(dev->rdma_ctx, &params);
}
void qedr_iw_qp_add_ref(struct ib_qp *ibqp)
{
struct qedr_qp *qp = get_qedr_qp(ibqp);
kref_get(&qp->refcnt);
}
void qedr_iw_qp_rem_ref(struct ib_qp *ibqp)
{
struct qedr_qp *qp = get_qedr_qp(ibqp);
kref_put(&qp->refcnt, qedr_iw_free_qp);
}
struct ib_qp *qedr_iw_get_qp(struct ib_device *ibdev, int qpn)
{
struct qedr_dev *dev = get_qedr_dev(ibdev);
return xa_load(&dev->qps, qpn);
}
@@ -0,0 +1,49 @@
/* QLogic qed NIC Driver
* Copyright (c) 2015-2017 QLogic Corporation
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* 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/iw_cm.h>
int qedr_iw_connect(struct iw_cm_id *cm_id,
struct iw_cm_conn_param *conn_param);
int qedr_iw_create_listen(struct iw_cm_id *cm_id, int backlog);
int qedr_iw_destroy_listen(struct iw_cm_id *cm_id);
int qedr_iw_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param);
int qedr_iw_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len);
void qedr_iw_qp_add_ref(struct ib_qp *qp);
void qedr_iw_qp_rem_ref(struct ib_qp *qp);
struct ib_qp *qedr_iw_get_qp(struct ib_device *dev, int qpn);
@@ -0,0 +1,727 @@
/* QLogic qedr NIC Driver
* Copyright (c) 2015-2016 QLogic Corporation
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* 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/dma-mapping.h>
#include <linux/crc32.h>
#include <linux/iommu.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/udp.h>
#include <rdma/ib_verbs.h>
#include <rdma/ib_user_verbs.h>
#include <rdma/iw_cm.h>
#include <rdma/ib_umem.h>
#include <rdma/ib_addr.h>
#include <rdma/ib_cache.h>
#include <linux/qed/qed_if.h>
#include <linux/qed/qed_rdma_if.h>
#include "qedr.h"
#include "verbs.h"
#include <rdma/qedr-abi.h>
#include "qedr_roce_cm.h"
void qedr_inc_sw_gsi_cons(struct qedr_qp_hwq_info *info)
{
info->gsi_cons = (info->gsi_cons + 1) % info->max_wr;
}
void qedr_store_gsi_qp_cq(struct qedr_dev *dev, struct qedr_qp *qp,
struct ib_qp_init_attr *attrs)
{
dev->gsi_qp_created = 1;
dev->gsi_sqcq = get_qedr_cq(attrs->send_cq);
dev->gsi_rqcq = get_qedr_cq(attrs->recv_cq);
dev->gsi_qp = qp;
}
static void qedr_ll2_complete_tx_packet(void *cxt, u8 connection_handle,
void *cookie,
dma_addr_t first_frag_addr,
bool b_last_fragment,
bool b_last_packet)
{
struct qedr_dev *dev = (struct qedr_dev *)cxt;
struct qed_roce_ll2_packet *pkt = cookie;
struct qedr_cq *cq = dev->gsi_sqcq;
struct qedr_qp *qp = dev->gsi_qp;
unsigned long flags;
DP_DEBUG(dev, QEDR_MSG_GSI,
"LL2 TX CB: gsi_sqcq=%p, gsi_rqcq=%p, gsi_cons=%d, ibcq_comp=%s\n",
dev->gsi_sqcq, dev->gsi_rqcq, qp->sq.gsi_cons,
cq->ibcq.comp_handler ? "Yes" : "No");
dma_free_coherent(&dev->pdev->dev, pkt->header.len, pkt->header.vaddr,
pkt->header.baddr);
kfree(pkt);
spin_lock_irqsave(&qp->q_lock, flags);
qedr_inc_sw_gsi_cons(&qp->sq);
spin_unlock_irqrestore(&qp->q_lock, flags);
if (cq->ibcq.comp_handler)
(*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context);
}
static void qedr_ll2_complete_rx_packet(void *cxt,
struct qed_ll2_comp_rx_data *data)
{
struct qedr_dev *dev = (struct qedr_dev *)cxt;
struct qedr_cq *cq = dev->gsi_rqcq;
struct qedr_qp *qp = dev->gsi_qp;
unsigned long flags;
spin_lock_irqsave(&qp->q_lock, flags);
qp->rqe_wr_id[qp->rq.gsi_cons].rc = data->u.data_length_error ?
-EINVAL : 0;
qp->rqe_wr_id[qp->rq.gsi_cons].vlan = data->vlan;
/* note: length stands for data length i.e. GRH is excluded */
qp->rqe_wr_id[qp->rq.gsi_cons].sg_list[0].length =
data->length.data_length;
*((u32 *)&qp->rqe_wr_id[qp->rq.gsi_cons].smac[0]) =
ntohl(data->opaque_data_0);
*((u16 *)&qp->rqe_wr_id[qp->rq.gsi_cons].smac[4]) =
ntohs((u16)data->opaque_data_1);
qedr_inc_sw_gsi_cons(&qp->rq);
spin_unlock_irqrestore(&qp->q_lock, flags);
if (cq->ibcq.comp_handler)
(*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context);
}
static void qedr_ll2_release_rx_packet(void *cxt, u8 connection_handle,
void *cookie, dma_addr_t rx_buf_addr,
bool b_last_packet)
{
/* Do nothing... */
}
static void qedr_destroy_gsi_cq(struct qedr_dev *dev,
struct ib_qp_init_attr *attrs)
{
struct qed_rdma_destroy_cq_in_params iparams;
struct qed_rdma_destroy_cq_out_params oparams;
struct qedr_cq *cq;
cq = get_qedr_cq(attrs->send_cq);
iparams.icid = cq->icid;
dev->ops->rdma_destroy_cq(dev->rdma_ctx, &iparams, &oparams);
dev->ops->common->chain_free(dev->cdev, &cq->pbl);
cq = get_qedr_cq(attrs->recv_cq);
/* if a dedicated recv_cq was used, delete it too */
if (iparams.icid != cq->icid) {
iparams.icid = cq->icid;
dev->ops->rdma_destroy_cq(dev->rdma_ctx, &iparams, &oparams);
dev->ops->common->chain_free(dev->cdev, &cq->pbl);
}
}
static inline int qedr_check_gsi_qp_attrs(struct qedr_dev *dev,
struct ib_qp_init_attr *attrs)
{
if (attrs->cap.max_recv_sge > QEDR_GSI_MAX_RECV_SGE) {
DP_ERR(dev,
" create gsi qp: failed. max_recv_sge is larger the max %d>%d\n",
attrs->cap.max_recv_sge, QEDR_GSI_MAX_RECV_SGE);
return -EINVAL;
}
if (attrs->cap.max_recv_wr > QEDR_GSI_MAX_RECV_WR) {
DP_ERR(dev,
" create gsi qp: failed. max_recv_wr is too large %d>%d\n",
attrs->cap.max_recv_wr, QEDR_GSI_MAX_RECV_WR);
return -EINVAL;
}
if (attrs->cap.max_send_wr > QEDR_GSI_MAX_SEND_WR) {
DP_ERR(dev,
" create gsi qp: failed. max_send_wr is too large %d>%d\n",
attrs->cap.max_send_wr, QEDR_GSI_MAX_SEND_WR);
return -EINVAL;
}
return 0;
}
static int qedr_ll2_post_tx(struct qedr_dev *dev,
struct qed_roce_ll2_packet *pkt)
{
enum qed_ll2_roce_flavor_type roce_flavor;
struct qed_ll2_tx_pkt_info ll2_tx_pkt;
int rc;
int i;
memset(&ll2_tx_pkt, 0, sizeof(ll2_tx_pkt));
roce_flavor = (pkt->roce_mode == ROCE_V1) ?
QED_LL2_ROCE : QED_LL2_RROCE;
if (pkt->roce_mode == ROCE_V2_IPV4)
ll2_tx_pkt.enable_ip_cksum = 1;
ll2_tx_pkt.num_of_bds = 1 /* hdr */ + pkt->n_seg;
ll2_tx_pkt.vlan = 0;
ll2_tx_pkt.tx_dest = pkt->tx_dest;
ll2_tx_pkt.qed_roce_flavor = roce_flavor;
ll2_tx_pkt.first_frag = pkt->header.baddr;
ll2_tx_pkt.first_frag_len = pkt->header.len;
ll2_tx_pkt.cookie = pkt;
/* tx header */
rc = dev->ops->ll2_prepare_tx_packet(dev->rdma_ctx,
dev->gsi_ll2_handle,
&ll2_tx_pkt, 1);
if (rc) {
/* TX failed while posting header - release resources */
dma_free_coherent(&dev->pdev->dev, pkt->header.len,
pkt->header.vaddr, pkt->header.baddr);
kfree(pkt);
DP_ERR(dev, "roce ll2 tx: header failed (rc=%d)\n", rc);
return rc;
}
/* tx payload */
for (i = 0; i < pkt->n_seg; i++) {
rc = dev->ops->ll2_set_fragment_of_tx_packet(
dev->rdma_ctx,
dev->gsi_ll2_handle,
pkt->payload[i].baddr,
pkt->payload[i].len);
if (rc) {
/* if failed not much to do here, partial packet has
* been posted we can't free memory, will need to wait
* for completion
*/
DP_ERR(dev, "ll2 tx: payload failed (rc=%d)\n", rc);
return rc;
}
}
return 0;
}
static int qedr_ll2_stop(struct qedr_dev *dev)
{
int rc;
if (dev->gsi_ll2_handle == QED_LL2_UNUSED_HANDLE)
return 0;
/* remove LL2 MAC address filter */
rc = dev->ops->ll2_set_mac_filter(dev->cdev,
dev->gsi_ll2_mac_address, NULL);
rc = dev->ops->ll2_terminate_connection(dev->rdma_ctx,
dev->gsi_ll2_handle);
if (rc)
DP_ERR(dev, "Failed to terminate LL2 connection (rc=%d)\n", rc);
dev->ops->ll2_release_connection(dev->rdma_ctx, dev->gsi_ll2_handle);
dev->gsi_ll2_handle = QED_LL2_UNUSED_HANDLE;
return rc;
}
static int qedr_ll2_start(struct qedr_dev *dev,
struct ib_qp_init_attr *attrs, struct qedr_qp *qp)
{
struct qed_ll2_acquire_data data;
struct qed_ll2_cbs cbs;
int rc;
/* configure and start LL2 */
cbs.rx_comp_cb = qedr_ll2_complete_rx_packet;
cbs.tx_comp_cb = qedr_ll2_complete_tx_packet;
cbs.rx_release_cb = qedr_ll2_release_rx_packet;
cbs.tx_release_cb = qedr_ll2_complete_tx_packet;
cbs.cookie = dev;
memset(&data, 0, sizeof(data));
data.input.conn_type = QED_LL2_TYPE_ROCE;
data.input.mtu = dev->ndev->mtu;
data.input.rx_num_desc = attrs->cap.max_recv_wr;
data.input.rx_drop_ttl0_flg = true;
data.input.rx_vlan_removal_en = false;
data.input.tx_num_desc = attrs->cap.max_send_wr;
data.input.tx_tc = 0;
data.input.tx_dest = QED_LL2_TX_DEST_NW;
data.input.ai_err_packet_too_big = QED_LL2_DROP_PACKET;
data.input.ai_err_no_buf = QED_LL2_DROP_PACKET;
data.input.gsi_enable = 1;
data.p_connection_handle = &dev->gsi_ll2_handle;
data.cbs = &cbs;
rc = dev->ops->ll2_acquire_connection(dev->rdma_ctx, &data);
if (rc) {
DP_ERR(dev,
"ll2 start: failed to acquire LL2 connection (rc=%d)\n",
rc);
return rc;
}
rc = dev->ops->ll2_establish_connection(dev->rdma_ctx,
dev->gsi_ll2_handle);
if (rc) {
DP_ERR(dev,
"ll2 start: failed to establish LL2 connection (rc=%d)\n",
rc);
goto err1;
}
rc = dev->ops->ll2_set_mac_filter(dev->cdev, NULL, dev->ndev->dev_addr);
if (rc)
goto err2;
return 0;
err2:
dev->ops->ll2_terminate_connection(dev->rdma_ctx, dev->gsi_ll2_handle);
err1:
dev->ops->ll2_release_connection(dev->rdma_ctx, dev->gsi_ll2_handle);
return rc;
}
int qedr_create_gsi_qp(struct qedr_dev *dev, struct ib_qp_init_attr *attrs,
struct qedr_qp *qp)
{
int rc;
rc = qedr_check_gsi_qp_attrs(dev, attrs);
if (rc)
return rc;
rc = qedr_ll2_start(dev, attrs, qp);
if (rc) {
DP_ERR(dev, "create gsi qp: failed on ll2 start. rc=%d\n", rc);
return rc;
}
/* create QP */
qp->ibqp.qp_num = 1;
qp->rq.max_wr = attrs->cap.max_recv_wr;
qp->sq.max_wr = attrs->cap.max_send_wr;
qp->rqe_wr_id = kzalloc_objs(*qp->rqe_wr_id, qp->rq.max_wr);
if (!qp->rqe_wr_id)
goto err;
qp->wqe_wr_id = kzalloc_objs(*qp->wqe_wr_id, qp->sq.max_wr);
if (!qp->wqe_wr_id)
goto err;
qedr_store_gsi_qp_cq(dev, qp, attrs);
ether_addr_copy(dev->gsi_ll2_mac_address, dev->ndev->dev_addr);
/* the GSI CQ is handled by the driver so remove it from the FW */
qedr_destroy_gsi_cq(dev, attrs);
dev->gsi_rqcq->cq_type = QEDR_CQ_TYPE_GSI;
DP_DEBUG(dev, QEDR_MSG_GSI, "created GSI QP %p\n", qp);
return 0;
err:
kfree(qp->rqe_wr_id);
rc = qedr_ll2_stop(dev);
if (rc)
DP_ERR(dev, "create gsi qp: failed destroy on create\n");
return -ENOMEM;
}
int qedr_destroy_gsi_qp(struct qedr_dev *dev)
{
return qedr_ll2_stop(dev);
}
#define QEDR_MAX_UD_HEADER_SIZE (100)
#define QEDR_GSI_QPN (1)
static inline int qedr_gsi_build_header(struct qedr_dev *dev,
struct qedr_qp *qp,
const struct ib_send_wr *swr,
struct ib_ud_header *udh,
int *roce_mode)
{
bool has_vlan = false, has_grh_ipv6 = true;
struct rdma_ah_attr *ah_attr = &get_qedr_ah(ud_wr(swr)->ah)->attr;
const struct ib_global_route *grh = rdma_ah_read_grh(ah_attr);
const struct ib_gid_attr *sgid_attr = grh->sgid_attr;
int send_size = 0;
u16 vlan_id = 0;
u16 ether_type;
int rc;
int ip_ver = 0;
bool has_udp = false;
int i;
rc = rdma_read_gid_l2_fields(sgid_attr, &vlan_id, NULL);
if (rc)
return rc;
if (vlan_id < VLAN_CFI_MASK)
has_vlan = true;
send_size = 0;
for (i = 0; i < swr->num_sge; ++i)
send_size += swr->sg_list[i].length;
has_udp = (sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP);
if (!has_udp) {
/* RoCE v1 */
ether_type = ETH_P_IBOE;
*roce_mode = ROCE_V1;
} else if (ipv6_addr_v4mapped((struct in6_addr *)&sgid_attr->gid)) {
/* RoCE v2 IPv4 */
ip_ver = 4;
ether_type = ETH_P_IP;
has_grh_ipv6 = false;
*roce_mode = ROCE_V2_IPV4;
} else {
/* RoCE v2 IPv6 */
ip_ver = 6;
ether_type = ETH_P_IPV6;
*roce_mode = ROCE_V2_IPV6;
}
rc = ib_ud_header_init(send_size, false, true, has_vlan,
has_grh_ipv6, ip_ver, has_udp, 0, udh);
if (rc) {
DP_ERR(dev, "gsi post send: failed to init header\n");
return rc;
}
/* ENET + VLAN headers */
ether_addr_copy(udh->eth.dmac_h, ah_attr->roce.dmac);
ether_addr_copy(udh->eth.smac_h, dev->ndev->dev_addr);
if (has_vlan) {
udh->eth.type = htons(ETH_P_8021Q);
udh->vlan.tag = htons(vlan_id);
udh->vlan.type = htons(ether_type);
} else {
udh->eth.type = htons(ether_type);
}
/* BTH */
udh->bth.solicited_event = !!(swr->send_flags & IB_SEND_SOLICITED);
udh->bth.pkey = QEDR_ROCE_PKEY_DEFAULT;
udh->bth.destination_qpn = htonl(ud_wr(swr)->remote_qpn);
udh->bth.psn = htonl((qp->sq_psn++) & ((1 << 24) - 1));
udh->bth.opcode = IB_OPCODE_UD_SEND_ONLY;
/* DETH */
udh->deth.qkey = htonl(0x80010000);
udh->deth.source_qpn = htonl(QEDR_GSI_QPN);
if (has_grh_ipv6) {
/* GRH / IPv6 header */
udh->grh.traffic_class = grh->traffic_class;
udh->grh.flow_label = grh->flow_label;
udh->grh.hop_limit = grh->hop_limit;
udh->grh.destination_gid = grh->dgid;
memcpy(&udh->grh.source_gid.raw, sgid_attr->gid.raw,
sizeof(udh->grh.source_gid.raw));
} else {
/* IPv4 header */
u32 ipv4_addr;
udh->ip4.protocol = IPPROTO_UDP;
udh->ip4.tos = htonl(grh->flow_label);
udh->ip4.frag_off = htons(IP_DF);
udh->ip4.ttl = grh->hop_limit;
ipv4_addr = qedr_get_ipv4_from_gid(sgid_attr->gid.raw);
udh->ip4.saddr = ipv4_addr;
ipv4_addr = qedr_get_ipv4_from_gid(grh->dgid.raw);
udh->ip4.daddr = ipv4_addr;
/* note: checksum is calculated by the device */
}
/* UDP */
if (has_udp) {
udh->udp.sport = htons(QEDR_ROCE_V2_UDP_SPORT);
udh->udp.dport = htons(ROCE_V2_UDP_DPORT);
udh->udp.csum = 0;
/* UDP length is untouched hence is zero */
}
return 0;
}
static inline int qedr_gsi_build_packet(struct qedr_dev *dev,
struct qedr_qp *qp,
const struct ib_send_wr *swr,
struct qed_roce_ll2_packet **p_packet)
{
u8 ud_header_buffer[QEDR_MAX_UD_HEADER_SIZE];
struct qed_roce_ll2_packet *packet;
struct pci_dev *pdev = dev->pdev;
int roce_mode, header_size;
struct ib_ud_header udh;
int i, rc;
*p_packet = NULL;
rc = qedr_gsi_build_header(dev, qp, swr, &udh, &roce_mode);
if (rc)
return rc;
header_size = ib_ud_header_pack(&udh, &ud_header_buffer);
packet = kzalloc_obj(*packet, GFP_ATOMIC);
if (!packet)
return -ENOMEM;
packet->header.vaddr = dma_alloc_coherent(&pdev->dev, header_size,
&packet->header.baddr,
GFP_ATOMIC);
if (!packet->header.vaddr) {
kfree(packet);
return -ENOMEM;
}
if (ether_addr_equal(udh.eth.smac_h, udh.eth.dmac_h))
packet->tx_dest = QED_LL2_TX_DEST_LB;
else
packet->tx_dest = QED_LL2_TX_DEST_NW;
packet->roce_mode = roce_mode;
memcpy(packet->header.vaddr, ud_header_buffer, header_size);
packet->header.len = header_size;
packet->n_seg = swr->num_sge;
for (i = 0; i < packet->n_seg; i++) {
packet->payload[i].baddr = swr->sg_list[i].addr;
packet->payload[i].len = swr->sg_list[i].length;
}
*p_packet = packet;
return 0;
}
int qedr_gsi_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
const struct ib_send_wr **bad_wr)
{
struct qed_roce_ll2_packet *pkt = NULL;
struct qedr_qp *qp = get_qedr_qp(ibqp);
struct qedr_dev *dev = qp->dev;
unsigned long flags;
int rc;
if (qp->state != QED_ROCE_QP_STATE_RTS) {
*bad_wr = wr;
DP_ERR(dev,
"gsi post recv: failed to post rx buffer. state is %d and not QED_ROCE_QP_STATE_RTS\n",
qp->state);
return -EINVAL;
}
if (wr->num_sge > RDMA_MAX_SGE_PER_SQ_WQE) {
DP_ERR(dev, "gsi post send: num_sge is too large (%d>%d)\n",
wr->num_sge, RDMA_MAX_SGE_PER_SQ_WQE);
rc = -EINVAL;
goto err;
}
if (wr->opcode != IB_WR_SEND) {
DP_ERR(dev,
"gsi post send: failed due to unsupported opcode %d\n",
wr->opcode);
rc = -EINVAL;
goto err;
}
spin_lock_irqsave(&qp->q_lock, flags);
rc = qedr_gsi_build_packet(dev, qp, wr, &pkt);
if (rc) {
spin_unlock_irqrestore(&qp->q_lock, flags);
goto err;
}
rc = qedr_ll2_post_tx(dev, pkt);
if (!rc) {
qp->wqe_wr_id[qp->sq.prod].wr_id = wr->wr_id;
qedr_inc_sw_prod(&qp->sq);
DP_DEBUG(qp->dev, QEDR_MSG_GSI,
"gsi post send: opcode=%d, wr_id=%llx\n", wr->opcode,
wr->wr_id);
} else {
DP_ERR(dev, "gsi post send: failed to transmit (rc=%d)\n", rc);
rc = -EAGAIN;
*bad_wr = wr;
}
spin_unlock_irqrestore(&qp->q_lock, flags);
if (wr->next) {
DP_ERR(dev,
"gsi post send: failed second WR. Only one WR may be passed at a time\n");
*bad_wr = wr->next;
rc = -EINVAL;
}
return rc;
err:
*bad_wr = wr;
return rc;
}
int qedr_gsi_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
const struct ib_recv_wr **bad_wr)
{
struct qedr_dev *dev = get_qedr_dev(ibqp->device);
struct qedr_qp *qp = get_qedr_qp(ibqp);
unsigned long flags;
int rc = 0;
if ((qp->state != QED_ROCE_QP_STATE_RTR) &&
(qp->state != QED_ROCE_QP_STATE_RTS)) {
*bad_wr = wr;
DP_ERR(dev,
"gsi post recv: failed to post rx buffer. state is %d and not QED_ROCE_QP_STATE_RTR/S\n",
qp->state);
return -EINVAL;
}
spin_lock_irqsave(&qp->q_lock, flags);
while (wr) {
if (wr->num_sge > QEDR_GSI_MAX_RECV_SGE) {
DP_ERR(dev,
"gsi post recv: failed to post rx buffer. too many sges %d>%d\n",
wr->num_sge, QEDR_GSI_MAX_RECV_SGE);
goto err;
}
rc = dev->ops->ll2_post_rx_buffer(dev->rdma_ctx,
dev->gsi_ll2_handle,
wr->sg_list[0].addr,
wr->sg_list[0].length,
NULL /* cookie */,
1 /* notify_fw */);
if (rc) {
DP_ERR(dev,
"gsi post recv: failed to post rx buffer (rc=%d)\n",
rc);
goto err;
}
memset(&qp->rqe_wr_id[qp->rq.prod], 0,
sizeof(qp->rqe_wr_id[qp->rq.prod]));
qp->rqe_wr_id[qp->rq.prod].sg_list[0] = wr->sg_list[0];
qp->rqe_wr_id[qp->rq.prod].wr_id = wr->wr_id;
qedr_inc_sw_prod(&qp->rq);
wr = wr->next;
}
spin_unlock_irqrestore(&qp->q_lock, flags);
return rc;
err:
spin_unlock_irqrestore(&qp->q_lock, flags);
*bad_wr = wr;
return -ENOMEM;
}
int qedr_gsi_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)
{
struct qedr_dev *dev = get_qedr_dev(ibcq->device);
struct qedr_cq *cq = get_qedr_cq(ibcq);
struct qedr_qp *qp = dev->gsi_qp;
unsigned long flags;
u16 vlan_id;
int i = 0;
spin_lock_irqsave(&cq->cq_lock, flags);
while (i < num_entries && qp->rq.cons != qp->rq.gsi_cons) {
memset(&wc[i], 0, sizeof(*wc));
wc[i].qp = &qp->ibqp;
wc[i].wr_id = qp->rqe_wr_id[qp->rq.cons].wr_id;
wc[i].opcode = IB_WC_RECV;
wc[i].pkey_index = 0;
wc[i].status = (qp->rqe_wr_id[qp->rq.cons].rc) ?
IB_WC_GENERAL_ERR : IB_WC_SUCCESS;
/* 0 - currently only one recv sg is supported */
wc[i].byte_len = qp->rqe_wr_id[qp->rq.cons].sg_list[0].length;
wc[i].wc_flags |= IB_WC_GRH | IB_WC_IP_CSUM_OK;
ether_addr_copy(wc[i].smac, qp->rqe_wr_id[qp->rq.cons].smac);
wc[i].wc_flags |= IB_WC_WITH_SMAC;
vlan_id = qp->rqe_wr_id[qp->rq.cons].vlan &
VLAN_VID_MASK;
if (vlan_id) {
wc[i].wc_flags |= IB_WC_WITH_VLAN;
wc[i].vlan_id = vlan_id;
wc[i].sl = (qp->rqe_wr_id[qp->rq.cons].vlan &
VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
}
qedr_inc_sw_cons(&qp->rq);
i++;
}
while (i < num_entries && qp->sq.cons != qp->sq.gsi_cons) {
memset(&wc[i], 0, sizeof(*wc));
wc[i].qp = &qp->ibqp;
wc[i].wr_id = qp->wqe_wr_id[qp->sq.cons].wr_id;
wc[i].opcode = IB_WC_SEND;
wc[i].status = IB_WC_SUCCESS;
qedr_inc_sw_cons(&qp->sq);
i++;
}
spin_unlock_irqrestore(&cq->cq_lock, flags);
DP_DEBUG(dev, QEDR_MSG_GSI,
"gsi poll_cq: requested entries=%d, actual=%d, qp->rq.cons=%d, qp->rq.gsi_cons=%x, qp->sq.cons=%d, qp->sq.gsi_cons=%d, qp_num=%d\n",
num_entries, i, qp->rq.cons, qp->rq.gsi_cons, qp->sq.cons,
qp->sq.gsi_cons, qp->ibqp.qp_num);
return i;
}
@@ -0,0 +1,59 @@
/* QLogic qedr NIC Driver
* Copyright (c) 2015-2016 QLogic Corporation
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* 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 LINUX_QEDR_CM_H_
#define LINUX_QEDR_CM_H_
#define QEDR_GSI_MAX_RECV_WR (4096)
#define QEDR_GSI_MAX_SEND_WR (4096)
#define QEDR_GSI_MAX_RECV_SGE (1) /* LL2 FW limitation */
#define QEDR_ROCE_V2_UDP_SPORT (0000)
static inline u32 qedr_get_ipv4_from_gid(const u8 *gid)
{
return *(u32 *)(void *)&gid[12];
}
/* RDMA CM */
int qedr_gsi_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc);
int qedr_gsi_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
const struct ib_recv_wr **bad_wr);
int qedr_gsi_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
const struct ib_send_wr **bad_wr);
int qedr_create_gsi_qp(struct qedr_dev *dev, struct ib_qp_init_attr *attrs,
struct qedr_qp *qp);
void qedr_store_gsi_qp_cq(struct qedr_dev *dev,
struct qedr_qp *qp, struct ib_qp_init_attr *attrs);
int qedr_destroy_gsi_qp(struct qedr_dev *dev);
void qedr_inc_sw_gsi_cons(struct qedr_qp_hwq_info *info);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,103 @@
/* QLogic qedr NIC Driver
* Copyright (c) 2015-2016 QLogic Corporation
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* 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 __QEDR_VERBS_H__
#define __QEDR_VERBS_H__
int qedr_query_device(struct ib_device *ibdev,
struct ib_device_attr *attr, struct ib_udata *udata);
int qedr_query_port(struct ib_device *ibdev, u32 port,
struct ib_port_attr *props);
int qedr_iw_query_gid(struct ib_device *ibdev, u32 port,
int index, union ib_gid *gid);
int qedr_query_pkey(struct ib_device *ibdev, u32 port, u16 index, u16 *pkey);
int qedr_alloc_ucontext(struct ib_ucontext *uctx, struct ib_udata *udata);
void qedr_dealloc_ucontext(struct ib_ucontext *uctx);
int qedr_mmap(struct ib_ucontext *ucontext, struct vm_area_struct *vma);
void qedr_mmap_free(struct rdma_user_mmap_entry *rdma_entry);
int qedr_alloc_pd(struct ib_pd *pd, struct ib_udata *udata);
int qedr_dealloc_pd(struct ib_pd *pd, struct ib_udata *udata);
int qedr_alloc_xrcd(struct ib_xrcd *ibxrcd, struct ib_udata *udata);
int qedr_dealloc_xrcd(struct ib_xrcd *ibxrcd, struct ib_udata *udata);
int qedr_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
struct uverbs_attr_bundle *attrs);
int qedr_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata);
int qedr_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags);
int qedr_create_qp(struct ib_qp *qp, struct ib_qp_init_attr *attrs,
struct ib_udata *udata);
int qedr_modify_qp(struct ib_qp *, struct ib_qp_attr *attr,
int attr_mask, struct ib_udata *udata);
int qedr_query_qp(struct ib_qp *, struct ib_qp_attr *qp_attr,
int qp_attr_mask, struct ib_qp_init_attr *);
int qedr_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata);
int qedr_create_srq(struct ib_srq *ibsrq, struct ib_srq_init_attr *attr,
struct ib_udata *udata);
int qedr_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
enum ib_srq_attr_mask attr_mask, struct ib_udata *udata);
int qedr_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr);
int qedr_destroy_srq(struct ib_srq *ibsrq, struct ib_udata *udata);
int qedr_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr,
const struct ib_recv_wr **bad_recv_wr);
int qedr_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *init_attr,
struct ib_udata *udata);
int qedr_destroy_ah(struct ib_ah *ibah, u32 flags);
int qedr_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata);
struct ib_mr *qedr_get_dma_mr(struct ib_pd *, int acc);
struct ib_mr *qedr_reg_user_mr(struct ib_pd *, u64 start, u64 length,
u64 virt, int acc, struct ib_dmah *dmah,
struct ib_udata *);
int qedr_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg,
int sg_nents, unsigned int *sg_offset);
struct ib_mr *qedr_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type,
u32 max_num_sg);
int qedr_poll_cq(struct ib_cq *, int num_entries, struct ib_wc *wc);
int qedr_post_send(struct ib_qp *, const struct ib_send_wr *,
const struct ib_send_wr **bad_wr);
int qedr_post_recv(struct ib_qp *, const struct ib_recv_wr *,
const struct ib_recv_wr **bad_wr);
int qedr_process_mad(struct ib_device *ibdev, int process_mad_flags,
u32 port_num, const struct ib_wc *in_wc,
const struct ib_grh *in_grh, const struct ib_mad *in_mad,
struct ib_mad *out_mad, size_t *out_mad_size,
u16 *out_mad_pkey_index);
int qedr_port_immutable(struct ib_device *ibdev, u32 port_num,
struct ib_port_immutable *immutable);
#endif