summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/infiniband/core/ucma.c3
-rw-r--r--drivers/infiniband/core/umem_odp.c3
-rw-r--r--drivers/infiniband/core/uverbs.h1
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c158
-rw-r--r--drivers/infiniband/core/uverbs_main.c1
-rw-r--r--drivers/infiniband/hw/cxgb4/ev.c9
-rw-r--r--drivers/infiniband/hw/cxgb4/iw_cxgb4.h29
-rw-r--r--drivers/infiniband/hw/mlx4/cm.c2
-rw-r--r--drivers/infiniband/hw/mlx4/cq.c7
-rw-r--r--drivers/infiniband/hw/mlx4/main.c10
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c6
-rw-r--r--drivers/infiniband/hw/mlx5/main.c4
-rw-r--r--drivers/infiniband/hw/mlx5/mr.c1
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma.h38
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_ah.c38
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_ah.h6
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_hw.c312
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_hw.h2
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_main.c12
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_sli.h68
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_stats.c241
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_stats.h6
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_verbs.c183
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.h4
-rw-r--r--drivers/infiniband/ulp/iser/iser_initiator.c16
-rw-r--r--drivers/infiniband/ulp/iser/iser_memory.c9
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c27
27 files changed, 1005 insertions, 191 deletions
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index 56a4b7ca7ee3..45d67e9228d7 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -1124,6 +1124,9 @@ static int ucma_set_ib_path(struct ucma_context *ctx,
if (!optlen)
return -EINVAL;
+ memset(&sa_path, 0, sizeof(sa_path));
+ sa_path.vlan_id = 0xffff;
+
ib_sa_unpack_path(path_data->path_rec, &sa_path);
ret = rdma_set_ib_paths(ctx->cm_id, &sa_path, 1);
if (ret)
diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c
index 6095872549e7..8b8cc6fa0ab0 100644
--- a/drivers/infiniband/core/umem_odp.c
+++ b/drivers/infiniband/core/umem_odp.c
@@ -294,7 +294,8 @@ int ib_umem_odp_get(struct ib_ucontext *context, struct ib_umem *umem)
if (likely(ib_umem_start(umem) != ib_umem_end(umem)))
rbt_ib_umem_insert(&umem->odp_data->interval_tree,
&context->umem_tree);
- if (likely(!atomic_read(&context->notifier_count)))
+ if (likely(!atomic_read(&context->notifier_count)) ||
+ context->odp_mrs_count == 1)
umem->odp_data->mn_counters_active = true;
else
list_add(&umem->odp_data->no_private_counters,
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index 643c08a025a5..b716b0815644 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -258,5 +258,6 @@ IB_UVERBS_DECLARE_CMD(close_xrcd);
IB_UVERBS_DECLARE_EX_CMD(create_flow);
IB_UVERBS_DECLARE_EX_CMD(destroy_flow);
+IB_UVERBS_DECLARE_EX_CMD(query_device);
#endif /* UVERBS_H */
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index b7943ff16ed3..a9f048990dfc 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -400,6 +400,52 @@ err:
return ret;
}
+static void copy_query_dev_fields(struct ib_uverbs_file *file,
+ struct ib_uverbs_query_device_resp *resp,
+ struct ib_device_attr *attr)
+{
+ resp->fw_ver = attr->fw_ver;
+ resp->node_guid = file->device->ib_dev->node_guid;
+ resp->sys_image_guid = attr->sys_image_guid;
+ resp->max_mr_size = attr->max_mr_size;
+ resp->page_size_cap = attr->page_size_cap;
+ resp->vendor_id = attr->vendor_id;
+ resp->vendor_part_id = attr->vendor_part_id;
+ resp->hw_ver = attr->hw_ver;
+ resp->max_qp = attr->max_qp;
+ resp->max_qp_wr = attr->max_qp_wr;
+ resp->device_cap_flags = attr->device_cap_flags;
+ resp->max_sge = attr->max_sge;
+ resp->max_sge_rd = attr->max_sge_rd;
+ resp->max_cq = attr->max_cq;
+ resp->max_cqe = attr->max_cqe;
+ resp->max_mr = attr->max_mr;
+ resp->max_pd = attr->max_pd;
+ resp->max_qp_rd_atom = attr->max_qp_rd_atom;
+ resp->max_ee_rd_atom = attr->max_ee_rd_atom;
+ resp->max_res_rd_atom = attr->max_res_rd_atom;
+ resp->max_qp_init_rd_atom = attr->max_qp_init_rd_atom;
+ resp->max_ee_init_rd_atom = attr->max_ee_init_rd_atom;
+ resp->atomic_cap = attr->atomic_cap;
+ resp->max_ee = attr->max_ee;
+ resp->max_rdd = attr->max_rdd;
+ resp->max_mw = attr->max_mw;
+ resp->max_raw_ipv6_qp = attr->max_raw_ipv6_qp;
+ resp->max_raw_ethy_qp = attr->max_raw_ethy_qp;
+ resp->max_mcast_grp = attr->max_mcast_grp;
+ resp->max_mcast_qp_attach = attr->max_mcast_qp_attach;
+ resp->max_total_mcast_qp_attach = attr->max_total_mcast_qp_attach;
+ resp->max_ah = attr->max_ah;
+ resp->max_fmr = attr->max_fmr;
+ resp->max_map_per_fmr = attr->max_map_per_fmr;
+ resp->max_srq = attr->max_srq;
+ resp->max_srq_wr = attr->max_srq_wr;
+ resp->max_srq_sge = attr->max_srq_sge;
+ resp->max_pkeys = attr->max_pkeys;
+ resp->local_ca_ack_delay = attr->local_ca_ack_delay;
+ resp->phys_port_cnt = file->device->ib_dev->phys_port_cnt;
+}
+
ssize_t ib_uverbs_query_device(struct ib_uverbs_file *file,
const char __user *buf,
int in_len, int out_len)
@@ -420,47 +466,7 @@ ssize_t ib_uverbs_query_device(struct ib_uverbs_file *file,
return ret;
memset(&resp, 0, sizeof resp);
-
- resp.fw_ver = attr.fw_ver;
- resp.node_guid = file->device->ib_dev->node_guid;
- resp.sys_image_guid = attr.sys_image_guid;
- resp.max_mr_size = attr.max_mr_size;
- resp.page_size_cap = attr.page_size_cap;
- resp.vendor_id = attr.vendor_id;
- resp.vendor_part_id = attr.vendor_part_id;
- resp.hw_ver = attr.hw_ver;
- resp.max_qp = attr.max_qp;
- resp.max_qp_wr = attr.max_qp_wr;
- resp.device_cap_flags = attr.device_cap_flags;
- resp.max_sge = attr.max_sge;
- resp.max_sge_rd = attr.max_sge_rd;
- resp.max_cq = attr.max_cq;
- resp.max_cqe = attr.max_cqe;
- resp.max_mr = attr.max_mr;
- resp.max_pd = attr.max_pd;
- resp.max_qp_rd_atom = attr.max_qp_rd_atom;
- resp.max_ee_rd_atom = attr.max_ee_rd_atom;
- resp.max_res_rd_atom = attr.max_res_rd_atom;
- resp.max_qp_init_rd_atom = attr.max_qp_init_rd_atom;
- resp.max_ee_init_rd_atom = attr.max_ee_init_rd_atom;
- resp.atomic_cap = attr.atomic_cap;
- resp.max_ee = attr.max_ee;
- resp.max_rdd = attr.max_rdd;
- resp.max_mw = attr.max_mw;
- resp.max_raw_ipv6_qp = attr.max_raw_ipv6_qp;
- resp.max_raw_ethy_qp = attr.max_raw_ethy_qp;
- resp.max_mcast_grp = attr.max_mcast_grp;
- resp.max_mcast_qp_attach = attr.max_mcast_qp_attach;
- resp.max_total_mcast_qp_attach = attr.max_total_mcast_qp_attach;
- resp.max_ah = attr.max_ah;
- resp.max_fmr = attr.max_fmr;
- resp.max_map_per_fmr = attr.max_map_per_fmr;
- resp.max_srq = attr.max_srq;
- resp.max_srq_wr = attr.max_srq_wr;
- resp.max_srq_sge = attr.max_srq_sge;
- resp.max_pkeys = attr.max_pkeys;
- resp.local_ca_ack_delay = attr.local_ca_ack_delay;
- resp.phys_port_cnt = file->device->ib_dev->phys_port_cnt;
+ copy_query_dev_fields(file, &resp, &attr);
if (copy_to_user((void __user *) (unsigned long) cmd.response,
&resp, sizeof resp))
@@ -2091,20 +2097,21 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
if (qp->real_qp == qp) {
ret = ib_resolve_eth_l2_attrs(qp, attr, &cmd.attr_mask);
if (ret)
- goto out;
+ goto release_qp;
ret = qp->device->modify_qp(qp, attr,
modify_qp_mask(qp->qp_type, cmd.attr_mask), &udata);
} else {
ret = ib_modify_qp(qp, attr, modify_qp_mask(qp->qp_type, cmd.attr_mask));
}
- put_qp_read(qp);
-
if (ret)
- goto out;
+ goto release_qp;
ret = in_len;
+release_qp:
+ put_qp_read(qp);
+
out:
kfree(attr);
@@ -3287,3 +3294,64 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
return ret ? ret : in_len;
}
+
+int ib_uverbs_ex_query_device(struct ib_uverbs_file *file,
+ struct ib_udata *ucore,
+ struct ib_udata *uhw)
+{
+ struct ib_uverbs_ex_query_device_resp resp;
+ struct ib_uverbs_ex_query_device cmd;
+ struct ib_device_attr attr;
+ struct ib_device *device;
+ int err;
+
+ device = file->device->ib_dev;
+ if (ucore->inlen < sizeof(cmd))
+ return -EINVAL;
+
+ err = ib_copy_from_udata(&cmd, ucore, sizeof(cmd));
+ if (err)
+ return err;
+
+ if (cmd.comp_mask)
+ return -EINVAL;
+
+ if (cmd.reserved)
+ return -EINVAL;
+
+ resp.response_length = offsetof(typeof(resp), odp_caps);
+
+ if (ucore->outlen < resp.response_length)
+ return -ENOSPC;
+
+ err = device->query_device(device, &attr);
+ if (err)
+ return err;
+
+ copy_query_dev_fields(file, &resp.base, &attr);
+ resp.comp_mask = 0;
+
+ if (ucore->outlen < resp.response_length + sizeof(resp.odp_caps))
+ goto end;
+
+#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
+ resp.odp_caps.general_caps = attr.odp_caps.general_caps;
+ resp.odp_caps.per_transport_caps.rc_odp_caps =
+ attr.odp_caps.per_transport_caps.rc_odp_caps;
+ resp.odp_caps.per_transport_caps.uc_odp_caps =
+ attr.odp_caps.per_transport_caps.uc_odp_caps;
+ resp.odp_caps.per_transport_caps.ud_odp_caps =
+ attr.odp_caps.per_transport_caps.ud_odp_caps;
+ resp.odp_caps.reserved = 0;
+#else
+ memset(&resp.odp_caps, 0, sizeof(resp.odp_caps));
+#endif
+ resp.response_length += sizeof(resp.odp_caps);
+
+end:
+ err = ib_copy_to_udata(ucore, &resp, resp.response_length);
+ if (err)
+ return err;
+
+ return 0;
+}
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index 5db1a8cc388d..259dcc7779f5 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -123,6 +123,7 @@ static int (*uverbs_ex_cmd_table[])(struct ib_uverbs_file *file,
struct ib_udata *uhw) = {
[IB_USER_VERBS_EX_CMD_CREATE_FLOW] = ib_uverbs_ex_create_flow,
[IB_USER_VERBS_EX_CMD_DESTROY_FLOW] = ib_uverbs_ex_destroy_flow,
+ [IB_USER_VERBS_EX_CMD_QUERY_DEVICE] = ib_uverbs_ex_query_device,
};
static void ib_uverbs_add_one(struct ib_device *device);
diff --git a/drivers/infiniband/hw/cxgb4/ev.c b/drivers/infiniband/hw/cxgb4/ev.c
index c9df0549f51d..4498a89f4ced 100644
--- a/drivers/infiniband/hw/cxgb4/ev.c
+++ b/drivers/infiniband/hw/cxgb4/ev.c
@@ -225,13 +225,20 @@ int c4iw_ev_handler(struct c4iw_dev *dev, u32 qid)
struct c4iw_cq *chp;
unsigned long flag;
+ spin_lock_irqsave(&dev->lock, flag);
chp = get_chp(dev, qid);
if (chp) {
+ atomic_inc(&chp->refcnt);
+ spin_unlock_irqrestore(&dev->lock, flag);
t4_clear_cq_armed(&chp->cq);
spin_lock_irqsave(&chp->comp_handler_lock, flag);
(*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
spin_unlock_irqrestore(&chp->comp_handler_lock, flag);
- } else
+ if (atomic_dec_and_test(&chp->refcnt))
+ wake_up(&chp->wait);
+ } else {
PDBG("%s unknown cqid 0x%x\n", __func__, qid);
+ spin_unlock_irqrestore(&dev->lock, flag);
+ }
return 0;
}
diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
index b5678ac97393..d87e1650f643 100644
--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
@@ -196,7 +196,7 @@ static inline int c4iw_num_stags(struct c4iw_rdev *rdev)
return (int)(rdev->lldi.vr->stag.size >> 5);
}
-#define C4IW_WR_TO (30*HZ)
+#define C4IW_WR_TO (60*HZ)
struct c4iw_wr_wait {
struct completion completion;
@@ -220,22 +220,21 @@ static inline int c4iw_wait_for_reply(struct c4iw_rdev *rdev,
u32 hwtid, u32 qpid,
const char *func)
{
- unsigned to = C4IW_WR_TO;
int ret;
- do {
- ret = wait_for_completion_timeout(&wr_waitp->completion, to);
- if (!ret) {
- printk(KERN_ERR MOD "%s - Device %s not responding - "
- "tid %u qpid %u\n", func,
- pci_name(rdev->lldi.pdev), hwtid, qpid);
- if (c4iw_fatal_error(rdev)) {
- wr_waitp->ret = -EIO;
- break;
- }
- to = to << 2;
- }
- } while (!ret);
+ if (c4iw_fatal_error(rdev)) {
+ wr_waitp->ret = -EIO;
+ goto out;
+ }
+
+ ret = wait_for_completion_timeout(&wr_waitp->completion, C4IW_WR_TO);
+ if (!ret) {
+ PDBG("%s - Device %s not responding (disabling device) - tid %u qpid %u\n",
+ func, pci_name(rdev->lldi.pdev), hwtid, qpid);
+ rdev->flags |= T4_FATAL_ERROR;
+ wr_waitp->ret = -EIO;
+ }
+out:
if (wr_waitp->ret)
PDBG("%s: FW reply %d tid %u qpid %u\n",
pci_name(rdev->lldi.pdev), wr_waitp->ret, hwtid, qpid);
diff --git a/drivers/infiniband/hw/mlx4/cm.c b/drivers/infiniband/hw/mlx4/cm.c
index 56a593e0ae5d..39a488889fc7 100644
--- a/drivers/infiniband/hw/mlx4/cm.c
+++ b/drivers/infiniband/hw/mlx4/cm.c
@@ -372,7 +372,7 @@ int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave,
*slave = mlx4_ib_find_real_gid(ibdev, port, gid.global.interface_id);
if (*slave < 0) {
mlx4_ib_warn(ibdev, "failed matching slave_id by gid (0x%llx)\n",
- gid.global.interface_id);
+ be64_to_cpu(gid.global.interface_id));
return -ENOENT;
}
return 0;
diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c
index a3b70f6c4035..cb63ecd2276f 100644
--- a/drivers/infiniband/hw/mlx4/cq.c
+++ b/drivers/infiniband/hw/mlx4/cq.c
@@ -367,8 +367,7 @@ int mlx4_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
int err;
mutex_lock(&cq->resize_mutex);
-
- if (entries < 1) {
+ if (entries < 1 || entries > dev->dev->caps.max_cqes) {
err = -EINVAL;
goto out;
}
@@ -379,7 +378,7 @@ int mlx4_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
goto out;
}
- if (entries > dev->dev->caps.max_cqes) {
+ if (entries > dev->dev->caps.max_cqes + 1) {
err = -EINVAL;
goto out;
}
@@ -392,7 +391,7 @@ int mlx4_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
/* Can't be smaller than the number of outstanding CQEs */
outst_cqe = mlx4_ib_get_outstanding_cqes(cq);
if (entries < outst_cqe + 1) {
- err = 0;
+ err = -EINVAL;
goto out;
}
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index 9117b7a2d5f8..0b280b1c98df 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -1222,8 +1222,7 @@ static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
struct mlx4_ib_qp *mqp = to_mqp(ibqp);
u64 reg_id;
struct mlx4_ib_steering *ib_steering = NULL;
- enum mlx4_protocol prot = (gid->raw[1] == 0x0e) ?
- MLX4_PROT_IB_IPV4 : MLX4_PROT_IB_IPV6;
+ enum mlx4_protocol prot = MLX4_PROT_IB_IPV6;
if (mdev->dev->caps.steering_mode ==
MLX4_STEERING_MODE_DEVICE_MANAGED) {
@@ -1236,8 +1235,10 @@ static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
!!(mqp->flags &
MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK),
prot, &reg_id);
- if (err)
+ if (err) {
+ pr_err("multicast attach op failed, err %d\n", err);
goto err_malloc;
+ }
err = add_gid_entry(ibqp, gid);
if (err)
@@ -1285,8 +1286,7 @@ static int mlx4_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
struct net_device *ndev;
struct mlx4_ib_gid_entry *ge;
u64 reg_id = 0;
- enum mlx4_protocol prot = (gid->raw[1] == 0x0e) ?
- MLX4_PROT_IB_IPV4 : MLX4_PROT_IB_IPV6;
+ enum mlx4_protocol prot = MLX4_PROT_IB_IPV6;
if (mdev->dev->caps.steering_mode ==
MLX4_STEERING_MODE_DEVICE_MANAGED) {
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index cf000b7ad64f..c880329b4d64 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -1674,8 +1674,10 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
qp->mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_GSI ||
qp->mlx4_ib_qp_type == MLX4_IB_QPT_TUN_GSI) {
err = handle_eth_ud_smac_index(dev, qp, (u8 *)attr->smac, context);
- if (err)
- return -EINVAL;
+ if (err) {
+ err = -EINVAL;
+ goto out;
+ }
if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_GSI)
dev->qp1_proxy[qp->port - 1] = qp;
}
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index 03bf81211a54..cc4ac1e583b2 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -997,7 +997,7 @@ static int get_port_caps(struct mlx5_ib_dev *dev)
struct ib_device_attr *dprops = NULL;
struct ib_port_attr *pprops = NULL;
struct mlx5_general_caps *gen;
- int err = 0;
+ int err = -ENOMEM;
int port;
gen = &dev->mdev->caps.gen;
@@ -1331,6 +1331,8 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
(1ull << IB_USER_VERBS_CMD_DESTROY_SRQ) |
(1ull << IB_USER_VERBS_CMD_CREATE_XSRQ) |
(1ull << IB_USER_VERBS_CMD_OPEN_QP);
+ dev->ib_dev.uverbs_ex_cmd_mask =
+ (1ull << IB_USER_VERBS_EX_CMD_QUERY_DEVICE);
dev->ib_dev.query_device = mlx5_ib_query_device;
dev->ib_dev.query_port = mlx5_ib_query_port;
diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c
index 32a28bd50b20..cd9822eeacae 100644
--- a/drivers/infiniband/hw/mlx5/mr.c
+++ b/drivers/infiniband/hw/mlx5/mr.c
@@ -1012,6 +1012,7 @@ static struct mlx5_ib_mr *reg_create(struct ib_pd *pd, u64 virt_addr,
goto err_2;
}
mr->umem = umem;
+ mr->dev = dev;
mr->live = 1;
kvfree(in);
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma.h b/drivers/infiniband/hw/ocrdma/ocrdma.h
index b43456ae124b..c9780d919769 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma.h
@@ -40,7 +40,7 @@
#include <be_roce.h>
#include "ocrdma_sli.h"
-#define OCRDMA_ROCE_DRV_VERSION "10.2.287.0u"
+#define OCRDMA_ROCE_DRV_VERSION "10.4.205.0u"
#define OCRDMA_ROCE_DRV_DESC "Emulex OneConnect RoCE Driver"
#define OCRDMA_NODE_DESC "Emulex OneConnect RoCE HCA"
@@ -55,12 +55,19 @@
#define OCRDMA_UVERBS(CMD_NAME) (1ull << IB_USER_VERBS_CMD_##CMD_NAME)
#define convert_to_64bit(lo, hi) ((u64)hi << 32 | (u64)lo)
+#define EQ_INTR_PER_SEC_THRSH_HI 150000
+#define EQ_INTR_PER_SEC_THRSH_LOW 100000
+#define EQ_AIC_MAX_EQD 20
+#define EQ_AIC_MIN_EQD 0
+
+void ocrdma_eqd_set_task(struct work_struct *work);
struct ocrdma_dev_attr {
u8 fw_ver[32];
u32 vendor_id;
u32 device_id;
u16 max_pd;
+ u16 max_dpp_pds;
u16 max_cq;
u16 max_cqe;
u16 max_qp;
@@ -116,12 +123,19 @@ struct ocrdma_queue_info {
bool created;
};
+struct ocrdma_aic_obj { /* Adaptive interrupt coalescing (AIC) info */
+ u32 prev_eqd;
+ u64 eq_intr_cnt;
+ u64 prev_eq_intr_cnt;
+};
+
struct ocrdma_eq {
struct ocrdma_queue_info q;
u32 vector;
int cq_cnt;
struct ocrdma_dev *dev;
char irq_name[32];
+ struct ocrdma_aic_obj aic_obj;
};
struct ocrdma_mq {
@@ -171,6 +185,21 @@ struct ocrdma_stats {
struct ocrdma_dev *dev;
};
+struct ocrdma_pd_resource_mgr {
+ u32 pd_norm_start;
+ u16 pd_norm_count;
+ u16 pd_norm_thrsh;
+ u16 max_normal_pd;
+ u32 pd_dpp_start;
+ u16 pd_dpp_count;
+ u16 pd_dpp_thrsh;
+ u16 max_dpp_pd;
+ u16 dpp_page_index;
+ unsigned long *pd_norm_bitmap;
+ unsigned long *pd_dpp_bitmap;
+ bool pd_prealloc_valid;
+};
+
struct stats_mem {
struct ocrdma_mqe mqe;
void *va;
@@ -198,6 +227,7 @@ struct ocrdma_dev {
struct ocrdma_eq *eq_tbl;
int eq_cnt;
+ struct delayed_work eqd_work;
u16 base_eqid;
u16 max_eq;
@@ -255,7 +285,12 @@ struct ocrdma_dev {
struct ocrdma_stats rx_qp_err_stats;
struct ocrdma_stats tx_dbg_stats;
struct ocrdma_stats rx_dbg_stats;
+ struct ocrdma_stats driver_stats;
+ struct ocrdma_stats reset_stats;
struct dentry *dir;
+ atomic_t async_err_stats[OCRDMA_MAX_ASYNC_ERRORS];
+ atomic_t cqe_err_stats[OCRDMA_MAX_CQE_ERR];
+ struct ocrdma_pd_resource_mgr *pd_mgr;
};
struct ocrdma_cq {
@@ -335,7 +370,6 @@ struct ocrdma_srq {
struct ocrdma_qp {
struct ib_qp ibqp;
- struct ocrdma_dev *dev;
u8 __iomem *sq_db;
struct ocrdma_qp_hwq_info sq;
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_ah.c b/drivers/infiniband/hw/ocrdma/ocrdma_ah.c
index f3cc8c9e65ae..d812904f3984 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_ah.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_ah.c
@@ -29,19 +29,22 @@
#include <net/netevent.h>
#include <rdma/ib_addr.h>
+#include <rdma/ib_mad.h>
#include "ocrdma.h"
#include "ocrdma_verbs.h"
#include "ocrdma_ah.h"
#include "ocrdma_hw.h"
+#include "ocrdma_stats.h"
#define OCRDMA_VID_PCP_SHIFT 0xD
static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah,
- struct ib_ah_attr *attr, union ib_gid *sgid, int pdid)
+ struct ib_ah_attr *attr, union ib_gid *sgid,
+ int pdid, bool *isvlan)
{
int status = 0;
- u16 vlan_tag; bool vlan_enabled = false;
+ u16 vlan_tag;
struct ocrdma_eth_vlan eth;
struct ocrdma_grh grh;
int eth_sz;
@@ -59,7 +62,7 @@ static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah,
vlan_tag |= (dev->sl & 0x07) << OCRDMA_VID_PCP_SHIFT;
eth.vlan_tag = cpu_to_be16(vlan_tag);
eth_sz = sizeof(struct ocrdma_eth_vlan);
- vlan_enabled = true;
+ *isvlan = true;
} else {
eth.eth_type = cpu_to_be16(OCRDMA_ROCE_ETH_TYPE);
eth_sz = sizeof(struct ocrdma_eth_basic);
@@ -82,7 +85,7 @@ static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah,
/* Eth HDR */
memcpy(&ah->av->eth_hdr, &eth, eth_sz);
memcpy((u8 *)ah->av + eth_sz, &grh, sizeof(struct ocrdma_grh));
- if (vlan_enabled)
+ if (*isvlan)
ah->av->valid |= OCRDMA_AV_VLAN_VALID;
ah->av->valid = cpu_to_le32(ah->av->valid);
return status;
@@ -91,6 +94,7 @@ static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah,
struct ib_ah *ocrdma_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr)
{
u32 *ahid_addr;
+ bool isvlan = false;
int status;
struct ocrdma_ah *ah;
struct ocrdma_pd *pd = get_ocrdma_pd(ibpd);
@@ -127,15 +131,20 @@ struct ib_ah *ocrdma_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr)
}
}
- status = set_av_attr(dev, ah, attr, &sgid, pd->id);
+ status = set_av_attr(dev, ah, attr, &sgid, pd->id, &isvlan);
if (status)
goto av_conf_err;
/* if pd is for the user process, pass the ah_id to user space */
if ((pd->uctx) && (pd->uctx->ah_tbl.va)) {
ahid_addr = pd->uctx->ah_tbl.va + attr->dlid;
- *ahid_addr = ah->id;
+ *ahid_addr = 0;
+ *ahid_addr |= ah->id & OCRDMA_AH_ID_MASK;
+ if (isvlan)
+ *ahid_addr |= (OCRDMA_AH_VLAN_VALID_MASK <<
+ OCRDMA_AH_VLAN_VALID_SHIFT);
}
+
return &ah->ibah;
av_conf_err:
@@ -191,5 +200,20 @@ int ocrdma_process_mad(struct ib_device *ibdev,
struct ib_grh *in_grh,
struct ib_mad *in_mad, struct ib_mad *out_mad)
{
- return IB_MAD_RESULT_SUCCESS;
+ int status;
+ struct ocrdma_dev *dev;
+
+ switch (in_mad->mad_hdr.mgmt_class) {
+ case IB_MGMT_CLASS_PERF_MGMT:
+ dev = get_ocrdma_dev(ibdev);
+ if (!ocrdma_pma_counters(dev, out_mad))
+ status = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
+ else
+ status = IB_MAD_RESULT_SUCCESS;
+ break;
+ default:
+ status = IB_MAD_RESULT_SUCCESS;
+ break;
+ }
+ return status;
}
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_ah.h b/drivers/infiniband/hw/ocrdma/ocrdma_ah.h
index 8ac49e7f96d1..726a87cf22dc 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_ah.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_ah.h
@@ -28,6 +28,12 @@
#ifndef __OCRDMA_AH_H__
#define __OCRDMA_AH_H__
+enum {
+ OCRDMA_AH_ID_MASK = 0x3FF,
+ OCRDMA_AH_VLAN_VALID_MASK = 0x01,
+ OCRDMA_AH_VLAN_VALID_SHIFT = 0x1F
+};
+
struct ib_ah *ocrdma_create_ah(struct ib_pd *, struct ib_ah_attr *);
int ocrdma_destroy_ah(struct ib_ah *);
int ocrdma_query_ah(struct ib_ah *, struct ib_ah_attr *);
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
index 638bff1ffc6c..0c9e95909a64 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
@@ -734,6 +734,9 @@ static void ocrdma_dispatch_ibevent(struct ocrdma_dev *dev,
break;
}
+ if (type < OCRDMA_MAX_ASYNC_ERRORS)
+ atomic_inc(&dev->async_err_stats[type]);
+
if (qp_event) {
if (qp->ibqp.event_handler)
qp->ibqp.event_handler(&ib_evt, qp->ibqp.qp_context);
@@ -831,20 +834,20 @@ static int ocrdma_mq_cq_handler(struct ocrdma_dev *dev, u16 cq_id)
return 0;
}
-static void ocrdma_qp_buddy_cq_handler(struct ocrdma_dev *dev,
- struct ocrdma_cq *cq)
+static struct ocrdma_cq *_ocrdma_qp_buddy_cq_handler(struct ocrdma_dev *dev,
+ struct ocrdma_cq *cq, bool sq)
{
- unsigned long flags;
struct ocrdma_qp *qp;
- bool buddy_cq_found = false;
- /* Go through list of QPs in error state which are using this CQ
- * and invoke its callback handler to trigger CQE processing for
- * error/flushed CQE. It is rare to find more than few entries in
- * this list as most consumers stops after getting error CQE.
- * List is traversed only once when a matching buddy cq found for a QP.
- */
- spin_lock_irqsave(&dev->flush_q_lock, flags);
- list_for_each_entry(qp, &cq->sq_head, sq_entry) {
+ struct list_head *cur;
+ struct ocrdma_cq *bcq = NULL;
+ struct list_head *head = sq?(&cq->sq_head):(&cq->rq_head);
+
+ list_for_each(cur, head) {
+ if (sq)
+ qp = list_entry(cur, struct ocrdma_qp, sq_entry);
+ else
+ qp = list_entry(cur, struct ocrdma_qp, rq_entry);
+
if (qp->srq)
continue;
/* if wq and rq share the same cq, than comp_handler
@@ -856,19 +859,41 @@ static void ocrdma_qp_buddy_cq_handler(struct ocrdma_dev *dev,
* if completion came on rq, sq's cq is buddy cq.
*/
if (qp->sq_cq == cq)
- cq = qp->rq_cq;
+ bcq = qp->rq_cq;
else
- cq = qp->sq_cq;
- buddy_cq_found = true;
- break;
+ bcq = qp->sq_cq;
+ return bcq;
}
+ return NULL;
+}
+
+static void ocrdma_qp_buddy_cq_handler(struct ocrdma_dev *dev,
+ struct ocrdma_cq *cq)
+{
+ unsigned long flags;
+ struct ocrdma_cq *bcq = NULL;
+
+ /* Go through list of QPs in error state which are using this CQ
+ * and invoke its callback handler to trigger CQE processing for
+ * error/flushed CQE. It is rare to find more than few entries in
+ * this list as most consumers stops after getting error CQE.
+ * List is traversed only once when a matching buddy cq found for a QP.
+ */
+ spin_lock_irqsave(&dev->flush_q_lock, flags);
+ /* Check if buddy CQ is present.
+ * true - Check for SQ CQ
+ * false - Check for RQ CQ
+ */
+ bcq = _ocrdma_qp_buddy_cq_handler(dev, cq, true);
+ if (bcq == NULL)
+ bcq = _ocrdma_qp_buddy_cq_handler(dev, cq, false);
spin_unlock_irqrestore(&dev->flush_q_lock, flags);
- if (buddy_cq_found == false)
- return;
- if (cq->ibcq.comp_handler) {
- spin_lock_irqsave(&cq->comp_handler_lock, flags);
- (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context);
- spin_unlock_irqrestore(&cq->comp_handler_lock, flags);
+
+ /* if there is valid buddy cq, look for its completion handler */
+ if (bcq && bcq->ibcq.comp_handler) {
+ spin_lock_irqsave(&bcq->comp_handler_lock, flags);
+ (*bcq->ibcq.comp_handler) (&bcq->ibcq, bcq->ibcq.cq_context);
+ spin_unlock_irqrestore(&bcq->comp_handler_lock, flags);
}
}
@@ -935,6 +960,7 @@ static irqreturn_t ocrdma_irq_handler(int irq, void *handle)
} while (budget);
+ eq->aic_obj.eq_intr_cnt++;
ocrdma_ring_eq_db(dev, eq->q.id, true, true, 0);
return IRQ_HANDLED;
}
@@ -1050,6 +1076,9 @@ static void ocrdma_get_attr(struct ocrdma_dev *dev,
attr->max_pd =
(rsp->max_pd_ca_ack_delay & OCRDMA_MBX_QUERY_CFG_MAX_PD_MASK) >>
OCRDMA_MBX_QUERY_CFG_MAX_PD_SHIFT;
+ attr->max_dpp_pds =
+ (rsp->max_dpp_pds_credits & OCRDMA_MBX_QUERY_CFG_MAX_DPP_PDS_MASK) >>
+ OCRDMA_MBX_QUERY_CFG_MAX_DPP_PDS_OFFSET;
attr->max_qp =
(rsp->qp_srq_cq_ird_ord & OCRDMA_MBX_QUERY_CFG_MAX_QP_MASK) >>
OCRDMA_MBX_QUERY_CFG_MAX_QP_SHIFT;
@@ -1396,6 +1425,122 @@ int ocrdma_mbx_dealloc_pd(struct ocrdma_dev *dev, struct ocrdma_pd *pd)
return status;
}
+
+static int ocrdma_mbx_alloc_pd_range(struct ocrdma_dev *dev)
+{
+ int status = -ENOMEM;
+ size_t pd_bitmap_size;
+ struct ocrdma_alloc_pd_range *cmd;
+ struct ocrdma_alloc_pd_range_rsp *rsp;
+
+ /* Pre allocate the DPP PDs */
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_ALLOC_PD_RANGE, sizeof(*cmd));
+ if (!cmd)
+ return -ENOMEM;
+ cmd->pd_count = dev->attr.max_dpp_pds;
+ cmd->enable_dpp_rsvd |= OCRDMA_ALLOC_PD_ENABLE_DPP;
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+ rsp = (struct ocrdma_alloc_pd_range_rsp *)cmd;
+
+ if ((rsp->dpp_page_pdid & OCRDMA_ALLOC_PD_RSP_DPP) && rsp->pd_count) {
+ dev->pd_mgr->dpp_page_index = rsp->dpp_page_pdid >>
+ OCRDMA_ALLOC_PD_RSP_DPP_PAGE_SHIFT;
+ dev->pd_mgr->pd_dpp_start = rsp->dpp_page_pdid &
+ OCRDMA_ALLOC_PD_RNG_RSP_START_PDID_MASK;
+ dev->pd_mgr->max_dpp_pd = rsp->pd_count;
+ pd_bitmap_size = BITS_TO_LONGS(rsp->pd_count) * sizeof(long);
+ dev->pd_mgr->pd_dpp_bitmap = kzalloc(pd_bitmap_size,
+ GFP_KERNEL);
+ }
+ kfree(cmd);
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_ALLOC_PD_RANGE, sizeof(*cmd));
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->pd_count = dev->attr.max_pd - dev->attr.max_dpp_pds;
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+ rsp = (struct ocrdma_alloc_pd_range_rsp *)cmd;
+ if (rsp->pd_count) {
+ dev->pd_mgr->pd_norm_start = rsp->dpp_page_pdid &
+ OCRDMA_ALLOC_PD_RNG_RSP_START_PDID_MASK;
+ dev->pd_mgr->max_normal_pd = rsp->pd_count;
+ pd_bitmap_size = BITS_TO_LONGS(rsp->pd_count) * sizeof(long);
+ dev->pd_mgr->pd_norm_bitmap = kzalloc(pd_bitmap_size,
+ GFP_KERNEL);
+ }
+
+ if (dev->pd_mgr->pd_norm_bitmap || dev->pd_mgr->pd_dpp_bitmap) {
+ /* Enable PD resource manager */
+ dev->pd_mgr->pd_prealloc_valid = true;
+ } else {
+ return -ENOMEM;
+ }
+mbx_err:
+ kfree(cmd);
+ return status;
+}
+
+static void ocrdma_mbx_dealloc_pd_range(struct ocrdma_dev *dev)
+{
+ struct ocrdma_dealloc_pd_range *cmd;
+
+ /* return normal PDs to firmware */
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_DEALLOC_PD_RANGE, sizeof(*cmd));
+ if (!cmd)
+ goto mbx_err;
+
+ if (dev->pd_mgr->max_normal_pd) {
+ cmd->start_pd_id = dev->pd_mgr->pd_norm_start;
+ cmd->pd_count = dev->pd_mgr->max_normal_pd;
+ ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ }
+
+ if (dev->pd_mgr->max_dpp_pd) {
+ kfree(cmd);
+ /* return DPP PDs to firmware */
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_DEALLOC_PD_RANGE,
+ sizeof(*cmd));
+ if (!cmd)
+ goto mbx_err;
+
+ cmd->start_pd_id = dev->pd_mgr->pd_dpp_start;
+ cmd->pd_count = dev->pd_mgr->max_dpp_pd;
+ ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ }
+mbx_err:
+ kfree(cmd);
+}
+
+void ocrdma_alloc_pd_pool(struct ocrdma_dev *dev)
+{
+ int status;
+
+ dev->pd_mgr = kzalloc(sizeof(struct ocrdma_pd_resource_mgr),
+ GFP_KERNEL);
+ if (!dev->pd_mgr) {
+ pr_err("%s(%d)Memory allocation failure.\n", __func__, dev->id);
+ return;
+ }
+ status = ocrdma_mbx_alloc_pd_range(dev);
+ if (status) {
+ pr_err("%s(%d) Unable to initialize PD pool, using default.\n",
+ __func__, dev->id);
+ }
+}
+
+static void ocrdma_free_pd_pool(struct ocrdma_dev *dev)
+{
+ ocrdma_mbx_dealloc_pd_range(dev);
+ kfree(dev->pd_mgr->pd_norm_bitmap);
+ kfree(dev->pd_mgr->pd_dpp_bitmap);
+ kfree(dev->pd_mgr);
+}
+
static int ocrdma_build_q_conf(u32 *num_entries, int entry_size,
int *num_pages, int *page_size)
{
@@ -1896,8 +2041,9 @@ void ocrdma_flush_qp(struct ocrdma_qp *qp)
{
bool found;
unsigned long flags;
+ struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
- spin_lock_irqsave(&qp->dev->flush_q_lock, flags);
+ spin_lock_irqsave(&dev->flush_q_lock, flags);
found = ocrdma_is_qp_in_sq_flushlist(qp->sq_cq, qp);
if (!found)
list_add_tail(&qp->sq_entry, &qp->sq_cq->sq_head);
@@ -1906,7 +2052,7 @@ void ocrdma_flush_qp(struct ocrdma_qp *qp)
if (!found)
list_add_tail(&qp->rq_entry, &qp->rq_cq->rq_head);
}
- spin_unlock_irqrestore(&qp->dev->flush_q_lock, flags);
+ spin_unlock_irqrestore(&dev->flush_q_lock, flags);
}
static void ocrdma_init_hwq_ptr(struct ocrdma_qp *qp)
@@ -1972,7 +2118,8 @@ static int ocrdma_set_create_qp_sq_cmd(struct ocrdma_create_qp_req *cmd,
int status;
u32 len, hw_pages, hw_page_size;
dma_addr_t pa;
- struct ocrdma_dev *dev = qp->dev;
+ struct ocrdma_pd *pd = qp->pd;
+ struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device);
struct pci_dev *pdev = dev->nic_info.pdev;
u32 max_wqe_allocated;
u32 max_sges = attrs->cap.max_send_sge;
@@ -2027,7 +2174,8 @@ static int ocrdma_set_create_qp_rq_cmd(struct ocrdma_create_qp_req *cmd,
int status;
u32 len, hw_pages, hw_page_size;
dma_addr_t pa = 0;
- struct ocrdma_dev *dev = qp->dev;
+ struct ocrdma_pd *pd = qp->pd;
+ struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device);
struct pci_dev *pdev = dev->nic_info.pdev;
u32 max_rqe_allocated = attrs->cap.max_recv_wr + 1;
@@ -2086,7 +2234,8 @@ static void ocrdma_set_create_qp_dpp_cmd(struct ocrdma_create_qp_req *cmd,
static int ocrdma_set_create_qp_ird_cmd(struct ocrdma_create_qp_req *cmd,
struct ocrdma_qp *qp)
{
- struct ocrdma_dev *dev = qp->dev;
+ struct ocrdma_pd *pd = qp->pd;
+ struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device);
struct pci_dev *pdev = dev->nic_info.pdev;
dma_addr_t pa = 0;
int ird_page_size = dev->attr.ird_page_size;
@@ -2157,8 +2306,8 @@ int ocrdma_mbx_create_qp(struct ocrdma_qp *qp, struct ib_qp_init_attr *attrs,
{
int status = -ENOMEM;
u32 flags = 0;
- struct ocrdma_dev *dev = qp->dev;
struct ocrdma_pd *pd = qp->pd;
+ struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device);
struct pci_dev *pdev = dev->nic_info.pdev;
struct ocrdma_cq *cq;
struct ocrdma_create_qp_req *cmd;
@@ -2281,11 +2430,12 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
union ib_gid sgid, zgid;
u32 vlan_id;
u8 mac_addr[6];
+ struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
if ((ah_attr->ah_flags & IB_AH_GRH) == 0)
return -EINVAL;
- if (atomic_cmpxchg(&qp->dev->update_sl, 1, 0))
- ocrdma_init_service_level(qp->dev);
+ if (atomic_cmpxchg(&dev->update_sl, 1, 0))
+ ocrdma_init_service_level(dev);
cmd->params.tclass_sq_psn |=
(ah_attr->grh.traffic_class << OCRDMA_QP_PARAMS_TCLASS_SHIFT);
cmd->params.rnt_rc_sl_fl |=
@@ -2296,7 +2446,7 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
cmd->flags |= OCRDMA_QP_PARA_FLOW_LBL_VALID;
memcpy(&cmd->params.dgid[0], &ah_attr->grh.dgid.raw[0],
sizeof(cmd->params.dgid));
- status = ocrdma_query_gid(&qp->dev->ibdev, 1,
+ status = ocrdma_query_gid(&dev->ibdev, 1,
ah_attr->grh.sgid_index, &sgid);
if (status)
return status;
@@ -2307,7 +2457,9 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
qp->sgid_idx = ah_attr->grh.sgid_index;
memcpy(&cmd->params.sgid[0], &sgid.raw[0], sizeof(cmd->params.sgid));
- ocrdma_resolve_dmac(qp->dev, ah_attr, &mac_addr[0]);
+ status = ocrdma_resolve_dmac(dev, ah_attr, &mac_addr[0]);
+ if (status)
+ return status;
cmd->params.dmac_b0_to_b3 = mac_addr[0] | (mac_addr[1] << 8) |
(mac_addr[2] << 16) | (mac_addr[3] << 24);
/* convert them to LE format. */
@@ -2320,7 +2472,7 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
vlan_id << OCRDMA_QP_PARAMS_VLAN_SHIFT;
cmd->flags |= OCRDMA_QP_PARA_VLAN_EN_VALID;
cmd->params.rnt_rc_sl_fl |=
- (qp->dev->sl & 0x07) << OCRDMA_QP_PARAMS_SL_SHIFT;
+ (dev->sl & 0x07) << OCRDMA_QP_PARAMS_SL_SHIFT;
}
return 0;
}
@@ -2330,6 +2482,7 @@ static int ocrdma_set_qp_params(struct ocrdma_qp *qp,
struct ib_qp_attr *attrs, int attr_mask)
{
int status = 0;
+ struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
if (attr_mask & IB_QP_PKEY_INDEX) {
cmd->params.path_mtu_pkey_indx |= (attrs->pkey_index &
@@ -2347,12 +2500,12 @@ static int ocrdma_set_qp_params(struct ocrdma_qp *qp,
return status;
} else if (qp->qp_type == IB_QPT_GSI || qp->qp_type == IB_QPT_UD) {
/* set the default mac address for UD, GSI QPs */
- cmd->params.dmac_b0_to_b3 = qp->dev->nic_info.mac_addr[0] |
- (qp->dev->nic_info.mac_addr[1] << 8) |
- (qp->dev->nic_info.mac_addr[2] << 16) |
- (qp->dev->nic_info.mac_addr[3] << 24);
- cmd->params.vlan_dmac_b4_to_b5 = qp->dev->nic_info.mac_addr[4] |
- (qp->dev->nic_info.mac_addr[5] << 8);
+ cmd->params.dmac_b0_to_b3 = dev->nic_info.mac_addr[0] |
+ (dev->nic_info.mac_addr[1] << 8) |
+ (dev->nic_info.mac_addr[2] << 16) |
+ (dev->nic_info.mac_addr[3] << 24);
+ cmd->params.vlan_dmac_b4_to_b5 = dev->nic_info.mac_addr[4] |
+ (dev->nic_info.mac_addr[5] << 8);
}
if ((attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY) &&
attrs->en_sqd_async_notify) {
@@ -2409,7 +2562,7 @@ static int ocrdma_set_qp_params(struct ocrdma_qp *qp,
cmd->flags |= OCRDMA_QP_PARA_RQPSN_VALID;
}
if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
- if (attrs->max_rd_atomic > qp->dev->attr.max_ord_per_qp) {
+ if (attrs->max_rd_atomic > dev->attr.max_ord_per_qp) {
status = -EINVAL;
goto pmtu_err;
}
@@ -2417,7 +2570,7 @@ static int ocrdma_set_qp_params(struct ocrdma_qp *qp,
cmd->flags |= OCRDMA_QP_PARA_MAX_ORD_VALID;
}
if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
- if (attrs->max_dest_rd_atomic > qp->dev->attr.max_ird_per_qp) {
+ if (attrs->max_dest_rd_atomic > dev->attr.max_ird_per_qp) {
status = -EINVAL;
goto pmtu_err;
}
@@ -2870,6 +3023,82 @@ done:
return status;
}
+static int ocrdma_mbx_modify_eqd(struct ocrdma_dev *dev, struct ocrdma_eq *eq,
+ int num)
+{
+ int i, status = -ENOMEM;
+ struct ocrdma_modify_eqd_req *cmd;
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_MODIFY_EQ_DELAY, sizeof(*cmd));
+ if (!cmd)
+ return status;
+
+ ocrdma_init_mch(&cmd->cmd.req, OCRDMA_CMD_MODIFY_EQ_DELAY,
+ OCRDMA_SUBSYS_COMMON, sizeof(*cmd));
+
+ cmd->cmd.num_eq = num;
+ for (i = 0; i < num; i++) {
+ cmd->cmd.set_eqd[i].eq_id = eq[i].q.id;
+ cmd->cmd.set_eqd[i].phase = 0;
+ cmd->cmd.set_eqd[i].delay_multiplier =
+ (eq[i].aic_obj.prev_eqd * 65)/100;
+ }
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+mbx_err:
+ kfree(cmd);
+ return status;
+}
+
+static int ocrdma_modify_eqd(struct ocrdma_dev *dev, struct ocrdma_eq *eq,
+ int num)
+{
+ int num_eqs, i = 0;
+ if (num > 8) {
+ while (num) {
+ num_eqs = min(num, 8);
+ ocrdma_mbx_modify_eqd(dev, &eq[i], num_eqs);
+ i += num_eqs;
+ num -= num_eqs;
+ }
+ } else {
+ ocrdma_mbx_modify_eqd(dev, eq, num);
+ }
+ return 0;
+}
+
+void ocrdma_eqd_set_task(struct work_struct *work)
+{
+ struct ocrdma_dev *dev =
+ container_of(work, struct ocrdma_dev, eqd_work.work);
+ struct ocrdma_eq *eq = 0;
+ int i, num = 0, status = -EINVAL;
+ u64 eq_intr;
+
+ for (i = 0; i < dev->eq_cnt; i++) {
+ eq = &dev->eq_tbl[i];
+ if (eq->aic_obj.eq_intr_cnt > eq->aic_obj.prev_eq_intr_cnt) {
+ eq_intr = eq->aic_obj.eq_intr_cnt -
+ eq->aic_obj.prev_eq_intr_cnt;
+ if ((eq_intr > EQ_INTR_PER_SEC_THRSH_HI) &&
+ (eq->aic_obj.prev_eqd == EQ_AIC_MIN_EQD)) {
+ eq->aic_obj.prev_eqd = EQ_AIC_MAX_EQD;
+ num++;
+ } else if ((eq_intr < EQ_INTR_PER_SEC_THRSH_LOW) &&
+ (eq->aic_obj.prev_eqd == EQ_AIC_MAX_EQD)) {
+ eq->aic_obj.prev_eqd = EQ_AIC_MIN_EQD;
+ num++;
+ }
+ }
+ eq->aic_obj.prev_eq_intr_cnt = eq->aic_obj.eq_intr_cnt;
+ }
+
+ if (num)
+ status = ocrdma_modify_eqd(dev, &dev->eq_tbl[0], num);
+ schedule_delayed_work(&dev->eqd_work, msecs_to_jiffies(1000));
+}
+
int ocrdma_init_hw(struct ocrdma_dev *dev)
{
int status;
@@ -2915,6 +3144,7 @@ qpeq_err:
void ocrdma_cleanup_hw(struct ocrdma_dev *dev)
{
+ ocrdma_free_pd_pool(dev);
ocrdma_mbx_delete_ah_tbl(dev);
/* cleanup the eqs */
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.h b/drivers/infiniband/hw/ocrdma/ocrdma_hw.h
index 6eed8f191322..e905972fceb7 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.h
@@ -136,5 +136,7 @@ int ocrdma_get_irq(struct ocrdma_dev *dev, struct ocrdma_eq *eq);
int ocrdma_mbx_rdma_stats(struct ocrdma_dev *, bool reset);
char *port_speed_string(struct ocrdma_dev *dev);
void ocrdma_init_service_level(struct ocrdma_dev *);
+void ocrdma_alloc_pd_pool(struct ocrdma_dev *dev);
+void ocrdma_free_pd_range(struct ocrdma_dev *dev);
#endif /* __OCRDMA_HW_H__ */
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
index b0b2257b8e04..7a2b59aca004 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
@@ -239,7 +239,7 @@ static int ocrdma_register_device(struct ocrdma_dev *dev)
dev->ibdev.node_type = RDMA_NODE_IB_CA;
dev->ibdev.phys_port_cnt = 1;
- dev->ibdev.num_comp_vectors = 1;
+ dev->ibdev.num_comp_vectors = dev->eq_cnt;
/* mandatory verbs. */
dev->ibdev.query_device = ocrdma_query_device;
@@ -329,6 +329,8 @@ static int ocrdma_alloc_resources(struct ocrdma_dev *dev)
if (dev->stag_arr == NULL)
goto alloc_err;
+ ocrdma_alloc_pd_pool(dev);
+
spin_lock_init(&dev->av_tbl.lock);
spin_lock_init(&dev->flush_q_lock);
return 0;
@@ -491,6 +493,9 @@ static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
spin_unlock(&ocrdma_devlist_lock);
/* Init stats */
ocrdma_add_port_stats(dev);
+ /* Interrupt Moderation */
+ INIT_DELAYED_WORK(&dev->eqd_work, ocrdma_eqd_set_task);
+ schedule_delayed_work(&dev->eqd_work, msecs_to_jiffies(1000));
pr_info("%s %s: %s \"%s\" port %d\n",
dev_name(&dev->nic_info.pdev->dev), hca_name(dev),
@@ -528,11 +533,12 @@ static void ocrdma_remove(struct ocrdma_dev *dev)
/* first unregister with stack to stop all the active traffic
* of the registered clients.
*/
- ocrdma_rem_port_stats(dev);
+ cancel_delayed_work_sync(&dev->eqd_work);
ocrdma_remove_sysfiles(dev);
-
ib_unregister_device(&dev->ibdev);
+ ocrdma_rem_port_stats(dev);
+
spin_lock(&ocrdma_devlist_lock);
list_del_rcu(&dev->entry);
spin_unlock(&ocrdma_devlist_lock);
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_sli.h b/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
index 4e036480c1a8..243c87c8bd65 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
@@ -75,6 +75,8 @@ enum {
OCRDMA_CMD_DESTROY_RBQ = 26,
OCRDMA_CMD_GET_RDMA_STATS = 27,
+ OCRDMA_CMD_ALLOC_PD_RANGE = 28,
+ OCRDMA_CMD_DEALLOC_PD_RANGE = 29,
OCRDMA_CMD_MAX
};
@@ -87,6 +89,7 @@ enum {
OCRDMA_CMD_CREATE_MQ = 21,
OCRDMA_CMD_GET_CTRL_ATTRIBUTES = 32,
OCRDMA_CMD_GET_FW_VER = 35,
+ OCRDMA_CMD_MODIFY_EQ_DELAY = 41,
OCRDMA_CMD_DELETE_MQ = 53,
OCRDMA_CMD_DELETE_CQ = 54,
OCRDMA_CMD_DELETE_EQ = 55,
@@ -101,7 +104,7 @@ enum {
QTYPE_MCCQ = 3
};
-#define OCRDMA_MAX_SGID 8
+#define OCRDMA_MAX_SGID 16
#define OCRDMA_MAX_QP 2048
#define OCRDMA_MAX_CQ 2048
@@ -314,6 +317,29 @@ struct ocrdma_create_eq_rsp {
#define OCRDMA_EQ_MINOR_OTHER 0x1
+struct ocrmda_set_eqd {
+ u32 eq_id;
+ u32 phase;
+ u32 delay_multiplier;
+};
+
+struct ocrdma_modify_eqd_cmd {
+ struct ocrdma_mbx_hdr req;
+ u32 num_eq;
+ struct ocrmda_set_eqd set_eqd[8];
+} __packed;
+
+struct ocrdma_modify_eqd_req {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_modify_eqd_cmd cmd;
+};
+
+
+struct ocrdma_modify_eq_delay_rsp {
+ struct ocrdma_mbx_rsp hdr;
+ u32 rsvd0;
+} __packed;
+
enum {
OCRDMA_MCQE_STATUS_SHIFT = 0,
OCRDMA_MCQE_STATUS_MASK = 0xFFFF,
@@ -441,7 +467,9 @@ enum OCRDMA_ASYNC_EVENT_TYPE {
OCRDMA_DEVICE_FATAL_EVENT = 0x08,
OCRDMA_SRQCAT_ERROR = 0x0E,
OCRDMA_SRQ_LIMIT_EVENT = 0x0F,
- OCRDMA_QP_LAST_WQE_EVENT = 0x10
+ OCRDMA_QP_LAST_WQE_EVENT = 0x10,
+
+ OCRDMA_MAX_ASYNC_ERRORS
};
/* mailbox command request and responses */
@@ -1297,6 +1325,37 @@ struct ocrdma_dealloc_pd_rsp {
struct ocrdma_mbx_rsp rsp;
};
+struct ocrdma_alloc_pd_range {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr req;
+ u32 enable_dpp_rsvd;
+ u32 pd_count;
+};
+
+struct ocrdma_alloc_pd_range_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rsp;
+ u32 dpp_page_pdid;
+ u32 pd_count;
+};
+
+enum {
+ OCRDMA_ALLOC_PD_RNG_RSP_START_PDID_MASK = 0xFFFF,
+};
+
+struct ocrdma_dealloc_pd_range {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr req;
+ u32 start_pd_id;
+ u32 pd_count;
+};
+
+struct ocrdma_dealloc_pd_range_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr req;
+ u32 rsvd;
+};
+
enum {
OCRDMA_ADDR_CHECK_ENABLE = 1,
OCRDMA_ADDR_CHECK_DISABLE = 0
@@ -1597,7 +1656,9 @@ enum OCRDMA_CQE_STATUS {
OCRDMA_CQE_INV_EEC_STATE_ERR,
OCRDMA_CQE_FATAL_ERR,
OCRDMA_CQE_RESP_TIMEOUT_ERR,
- OCRDMA_CQE_GENERAL_ERR
+ OCRDMA_CQE_GENERAL_ERR,
+
+ OCRDMA_MAX_CQE_ERR
};
enum {
@@ -1673,6 +1734,7 @@ enum {
OCRDMA_FLAG_FENCE_R = 0x8,
OCRDMA_FLAG_SOLICIT = 0x10,
OCRDMA_FLAG_IMM = 0x20,
+ OCRDMA_FLAG_AH_VLAN_PR = 0x40,
/* Stag flags */
OCRDMA_LKEY_FLAG_LOCAL_WR = 0x1,
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_stats.c b/drivers/infiniband/hw/ocrdma/ocrdma_stats.c
index 41a9aec9998d..48d7ef51aa0c 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_stats.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_stats.c
@@ -26,6 +26,7 @@
*******************************************************************/
#include <rdma/ib_addr.h>
+#include <rdma/ib_pma.h>
#include "ocrdma_stats.h"
static struct dentry *ocrdma_dbgfs_dir;
@@ -249,6 +250,27 @@ static char *ocrdma_rx_stats(struct ocrdma_dev *dev)
return stats;
}
+static u64 ocrdma_sysfs_rcv_pkts(struct ocrdma_dev *dev)
+{
+ struct ocrdma_rdma_stats_resp *rdma_stats =
+ (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
+ struct ocrdma_rx_stats *rx_stats = &rdma_stats->rx_stats;
+
+ return convert_to_64bit(rx_stats->roce_frames_lo,
+ rx_stats->roce_frames_hi) + (u64)rx_stats->roce_frame_icrc_drops
+ + (u64)rx_stats->roce_frame_payload_len_drops;
+}
+
+static u64 ocrdma_sysfs_rcv_data(struct ocrdma_dev *dev)
+{
+ struct ocrdma_rdma_stats_resp *rdma_stats =
+ (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
+ struct ocrdma_rx_stats *rx_stats = &rdma_stats->rx_stats;
+
+ return (convert_to_64bit(rx_stats->roce_frame_bytes_lo,
+ rx_stats->roce_frame_bytes_hi))/4;
+}
+
static char *ocrdma_tx_stats(struct ocrdma_dev *dev)
{
char *stats = dev->stats_mem.debugfs_mem, *pcur;
@@ -292,6 +314,37 @@ static char *ocrdma_tx_stats(struct ocrdma_dev *dev)
return stats;
}
+static u64 ocrdma_sysfs_xmit_pkts(struct ocrdma_dev *dev)
+{
+ struct ocrdma_rdma_stats_resp *rdma_stats =
+ (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
+ struct ocrdma_tx_stats *tx_stats = &rdma_stats->tx_stats;
+
+ return (convert_to_64bit(tx_stats->send_pkts_lo,
+ tx_stats->send_pkts_hi) +
+ convert_to_64bit(tx_stats->write_pkts_lo, tx_stats->write_pkts_hi) +
+ convert_to_64bit(tx_stats->read_pkts_lo, tx_stats->read_pkts_hi) +
+ convert_to_64bit(tx_stats->read_rsp_pkts_lo,
+ tx_stats->read_rsp_pkts_hi) +
+ convert_to_64bit(tx_stats->ack_pkts_lo, tx_stats->ack_pkts_hi));
+}
+
+static u64 ocrdma_sysfs_xmit_data(struct ocrdma_dev *dev)
+{
+ struct ocrdma_rdma_stats_resp *rdma_stats =
+ (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
+ struct ocrdma_tx_stats *tx_stats = &rdma_stats->tx_stats;
+
+ return (convert_to_64bit(tx_stats->send_bytes_lo,
+ tx_stats->send_bytes_hi) +
+ convert_to_64bit(tx_stats->write_bytes_lo,
+ tx_stats->write_bytes_hi) +
+ convert_to_64bit(tx_stats->read_req_bytes_lo,
+ tx_stats->read_req_bytes_hi) +
+ convert_to_64bit(tx_stats->read_rsp_bytes_lo,
+ tx_stats->read_rsp_bytes_hi))/4;
+}
+
static char *ocrdma_wqe_stats(struct ocrdma_dev *dev)
{
char *stats = dev->stats_mem.debugfs_mem, *pcur;
@@ -432,10 +485,118 @@ static char *ocrdma_rx_dbg_stats(struct ocrdma_dev *dev)
return dev->stats_mem.debugfs_mem;
}
+static char *ocrdma_driver_dbg_stats(struct ocrdma_dev *dev)
+{
+ char *stats = dev->stats_mem.debugfs_mem, *pcur;
+
+
+ memset(stats, 0, (OCRDMA_MAX_DBGFS_MEM));
+
+ pcur = stats;
+ pcur += ocrdma_add_stat(stats, pcur, "async_cq_err",
+ (u64)(dev->async_err_stats
+ [OCRDMA_CQ_ERROR].counter));
+ pcur += ocrdma_add_stat(stats, pcur, "async_cq_overrun_err",
+ (u64)dev->async_err_stats
+ [OCRDMA_CQ_OVERRUN_ERROR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "async_cq_qpcat_err",
+ (u64)dev->async_err_stats
+ [OCRDMA_CQ_QPCAT_ERROR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "async_qp_access_err",
+ (u64)dev->async_err_stats
+ [OCRDMA_QP_ACCESS_ERROR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "async_qp_commm_est_evt",
+ (u64)dev->async_err_stats
+ [OCRDMA_QP_COMM_EST_EVENT].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "async_sq_drained_evt",
+ (u64)dev->async_err_stats
+ [OCRDMA_SQ_DRAINED_EVENT].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "async_dev_fatal_evt",
+ (u64)dev->async_err_stats
+ [OCRDMA_DEVICE_FATAL_EVENT].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "async_srqcat_err",
+ (u64)dev->async_err_stats
+ [OCRDMA_SRQCAT_ERROR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "async_srq_limit_evt",
+ (u64)dev->async_err_stats
+ [OCRDMA_SRQ_LIMIT_EVENT].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "async_qp_last_wqe_evt",
+ (u64)dev->async_err_stats
+ [OCRDMA_QP_LAST_WQE_EVENT].counter);
+
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_loc_len_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_LOC_LEN_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_loc_qp_op_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_LOC_QP_OP_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_loc_eec_op_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_LOC_EEC_OP_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_loc_prot_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_LOC_PROT_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_wr_flush_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_WR_FLUSH_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_mw_bind_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_MW_BIND_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_bad_resp_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_BAD_RESP_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_loc_access_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_LOC_ACCESS_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_rem_inv_req_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_REM_INV_REQ_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_rem_access_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_REM_ACCESS_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_rem_op_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_REM_OP_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_retry_exc_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_RETRY_EXC_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_rnr_retry_exc_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_RNR_RETRY_EXC_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_loc_rdd_viol_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_LOC_RDD_VIOL_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_rem_inv_rd_req_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_REM_INV_RD_REQ_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_rem_abort_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_REM_ABORT_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_inv_eecn_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_INV_EECN_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_inv_eec_state_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_INV_EEC_STATE_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_fatal_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_FATAL_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_resp_timeout_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_RESP_TIMEOUT_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_general_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_GENERAL_ERR].counter);
+ return stats;
+}
+
static void ocrdma_update_stats(struct ocrdma_dev *dev)
{
ulong now = jiffies, secs;
int status = 0;
+ struct ocrdma_rdma_stats_resp *rdma_stats =
+ (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
+ struct ocrdma_rsrc_stats *rsrc_stats = &rdma_stats->act_rsrc_stats;
secs = jiffies_to_msecs(now - dev->last_stats_time) / 1000U;
if (secs) {
@@ -444,10 +605,74 @@ static void ocrdma_update_stats(struct ocrdma_dev *dev)
if (status)
pr_err("%s: stats mbox failed with status = %d\n",
__func__, status);
+ /* Update PD counters from PD resource manager */
+ if (dev->pd_mgr->pd_prealloc_valid) {
+ rsrc_stats->dpp_pds = dev->pd_mgr->pd_dpp_count;
+ rsrc_stats->non_dpp_pds = dev->pd_mgr->pd_norm_count;
+ /* Threshold stata*/
+ rsrc_stats = &rdma_stats->th_rsrc_stats;
+ rsrc_stats->dpp_pds = dev->pd_mgr->pd_dpp_thrsh;
+ rsrc_stats->non_dpp_pds = dev->pd_mgr->pd_norm_thrsh;
+ }
dev->last_stats_time = jiffies;
}
}
+static ssize_t ocrdma_dbgfs_ops_write(struct file *filp,
+ const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ char tmp_str[32];
+ long reset;
+ int status = 0;
+ struct ocrdma_stats *pstats = filp->private_data;
+ struct ocrdma_dev *dev = pstats->dev;
+
+ if (count > 32)
+ goto err;
+
+ if (copy_from_user(tmp_str, buffer, count))
+ goto err;
+
+ tmp_str[count-1] = '\0';
+ if (kstrtol(tmp_str, 10, &reset))
+ goto err;
+
+ switch (pstats->type) {
+ case OCRDMA_RESET_STATS:
+ if (reset) {
+ status = ocrdma_mbx_rdma_stats(dev, true);
+ if (status) {
+ pr_err("Failed to reset stats = %d", status);
+ goto err;
+ }
+ }
+ break;
+ default:
+ goto err;
+ }
+
+ return count;
+err:
+ return -EFAULT;
+}
+
+int ocrdma_pma_counters(struct ocrdma_dev *dev,
+ struct ib_mad *out_mad)
+{
+ struct ib_pma_portcounters *pma_cnt;
+
+ memset(out_mad->data, 0, sizeof out_mad->data);
+ pma_cnt = (void *)(out_mad->data + 40);
+ ocrdma_update_stats(dev);
+
+ pma_cnt->port_xmit_data = cpu_to_be32(ocrdma_sysfs_xmit_data(dev));
+ pma_cnt->port_rcv_data = cpu_to_be32(ocrdma_sysfs_rcv_data(dev));
+ pma_cnt->port_xmit_packets = cpu_to_be32(ocrdma_sysfs_xmit_pkts(dev));
+ pma_cnt->port_rcv_packets = cpu_to_be32(ocrdma_sysfs_rcv_pkts(dev));
+ return 0;
+}
+
static ssize_t ocrdma_dbgfs_ops_read(struct file *filp, char __user *buffer,
size_t usr_buf_len, loff_t *ppos)
{
@@ -492,6 +717,9 @@ static ssize_t ocrdma_dbgfs_ops_read(struct file *filp, char __user *buffer,
case OCRDMA_RX_DBG_STATS:
data = ocrdma_rx_dbg_stats(dev);
break;
+ case OCRDMA_DRV_STATS:
+ data = ocrdma_driver_dbg_stats(dev);
+ break;
default:
status = -EFAULT;
@@ -514,6 +742,7 @@ static const struct file_operations ocrdma_dbg_ops = {
.owner = THIS_MODULE,
.open = simple_open,
.read = ocrdma_dbgfs_ops_read,
+ .write = ocrdma_dbgfs_ops_write,
};
void ocrdma_add_port_stats(struct ocrdma_dev *dev)
@@ -582,6 +811,18 @@ void ocrdma_add_port_stats(struct ocrdma_dev *dev)
&dev->rx_dbg_stats, &ocrdma_dbg_ops))
goto err;
+ dev->driver_stats.type = OCRDMA_DRV_STATS;
+ dev->driver_stats.dev = dev;
+ if (!debugfs_create_file("driver_dbg_stats", S_IRUSR, dev->dir,
+ &dev->driver_stats, &ocrdma_dbg_ops))
+ goto err;
+
+ dev->reset_stats.type = OCRDMA_RESET_STATS;
+ dev->reset_stats.dev = dev;
+ if (!debugfs_create_file("reset_stats", S_IRUSR, dev->dir,
+ &dev->reset_stats, &ocrdma_dbg_ops))
+ goto err;
+
/* Now create dma_mem for stats mbx command */
if (!ocrdma_alloc_stats_mem(dev))
goto err;
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_stats.h b/drivers/infiniband/hw/ocrdma/ocrdma_stats.h
index 5f5e20c46d7c..091edd68a8a3 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_stats.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_stats.h
@@ -43,12 +43,16 @@ enum OCRDMA_STATS_TYPE {
OCRDMA_RXQP_ERRSTATS,
OCRDMA_TXQP_ERRSTATS,
OCRDMA_TX_DBG_STATS,
- OCRDMA_RX_DBG_STATS
+ OCRDMA_RX_DBG_STATS,
+ OCRDMA_DRV_STATS,
+ OCRDMA_RESET_STATS
};
void ocrdma_rem_debugfs(void);
void ocrdma_init_debugfs(void);
void ocrdma_rem_port_stats(struct ocrdma_dev *dev);
void ocrdma_add_port_stats(struct ocrdma_dev *dev);
+int ocrdma_pma_counters(struct ocrdma_dev *dev,
+ struct ib_mad *out_mad);
#endif /* __OCRDMA_STATS_H__ */
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
index fb8d8c4dfbb9..877175563634 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
@@ -53,7 +53,7 @@ int ocrdma_query_gid(struct ib_device *ibdev, u8 port,
dev = get_ocrdma_dev(ibdev);
memset(sgid, 0, sizeof(*sgid));
- if (index > OCRDMA_MAX_SGID)
+ if (index >= OCRDMA_MAX_SGID)
return -EINVAL;
memcpy(sgid, &dev->sgid_tbl[index], sizeof(*sgid));
@@ -253,6 +253,107 @@ static bool ocrdma_search_mmap(struct ocrdma_ucontext *uctx, u64 phy_addr,
return found;
}
+
+static u16 _ocrdma_pd_mgr_get_bitmap(struct ocrdma_dev *dev, bool dpp_pool)
+{
+ u16 pd_bitmap_idx = 0;
+ const unsigned long *pd_bitmap;
+
+ if (dpp_pool) {
+ pd_bitmap = dev->pd_mgr->pd_dpp_bitmap;
+ pd_bitmap_idx = find_first_zero_bit(pd_bitmap,
+ dev->pd_mgr->max_dpp_pd);
+ __set_bit(pd_bitmap_idx, dev->pd_mgr->pd_dpp_bitmap);
+ dev->pd_mgr->pd_dpp_count++;
+ if (dev->pd_mgr->pd_dpp_count > dev->pd_mgr->pd_dpp_thrsh)
+ dev->pd_mgr->pd_dpp_thrsh = dev->pd_mgr->pd_dpp_count;
+ } else {
+ pd_bitmap = dev->pd_mgr->pd_norm_bitmap;
+ pd_bitmap_idx = find_first_zero_bit(pd_bitmap,
+ dev->pd_mgr->max_normal_pd);
+ __set_bit(pd_bitmap_idx, dev->pd_mgr->pd_norm_bitmap);
+ dev->pd_mgr->pd_norm_count++;
+ if (dev->pd_mgr->pd_norm_count > dev->pd_mgr->pd_norm_thrsh)
+ dev->pd_mgr->pd_norm_thrsh = dev->pd_mgr->pd_norm_count;
+ }
+ return pd_bitmap_idx;
+}
+
+static int _ocrdma_pd_mgr_put_bitmap(struct ocrdma_dev *dev, u16 pd_id,
+ bool dpp_pool)
+{
+ u16 pd_count;
+ u16 pd_bit_index;
+
+ pd_count = dpp_pool ? dev->pd_mgr->pd_dpp_count :
+ dev->pd_mgr->pd_norm_count;
+ if (pd_count == 0)
+ return -EINVAL;
+
+ if (dpp_pool) {
+ pd_bit_index = pd_id - dev->pd_mgr->pd_dpp_start;
+ if (pd_bit_index >= dev->pd_mgr->max_dpp_pd) {
+ return -EINVAL;
+ } else {
+ __clear_bit(pd_bit_index, dev->pd_mgr->pd_dpp_bitmap);
+ dev->pd_mgr->pd_dpp_count--;
+ }
+ } else {
+ pd_bit_index = pd_id - dev->pd_mgr->pd_norm_start;
+ if (pd_bit_index >= dev->pd_mgr->max_normal_pd) {
+ return -EINVAL;
+ } else {
+ __clear_bit(pd_bit_index, dev->pd_mgr->pd_norm_bitmap);
+ dev->pd_mgr->pd_norm_count--;
+ }
+ }
+
+ return 0;
+}
+
+static u8 ocrdma_put_pd_num(struct ocrdma_dev *dev, u16 pd_id,
+ bool dpp_pool)
+{
+ int status;
+
+ mutex_lock(&dev->dev_lock);
+ status = _ocrdma_pd_mgr_put_bitmap(dev, pd_id, dpp_pool);
+ mutex_unlock(&dev->dev_lock);
+ return status;
+}
+
+static int ocrdma_get_pd_num(struct ocrdma_dev *dev, struct ocrdma_pd *pd)
+{
+ u16 pd_idx = 0;
+ int status = 0;
+
+ mutex_lock(&dev->dev_lock);
+ if (pd->dpp_enabled) {
+ /* try allocating DPP PD, if not available then normal PD */
+ if (dev->pd_mgr->pd_dpp_count < dev->pd_mgr->max_dpp_pd) {
+ pd_idx = _ocrdma_pd_mgr_get_bitmap(dev, true);
+ pd->id = dev->pd_mgr->pd_dpp_start + pd_idx;
+ pd->dpp_page = dev->pd_mgr->dpp_page_index + pd_idx;
+ } else if (dev->pd_mgr->pd_norm_count <
+ dev->pd_mgr->max_normal_pd) {
+ pd_idx = _ocrdma_pd_mgr_get_bitmap(dev, false);
+ pd->id = dev->pd_mgr->pd_norm_start + pd_idx;
+ pd->dpp_enabled = false;
+ } else {
+ status = -EINVAL;
+ }
+ } else {
+ if (dev->pd_mgr->pd_norm_count < dev->pd_mgr->max_normal_pd) {
+ pd_idx = _ocrdma_pd_mgr_get_bitmap(dev, false);
+ pd->id = dev->pd_mgr->pd_norm_start + pd_idx;
+ } else {
+ status = -EINVAL;
+ }
+ }
+ mutex_unlock(&dev->dev_lock);
+ return status;
+}
+
static struct ocrdma_pd *_ocrdma_alloc_pd(struct ocrdma_dev *dev,
struct ocrdma_ucontext *uctx,
struct ib_udata *udata)
@@ -272,6 +373,11 @@ static struct ocrdma_pd *_ocrdma_alloc_pd(struct ocrdma_dev *dev,
dev->attr.wqe_size) : 0;
}
+ if (dev->pd_mgr->pd_prealloc_valid) {
+ status = ocrdma_get_pd_num(dev, pd);
+ return (status == 0) ? pd : ERR_PTR(status);
+ }
+
retry:
status = ocrdma_mbx_alloc_pd(dev, pd);
if (status) {
@@ -299,7 +405,11 @@ static int _ocrdma_dealloc_pd(struct ocrdma_dev *dev,
{
int status = 0;
- status = ocrdma_mbx_dealloc_pd(dev, pd);
+ if (dev->pd_mgr->pd_prealloc_valid)
+ status = ocrdma_put_pd_num(dev, pd->id, pd->dpp_enabled);
+ else
+ status = ocrdma_mbx_dealloc_pd(dev, pd);
+
kfree(pd);
return status;
}
@@ -325,7 +435,6 @@ err:
static int ocrdma_dealloc_ucontext_pd(struct ocrdma_ucontext *uctx)
{
- int status = 0;
struct ocrdma_pd *pd = uctx->cntxt_pd;
struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device);
@@ -334,8 +443,8 @@ static int ocrdma_dealloc_ucontext_pd(struct ocrdma_ucontext *uctx)
__func__, dev->id, pd->id);
}
uctx->cntxt_pd = NULL;
- status = _ocrdma_dealloc_pd(dev, pd);
- return status;
+ (void)_ocrdma_dealloc_pd(dev, pd);
+ return 0;
}
static struct ocrdma_pd *ocrdma_get_ucontext_pd(struct ocrdma_ucontext *uctx)
@@ -569,7 +678,7 @@ err:
if (is_uctx_pd) {
ocrdma_release_ucontext_pd(uctx);
} else {
- status = ocrdma_mbx_dealloc_pd(dev, pd);
+ status = _ocrdma_dealloc_pd(dev, pd);
kfree(pd);
}
exit:
@@ -837,9 +946,8 @@ int ocrdma_dereg_mr(struct ib_mr *ib_mr)
{
struct ocrdma_mr *mr = get_ocrdma_mr(ib_mr);
struct ocrdma_dev *dev = get_ocrdma_dev(ib_mr->device);
- int status;
- status = ocrdma_mbx_dealloc_lkey(dev, mr->hwmr.fr_mr, mr->hwmr.lkey);
+ (void) ocrdma_mbx_dealloc_lkey(dev, mr->hwmr.fr_mr, mr->hwmr.lkey);
ocrdma_free_mr_pbl_tbl(dev, &mr->hwmr);
@@ -850,11 +958,10 @@ int ocrdma_dereg_mr(struct ib_mr *ib_mr)
/* Don't stop cleanup, in case FW is unresponsive */
if (dev->mqe_ctx.fw_error_state) {
- status = 0;
pr_err("%s(%d) fw not responding.\n",
__func__, dev->id);
}
- return status;
+ return 0;
}
static int ocrdma_copy_cq_uresp(struct ocrdma_dev *dev, struct ocrdma_cq *cq,
@@ -986,7 +1093,6 @@ static void ocrdma_flush_cq(struct ocrdma_cq *cq)
int ocrdma_destroy_cq(struct ib_cq *ibcq)
{
- int status;
struct ocrdma_cq *cq = get_ocrdma_cq(ibcq);
struct ocrdma_eq *eq = NULL;
struct ocrdma_dev *dev = get_ocrdma_dev(ibcq->device);
@@ -1003,7 +1109,7 @@ int ocrdma_destroy_cq(struct ib_cq *ibcq)
synchronize_irq(irq);
ocrdma_flush_cq(cq);
- status = ocrdma_mbx_destroy_cq(dev, cq);
+ (void)ocrdma_mbx_destroy_cq(dev, cq);
if (cq->ucontext) {
pdid = cq->ucontext->cntxt_pd->id;
ocrdma_del_mmap(cq->ucontext, (u64) cq->pa,
@@ -1014,7 +1120,7 @@ int ocrdma_destroy_cq(struct ib_cq *ibcq)
}
kfree(cq);
- return status;
+ return 0;
}
static int ocrdma_add_qpn_map(struct ocrdma_dev *dev, struct ocrdma_qp *qp)
@@ -1113,8 +1219,8 @@ static int ocrdma_copy_qp_uresp(struct ocrdma_qp *qp,
int status = 0;
u64 usr_db;
struct ocrdma_create_qp_uresp uresp;
- struct ocrdma_dev *dev = qp->dev;
struct ocrdma_pd *pd = qp->pd;
+ struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device);
memset(&uresp, 0, sizeof(uresp));
usr_db = dev->nic_info.unmapped_db +
@@ -1253,7 +1359,6 @@ struct ib_qp *ocrdma_create_qp(struct ib_pd *ibpd,
status = -ENOMEM;
goto gen_err;
}
- qp->dev = dev;
ocrdma_set_qp_init_params(qp, pd, attrs);
if (udata == NULL)
qp->cap_flags |= (OCRDMA_QP_MW_BIND | OCRDMA_QP_LKEY0 |
@@ -1312,7 +1417,7 @@ int _ocrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
enum ib_qp_state old_qps;
qp = get_ocrdma_qp(ibqp);
- dev = qp->dev;
+ dev = get_ocrdma_dev(ibqp->device);
if (attr_mask & IB_QP_STATE)
status = ocrdma_qp_state_change(qp, attr->qp_state, &old_qps);
/* if new and previous states are same hw doesn't need to
@@ -1335,7 +1440,7 @@ int ocrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
enum ib_qp_state old_qps, new_qps;
qp = get_ocrdma_qp(ibqp);
- dev = qp->dev;
+ dev = get_ocrdma_dev(ibqp->device);
/* syncronize with multiple context trying to change, retrive qps */
mutex_lock(&dev->dev_lock);
@@ -1402,7 +1507,7 @@ int ocrdma_query_qp(struct ib_qp *ibqp,
u32 qp_state;
struct ocrdma_qp_params params;
struct ocrdma_qp *qp = get_ocrdma_qp(ibqp);
- struct ocrdma_dev *dev = qp->dev;
+ struct ocrdma_dev *dev = get_ocrdma_dev(ibqp->device);
memset(&params, 0, sizeof(params));
mutex_lock(&dev->dev_lock);
@@ -1412,8 +1517,6 @@ int ocrdma_query_qp(struct ib_qp *ibqp,
goto mbx_err;
if (qp->qp_type == IB_QPT_UD)
qp_attr->qkey = params.qkey;
- qp_attr->qp_state = get_ibqp_state(IB_QPS_INIT);
- qp_attr->cur_qp_state = get_ibqp_state(IB_QPS_INIT);
qp_attr->path_mtu =
ocrdma_mtu_int_to_enum(params.path_mtu_pkey_indx &
OCRDMA_QP_PARAMS_PATH_MTU_MASK) >>
@@ -1468,6 +1571,8 @@ int ocrdma_query_qp(struct ib_qp *ibqp,
memset(&qp_attr->alt_ah_attr, 0, sizeof(qp_attr->alt_ah_attr));
qp_state = (params.max_sge_recv_flags & OCRDMA_QP_PARAMS_STATE_MASK) >>
OCRDMA_QP_PARAMS_STATE_SHIFT;
+ qp_attr->qp_state = get_ibqp_state(qp_state);
+ qp_attr->cur_qp_state = qp_attr->qp_state;
qp_attr->sq_draining = (qp_state == OCRDMA_QPS_SQ_DRAINING) ? 1 : 0;
qp_attr->max_dest_rd_atomic =
params.max_ord_ird >> OCRDMA_QP_PARAMS_MAX_ORD_SHIFT;
@@ -1475,19 +1580,18 @@ int ocrdma_query_qp(struct ib_qp *ibqp,
params.max_ord_ird & OCRDMA_QP_PARAMS_MAX_IRD_MASK;
qp_attr->en_sqd_async_notify = (params.max_sge_recv_flags &
OCRDMA_QP_PARAMS_FLAGS_SQD_ASYNC) ? 1 : 0;
+ /* Sync driver QP state with FW */
+ ocrdma_qp_state_change(qp, qp_attr->qp_state, NULL);
mbx_err:
return status;
}
-static void ocrdma_srq_toggle_bit(struct ocrdma_srq *srq, int idx)
+static void ocrdma_srq_toggle_bit(struct ocrdma_srq *srq, unsigned int idx)
{
- int i = idx / 32;
- unsigned int mask = (1 << (idx % 32));
+ unsigned int i = idx / 32;
+ u32 mask = (1U << (idx % 32));
- if (srq->idx_bit_fields[i] & mask)
- srq->idx_bit_fields[i] &= ~mask;
- else
- srq->idx_bit_fields[i] |= mask;
+ srq->idx_bit_fields[i] ^= mask;
}
static int ocrdma_hwq_free_cnt(struct ocrdma_qp_hwq_info *q)
@@ -1596,7 +1700,7 @@ void ocrdma_del_flush_qp(struct ocrdma_qp *qp)
{
int found = false;
unsigned long flags;
- struct ocrdma_dev *dev = qp->dev;
+ struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
/* sync with any active CQ poll */
spin_lock_irqsave(&dev->flush_q_lock, flags);
@@ -1613,7 +1717,6 @@ void ocrdma_del_flush_qp(struct ocrdma_qp *qp)
int ocrdma_destroy_qp(struct ib_qp *ibqp)
{
- int status;
struct ocrdma_pd *pd;
struct ocrdma_qp *qp;
struct ocrdma_dev *dev;
@@ -1622,7 +1725,7 @@ int ocrdma_destroy_qp(struct ib_qp *ibqp)
unsigned long flags;
qp = get_ocrdma_qp(ibqp);
- dev = qp->dev;
+ dev = get_ocrdma_dev(ibqp->device);
attrs.qp_state = IB_QPS_ERR;
pd = qp->pd;
@@ -1635,7 +1738,7 @@ int ocrdma_destroy_qp(struct ib_qp *ibqp)
* discarded until the old CQEs are discarded.
*/
mutex_lock(&dev->dev_lock);
- status = ocrdma_mbx_destroy_qp(dev, qp);
+ (void) ocrdma_mbx_destroy_qp(dev, qp);
/*
* acquire CQ lock while destroy is in progress, in order to
@@ -1670,7 +1773,7 @@ int ocrdma_destroy_qp(struct ib_qp *ibqp)
kfree(qp->wqe_wr_id_tbl);
kfree(qp->rqe_wr_id_tbl);
kfree(qp);
- return status;
+ return 0;
}
static int ocrdma_copy_srq_uresp(struct ocrdma_dev *dev, struct ocrdma_srq *srq,
@@ -1831,6 +1934,8 @@ static void ocrdma_build_ud_hdr(struct ocrdma_qp *qp,
else
ud_hdr->qkey = wr->wr.ud.remote_qkey;
ud_hdr->rsvd_ahid = ah->id;
+ if (ah->av->valid & OCRDMA_AV_VLAN_VALID)
+ hdr->cw |= (OCRDMA_FLAG_AH_VLAN_PR << OCRDMA_WQE_FLAGS_SHIFT);
}
static void ocrdma_build_sges(struct ocrdma_hdr_wqe *hdr,
@@ -2007,11 +2112,12 @@ static int ocrdma_build_fr(struct ocrdma_qp *qp, struct ocrdma_hdr_wqe *hdr,
u64 fbo;
struct ocrdma_ewqe_fr *fast_reg = (struct ocrdma_ewqe_fr *)(hdr + 1);
struct ocrdma_mr *mr;
+ struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
u32 wqe_size = sizeof(*fast_reg) + sizeof(*hdr);
wqe_size = roundup(wqe_size, OCRDMA_WQE_ALIGN_BYTES);
- if (wr->wr.fast_reg.page_list_len > qp->dev->attr.max_pages_per_frmr)
+ if (wr->wr.fast_reg.page_list_len > dev->attr.max_pages_per_frmr)
return -EINVAL;
hdr->cw |= (OCRDMA_FR_MR << OCRDMA_WQE_OPCODE_SHIFT);
@@ -2039,7 +2145,7 @@ static int ocrdma_build_fr(struct ocrdma_qp *qp, struct ocrdma_hdr_wqe *hdr,
fast_reg->size_sge =
get_encoded_page_size(1 << wr->wr.fast_reg.page_shift);
mr = (struct ocrdma_mr *) (unsigned long)
- qp->dev->stag_arr[(hdr->lkey >> 8) & (OCRDMA_MAX_STAG - 1)];
+ dev->stag_arr[(hdr->lkey >> 8) & (OCRDMA_MAX_STAG - 1)];
build_frmr_pbes(wr, mr->hwmr.pbl_table, &mr->hwmr);
return 0;
}
@@ -2112,8 +2218,6 @@ int ocrdma_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
hdr->cw |= (OCRDMA_WRITE << OCRDMA_WQE_OPCODE_SHIFT);
status = ocrdma_build_write(qp, hdr, wr);
break;
- case IB_WR_RDMA_READ_WITH_INV:
- hdr->cw |= (OCRDMA_FLAG_INV << OCRDMA_WQE_FLAGS_SHIFT);
case IB_WR_RDMA_READ:
ocrdma_build_read(qp, hdr, wr);
break;
@@ -2484,8 +2588,11 @@ static bool ocrdma_poll_err_scqe(struct ocrdma_qp *qp,
bool *polled, bool *stop)
{
bool expand;
+ struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
int status = (le32_to_cpu(cqe->flags_status_srcqpn) &
OCRDMA_CQE_STATUS_MASK) >> OCRDMA_CQE_STATUS_SHIFT;
+ if (status < OCRDMA_MAX_CQE_ERR)
+ atomic_inc(&dev->cqe_err_stats[status]);
/* when hw sq is empty, but rq is not empty, so we continue
* to keep the cqe in order to get the cq event again.
@@ -2604,6 +2711,10 @@ static bool ocrdma_poll_err_rcqe(struct ocrdma_qp *qp, struct ocrdma_cqe *cqe,
int status)
{
bool expand;
+ struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
+
+ if (status < OCRDMA_MAX_CQE_ERR)
+ atomic_inc(&dev->cqe_err_stats[status]);
/* when hw_rq is empty, but wq is not empty, so continue
* to keep the cqe to get the cq event again.
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index 5ce26817e7e1..b47aea1094b2 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -654,7 +654,9 @@ int iser_dma_map_task_data(struct iscsi_iser_task *iser_task,
enum dma_data_direction dma_dir);
void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task,
- struct iser_data_buf *data);
+ struct iser_data_buf *data,
+ enum dma_data_direction dir);
+
int iser_initialize_task_headers(struct iscsi_task *task,
struct iser_tx_desc *tx_desc);
int iser_alloc_rx_descriptors(struct iser_conn *iser_conn,
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index 3821633f1065..20e859a6f1a6 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -320,9 +320,6 @@ void iser_free_rx_descriptors(struct iser_conn *iser_conn)
struct ib_conn *ib_conn = &iser_conn->ib_conn;
struct iser_device *device = ib_conn->device;
- if (!iser_conn->rx_descs)
- goto free_login_buf;
-
if (device->iser_free_rdma_reg_res)
device->iser_free_rdma_reg_res(ib_conn);
@@ -334,7 +331,6 @@ void iser_free_rx_descriptors(struct iser_conn *iser_conn)
/* make sure we never redo any unmapping */
iser_conn->rx_descs = NULL;
-free_login_buf:
iser_free_login_buf(iser_conn);
}
@@ -714,19 +710,23 @@ void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task)
device->iser_unreg_rdma_mem(iser_task, ISER_DIR_IN);
if (is_rdma_data_aligned)
iser_dma_unmap_task_data(iser_task,
- &iser_task->data[ISER_DIR_IN]);
+ &iser_task->data[ISER_DIR_IN],
+ DMA_FROM_DEVICE);
if (prot_count && is_rdma_prot_aligned)
iser_dma_unmap_task_data(iser_task,
- &iser_task->prot[ISER_DIR_IN]);
+ &iser_task->prot[ISER_DIR_IN],
+ DMA_FROM_DEVICE);
}
if (iser_task->dir[ISER_DIR_OUT]) {
device->iser_unreg_rdma_mem(iser_task, ISER_DIR_OUT);
if (is_rdma_data_aligned)
iser_dma_unmap_task_data(iser_task,
- &iser_task->data[ISER_DIR_OUT]);
+ &iser_task->data[ISER_DIR_OUT],
+ DMA_TO_DEVICE);
if (prot_count && is_rdma_prot_aligned)
iser_dma_unmap_task_data(iser_task,
- &iser_task->prot[ISER_DIR_OUT]);
+ &iser_task->prot[ISER_DIR_OUT],
+ DMA_TO_DEVICE);
}
}
diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c
index abce9339333f..341040bf0984 100644
--- a/drivers/infiniband/ulp/iser/iser_memory.c
+++ b/drivers/infiniband/ulp/iser/iser_memory.c
@@ -332,12 +332,13 @@ int iser_dma_map_task_data(struct iscsi_iser_task *iser_task,
}
void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task,
- struct iser_data_buf *data)
+ struct iser_data_buf *data,
+ enum dma_data_direction dir)
{
struct ib_device *dev;
dev = iser_task->iser_conn->ib_conn.device->ib_device;
- ib_dma_unmap_sg(dev, data->buf, data->size, DMA_FROM_DEVICE);
+ ib_dma_unmap_sg(dev, data->buf, data->size, dir);
}
static int fall_to_bounce_buf(struct iscsi_iser_task *iser_task,
@@ -357,7 +358,9 @@ static int fall_to_bounce_buf(struct iscsi_iser_task *iser_task,
iser_data_buf_dump(mem, ibdev);
/* unmap the command data before accessing it */
- iser_dma_unmap_task_data(iser_task, mem);
+ iser_dma_unmap_task_data(iser_task, mem,
+ (cmd_dir == ISER_DIR_OUT) ?
+ DMA_TO_DEVICE : DMA_FROM_DEVICE);
/* allocate copy buf, if we are writing, copy the */
/* unaligned scatterlist, dma map the copy */
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index 695a2704bd43..4065abe28829 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -600,16 +600,16 @@ void iser_release_work(struct work_struct *work)
/**
* iser_free_ib_conn_res - release IB related resources
* @iser_conn: iser connection struct
- * @destroy_device: indicator if we need to try to release
- * the iser device (only iscsi shutdown and DEVICE_REMOVAL
- * will use this.
+ * @destroy: indicator if we need to try to release the
+ * iser device and memory regoins pool (only iscsi
+ * shutdown and DEVICE_REMOVAL will use this).
*
* This routine is called with the iser state mutex held
* so the cm_id removal is out of here. It is Safe to
* be invoked multiple times.
*/
static void iser_free_ib_conn_res(struct iser_conn *iser_conn,
- bool destroy_device)
+ bool destroy)
{
struct ib_conn *ib_conn = &iser_conn->ib_conn;
struct iser_device *device = ib_conn->device;
@@ -617,17 +617,20 @@ static void iser_free_ib_conn_res(struct iser_conn *iser_conn,
iser_info("freeing conn %p cma_id %p qp %p\n",
iser_conn, ib_conn->cma_id, ib_conn->qp);
- iser_free_rx_descriptors(iser_conn);
-
if (ib_conn->qp != NULL) {
ib_conn->comp->active_qps--;
rdma_destroy_qp(ib_conn->cma_id);
ib_conn->qp = NULL;
}
- if (destroy_device && device != NULL) {
- iser_device_try_release(device);
- ib_conn->device = NULL;
+ if (destroy) {
+ if (iser_conn->rx_descs)
+ iser_free_rx_descriptors(iser_conn);
+
+ if (device != NULL) {
+ iser_device_try_release(device);
+ ib_conn->device = NULL;
+ }
}
}
@@ -643,9 +646,11 @@ void iser_conn_release(struct iser_conn *iser_conn)
mutex_unlock(&ig.connlist_mutex);
mutex_lock(&iser_conn->state_mutex);
+ /* In case we endup here without ep_disconnect being invoked. */
if (iser_conn->state != ISER_CONN_DOWN) {
iser_warn("iser conn %p state %d, expected state down.\n",
iser_conn, iser_conn->state);
+ iscsi_destroy_endpoint(iser_conn->ep);
iser_conn->state = ISER_CONN_DOWN;
}
/*
@@ -840,7 +845,7 @@ static void iser_disconnected_handler(struct rdma_cm_id *cma_id)
}
static void iser_cleanup_handler(struct rdma_cm_id *cma_id,
- bool destroy_device)
+ bool destroy)
{
struct iser_conn *iser_conn = (struct iser_conn *)cma_id->context;
@@ -850,7 +855,7 @@ static void iser_cleanup_handler(struct rdma_cm_id *cma_id,
* and flush errors.
*/
iser_disconnected_handler(cma_id);
- iser_free_ib_conn_res(iser_conn, destroy_device);
+ iser_free_ib_conn_res(iser_conn, destroy);
complete(&iser_conn->ib_completion);
};