summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/infiniband/user_mad.rst2
-rw-r--r--drivers/infiniband/core/Makefile1
-rw-r--r--drivers/infiniband/core/addr.c2
-rw-r--r--drivers/infiniband/core/cma.c2
-rw-r--r--drivers/infiniband/core/counters.c5
-rw-r--r--drivers/infiniband/core/cq.c5
-rw-r--r--drivers/infiniband/core/device.c7
-rw-r--r--drivers/infiniband/core/iwpm_msg.c2
-rw-r--r--drivers/infiniband/core/nldev.c43
-rw-r--r--drivers/infiniband/core/rdma_core.h1
-rw-r--r--drivers/infiniband/core/restrack.c169
-rw-r--r--drivers/infiniband/core/restrack.h3
-rw-r--r--drivers/infiniband/core/umem.c5
-rw-r--r--drivers/infiniband/core/umem_dmabuf.c4
-rw-r--r--drivers/infiniband/core/uverbs_std_types_comp_cntr.c172
-rw-r--r--drivers/infiniband/core/uverbs_std_types_device.c51
-rw-r--r--drivers/infiniband/core/uverbs_std_types_dmah.c7
-rw-r--r--drivers/infiniband/core/uverbs_std_types_mr.c6
-rw-r--r--drivers/infiniband/core/uverbs_std_types_qp.c67
-rw-r--r--drivers/infiniband/core/uverbs_uapi.c1
-rw-r--r--drivers/infiniband/core/verbs.c36
-rw-r--r--drivers/infiniband/hw/bng_re/bng_fw.c10
-rw-r--r--drivers/infiniband/hw/bnxt_re/ib_verbs.c72
-rw-r--r--drivers/infiniband/hw/cxgb4/mem.c4
-rw-r--r--drivers/infiniband/hw/cxgb4/provider.c4
-rw-r--r--drivers/infiniband/hw/efa/Makefile4
-rw-r--r--drivers/infiniband/hw/efa/efa.h20
-rw-r--r--drivers/infiniband/hw/efa/efa_admin_cmds_defs.h192
-rw-r--r--drivers/infiniband/hw/efa/efa_ah_cache.c135
-rw-r--r--drivers/infiniband/hw/efa/efa_ah_cache.h39
-rw-r--r--drivers/infiniband/hw/efa/efa_com.c12
-rw-r--r--drivers/infiniband/hw/efa/efa_com.h3
-rw-r--r--drivers/infiniband/hw/efa/efa_com_cmd.c177
-rw-r--r--drivers/infiniband/hw/efa/efa_com_cmd.h46
-rw-r--r--drivers/infiniband/hw/efa/efa_io_defs.h20
-rw-r--r--drivers/infiniband/hw/efa/efa_main.c10
-rw-r--r--drivers/infiniband/hw/efa/efa_verbs.c247
-rw-r--r--drivers/infiniband/hw/erdma/erdma_eq.c1
-rw-r--r--drivers/infiniband/hw/erdma/erdma_verbs.c6
-rw-r--r--drivers/infiniband/hw/hfi1/chip.c21
-rw-r--r--drivers/infiniband/hw/hfi1/chip.h2
-rw-r--r--drivers/infiniband/hw/hfi1/device.c32
-rw-r--r--drivers/infiniband/hw/hfi1/device.h1
-rw-r--r--drivers/infiniband/hw/hfi1/file_ops.c2
-rw-r--r--drivers/infiniband/hw/hfi1/hfi.h4
-rw-r--r--drivers/infiniband/hw/hfi1/init.c194
-rw-r--r--drivers/infiniband/hw/hfi1/pcie.c32
-rw-r--r--drivers/infiniband/hw/hfi1/user_sdma.c13
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_hw_v2.c2
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_main.c6
-rw-r--r--drivers/infiniband/hw/ionic/ionic_controlpath.c72
-rw-r--r--drivers/infiniband/hw/ionic/ionic_datapath.c43
-rw-r--r--drivers/infiniband/hw/ionic/ionic_fw.h12
-rw-r--r--drivers/infiniband/hw/ionic/ionic_ibdev.c5
-rw-r--r--drivers/infiniband/hw/ionic/ionic_ibdev.h3
-rw-r--r--drivers/infiniband/hw/ionic/ionic_lif_cfg.c2
-rw-r--r--drivers/infiniband/hw/ionic/ionic_lif_cfg.h1
-rw-r--r--drivers/infiniband/hw/irdma/i40iw_hw.c4
-rw-r--r--drivers/infiniband/hw/irdma/icrdma_hw.c2
-rw-r--r--drivers/infiniband/hw/irdma/icrdma_hw.h2
-rw-r--r--drivers/infiniband/hw/irdma/icrdma_if.c8
-rw-r--r--drivers/infiniband/hw/irdma/irdma.h2
-rw-r--r--drivers/infiniband/hw/irdma/utils.c6
-rw-r--r--drivers/infiniband/hw/irdma/verbs.c337
-rw-r--r--drivers/infiniband/hw/irdma/verbs.h3
-rw-r--r--drivers/infiniband/hw/mana/cq.c8
-rw-r--r--drivers/infiniband/hw/mana/device.c1
-rw-r--r--drivers/infiniband/hw/mana/main.c30
-rw-r--r--drivers/infiniband/hw/mana/mr.c13
-rw-r--r--drivers/infiniband/hw/mana/qp.c48
-rw-r--r--drivers/infiniband/hw/mana/wq.c12
-rw-r--r--drivers/infiniband/hw/mlx4/cm.c120
-rw-r--r--drivers/infiniband/hw/mlx4/main.c2
-rw-r--r--drivers/infiniband/hw/mlx4/mr.c6
-rw-r--r--drivers/infiniband/hw/mlx5/main.c9
-rw-r--r--drivers/infiniband/hw/mlx5/mr.c6
-rw-r--r--drivers/infiniband/hw/mlx5/odp.c6
-rw-r--r--drivers/infiniband/hw/mlx5/umr.c13
-rw-r--r--drivers/infiniband/hw/mthca/mthca_allocator.c6
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.c10
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_verbs.c5
-rw-r--r--drivers/infiniband/hw/qedr/verbs.c8
-rw-r--r--drivers/infiniband/hw/usnic/usnic_ib_verbs.c5
-rw-r--r--drivers/infiniband/hw/usnic/usnic_uiom.c4
-rw-r--r--drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c4
-rw-r--r--drivers/infiniband/sw/rdmavt/qp.c8
-rw-r--r--drivers/infiniband/sw/rdmavt/vt.c8
-rw-r--r--drivers/infiniband/sw/rxe/rxe_mw.c20
-rw-r--r--drivers/infiniband/sw/rxe/rxe_odp.c11
-rw-r--r--drivers/infiniband/sw/rxe/rxe_qp.c37
-rw-r--r--drivers/infiniband/sw/rxe/rxe_req.c15
-rw-r--r--drivers/infiniband/sw/rxe/rxe_resp.c9
-rw-r--r--drivers/infiniband/sw/rxe/rxe_srq.c16
-rw-r--r--drivers/infiniband/sw/rxe/rxe_verbs.c4
-rw-r--r--drivers/infiniband/sw/siw/siw_verbs.c6
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c10
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_verbs.c3
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c5
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.c7
-rw-r--r--drivers/infiniband/ulp/rtrs/rtrs-clt.c11
-rw-r--r--drivers/infiniband/ulp/rtrs/rtrs-srv.c11
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c2
-rw-r--r--drivers/infiniband/ulp/srpt/ib_srpt.c30
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_ethtool.c12
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_if.h1
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_lif.c5
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_lif.h3
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_phc.c63
-rw-r--r--drivers/nvme/host/rdma.c8
-rw-r--r--drivers/nvme/target/rdma.c26
-rw-r--r--fs/smb/smbdirect/accept.c5
-rw-r--r--fs/smb/smbdirect/connect.c5
-rw-r--r--fs/smb/smbdirect/connection.c8
-rw-r--r--include/linux/sunrpc/svc_rdma.h4
-rw-r--r--include/rdma/ib_umem.h2
-rw-r--r--include/rdma/ib_verbs.h102
-rw-r--r--include/rdma/restrack.h6
-rw-r--r--include/rdma/uverbs_ioctl.h20
-rw-r--r--include/uapi/rdma/efa-abi.h6
-rw-r--r--include/uapi/rdma/ib_user_ioctl_cmds.h43
-rw-r--r--include/uapi/rdma/ib_user_ioctl_verbs.h19
-rw-r--r--include/uapi/rdma/ib_user_verbs.h33
-rw-r--r--include/uapi/rdma/ionic-abi.h1
-rw-r--r--include/uapi/rdma/irdma-abi.h1
-rw-r--r--include/uapi/rdma/mana-abi.h2
-rw-r--r--include/uapi/rdma/mlx5-abi.h15
-rw-r--r--include/uapi/rdma/rdma_netlink.h5
-rw-r--r--net/rds/ib.c10
-rw-r--r--net/rds/ib_cm.c10
-rw-r--r--net/sunrpc/xprtrdma/frwr_ops.c7
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_transport.c5
-rw-r--r--net/sunrpc/xprtrdma/verbs.c2
132 files changed, 2628 insertions, 734 deletions
diff --git a/Documentation/infiniband/user_mad.rst b/Documentation/infiniband/user_mad.rst
index d88abfc0e370..cd66e7623d66 100644
--- a/Documentation/infiniband/user_mad.rst
+++ b/Documentation/infiniband/user_mad.rst
@@ -62,7 +62,7 @@ Receiving MADs
struct ib_user_mad *mad;
mad = malloc(sizeof *mad + 256);
ret = read(fd, mad, sizeof *mad + 256);
- if (ret == -ENOSPC)) {
+ if (ret == -ENOSPC) {
length = mad.length;
free(mad);
mad = malloc(sizeof *mad + length);
diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile
index ab7a2197bc86..47ef6b0afd29 100644
--- a/drivers/infiniband/core/Makefile
+++ b/drivers/infiniband/core/Makefile
@@ -38,6 +38,7 @@ ib_umad-y := user_mad.o
ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_marshall.o \
uverbs_std_types.o uverbs_ioctl.o \
uverbs_std_types_cq.o \
+ uverbs_std_types_comp_cntr.o \
uverbs_std_types_dmabuf.o \
uverbs_std_types_dmah.o \
uverbs_std_types_flow_action.o uverbs_std_types_dm.o \
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index e9fb7ad4c377..bdaa3eb83bcc 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -769,7 +769,7 @@ void rdma_addr_cancel(struct rdma_dev_addr *addr)
/*
* sync canceling the work after removing it from the req_list
- * guarentees no work is running and none will be started.
+ * guarantees no work is running and none will be started.
*/
cancel_delayed_work_sync(&found->work);
kfree(found);
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index e88d3efb967b..cc24fddf9aaa 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -2104,7 +2104,7 @@ static void destroy_id_handler_unlock(struct rdma_id_private *id_priv)
/*
* Setting the state to destroyed under the handler mutex provides a
* fence against calling handler callbacks. If this is invoked due to
- * the failure of a handler callback then it guarentees that no future
+ * the failure of a handler callback then it guarantees that no future
* handlers will be called.
*/
lockdep_assert_held(&id_priv->handler_mutex);
diff --git a/drivers/infiniband/core/counters.c b/drivers/infiniband/core/counters.c
index a9e189194c13..a2c85840c501 100644
--- a/drivers/infiniband/core/counters.c
+++ b/drivers/infiniband/core/counters.c
@@ -234,7 +234,6 @@ static void rdma_counter_free(struct rdma_counter *counter)
mutex_unlock(&port_counter->lock);
- rdma_restrack_del(&counter->res);
rdma_free_hw_stats_struct(counter->stats);
kfree(counter);
}
@@ -329,6 +328,7 @@ static void counter_release(struct kref *kref)
counter = container_of(kref, struct rdma_counter, kref);
counter_history_stat_update(counter);
+ rdma_restrack_del(&counter->res);
counter->device->ops.counter_dealloc(counter);
rdma_counter_free(counter);
}
@@ -490,7 +490,8 @@ static struct rdma_counter *rdma_get_counter_by_id(struct ib_device *dev,
return NULL;
counter = container_of(res, struct rdma_counter, res);
- kref_get(&counter->kref);
+ if (!kref_get_unless_zero(&counter->kref))
+ counter = NULL;
rdma_restrack_put(res);
return counter;
diff --git a/drivers/infiniband/core/cq.c b/drivers/infiniband/core/cq.c
index 3d7b6cddd131..12304c9a9403 100644
--- a/drivers/infiniband/core/cq.c
+++ b/drivers/infiniband/core/cq.c
@@ -327,6 +327,7 @@ void ib_free_cq(struct ib_cq *cq)
if (WARN_ON_ONCE(cq->cqe_used))
return;
+ rdma_restrack_del(&cq->res);
if (cq->device->ops.pre_destroy_cq) {
ret = cq->device->ops.pre_destroy_cq(cq);
WARN_ONCE(ret, "Disable of kernel CQ shouldn't fail");
@@ -353,7 +354,6 @@ void ib_free_cq(struct ib_cq *cq)
else
ret = cq->device->ops.destroy_cq(cq, NULL);
WARN_ONCE(ret, "Destroy of kernel CQ shouldn't fail");
- rdma_restrack_del(&cq->res);
kfree(cq->wc);
kfree(cq);
}
@@ -393,8 +393,7 @@ static int ib_alloc_cqs(struct ib_device *dev, unsigned int nr_cqes,
* a reasonable batch size so that we can share CQs between
* multiple users instead of allocating a larger number of CQs.
*/
- nr_cqes = min_t(unsigned int, dev->attrs.max_cqe,
- max(nr_cqes, IB_MAX_SHARED_CQ_SZ));
+ nr_cqes = min(dev->attrs.max_cqe, max(nr_cqes, IB_MAX_SHARED_CQ_SZ));
nr_cqs = min_t(unsigned int, dev->num_comp_vectors, num_online_cpus());
for (i = 0; i < nr_cqs; i++) {
cq = ib_alloc_cq(dev, NULL, nr_cqes, i, poll_ctx);
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
index d954eda63134..950a001b1de7 100644
--- a/drivers/infiniband/core/device.c
+++ b/drivers/infiniband/core/device.c
@@ -2742,6 +2742,7 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)
SET_DEVICE_OP(dev_ops, create_ah);
SET_DEVICE_OP(dev_ops, create_counters);
SET_DEVICE_OP(dev_ops, create_cq);
+ SET_DEVICE_OP(dev_ops, create_comp_cntr);
SET_DEVICE_OP(dev_ops, create_user_cq);
SET_DEVICE_OP(dev_ops, create_flow);
SET_DEVICE_OP(dev_ops, create_qp);
@@ -2762,6 +2763,7 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)
SET_DEVICE_OP(dev_ops, destroy_ah);
SET_DEVICE_OP(dev_ops, destroy_counters);
SET_DEVICE_OP(dev_ops, destroy_cq);
+ SET_DEVICE_OP(dev_ops, destroy_comp_cntr);
SET_DEVICE_OP(dev_ops, destroy_flow);
SET_DEVICE_OP(dev_ops, destroy_flow_action);
SET_DEVICE_OP(dev_ops, destroy_qp);
@@ -2813,6 +2815,7 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)
SET_DEVICE_OP(dev_ops, modify_hw_stat);
SET_DEVICE_OP(dev_ops, modify_port);
SET_DEVICE_OP(dev_ops, modify_qp);
+ SET_DEVICE_OP(dev_ops, qp_attach_comp_cntr);
SET_DEVICE_OP(dev_ops, modify_srq);
SET_DEVICE_OP(dev_ops, modify_wq);
SET_DEVICE_OP(dev_ops, peek_cq);
@@ -2826,6 +2829,7 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)
SET_DEVICE_OP(dev_ops, post_srq_recv);
SET_DEVICE_OP(dev_ops, process_mad);
SET_DEVICE_OP(dev_ops, query_ah);
+ SET_DEVICE_OP(dev_ops, query_comp_cntr_caps);
SET_DEVICE_OP(dev_ops, query_device);
SET_DEVICE_OP(dev_ops, query_gid);
SET_DEVICE_OP(dev_ops, query_pkey);
@@ -2836,12 +2840,14 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)
SET_DEVICE_OP(dev_ops, query_ucontext);
SET_DEVICE_OP(dev_ops, rdma_netdev_get_params);
SET_DEVICE_OP(dev_ops, read_counters);
+ SET_DEVICE_OP(dev_ops, read_comp_cntr);
SET_DEVICE_OP(dev_ops, reg_dm_mr);
SET_DEVICE_OP(dev_ops, reg_user_mr);
SET_DEVICE_OP(dev_ops, reg_user_mr_dmabuf);
SET_DEVICE_OP(dev_ops, req_notify_cq);
SET_DEVICE_OP(dev_ops, rereg_user_mr);
SET_DEVICE_OP(dev_ops, resize_user_cq);
+ SET_DEVICE_OP(dev_ops, modify_comp_cntr);
SET_DEVICE_OP(dev_ops, set_vf_guid);
SET_DEVICE_OP(dev_ops, set_vf_link_state);
SET_DEVICE_OP(dev_ops, ufile_hw_cleanup);
@@ -2850,6 +2856,7 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops)
SET_OBJ_SIZE(dev_ops, ib_ah);
SET_OBJ_SIZE(dev_ops, ib_counters);
SET_OBJ_SIZE(dev_ops, ib_cq);
+ SET_OBJ_SIZE(dev_ops, ib_comp_cntr);
SET_OBJ_SIZE(dev_ops, ib_dmah);
SET_OBJ_SIZE(dev_ops, ib_mw);
SET_OBJ_SIZE(dev_ops, ib_pd);
diff --git a/drivers/infiniband/core/iwpm_msg.c b/drivers/infiniband/core/iwpm_msg.c
index 4625abd29ac0..1b10f2973ad9 100644
--- a/drivers/infiniband/core/iwpm_msg.c
+++ b/drivers/infiniband/core/iwpm_msg.c
@@ -268,7 +268,7 @@ int iwpm_add_and_query_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client)
if (ret)
goto query_mapping_error;
- /* If flags are required and we're not V4, then return a quite error */
+ /* If flags are required and we're not V4, then return a quiet error */
if (pm_msg->flags && iwpm_ulib_version == IWPM_UABI_VERSION_MIN) {
ret = -EINVAL;
goto query_mapping_error_nowarn;
diff --git a/drivers/infiniband/core/nldev.c b/drivers/infiniband/core/nldev.c
index 02a0a9c0a4a6..b4bae92c5c4e 100644
--- a/drivers/infiniband/core/nldev.c
+++ b/drivers/infiniband/core/nldev.c
@@ -188,6 +188,7 @@ static const struct nla_policy nldev_policy[RDMA_NLDEV_ATTR_MAX] = {
[RDMA_NLDEV_ATTR_FRMR_POOLS_AGING_PERIOD] = { .type = NLA_U32 },
[RDMA_NLDEV_ATTR_FRMR_POOL_PINNED_HANDLES] = { .type = NLA_U32 },
[RDMA_NLDEV_ATTR_FRMR_POOL_KEY_KERNEL_VENDOR_KEY] = { .type = NLA_U64 },
+ [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_MAX] = { .type = NLA_U64 },
};
static int put_driver_name_print_type(struct sk_buff *msg, const char *name,
@@ -413,7 +414,7 @@ out:
}
static int fill_res_info_entry(struct sk_buff *msg,
- const char *name, u64 curr)
+ const char *name, u64 curr, u64 max)
{
struct nlattr *entry_attr;
@@ -427,6 +428,9 @@ static int fill_res_info_entry(struct sk_buff *msg,
if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR, curr,
RDMA_NLDEV_ATTR_PAD))
goto err;
+ if (max && nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_MAX,
+ max, RDMA_NLDEV_ATTR_PAD))
+ goto err;
nla_nest_end(msg, entry_attr);
return 0;
@@ -447,10 +451,13 @@ static int fill_res_info(struct sk_buff *msg, struct ib_device *device,
[RDMA_RESTRACK_MR] = "mr",
[RDMA_RESTRACK_CTX] = "ctx",
[RDMA_RESTRACK_SRQ] = "srq",
+ [RDMA_RESTRACK_COMP_CNTR] = "comp_cntr",
};
+ struct ib_comp_cntr_caps comp_cntr_caps = {};
struct nlattr *table_attr;
- int ret, i, curr;
+ u64 curr, max;
+ int ret, i;
if (fill_nldev_handle(msg, device))
return -EMSGSIZE;
@@ -459,11 +466,36 @@ static int fill_res_info(struct sk_buff *msg, struct ib_device *device,
if (!table_attr)
return -EMSGSIZE;
+ if (device->ops.query_comp_cntr_caps)
+ device->ops.query_comp_cntr_caps(device, &comp_cntr_caps, NULL);
+
for (i = 0; i < RDMA_RESTRACK_MAX; i++) {
if (!names[i])
continue;
curr = rdma_restrack_count(device, i, show_details);
- ret = fill_res_info_entry(msg, names[i], curr);
+ switch (i) {
+ case RDMA_RESTRACK_QP:
+ max = device->attrs.max_qp;
+ break;
+ case RDMA_RESTRACK_CQ:
+ max = device->attrs.max_cq;
+ break;
+ case RDMA_RESTRACK_MR:
+ max = device->attrs.max_mr;
+ break;
+ case RDMA_RESTRACK_PD:
+ max = device->attrs.max_pd;
+ break;
+ case RDMA_RESTRACK_SRQ:
+ max = device->attrs.max_srq;
+ break;
+ case RDMA_RESTRACK_COMP_CNTR:
+ max = comp_cntr_caps.max_counters;
+ break;
+ default:
+ max = 0;
+ }
+ ret = fill_res_info_entry(msg, names[i], curr, max);
if (ret)
goto err;
}
@@ -2133,6 +2165,11 @@ static int nldev_stat_set_counter_dynamic_doit(struct nlattr *tb[],
nla_for_each_nested(entry_attr, tb[RDMA_NLDEV_ATTR_STAT_HWCOUNTERS],
rem) {
+ if (nla_len(entry_attr) != sizeof(u32)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
index = nla_get_u32(entry_attr);
if ((index >= stats->num_counters) ||
!(stats->descs[index].flags & IB_STAT_FLAG_OPTIONAL)) {
diff --git a/drivers/infiniband/core/rdma_core.h b/drivers/infiniband/core/rdma_core.h
index 56121103e9f4..2b91e8527287 100644
--- a/drivers/infiniband/core/rdma_core.h
+++ b/drivers/infiniband/core/rdma_core.h
@@ -159,6 +159,7 @@ void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile);
extern const struct uapi_definition uverbs_def_obj_async_fd[];
extern const struct uapi_definition uverbs_def_obj_counters[];
+extern const struct uapi_definition uverbs_def_obj_comp_cntr[];
extern const struct uapi_definition uverbs_def_obj_cq[];
extern const struct uapi_definition uverbs_def_obj_device[];
extern const struct uapi_definition uverbs_def_obj_dm[];
diff --git a/drivers/infiniband/core/restrack.c b/drivers/infiniband/core/restrack.c
index cfee2071586c..f89a81dad72f 100644
--- a/drivers/infiniband/core/restrack.c
+++ b/drivers/infiniband/core/restrack.c
@@ -61,7 +61,7 @@ void rdma_restrack_clean(struct ib_device *dev)
* @type: actual type of object to operate
* @show_details: count driver specific objects
*/
-int rdma_restrack_count(struct ib_device *dev, enum rdma_restrack_type type,
+u32 rdma_restrack_count(struct ib_device *dev, enum rdma_restrack_type type,
bool show_details)
{
struct rdma_restrack_root *rt = &dev->res[type];
@@ -104,6 +104,8 @@ static struct ib_device *res_to_dev(struct rdma_restrack_entry *res)
return container_of(res, struct ib_srq, res)->device;
case RDMA_RESTRACK_DMAH:
return container_of(res, struct ib_dmah, res)->device;
+ case RDMA_RESTRACK_COMP_CNTR:
+ return container_of(res, struct ib_comp_cntr, res)->device;
default:
WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type);
return NULL;
@@ -129,6 +131,46 @@ static void rdma_restrack_attach_task(struct rdma_restrack_entry *res,
res->user = true;
}
+static struct rdma_restrack_root *res_to_rt(struct rdma_restrack_entry *res)
+{
+ struct ib_device *dev = res_to_dev(res);
+
+ if (WARN_ON(!dev))
+ return NULL;
+
+ return &dev->res[res->type];
+}
+
+static void restrack_drain_res(struct rdma_restrack_root *rt,
+ struct rdma_restrack_entry *res)
+{
+ if (rt) {
+ struct rdma_restrack_entry *old;
+
+ old = xa_cmpxchg(&rt->xa, res->id, res, XA_ZERO_ENTRY,
+ GFP_KERNEL);
+ WARN_ON(old != res);
+ }
+
+ rdma_restrack_put(res);
+ wait_for_completion(&res->comp);
+}
+
+static void restrack_restore_res(struct rdma_restrack_root *rt,
+ struct rdma_restrack_entry *res)
+{
+ reinit_completion(&res->comp);
+ kref_init(&res->kref);
+
+ if (rt) {
+ struct rdma_restrack_entry *old;
+
+ old = xa_cmpxchg(&rt->xa, res->id, XA_ZERO_ENTRY, res,
+ GFP_KERNEL);
+ WARN_ON(old);
+ }
+}
+
/**
* rdma_restrack_set_name() - set the task for this resource
* @res: resource entry
@@ -177,22 +219,23 @@ void rdma_restrack_new(struct rdma_restrack_entry *res,
EXPORT_SYMBOL(rdma_restrack_new);
/**
- * rdma_restrack_add() - add object to the resource tracking database
+ * rdma_restrack_add() - add object to the resource tracking database.
+ * If this resource reuses an ID of a resource that was already destroyed
+ * after calling rdma_restrack_begin() but didn't yet call
+ * rdma_restrack_commit_del() it can result in an untracked QP.
* @res: resource entry
*/
void rdma_restrack_add(struct rdma_restrack_entry *res)
{
- struct ib_device *dev = res_to_dev(res);
struct rdma_restrack_root *rt;
int ret = 0;
- if (!dev)
- return;
-
if (res->no_track)
goto out;
- rt = &dev->res[res->type];
+ rt = res_to_rt(res);
+ if (!rt)
+ return;
if (res->type == RDMA_RESTRACK_QP) {
/* Special case to ensure that LQPN points to right QP */
@@ -229,6 +272,28 @@ out:
}
EXPORT_SYMBOL(rdma_restrack_add);
+/**
+ * rdma_restrack_abort_del() - re-add object to the resource tracking database
+ * it can only be used after rdma_restrack_begin_del().
+ * @res: resource entry
+ */
+void rdma_restrack_abort_del(struct rdma_restrack_entry *res)
+{
+ struct rdma_restrack_root *rt = NULL;
+
+ if (!res->valid)
+ return;
+
+ if (!res->no_track) {
+ rt = res_to_rt(res);
+ if (!rt)
+ return;
+ }
+
+ restrack_restore_res(rt, res);
+}
+EXPORT_SYMBOL(rdma_restrack_abort_del);
+
int __must_check rdma_restrack_get(struct rdma_restrack_entry *res)
{
return kref_get_unless_zero(&res->kref);
@@ -265,7 +330,7 @@ static void restrack_release(struct kref *kref)
struct rdma_restrack_entry *res;
res = container_of(kref, struct rdma_restrack_entry, kref);
- if (res->task) {
+ if (res->task && !res->valid) {
put_task_struct(res->task);
res->task = NULL;
}
@@ -291,37 +356,20 @@ EXPORT_SYMBOL(rdma_restrack_put);
*/
void rdma_restrack_sync(struct rdma_restrack_entry *res)
{
- struct rdma_restrack_entry *old;
struct rdma_restrack_root *rt;
- struct task_struct *task;
- struct ib_device *dev;
if (!res->valid || res->no_track)
return;
- dev = res_to_dev(res);
- if (WARN_ON(!dev))
+ rt = res_to_rt(res);
+ if (!rt)
return;
- rt = &dev->res[res->type];
if (WARN_ON(xa_get_mark(&rt->xa, res->id, RESTRACK_DD)))
return;
- old = xa_cmpxchg(&rt->xa, res->id, res, XA_ZERO_ENTRY, GFP_KERNEL);
- if (WARN_ON(old != res))
- return;
-
- task = res->task;
- if (task)
- get_task_struct(task);
- rdma_restrack_put(res);
- wait_for_completion(&res->comp);
- reinit_completion(&res->comp);
- if (task)
- res->task = task;
- kref_init(&res->kref);
-
- xa_cmpxchg(&rt->xa, res->id, XA_ZERO_ENTRY, res, GFP_KERNEL);
+ restrack_drain_res(rt, res);
+ restrack_restore_res(rt, res);
}
EXPORT_SYMBOL(rdma_restrack_sync);
@@ -333,7 +381,6 @@ void rdma_restrack_del(struct rdma_restrack_entry *res)
{
struct rdma_restrack_entry *old;
struct rdma_restrack_root *rt;
- struct ib_device *dev;
if (!res->valid) {
if (res->task) {
@@ -346,12 +393,10 @@ void rdma_restrack_del(struct rdma_restrack_entry *res)
if (res->no_track)
goto out;
- dev = res_to_dev(res);
- if (WARN_ON(!dev))
+ rt = res_to_rt(res);
+ if (!rt)
return;
- rt = &dev->res[res->type];
-
old = xa_erase(&rt->xa, res->id);
WARN_ON(old != res);
@@ -359,5 +404,61 @@ out:
res->valid = false;
rdma_restrack_put(res);
wait_for_completion(&res->comp);
+ if (res->task) {
+ put_task_struct(res->task);
+ res->task = NULL;
+ }
}
EXPORT_SYMBOL(rdma_restrack_del);
+
+/**
+ * rdma_restrack_begin_del() - invalidate the object from the resource tracking
+ * database but preserve its index in the array.
+ * Since this preserves the index in the array until rdma_restrack_commit_del()
+ * is called, if rdma_restrack_add() is called in between with an old QP ID it
+ * can result in an untracked QP.
+ * @res: resource entry
+ */
+void rdma_restrack_begin_del(struct rdma_restrack_entry *res)
+{
+ struct rdma_restrack_root *rt = NULL;
+
+ if (!res->valid)
+ return;
+
+ if (!res->no_track) {
+ rt = res_to_rt(res);
+ if (!rt)
+ return;
+ }
+
+ restrack_drain_res(rt, res);
+}
+EXPORT_SYMBOL(rdma_restrack_begin_del);
+
+/**
+ * rdma_restrack_commit_del() - delete object from the resource tracking
+ * database and free the task.
+ * @res: resource entry
+ */
+void rdma_restrack_commit_del(struct rdma_restrack_entry *res)
+{
+ struct rdma_restrack_root *rt;
+
+ if (!res->valid || res->no_track)
+ goto out;
+
+ rt = res_to_rt(res);
+ if (!rt)
+ return;
+
+ xa_erase(&rt->xa, res->id);
+
+out:
+ res->valid = false;
+ if (res->task) {
+ put_task_struct(res->task);
+ res->task = NULL;
+ }
+}
+EXPORT_SYMBOL(rdma_restrack_commit_del);
diff --git a/drivers/infiniband/core/restrack.h b/drivers/infiniband/core/restrack.h
index 75b8d1005a98..2df78e084e10 100644
--- a/drivers/infiniband/core/restrack.h
+++ b/drivers/infiniband/core/restrack.h
@@ -26,8 +26,11 @@ struct rdma_restrack_root {
int rdma_restrack_init(struct ib_device *dev);
void rdma_restrack_clean(struct ib_device *dev);
void rdma_restrack_add(struct rdma_restrack_entry *res);
+void rdma_restrack_abort_del(struct rdma_restrack_entry *res);
void rdma_restrack_del(struct rdma_restrack_entry *res);
void rdma_restrack_sync(struct rdma_restrack_entry *res);
+void rdma_restrack_begin_del(struct rdma_restrack_entry *res);
+void rdma_restrack_commit_del(struct rdma_restrack_entry *res);
void rdma_restrack_new(struct rdma_restrack_entry *res,
enum rdma_restrack_type type);
void rdma_restrack_set_name(struct rdma_restrack_entry *res,
diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
index 73498723a5d5..81f44dadfa52 100644
--- a/drivers/infiniband/core/umem.c
+++ b/drivers/infiniband/core/umem.c
@@ -209,7 +209,8 @@ static struct ib_umem *__ib_umem_get_va(struct ib_device *device,
mmgrab(mm);
- page_list = (struct page **) __get_free_page(GFP_KERNEL);
+ /* TODO: switch to "fast and as large as possible" allocation helper */
+ page_list = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!page_list) {
ret = -ENOMEM;
goto umem_kfree;
@@ -269,7 +270,7 @@ umem_release:
__ib_umem_release(device, umem, 0);
atomic64_sub(ib_umem_num_pages(umem), &mm->pinned_vm);
out:
- free_page((unsigned long) page_list);
+ kfree(page_list);
umem_kfree:
if (ret) {
mmdrop(umem->owning_mm);
diff --git a/drivers/infiniband/core/umem_dmabuf.c b/drivers/infiniband/core/umem_dmabuf.c
index ad023c2d84d8..39b5564a4c35 100644
--- a/drivers/infiniband/core/umem_dmabuf.c
+++ b/drivers/infiniband/core/umem_dmabuf.c
@@ -181,7 +181,7 @@ struct ib_umem_dmabuf *ib_umem_dmabuf_get(struct ib_device *device,
}
EXPORT_SYMBOL(ib_umem_dmabuf_get);
-static struct dma_buf_attach_ops ib_umem_dmabuf_attach_pinned_ops = {
+static const struct dma_buf_attach_ops ib_umem_dmabuf_attach_pinned_ops = {
.allow_peer2peer = true,
};
@@ -205,7 +205,7 @@ static void ib_umem_dmabuf_revoke_locked(struct dma_buf_attachment *attach)
umem_dmabuf->revoked = 1;
}
-static struct dma_buf_attach_ops ib_umem_dmabuf_attach_pinned_revocable_ops = {
+static const struct dma_buf_attach_ops ib_umem_dmabuf_attach_pinned_revocable_ops = {
.allow_peer2peer = true,
.invalidate_mappings = ib_umem_dmabuf_revoke_locked,
};
diff --git a/drivers/infiniband/core/uverbs_std_types_comp_cntr.c b/drivers/infiniband/core/uverbs_std_types_comp_cntr.c
new file mode 100644
index 000000000000..2e7de84d94a6
--- /dev/null
+++ b/drivers/infiniband/core/uverbs_std_types_comp_cntr.c
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All rights reserved.
+ */
+
+#include <rdma/uverbs_std_types.h>
+#include "rdma_core.h"
+#include "uverbs.h"
+#include "restrack.h"
+
+static int uverbs_free_comp_cntr(struct ib_uobject *uobject, enum rdma_remove_reason why,
+ struct uverbs_attr_bundle *attrs)
+{
+ struct ib_comp_cntr *cc = uobject->object;
+ int ret;
+
+ if (atomic_read(&cc->usecnt))
+ return -EBUSY;
+
+ rdma_restrack_begin_del(&cc->res);
+ ret = cc->device->ops.destroy_comp_cntr(cc);
+ if (ret) {
+ rdma_restrack_abort_del(&cc->res);
+ return ret;
+ }
+
+ rdma_restrack_commit_del(&cc->res);
+ kfree(cc);
+ return 0;
+}
+
+static int UVERBS_HANDLER(UVERBS_METHOD_COMP_CNTR_CREATE)(struct uverbs_attr_bundle *attrs)
+{
+ struct ib_uobject *uobj = uverbs_attr_get_uobject(attrs,
+ UVERBS_ATTR_CREATE_COMP_CNTR_HANDLE);
+ struct ib_device *ib_dev = attrs->context->device;
+ struct ib_comp_cntr *cc;
+ int ret;
+
+ if (!ib_dev->ops.create_comp_cntr ||
+ !ib_dev->ops.destroy_comp_cntr ||
+ !ib_dev->ops.qp_attach_comp_cntr)
+ return -EOPNOTSUPP;
+
+ cc = rdma_zalloc_drv_obj(ib_dev, ib_comp_cntr);
+ if (!cc)
+ return -ENOMEM;
+
+ cc->device = ib_dev;
+ cc->uobject = uobj;
+
+ rdma_restrack_new(&cc->res, RDMA_RESTRACK_COMP_CNTR);
+ rdma_restrack_set_name(&cc->res, NULL);
+
+ ret = ib_dev->ops.create_comp_cntr(cc, attrs);
+ if (ret)
+ goto err_free;
+
+ uobj->object = cc;
+ rdma_restrack_add(&cc->res);
+ uverbs_finalize_uobj_create(attrs, UVERBS_ATTR_CREATE_COMP_CNTR_HANDLE);
+ return 0;
+
+err_free:
+ rdma_restrack_put(&cc->res);
+ kfree(cc);
+ return ret;
+}
+
+static int UVERBS_HANDLER(UVERBS_METHOD_COMP_CNTR_MODIFY)(struct uverbs_attr_bundle *attrs)
+{
+ struct ib_comp_cntr *cc = uverbs_attr_get_obj(attrs, UVERBS_ATTR_MODIFY_COMP_CNTR_HANDLE);
+ enum ib_comp_cntr_modify_op op;
+ enum ib_comp_cntr_entry entry;
+ u64 value;
+ int ret;
+
+ if (!cc->device->ops.modify_comp_cntr)
+ return -EOPNOTSUPP;
+
+ ret = uverbs_get_const(&entry, attrs, UVERBS_ATTR_MODIFY_COMP_CNTR_ENTRY);
+ if (ret)
+ return ret;
+
+ ret = uverbs_get_const(&op, attrs, UVERBS_ATTR_MODIFY_COMP_CNTR_OP);
+ if (ret)
+ return ret;
+
+ ret = uverbs_copy_from(&value, attrs, UVERBS_ATTR_MODIFY_COMP_CNTR_VALUE);
+ if (ret)
+ return ret;
+
+ return cc->device->ops.modify_comp_cntr(cc, entry, op, value);
+}
+
+static int UVERBS_HANDLER(UVERBS_METHOD_COMP_CNTR_READ)(struct uverbs_attr_bundle *attrs)
+{
+ struct ib_comp_cntr *cc = uverbs_attr_get_obj(attrs, UVERBS_ATTR_READ_COMP_CNTR_HANDLE);
+ enum ib_comp_cntr_entry entry;
+ u64 value = 0;
+ int ret;
+
+ if (!cc->device->ops.read_comp_cntr)
+ return -EOPNOTSUPP;
+
+ ret = uverbs_get_const(&entry, attrs, UVERBS_ATTR_READ_COMP_CNTR_ENTRY);
+ if (ret)
+ return ret;
+
+ ret = cc->device->ops.read_comp_cntr(cc, entry, &value);
+ if (ret)
+ return ret;
+
+ return uverbs_copy_to(attrs, UVERBS_ATTR_READ_COMP_CNTR_RESP_VALUE, &value, sizeof(value));
+}
+
+DECLARE_UVERBS_NAMED_METHOD(
+ UVERBS_METHOD_COMP_CNTR_CREATE,
+ UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_COMP_CNTR_HANDLE,
+ UVERBS_OBJECT_COMP_CNTR,
+ UVERBS_ACCESS_NEW,
+ UA_MANDATORY));
+
+DECLARE_UVERBS_NAMED_METHOD_DESTROY(
+ UVERBS_METHOD_COMP_CNTR_DESTROY,
+ UVERBS_ATTR_IDR(UVERBS_ATTR_DESTROY_COMP_CNTR_HANDLE,
+ UVERBS_OBJECT_COMP_CNTR,
+ UVERBS_ACCESS_DESTROY,
+ UA_MANDATORY));
+
+DECLARE_UVERBS_NAMED_METHOD(
+ UVERBS_METHOD_COMP_CNTR_MODIFY,
+ UVERBS_ATTR_IDR(UVERBS_ATTR_MODIFY_COMP_CNTR_HANDLE,
+ UVERBS_OBJECT_COMP_CNTR,
+ UVERBS_ACCESS_WRITE,
+ UA_MANDATORY),
+ UVERBS_ATTR_CONST_IN(UVERBS_ATTR_MODIFY_COMP_CNTR_ENTRY,
+ enum ib_uverbs_comp_cntr_entry,
+ UA_MANDATORY),
+ UVERBS_ATTR_CONST_IN(UVERBS_ATTR_MODIFY_COMP_CNTR_OP,
+ enum ib_uverbs_comp_cntr_modify_op,
+ UA_MANDATORY),
+ UVERBS_ATTR_PTR_IN(UVERBS_ATTR_MODIFY_COMP_CNTR_VALUE,
+ UVERBS_ATTR_TYPE(u64),
+ UA_MANDATORY));
+
+DECLARE_UVERBS_NAMED_METHOD(
+ UVERBS_METHOD_COMP_CNTR_READ,
+ UVERBS_ATTR_IDR(UVERBS_ATTR_READ_COMP_CNTR_HANDLE,
+ UVERBS_OBJECT_COMP_CNTR,
+ UVERBS_ACCESS_READ,
+ UA_MANDATORY),
+ UVERBS_ATTR_CONST_IN(UVERBS_ATTR_READ_COMP_CNTR_ENTRY,
+ enum ib_uverbs_comp_cntr_entry,
+ UA_MANDATORY),
+ UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_READ_COMP_CNTR_RESP_VALUE,
+ UVERBS_ATTR_TYPE(u64),
+ UA_MANDATORY));
+
+DECLARE_UVERBS_NAMED_OBJECT(
+ UVERBS_OBJECT_COMP_CNTR,
+ UVERBS_TYPE_ALLOC_IDR(uverbs_free_comp_cntr),
+ &UVERBS_METHOD(UVERBS_METHOD_COMP_CNTR_CREATE),
+ &UVERBS_METHOD(UVERBS_METHOD_COMP_CNTR_DESTROY),
+ &UVERBS_METHOD(UVERBS_METHOD_COMP_CNTR_MODIFY),
+ &UVERBS_METHOD(UVERBS_METHOD_COMP_CNTR_READ));
+
+const struct uapi_definition uverbs_def_obj_comp_cntr[] = {
+ UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_COMP_CNTR,
+ UAPI_DEF_OBJ_NEEDS_FN(destroy_comp_cntr)),
+ {}
+};
diff --git a/drivers/infiniband/core/uverbs_std_types_device.c b/drivers/infiniband/core/uverbs_std_types_device.c
index 12ca15739cd2..ce0a7de00405 100644
--- a/drivers/infiniband/core/uverbs_std_types_device.c
+++ b/drivers/infiniband/core/uverbs_std_types_device.c
@@ -472,6 +472,42 @@ out:
return ret;
}
+static int UVERBS_HANDLER(UVERBS_METHOD_QUERY_COMP_CNTR_CAPS)(
+ struct uverbs_attr_bundle *attrs)
+{
+ struct ib_comp_cntr_caps caps = {};
+ struct ib_ucontext *ucontext;
+ struct ib_device *ib_dev;
+ int ret;
+
+ ucontext = ib_uverbs_get_ucontext(attrs);
+ if (IS_ERR(ucontext))
+ return PTR_ERR(ucontext);
+ ib_dev = ucontext->device;
+
+ if (!ib_dev->ops.query_comp_cntr_caps)
+ return -EOPNOTSUPP;
+
+ ret = ib_dev->ops.query_comp_cntr_caps(ib_dev, &caps, attrs);
+ if (ret)
+ return ret;
+
+ ret = uverbs_copy_to(attrs, UVERBS_ATTR_QUERY_COMP_CNTR_CAPS_MAX_COUNTERS,
+ &caps.max_counters, sizeof(caps.max_counters));
+ if (IS_UVERBS_COPY_ERR(ret))
+ return ret;
+
+ ret = uverbs_copy_to(attrs, UVERBS_ATTR_QUERY_COMP_CNTR_CAPS_MAX_VALUE,
+ &caps.max_value, sizeof(caps.max_value));
+ if (IS_UVERBS_COPY_ERR(ret))
+ return ret;
+
+ ret = uverbs_copy_to(attrs, UVERBS_ATTR_QUERY_COMP_CNTR_CAPS_SUPPORTED_QP_ATTACH_OPS,
+ &caps.supported_qp_attach_ops,
+ sizeof(caps.supported_qp_attach_ops));
+ return IS_UVERBS_COPY_ERR(ret) ? ret : 0;
+}
+
DECLARE_UVERBS_NAMED_METHOD(
UVERBS_METHOD_GET_CONTEXT,
UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_GET_CONTEXT_NUM_COMP_VECTORS,
@@ -542,6 +578,18 @@ DECLARE_UVERBS_NAMED_METHOD(
netdev_ifindex),
UA_MANDATORY));
+DECLARE_UVERBS_NAMED_METHOD(
+ UVERBS_METHOD_QUERY_COMP_CNTR_CAPS,
+ UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_QUERY_COMP_CNTR_CAPS_MAX_COUNTERS,
+ UVERBS_ATTR_TYPE(u32),
+ UA_OPTIONAL),
+ UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_QUERY_COMP_CNTR_CAPS_MAX_VALUE,
+ UVERBS_ATTR_TYPE(u64),
+ UA_OPTIONAL),
+ UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_QUERY_COMP_CNTR_CAPS_SUPPORTED_QP_ATTACH_OPS,
+ UVERBS_ATTR_TYPE(u32),
+ UA_OPTIONAL));
+
DECLARE_UVERBS_GLOBAL_METHODS(UVERBS_OBJECT_DEVICE,
&UVERBS_METHOD(UVERBS_METHOD_GET_CONTEXT),
&UVERBS_METHOD(UVERBS_METHOD_INVOKE_WRITE),
@@ -550,7 +598,8 @@ DECLARE_UVERBS_GLOBAL_METHODS(UVERBS_OBJECT_DEVICE,
&UVERBS_METHOD(UVERBS_METHOD_QUERY_PORT_SPEED),
&UVERBS_METHOD(UVERBS_METHOD_QUERY_CONTEXT),
&UVERBS_METHOD(UVERBS_METHOD_QUERY_GID_TABLE),
- &UVERBS_METHOD(UVERBS_METHOD_QUERY_GID_ENTRY));
+ &UVERBS_METHOD(UVERBS_METHOD_QUERY_GID_ENTRY),
+ &UVERBS_METHOD(UVERBS_METHOD_QUERY_COMP_CNTR_CAPS));
const struct uapi_definition uverbs_def_obj_device[] = {
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_DEVICE),
diff --git a/drivers/infiniband/core/uverbs_std_types_dmah.c b/drivers/infiniband/core/uverbs_std_types_dmah.c
index 97101e093826..9873ab49a601 100644
--- a/drivers/infiniband/core/uverbs_std_types_dmah.c
+++ b/drivers/infiniband/core/uverbs_std_types_dmah.c
@@ -18,11 +18,14 @@ static int uverbs_free_dmah(struct ib_uobject *uobject,
if (atomic_read(&dmah->usecnt))
return -EBUSY;
+ rdma_restrack_begin_del(&dmah->res);
ret = dmah->device->ops.dealloc_dmah(dmah, attrs);
- if (ret)
+ if (ret) {
+ rdma_restrack_abort_del(&dmah->res);
return ret;
+ }
- rdma_restrack_del(&dmah->res);
+ rdma_restrack_commit_del(&dmah->res);
kfree(dmah);
return 0;
}
diff --git a/drivers/infiniband/core/uverbs_std_types_mr.c b/drivers/infiniband/core/uverbs_std_types_mr.c
index 570b9656801d..0c72f801e0d3 100644
--- a/drivers/infiniband/core/uverbs_std_types_mr.c
+++ b/drivers/infiniband/core/uverbs_std_types_mr.c
@@ -364,7 +364,8 @@ static int UVERBS_HANDLER(UVERBS_METHOD_REG_MR)(
dmah, attrs);
else
mr = pd->device->ops.reg_user_mr(pd, addr, length, iova,
- access_flags, dmah, NULL);
+ access_flags, dmah,
+ &attrs->driver_udata);
if (IS_ERR(mr))
return PTR_ERR(mr);
@@ -527,7 +528,8 @@ DECLARE_UVERBS_NAMED_METHOD(
UA_MANDATORY),
UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_REG_MR_RESP_RKEY,
UVERBS_ATTR_TYPE(u32),
- UA_MANDATORY));
+ UA_MANDATORY),
+ UVERBS_ATTR_UHW());
DECLARE_UVERBS_NAMED_METHOD_DESTROY(
UVERBS_METHOD_MR_DESTROY,
diff --git a/drivers/infiniband/core/uverbs_std_types_qp.c b/drivers/infiniband/core/uverbs_std_types_qp.c
index 5767607dd420..30fc20fb251f 100644
--- a/drivers/infiniband/core/uverbs_std_types_qp.c
+++ b/drivers/infiniband/core/uverbs_std_types_qp.c
@@ -372,11 +372,76 @@ DECLARE_UVERBS_NAMED_METHOD(
UVERBS_ATTR_TYPE(struct ib_uverbs_destroy_qp_resp),
UA_MANDATORY));
+static int UVERBS_HANDLER(UVERBS_METHOD_QP_ATTACH_COMP_CNTR)(
+ struct uverbs_attr_bundle *attrs)
+{
+ struct ib_uobject *qp_uobj = uverbs_attr_get_uobject(
+ attrs, UVERBS_ATTR_QP_ATTACH_COMP_CNTR_HANDLE);
+ struct ib_comp_cntr *cc = uverbs_attr_get_obj(
+ attrs, UVERBS_ATTR_QP_ATTACH_COMP_CNTR_CNTR_HANDLE);
+ struct ib_qp_attach_comp_cntr_attr attr = {};
+ struct ib_qp *qp = qp_uobj->object;
+ int ret;
+
+ if (!cc->device->ops.qp_attach_comp_cntr)
+ return -EOPNOTSUPP;
+
+ if (qp->real_qp != qp)
+ return -EINVAL;
+
+ ret = uverbs_get_flags32(&attr.op_mask, attrs,
+ UVERBS_ATTR_QP_ATTACH_COMP_CNTR_OP_MASK,
+ IB_UVERBS_QP_ATTACH_COMP_CNTR_OP_SEND |
+ IB_UVERBS_QP_ATTACH_COMP_CNTR_OP_RECV |
+ IB_UVERBS_QP_ATTACH_COMP_CNTR_OP_RDMA_READ |
+ IB_UVERBS_QP_ATTACH_COMP_CNTR_OP_REMOTE_RDMA_READ |
+ IB_UVERBS_QP_ATTACH_COMP_CNTR_OP_RDMA_WRITE |
+ IB_UVERBS_QP_ATTACH_COMP_CNTR_OP_REMOTE_RDMA_WRITE);
+ if (ret)
+ return ret;
+
+ if (!attr.op_mask)
+ return -EINVAL;
+
+ if (attr.op_mask & qp->comp_cntr_op_mask)
+ return -EBUSY;
+
+ ret = xa_err(xa_store(&qp->comp_cntrs, attr.op_mask, cc, GFP_KERNEL));
+ if (ret)
+ return ret;
+
+ ret = qp->device->ops.qp_attach_comp_cntr(qp, cc, &attr);
+ if (ret) {
+ xa_erase(&qp->comp_cntrs, attr.op_mask);
+ return ret;
+ }
+
+ atomic_inc(&cc->usecnt);
+ qp->comp_cntr_op_mask |= attr.op_mask;
+
+ return 0;
+}
+
+DECLARE_UVERBS_NAMED_METHOD(
+ UVERBS_METHOD_QP_ATTACH_COMP_CNTR,
+ UVERBS_ATTR_IDR(UVERBS_ATTR_QP_ATTACH_COMP_CNTR_HANDLE,
+ UVERBS_OBJECT_QP,
+ UVERBS_ACCESS_WRITE,
+ UA_MANDATORY),
+ UVERBS_ATTR_IDR(UVERBS_ATTR_QP_ATTACH_COMP_CNTR_CNTR_HANDLE,
+ UVERBS_OBJECT_COMP_CNTR,
+ UVERBS_ACCESS_READ,
+ UA_MANDATORY),
+ UVERBS_ATTR_FLAGS_IN(UVERBS_ATTR_QP_ATTACH_COMP_CNTR_OP_MASK,
+ enum ib_uverbs_qp_attach_comp_cntr_op,
+ UA_MANDATORY));
+
DECLARE_UVERBS_NAMED_OBJECT(
UVERBS_OBJECT_QP,
UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_uqp_object), uverbs_free_qp),
&UVERBS_METHOD(UVERBS_METHOD_QP_CREATE),
- &UVERBS_METHOD(UVERBS_METHOD_QP_DESTROY));
+ &UVERBS_METHOD(UVERBS_METHOD_QP_DESTROY),
+ &UVERBS_METHOD(UVERBS_METHOD_QP_ATTACH_COMP_CNTR));
const struct uapi_definition uverbs_def_obj_qp[] = {
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_QP,
diff --git a/drivers/infiniband/core/uverbs_uapi.c b/drivers/infiniband/core/uverbs_uapi.c
index 4e2e556c8119..d150099b99d2 100644
--- a/drivers/infiniband/core/uverbs_uapi.c
+++ b/drivers/infiniband/core/uverbs_uapi.c
@@ -628,6 +628,7 @@ void uverbs_destroy_api(struct uverbs_api *uapi)
static const struct uapi_definition uverbs_core_api[] = {
UAPI_DEF_CHAIN(uverbs_def_obj_async_fd),
UAPI_DEF_CHAIN(uverbs_def_obj_counters),
+ UAPI_DEF_CHAIN(uverbs_def_obj_comp_cntr),
UAPI_DEF_CHAIN(uverbs_def_obj_cq),
UAPI_DEF_CHAIN(uverbs_def_obj_device),
UAPI_DEF_CHAIN(uverbs_def_obj_dm),
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index 86811d31092c..04abc80c1327 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -392,6 +392,7 @@ int ib_dealloc_pd_user(struct ib_pd *pd, struct ib_udata *udata)
{
int ret;
+ rdma_restrack_begin_del(&pd->res);
if (pd->__internal_mr) {
ret = pd->device->ops.dereg_mr(pd->__internal_mr, NULL);
WARN_ON(ret);
@@ -399,10 +400,12 @@ int ib_dealloc_pd_user(struct ib_pd *pd, struct ib_udata *udata)
}
ret = pd->device->ops.dealloc_pd(pd, udata);
- if (ret)
+ if (ret) {
+ rdma_restrack_abort_del(&pd->res);
return ret;
+ }
- rdma_restrack_del(&pd->res);
+ rdma_restrack_commit_del(&pd->res);
kfree(pd);
return ret;
}
@@ -1140,16 +1143,20 @@ int ib_destroy_srq_user(struct ib_srq *srq, struct ib_udata *udata)
if (atomic_read(&srq->usecnt))
return -EBUSY;
+ rdma_restrack_begin_del(&srq->res);
+
ret = srq->device->ops.destroy_srq(srq, udata);
- if (ret)
+ if (ret) {
+ rdma_restrack_abort_del(&srq->res);
return ret;
+ }
atomic_dec(&srq->pd->usecnt);
if (srq->srq_type == IB_SRQT_XRC && srq->ext.xrc.xrcd)
atomic_dec(&srq->ext.xrc.xrcd->usecnt);
if (ib_srq_has_cq(srq->srq_type))
atomic_dec(&srq->ext.cq->usecnt);
- rdma_restrack_del(&srq->res);
+ rdma_restrack_commit_del(&srq->res);
kfree(srq);
return ret;
@@ -1293,6 +1300,7 @@ static struct ib_qp *create_qp(struct ib_device *dev, struct ib_pd *pd,
qp->qp_context = attr->qp_context;
spin_lock_init(&qp->mr_lock);
+ xa_init(&qp->comp_cntrs);
INIT_LIST_HEAD(&qp->rdma_mrs);
INIT_LIST_HEAD(&qp->sig_mrs);
init_completion(&qp->srq_completion);
@@ -1327,6 +1335,7 @@ err_security:
qp, uattrs ? uverbs_get_cleared_udata(uattrs) : NULL);
err_create:
rdma_restrack_put(&qp->res);
+ xa_destroy(&qp->comp_cntrs);
kfree(qp);
return ERR_PTR(ret);
@@ -2144,6 +2153,8 @@ int ib_destroy_qp_user(struct ib_qp *qp, struct ib_udata *udata)
const struct ib_gid_attr *alt_path_sgid_attr = qp->alt_path_sgid_attr;
const struct ib_gid_attr *av_sgid_attr = qp->av_sgid_attr;
struct ib_qp_security *sec;
+ struct ib_comp_cntr *cc;
+ unsigned long index;
int ret;
WARN_ON_ONCE(qp->mrs_used > 0);
@@ -2154,6 +2165,8 @@ int ib_destroy_qp_user(struct ib_qp *qp, struct ib_udata *udata)
if (qp->real_qp != qp)
return __ib_destroy_shared_qp(qp);
+ rdma_restrack_begin_del(&qp->res);
+
sec = qp->qp_sec;
if (sec)
ib_destroy_qp_security_begin(sec);
@@ -2166,6 +2179,7 @@ int ib_destroy_qp_user(struct ib_qp *qp, struct ib_udata *udata)
if (ret) {
if (sec)
ib_destroy_qp_security_abort(sec);
+ rdma_restrack_abort_del(&qp->res);
return ret;
}
@@ -2174,11 +2188,15 @@ int ib_destroy_qp_user(struct ib_qp *qp, struct ib_udata *udata)
if (av_sgid_attr)
rdma_put_gid_attr(av_sgid_attr);
+ xa_for_each(&qp->comp_cntrs, index, cc)
+ atomic_dec(&cc->usecnt);
+ xa_destroy(&qp->comp_cntrs);
+
ib_qp_usecnt_dec(qp);
if (sec)
ib_destroy_qp_security_end(sec);
- rdma_restrack_del(&qp->res);
+ rdma_restrack_commit_del(&qp->res);
kfree(qp);
return ret;
}
@@ -2244,11 +2262,15 @@ int ib_destroy_cq_user(struct ib_cq *cq, struct ib_udata *udata)
if (atomic_read(&cq->usecnt))
return -EBUSY;
+ rdma_restrack_begin_del(&cq->res);
+
ret = cq->device->ops.destroy_cq(cq, udata);
- if (ret)
+ if (ret) {
+ rdma_restrack_abort_del(&cq->res);
return ret;
+ }
- rdma_restrack_del(&cq->res);
+ rdma_restrack_commit_del(&cq->res);
kfree(cq);
return ret;
}
diff --git a/drivers/infiniband/hw/bng_re/bng_fw.c b/drivers/infiniband/hw/bng_re/bng_fw.c
index 50156c300b33..ab6a2d2e95b5 100644
--- a/drivers/infiniband/hw/bng_re/bng_fw.c
+++ b/drivers/infiniband/hw/bng_re/bng_fw.c
@@ -401,14 +401,15 @@ static int __wait_for_resp(struct bng_re_rcfw *rcfw, u16 cookie)
{
struct bng_re_cmdq_ctx *cmdq;
struct bng_re_crsqe *crsqe;
+ unsigned long time_left;
cmdq = &rcfw->cmdq;
crsqe = &rcfw->crsqe_tbl[cookie];
do {
- wait_event_timeout(cmdq->waitq,
- !crsqe->is_in_used,
- secs_to_jiffies(rcfw->max_timeout));
+ time_left = wait_event_timeout(cmdq->waitq,
+ !crsqe->is_in_used,
+ secs_to_jiffies(rcfw->max_timeout));
if (!crsqe->is_in_used)
return 0;
@@ -417,6 +418,9 @@ static int __wait_for_resp(struct bng_re_rcfw *rcfw, u16 cookie)
if (!crsqe->is_in_used)
return 0;
+
+ if (!time_left)
+ return -ENODEV;
} while (true);
};
diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
index 565762529007..a2a354a0fbef 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
@@ -193,7 +193,6 @@ int bnxt_re_query_device(struct ib_device *ibdev,
if (rc)
return rc;
- memset(ib_attr, 0, sizeof(*ib_attr));
memcpy(&ib_attr->fw_ver, dev_attr->fw_ver,
min(sizeof(dev_attr->fw_ver),
sizeof(ib_attr->fw_ver)));
@@ -695,7 +694,7 @@ int bnxt_re_dealloc_pd(struct ib_pd *ib_pd, struct ib_udata *udata)
struct bnxt_re_dev *rdev = pd->rdev;
int ret;
- ret = ib_is_udata_in_empty(udata);
+ ret = ib_no_udata_io(udata);
if (ret)
return ret;
@@ -712,7 +711,7 @@ int bnxt_re_dealloc_pd(struct ib_pd *ib_pd, struct ib_udata *udata)
&pd->qplib_pd))
atomic_dec(&rdev->stats.res.pd_count);
}
- return ib_respond_empty_udata(udata);
+ return 0;
}
int bnxt_re_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
@@ -844,7 +843,7 @@ int bnxt_re_create_ah(struct ib_ah *ib_ah, struct rdma_ah_init_attr *init_attr,
u8 nw_type;
int rc;
- rc = ib_is_udata_in_empty(udata);
+ rc = ib_no_udata_io(udata);
if (rc)
return rc;
@@ -901,7 +900,7 @@ int bnxt_re_create_ah(struct ib_ah *ib_ah, struct rdma_ah_init_attr *init_attr,
if (active_ahs > rdev->stats.res.ah_watermark)
rdev->stats.res.ah_watermark = active_ahs;
- return ib_respond_empty_udata(udata);
+ return 0;
}
int bnxt_re_query_ah(struct ib_ah *ib_ah, struct rdma_ah_attr *ah_attr)
@@ -1015,7 +1014,7 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata)
unsigned int flags;
int rc;
- rc = ib_is_udata_in_empty(udata);
+ rc = ib_no_udata_io(udata);
if (rc)
return rc;
@@ -1064,7 +1063,7 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata)
if (scq_nq != rcq_nq)
bnxt_re_synchronize_nq(rcq_nq);
- return ib_respond_empty_udata(udata);
+ return 0;
}
static u8 __from_ib_qp_type(enum ib_qp_type type)
@@ -2148,7 +2147,7 @@ int bnxt_re_destroy_srq(struct ib_srq *ib_srq, struct ib_udata *udata)
struct bnxt_qplib_srq *qplib_srq = &srq->qplib_srq;
int ret;
- ret = ib_is_udata_in_empty(udata);
+ ret = ib_no_udata_io(udata);
if (ret)
return ret;
@@ -2159,7 +2158,7 @@ int bnxt_re_destroy_srq(struct ib_srq *ib_srq, struct ib_udata *udata)
free_page((unsigned long)srq->uctx_srq_page);
ib_umem_release(srq->umem);
atomic_dec(&rdev->stats.res.srq_count);
- return ib_respond_empty_udata(udata);
+ return 0;
}
static int bnxt_re_init_user_srq(struct bnxt_re_dev *rdev,
@@ -2297,34 +2296,25 @@ int bnxt_re_modify_srq(struct ib_srq *ib_srq, struct ib_srq_attr *srq_attr,
{
struct bnxt_re_srq *srq = container_of(ib_srq, struct bnxt_re_srq,
ib_srq);
- struct bnxt_re_dev *rdev = srq->rdev;
int ret;
- ret = ib_is_udata_in_empty(udata);
+ ret = ib_no_udata_io(udata);
if (ret)
return ret;
- switch (srq_attr_mask) {
- case IB_SRQ_MAX_WR:
- /* SRQ resize is not supported */
+ if (srq_attr_mask != IB_SRQ_LIMIT)
return -EINVAL;
- case IB_SRQ_LIMIT:
- /* Change the SRQ threshold */
- if (srq_attr->srq_limit > srq->qplib_srq.max_wqe)
- return -EINVAL;
-
- srq->qplib_srq.threshold = srq_attr->srq_limit;
- bnxt_qplib_srq_arm_db(&srq->qplib_srq.dbinfo, srq->qplib_srq.threshold);
- /* On success, update the shadow */
- srq->srq_limit = srq_attr->srq_limit;
- /* No need to Build and send response back to udata */
- return ib_respond_empty_udata(udata);
- default:
- ibdev_err(&rdev->ibdev,
- "Unsupported srq_attr_mask 0x%x", srq_attr_mask);
+ if (srq_attr->srq_limit > srq->qplib_srq.max_wqe)
return -EINVAL;
- }
+
+ srq->qplib_srq.threshold = srq_attr->srq_limit;
+ bnxt_qplib_srq_arm_db(&srq->qplib_srq.dbinfo, srq->qplib_srq.threshold);
+
+ /* On success, update the shadow */
+ srq->srq_limit = srq_attr->srq_limit;
+ /* No need to Build and send response back to udata */
+ return 0;
}
int bnxt_re_query_srq(struct ib_srq *ib_srq, struct ib_srq_attr *srq_attr)
@@ -2437,7 +2427,7 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr,
unsigned int flags;
u8 nw_type;
- rc = ib_is_udata_in_empty(udata);
+ rc = ib_no_udata_io(udata);
if (rc)
return rc;
@@ -2689,7 +2679,7 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr,
if (rc)
return rc;
}
- return ib_respond_empty_udata(udata);
+ return 0;
}
int bnxt_re_query_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr,
@@ -3471,7 +3461,7 @@ int bnxt_re_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
nq = cq->qplib_cq.nq;
cctx = rdev->chip_ctx;
- ret = ib_is_udata_in_empty(udata);
+ ret = ib_no_udata_io(udata);
if (ret)
return ret;
@@ -3486,7 +3476,7 @@ int bnxt_re_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
atomic_dec(&rdev->stats.res.cq_count);
kfree(cq->cql);
ib_umem_release(cq->umem);
- return ib_respond_empty_udata(udata);
+ return 0;
}
int bnxt_re_create_user_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
@@ -3688,6 +3678,10 @@ int bnxt_re_resize_cq(struct ib_cq *ibcq, unsigned int cqe,
if (rc)
goto fail;
+ rc = ib_respond_empty_udata(udata);
+ if (rc)
+ goto fail;
+
cq->resize_umem = ib_umem_get_va(&rdev->ibdev, req.cq_va,
entries * sizeof(struct cq_base),
IB_ACCESS_LOCAL_WRITE);
@@ -3717,7 +3711,7 @@ int bnxt_re_resize_cq(struct ib_cq *ibcq, unsigned int cqe,
cq->ib_cq.cqe = cq->resize_cqe;
atomic_inc(&rdev->stats.res.resize_count);
- return ib_respond_empty_udata(udata);
+ return 0;
fail:
if (cq->resize_umem) {
@@ -4449,7 +4443,7 @@ int bnxt_re_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata)
struct bnxt_re_dev *rdev = mr->rdev;
int rc;
- rc = ib_is_udata_in_empty(udata);
+ rc = ib_no_udata_io(udata);
if (rc)
return rc;
@@ -4472,7 +4466,7 @@ int bnxt_re_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata)
atomic_dec(&rdev->stats.res.mr_count);
if (rc)
return rc;
- return ib_respond_empty_udata(udata);
+ return 0;
}
static int bnxt_re_set_page(struct ib_mr *ib_mr, u64 addr)
@@ -4991,11 +4985,13 @@ int bnxt_re_mmap(struct ib_ucontext *ib_uctx, struct vm_area_struct *vma)
case BNXT_RE_MMAP_DBR_PAGE:
case BNXT_RE_MMAP_TOGGLE_PAGE:
/* Driver doesn't expect write access for user space */
- if (vma->vm_flags & VM_WRITE)
+ if (vma->vm_flags & VM_WRITE) {
ret = -EFAULT;
- else
+ } else {
+ vm_flags_clear(vma, VM_MAYWRITE);
ret = vm_insert_page(vma, vma->vm_start,
virt_to_page((void *)bnxt_entry->mem_offset));
+ }
break;
default:
ret = -EINVAL;
diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c
index cd1b01014198..49498c75f38f 100644
--- a/drivers/infiniband/hw/cxgb4/mem.c
+++ b/drivers/infiniband/hw/cxgb4/mem.c
@@ -541,7 +541,7 @@ struct ib_mr *c4iw_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
if (err)
goto err_umem_release;
- pages = (__be64 *) __get_free_page(GFP_KERNEL);
+ pages = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!pages) {
err = -ENOMEM;
goto err_pbl_free;
@@ -568,7 +568,7 @@ struct ib_mr *c4iw_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
mhp->wr_waitp);
pbl_done:
- free_page((unsigned long) pages);
+ kfree(pages);
if (err)
goto err_pbl_free;
diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c
index e1eec37ee822..ebe3170a641c 100644
--- a/drivers/infiniband/hw/cxgb4/provider.c
+++ b/drivers/infiniband/hw/cxgb4/provider.c
@@ -263,7 +263,7 @@ static int c4iw_query_device(struct ib_device *ibdev, struct ib_device_attr *pro
pr_debug("ibdev %p\n", ibdev);
- err = ib_is_udata_in_empty(uhw);
+ err = ib_no_udata_io(uhw);
if (err)
return err;
@@ -300,7 +300,7 @@ static int c4iw_query_device(struct ib_device *ibdev, struct ib_device_attr *pro
props->max_fast_reg_page_list_len =
t4_max_fr_depth(dev->rdev.lldi.ulptx_memwrite_dsgl && use_dsgl);
- return ib_respond_empty_udata(uhw);
+ return 0;
}
static int c4iw_query_port(struct ib_device *ibdev, u32 port,
diff --git a/drivers/infiniband/hw/efa/Makefile b/drivers/infiniband/hw/efa/Makefile
index 6e83083af0bc..a6a433b0ba2f 100644
--- a/drivers/infiniband/hw/efa/Makefile
+++ b/drivers/infiniband/hw/efa/Makefile
@@ -1,9 +1,9 @@
# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
-# Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All rights reserved.
+# Copyright 2018-2026 Amazon.com, Inc. or its affiliates. All rights reserved.
#
# Makefile for Amazon Elastic Fabric Adapter (EFA) device driver.
#
obj-$(CONFIG_INFINIBAND_EFA) += efa.o
-efa-y := efa_com_cmd.o efa_com.o efa_main.o efa_verbs.o
+efa-y := efa_com_cmd.o efa_ah_cache.o efa_com.o efa_main.o efa_verbs.o
diff --git a/drivers/infiniband/hw/efa/efa.h b/drivers/infiniband/hw/efa/efa.h
index f4586bb170c1..6f6686eefb1a 100644
--- a/drivers/infiniband/hw/efa/efa.h
+++ b/drivers/infiniband/hw/efa/efa.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
/*
- * Copyright 2018-2025 Amazon.com, Inc. or its affiliates. All rights reserved.
+ * Copyright 2018-2026 Amazon.com, Inc. or its affiliates. All rights reserved.
*/
#ifndef _EFA_H_
@@ -110,6 +110,14 @@ struct efa_cq {
struct ib_umem *umem;
};
+struct efa_comp_cntr {
+ struct ib_comp_cntr ibcc;
+ struct ib_umem *comp_umem;
+ struct ib_umem *err_umem;
+ u32 comp_handle;
+ u32 err_handle;
+};
+
struct efa_qp {
struct ib_qp ibqp;
dma_addr_t rq_dma_addr;
@@ -164,6 +172,16 @@ int efa_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *init_attr,
int efa_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata);
int efa_create_user_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
struct uverbs_attr_bundle *attrs);
+int efa_query_comp_cntr_caps(struct ib_device *ibdev,
+ struct ib_comp_cntr_caps *caps,
+ struct uverbs_attr_bundle *attrs);
+int efa_create_comp_cntr(struct ib_comp_cntr *ibcc,
+ struct uverbs_attr_bundle *attrs);
+int efa_destroy_comp_cntr(struct ib_comp_cntr *ibcc);
+int efa_modify_comp_cntr(struct ib_comp_cntr *ibcc, enum ib_comp_cntr_entry entry,
+ enum ib_comp_cntr_modify_op op, u64 value);
+int efa_qp_attach_comp_cntr(struct ib_qp *ibqp, struct ib_comp_cntr *ibcc,
+ struct ib_qp_attach_comp_cntr_attr *attr);
struct ib_mr *efa_reg_mr(struct ib_pd *ibpd, u64 start, u64 length,
u64 virt_addr, int access_flags,
struct ib_dmah *dmah,
diff --git a/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h b/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h
index 826790ca9d83..fc07213e26af 100644
--- a/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h
+++ b/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h
@@ -28,7 +28,13 @@ enum efa_admin_aq_opcode {
EFA_ADMIN_CREATE_EQ = 18,
EFA_ADMIN_DESTROY_EQ = 19,
EFA_ADMIN_ALLOC_MR = 20,
- EFA_ADMIN_MAX_OPCODE = 20,
+ EFA_ADMIN_SERVICE = 21,
+ EFA_ADMIN_CREATE_EVENT_COUNTER = 25,
+ EFA_ADMIN_DESTROY_EVENT_COUNTER = 26,
+ EFA_ADMIN_ATTACH_EVENT_COUNTER = 27,
+ EFA_ADMIN_MODIFY_EVENT_COUNTER = 28,
+ EFA_ADMIN_DETACH_EVENT_COUNTER = 29,
+ EFA_ADMIN_MAX_OPCODE = 29,
};
enum efa_admin_aq_feature_id {
@@ -367,10 +373,10 @@ struct efa_admin_reg_mr_cmd {
/*
* flags and page size
- * 4:0 : phys_page_size_shift - page size is (1 <<
+ * 5:0 : phys_page_size_shift - page size is (1 <<
* phys_page_size_shift). Page size is used for
* building the Virtual to Physical address mapping
- * 6:5 : reserved - MBZ
+ * 6 : reserved - MBZ
* 7 : mem_addr_phy_mode_en - Enable bit for physical
* memory registration (no translation), can be used
* only by privileged clients. If set, PBL must
@@ -722,7 +728,9 @@ struct efa_admin_feature_device_attr_desc {
* on TX queues
* 4 : unsolicited_write_recv - If set, unsolicited
* write with imm. receive is supported
- * 31:5 : reserved - MBZ
+ * 5 : event_counters - If set, event counters are
+ * supported
+ * 31:6 : reserved - MBZ
*/
u32 device_caps;
@@ -811,6 +819,34 @@ struct efa_admin_feature_queue_attr_desc_1 {
struct efa_admin_feature_queue_attr_desc_2 {
/* Maximum size of data that can be sent inline in a Send WQE */
u16 inline_buf_size_ex;
+
+ /* MBZ */
+ u8 reserved[6];
+
+ /*
+ * Supported counter QP events
+ * 0 : send_comp
+ * 1 : send_comp_err
+ * 2 : recv_comp
+ * 3 : recv_comp_err
+ * 4 : read_comp
+ * 5 : read_comp_err
+ * 6 : write_comp
+ * 7 : write_comp_err
+ * 8 : remote_read_comp
+ * 9 : remote_write_comp
+ * 31:10 : reserved - MBZ
+ */
+ u32 supported_event_counter_qp_events;
+
+ /* Maximum number of counters */
+ u32 max_event_counters;
+
+ /*
+ * Maximum counter value, counter wraps around to 0 after reaching
+ * this value
+ */
+ u64 event_counter_max_val;
};
struct efa_admin_event_queue_attr_desc {
@@ -1089,6 +1125,127 @@ struct efa_admin_host_info {
u32 flags;
};
+struct efa_admin_service_cmd {
+ struct efa_admin_aq_common_desc aq_common_descriptor;
+
+ u8 buffer[60];
+};
+
+struct efa_admin_service_resp {
+ struct efa_admin_acq_common_desc acq_common_desc;
+
+ u8 buffer[56];
+};
+
+/* Create Counter command */
+struct efa_admin_create_event_counter_cmd {
+ struct efa_admin_aq_common_desc aq_common_descriptor;
+
+ /* UAR number */
+ u16 uar;
+
+ /* MBZ */
+ u16 reserved;
+
+ /* Counter physical address */
+ u64 paddr;
+};
+
+struct efa_admin_create_event_counter_resp {
+ struct efa_admin_acq_common_desc acq_common_desc;
+
+ /* Counter handle */
+ u32 cntr_handle;
+
+ /* MBZ */
+ u32 reserved;
+};
+
+struct efa_admin_destroy_event_counter_cmd {
+ struct efa_admin_aq_common_desc aq_common_descriptor;
+
+ /* Counter handle */
+ u32 cntr_handle;
+};
+
+struct efa_admin_destroy_event_counter_resp {
+ struct efa_admin_acq_common_desc acq_common_desc;
+};
+
+enum efa_admin_event_counter_attach_type {
+ EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS = 0,
+};
+
+struct efa_admin_event_counter_attach_qp_events {
+ /* QP handle */
+ u32 qp_handle;
+
+ /*
+ * Bitmask of counter QP events
+ * 0 : send_comp
+ * 1 : send_comp_err
+ * 2 : recv_comp
+ * 3 : recv_comp_err
+ * 4 : read_comp
+ * 5 : read_comp_err
+ * 6 : write_comp
+ * 7 : write_comp_err
+ * 8 : remote_read_comp
+ * 9 : remote_write_comp
+ * 31:10 : reserved - MBZ
+ */
+ u32 events;
+};
+
+struct efa_admin_attach_detach_event_counter_cmd {
+ struct efa_admin_aq_common_desc aq_common_descriptor;
+
+ /* Counter handle */
+ u32 cntr_handle;
+
+ /* efa_admin_event_counter_attach_type */
+ u8 attach_type;
+
+ /* MBZ */
+ u8 reserved[3];
+
+ union {
+ struct efa_admin_event_counter_attach_qp_events qp_events;
+ } u;
+};
+
+struct efa_admin_attach_detach_event_counter_resp {
+ struct efa_admin_acq_common_desc acq_common_desc;
+};
+
+/* Counter modify operations */
+enum efa_admin_event_counter_modify_ops {
+ /* Set counter value */
+ EFA_ADMIN_EVENT_COUNTER_MODIFY_SET = 0,
+ /* Add to counter value */
+ EFA_ADMIN_EVENT_COUNTER_MODIFY_ADD = 1,
+};
+
+struct efa_admin_modify_event_counter_cmd {
+ struct efa_admin_aq_common_desc aq_common_descriptor;
+
+ /* Counter handle */
+ u32 cntr_handle;
+
+ /* Counter operation type (efa_admin_event_counter_modify_ops) */
+ u8 operation;
+
+ /* MBZ */
+ u8 reserved[7];
+
+ /* Value for SET or ADD */
+ u64 value;
+};
+
+struct efa_admin_modify_event_counter_resp {
+ struct efa_admin_acq_common_desc acq_common_desc;
+};
+
/* create_qp_cmd */
#define EFA_ADMIN_CREATE_QP_CMD_SQ_VIRT_MASK BIT(0)
#define EFA_ADMIN_CREATE_QP_CMD_RQ_VIRT_MASK BIT(1)
@@ -1103,7 +1260,7 @@ struct efa_admin_host_info {
#define EFA_ADMIN_MODIFY_QP_CMD_RNR_RETRY_MASK BIT(5)
/* reg_mr_cmd */
-#define EFA_ADMIN_REG_MR_CMD_PHYS_PAGE_SIZE_SHIFT_MASK GENMASK(4, 0)
+#define EFA_ADMIN_REG_MR_CMD_PHYS_PAGE_SIZE_SHIFT_MASK GENMASK(5, 0)
#define EFA_ADMIN_REG_MR_CMD_MEM_ADDR_PHY_MODE_EN_MASK BIT(7)
#define EFA_ADMIN_REG_MR_CMD_LOCAL_WRITE_ENABLE_MASK BIT(0)
#define EFA_ADMIN_REG_MR_CMD_REMOTE_WRITE_ENABLE_MASK BIT(1)
@@ -1129,6 +1286,19 @@ struct efa_admin_host_info {
#define EFA_ADMIN_FEATURE_DEVICE_ATTR_DESC_DATA_POLLING_128_MASK BIT(2)
#define EFA_ADMIN_FEATURE_DEVICE_ATTR_DESC_RDMA_WRITE_MASK BIT(3)
#define EFA_ADMIN_FEATURE_DEVICE_ATTR_DESC_UNSOLICITED_WRITE_RECV_MASK BIT(4)
+#define EFA_ADMIN_FEATURE_DEVICE_ATTR_DESC_EVENT_COUNTERS_MASK BIT(5)
+
+/* feature_queue_attr_desc_2 */
+#define EFA_ADMIN_FEATURE_QUEUE_ATTR_DESC_2_SEND_COMP_MASK BIT(0)
+#define EFA_ADMIN_FEATURE_QUEUE_ATTR_DESC_2_SEND_COMP_ERR_MASK BIT(1)
+#define EFA_ADMIN_FEATURE_QUEUE_ATTR_DESC_2_RECV_COMP_MASK BIT(2)
+#define EFA_ADMIN_FEATURE_QUEUE_ATTR_DESC_2_RECV_COMP_ERR_MASK BIT(3)
+#define EFA_ADMIN_FEATURE_QUEUE_ATTR_DESC_2_READ_COMP_MASK BIT(4)
+#define EFA_ADMIN_FEATURE_QUEUE_ATTR_DESC_2_READ_COMP_ERR_MASK BIT(5)
+#define EFA_ADMIN_FEATURE_QUEUE_ATTR_DESC_2_WRITE_COMP_MASK BIT(6)
+#define EFA_ADMIN_FEATURE_QUEUE_ATTR_DESC_2_WRITE_COMP_ERR_MASK BIT(7)
+#define EFA_ADMIN_FEATURE_QUEUE_ATTR_DESC_2_REMOTE_READ_COMP_MASK BIT(8)
+#define EFA_ADMIN_FEATURE_QUEUE_ATTR_DESC_2_REMOTE_WRITE_COMP_MASK BIT(9)
/* create_eq_cmd */
#define EFA_ADMIN_CREATE_EQ_CMD_ENTRY_SIZE_WORDS_MASK GENMASK(4, 0)
@@ -1147,4 +1317,16 @@ struct efa_admin_host_info {
#define EFA_ADMIN_HOST_INFO_INTREE_MASK BIT(0)
#define EFA_ADMIN_HOST_INFO_GDR_MASK BIT(1)
+/* counter_attach_qp_events */
+#define EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_SEND_COMP_MASK BIT(0)
+#define EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_SEND_COMP_ERR_MASK BIT(1)
+#define EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_RECV_COMP_MASK BIT(2)
+#define EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_RECV_COMP_ERR_MASK BIT(3)
+#define EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_READ_COMP_MASK BIT(4)
+#define EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_READ_COMP_ERR_MASK BIT(5)
+#define EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_WRITE_COMP_MASK BIT(6)
+#define EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_WRITE_COMP_ERR_MASK BIT(7)
+#define EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_REMOTE_READ_COMP_MASK BIT(8)
+#define EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_REMOTE_WRITE_COMP_MASK BIT(9)
+
#endif /* _EFA_ADMIN_CMDS_H_ */
diff --git a/drivers/infiniband/hw/efa/efa_ah_cache.c b/drivers/infiniband/hw/efa/efa_ah_cache.c
new file mode 100644
index 000000000000..6219529fa889
--- /dev/null
+++ b/drivers/infiniband/hw/efa/efa_ah_cache.c
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/*
+ * Copyright 2026 Amazon.com, Inc. or its affiliates. All rights reserved.
+ */
+
+#include <linux/slab.h>
+
+#include "efa_ah_cache.h"
+
+static const struct rhashtable_params ah_cache_params = {
+ .key_len = sizeof(struct efa_ah_cache_key),
+ .key_offset = offsetof(struct efa_ah_cache_entry, key),
+ .head_offset = offsetof(struct efa_ah_cache_entry, linkage),
+};
+
+int efa_ah_cache_init(struct efa_ah_cache *ah_cache)
+{
+ int err;
+
+ mutex_init(&ah_cache->lock);
+ err = rhashtable_init(&ah_cache->hashtable, &ah_cache_params);
+ if (err)
+ mutex_destroy(&ah_cache->lock);
+
+ return err;
+}
+
+static void efa_ah_cache_entry_free(void *ptr, void *arg)
+{
+ struct efa_ah_cache_entry *entry = ptr;
+
+ WARN_ON(entry->usecnt);
+ mutex_destroy(&entry->lock);
+ kfree(entry);
+}
+
+void efa_ah_cache_destroy(struct efa_ah_cache *ah_cache)
+{
+ rhashtable_free_and_destroy(&ah_cache->hashtable, efa_ah_cache_entry_free, NULL);
+ mutex_destroy(&ah_cache->lock);
+}
+
+static struct efa_ah_cache_entry *efa_ah_cache_lookup_locked(struct efa_ah_cache *ah_cache, u16 pd,
+ u8 *gid)
+ __must_hold(&ah_cache->lock)
+{
+ struct efa_ah_cache_key key = {};
+
+ memcpy(key.gid, gid, sizeof(key.gid));
+ key.pd = pd;
+
+ return rhashtable_lookup_fast(&ah_cache->hashtable, &key, ah_cache_params);
+}
+
+struct efa_ah_cache_entry *efa_ah_cache_lookup(struct efa_ah_cache *ah_cache, u16 pd, u8 *gid)
+{
+ struct efa_ah_cache_entry *entry;
+
+ mutex_lock(&ah_cache->lock);
+ entry = efa_ah_cache_lookup_locked(ah_cache, pd, gid);
+ mutex_unlock(&ah_cache->lock);
+
+ return entry;
+}
+
+/**
+ * efa_ah_cache_get - Get or create an AH cache entry
+ * @ah_cache: AH cache
+ * @pd: Protection domain number
+ * @gid: GID address
+ *
+ * Look up an AH cache entry by PD and GID. If found, take a reference and
+ * return it. If not found, allocate a new entry and insert it. The caller must lock
+ * the entry mutex and check usecnt to determine whether a device create
+ * command is needed.
+ *
+ * Return: Pointer to the entry on success, ERR_PTR on failure.
+ */
+struct efa_ah_cache_entry *efa_ah_cache_get(struct efa_ah_cache *ah_cache, u16 pd, u8 *gid)
+{
+ struct efa_ah_cache_entry *entry;
+ int err;
+
+ mutex_lock(&ah_cache->lock);
+
+ entry = efa_ah_cache_lookup_locked(ah_cache, pd, gid);
+ if (entry) {
+ refcount_inc(&entry->refcount);
+ mutex_unlock(&ah_cache->lock);
+ return entry;
+ }
+
+ entry = kzalloc_obj(*entry);
+ if (!entry) {
+ mutex_unlock(&ah_cache->lock);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ memcpy(entry->key.gid, gid, sizeof(entry->key.gid));
+ entry->key.pd = pd;
+ refcount_set(&entry->refcount, 1);
+ mutex_init(&entry->lock);
+
+ err = rhashtable_insert_fast(&ah_cache->hashtable, &entry->linkage, ah_cache_params);
+ if (err) {
+ mutex_destroy(&entry->lock);
+ kfree(entry);
+ mutex_unlock(&ah_cache->lock);
+ return ERR_PTR(err);
+ }
+
+ mutex_unlock(&ah_cache->lock);
+ return entry;
+}
+
+/**
+ * efa_ah_cache_put - Put a refcount of an AH cache entry
+ * @ah_cache: AH cache
+ * @entry: AH cache entry
+ *
+ * Drop the refcount. If it reaches zero, remove the entry from the hashtable
+ * and free it.
+ */
+void efa_ah_cache_put(struct efa_ah_cache *ah_cache, struct efa_ah_cache_entry *entry)
+{
+ if (!refcount_dec_and_mutex_lock(&entry->refcount, &ah_cache->lock))
+ return;
+
+ /* AH cache lock is held here */
+ rhashtable_remove_fast(&ah_cache->hashtable, &entry->linkage, ah_cache_params);
+ mutex_unlock(&ah_cache->lock);
+
+ mutex_destroy(&entry->lock);
+ kfree(entry);
+}
diff --git a/drivers/infiniband/hw/efa/efa_ah_cache.h b/drivers/infiniband/hw/efa/efa_ah_cache.h
new file mode 100644
index 000000000000..e7cdcbb64070
--- /dev/null
+++ b/drivers/infiniband/hw/efa/efa_ah_cache.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/*
+ * Copyright 2026 Amazon.com, Inc. or its affiliates. All rights reserved.
+ */
+
+#ifndef _EFA_AH_CACHE_H_
+#define _EFA_AH_CACHE_H_
+
+#include <linux/refcount.h>
+#include <linux/rhashtable.h>
+
+#define EFA_AH_GID_SIZE 16
+
+struct efa_ah_cache_key {
+ u8 gid[EFA_AH_GID_SIZE];
+ u16 pd;
+};
+
+struct efa_ah_cache_entry {
+ struct efa_ah_cache_key key;
+ u16 ah;
+ unsigned int usecnt;
+ refcount_t refcount;
+ struct rhash_head linkage;
+ struct mutex lock; /* Serializes device commands per cache entry */
+};
+
+struct efa_ah_cache {
+ struct rhashtable hashtable;
+ struct mutex lock; /* Protects AH cache hashtable */
+};
+
+int efa_ah_cache_init(struct efa_ah_cache *ah_cache);
+void efa_ah_cache_destroy(struct efa_ah_cache *ah_cache);
+struct efa_ah_cache_entry *efa_ah_cache_get(struct efa_ah_cache *ah_cache, u16 pd, u8 *gid);
+struct efa_ah_cache_entry *efa_ah_cache_lookup(struct efa_ah_cache *ah_cache, u16 pd, u8 *gid);
+void efa_ah_cache_put(struct efa_ah_cache *ah_cache, struct efa_ah_cache_entry *entry);
+
+#endif /* _EFA_AH_CACHE_H_ */
diff --git a/drivers/infiniband/hw/efa/efa_com.c b/drivers/infiniband/hw/efa/efa_com.c
index 7cc3f4af0bb9..7097d1c2f23d 100644
--- a/drivers/infiniband/hw/efa/efa_com.c
+++ b/drivers/infiniband/hw/efa/efa_com.c
@@ -724,6 +724,8 @@ void efa_com_admin_destroy(struct efa_com_dev *edev)
size = aenq->depth * sizeof(*aenq->entries);
dma_free_coherent(edev->dmadev, size, aenq->entries, aenq->dma_addr);
+
+ efa_ah_cache_destroy(&edev->ah_cache);
}
/**
@@ -782,6 +784,12 @@ int efa_com_admin_init(struct efa_com_dev *edev,
return -ENODEV;
}
+ err = efa_ah_cache_init(&edev->ah_cache);
+ if (err) {
+ ibdev_err(edev->efa_dev, "Failed to init AH cache\n");
+ return err;
+ }
+
aq->depth = EFA_ADMIN_QUEUE_DEPTH;
aq->dmadev = edev->dmadev;
@@ -794,7 +802,7 @@ int efa_com_admin_init(struct efa_com_dev *edev,
err = efa_com_init_comp_ctxt(aq);
if (err)
- return err;
+ goto err_destroy_ah_cache;
err = efa_com_admin_init_sq(edev);
if (err)
@@ -832,6 +840,8 @@ err_destroy_sq:
aq->sq.entries, aq->sq.dma_addr);
err_destroy_comp_ctxt:
devm_kfree(edev->dmadev, aq->comp_ctx);
+err_destroy_ah_cache:
+ efa_ah_cache_destroy(&edev->ah_cache);
return err;
}
diff --git a/drivers/infiniband/hw/efa/efa_com.h b/drivers/infiniband/hw/efa/efa_com.h
index f8c692b0e092..599db9d583bf 100644
--- a/drivers/infiniband/hw/efa/efa_com.h
+++ b/drivers/infiniband/hw/efa/efa_com.h
@@ -14,6 +14,7 @@
#include <rdma/ib_verbs.h>
+#include "efa_ah_cache.h"
#include "efa_common_defs.h"
#include "efa_admin_defs.h"
#include "efa_admin_cmds_defs.h"
@@ -113,6 +114,8 @@ struct efa_com_dev {
u32 supported_features;
u32 dma_addr_bits;
+ struct efa_ah_cache ah_cache;
+
u32 dev_api_ver;
struct efa_com_mmio_read mmio_read;
};
diff --git a/drivers/infiniband/hw/efa/efa_com_cmd.c b/drivers/infiniband/hw/efa/efa_com_cmd.c
index 5db4f5805b59..a9fd44b4debf 100644
--- a/drivers/infiniband/hw/efa/efa_com_cmd.c
+++ b/drivers/infiniband/hw/efa/efa_com_cmd.c
@@ -322,8 +322,21 @@ int efa_com_create_ah(struct efa_com_dev *edev,
struct efa_admin_create_ah_resp cmd_completion;
struct efa_com_admin_queue *aq = &edev->aq;
struct efa_admin_create_ah_cmd ah_cmd = {};
+ struct efa_ah_cache_entry *entry;
int err;
+ entry = efa_ah_cache_get(&edev->ah_cache, params->pdn, params->dest_addr);
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
+
+ mutex_lock(&entry->lock);
+ if (entry->usecnt) {
+ result->ah = entry->ah;
+ entry->usecnt++;
+ mutex_unlock(&entry->lock);
+ return 0;
+ }
+
ah_cmd.aq_common_desc.opcode = EFA_ADMIN_CREATE_AH;
memcpy(ah_cmd.dest_addr, params->dest_addr, sizeof(ah_cmd.dest_addr));
@@ -335,13 +348,18 @@ int efa_com_create_ah(struct efa_com_dev *edev,
(struct efa_admin_acq_entry *)&cmd_completion,
sizeof(cmd_completion));
if (err) {
+ mutex_unlock(&entry->lock);
+ efa_ah_cache_put(&edev->ah_cache, entry);
ibdev_err_ratelimited(edev->efa_dev,
"Failed to create ah for %pI6 [%d]\n",
ah_cmd.dest_addr, err);
return err;
}
+ entry->ah = cmd_completion.ah;
result->ah = cmd_completion.ah;
+ entry->usecnt++;
+ mutex_unlock(&entry->lock);
return 0;
}
@@ -352,11 +370,20 @@ int efa_com_destroy_ah(struct efa_com_dev *edev,
struct efa_admin_destroy_ah_resp cmd_completion;
struct efa_admin_destroy_ah_cmd ah_cmd = {};
struct efa_com_admin_queue *aq = &edev->aq;
- int err;
+ struct efa_ah_cache_entry *entry;
+ int err = 0;
+
+ entry = efa_ah_cache_lookup(&edev->ah_cache, params->pdn, params->gid);
+ if (!entry)
+ return -EINVAL;
+
+ mutex_lock(&entry->lock);
+ if (entry->usecnt > 1)
+ goto out_put;
ah_cmd.aq_common_desc.opcode = EFA_ADMIN_DESTROY_AH;
- ah_cmd.ah = params->ah;
- ah_cmd.pd = params->pdn;
+ ah_cmd.ah = entry->ah;
+ ah_cmd.pd = entry->key.pd;
err = efa_com_cmd_exec(aq,
(struct efa_admin_aq_entry *)&ah_cmd,
@@ -364,13 +391,19 @@ int efa_com_destroy_ah(struct efa_com_dev *edev,
(struct efa_admin_acq_entry *)&cmd_completion,
sizeof(cmd_completion));
if (err) {
+ mutex_unlock(&entry->lock);
ibdev_err_ratelimited(edev->efa_dev,
"Failed to destroy ah-%d pd-%d [%d]\n",
ah_cmd.ah, ah_cmd.pd, err);
return err;
}
- return 0;
+out_put:
+ entry->usecnt--;
+ mutex_unlock(&entry->lock);
+ efa_ah_cache_put(&edev->ah_cache, entry);
+
+ return err;
}
bool
@@ -520,6 +553,10 @@ int efa_com_get_device_attr(struct efa_com_dev *edev,
}
result->inline_buf_size_ex = resp.u.queue_attr_2.inline_buf_size_ex;
+ result->max_event_counters = resp.u.queue_attr_2.max_event_counters;
+ result->event_counter_max_val = resp.u.queue_attr_2.event_counter_max_val;
+ result->supported_event_counter_qp_events =
+ resp.u.queue_attr_2.supported_event_counter_qp_events;
} else {
result->inline_buf_size_ex = result->inline_buf_size;
}
@@ -855,3 +892,135 @@ int efa_com_get_stats(struct efa_com_dev *edev,
return 0;
}
+
+int efa_com_create_event_counter(struct efa_com_dev *edev,
+ struct efa_com_create_event_counter_params *params,
+ struct efa_com_create_event_counter_result *result)
+{
+ struct efa_admin_create_event_counter_cmd cmd = {};
+ struct efa_admin_create_event_counter_resp resp;
+ struct efa_com_admin_queue *aq = &edev->aq;
+ int err;
+
+ cmd.aq_common_descriptor.opcode = EFA_ADMIN_CREATE_EVENT_COUNTER;
+ cmd.uar = params->uarn;
+ cmd.paddr = params->dma_addr;
+
+ err = efa_com_cmd_exec(aq, (struct efa_admin_aq_entry *)&cmd,
+ sizeof(cmd),
+ (struct efa_admin_acq_entry *)&resp,
+ sizeof(resp));
+ if (err) {
+ ibdev_err_ratelimited(edev->efa_dev,
+ "Failed to create event counter [%d]\n",
+ err);
+ return err;
+ }
+
+ result->cntr_handle = resp.cntr_handle;
+ return 0;
+}
+
+int efa_com_destroy_event_counter(struct efa_com_dev *edev,
+ struct efa_com_destroy_event_counter_params *params)
+{
+ struct efa_admin_destroy_event_counter_cmd cmd = {};
+ struct efa_admin_destroy_event_counter_resp resp;
+ struct efa_com_admin_queue *aq = &edev->aq;
+ int err;
+
+ cmd.aq_common_descriptor.opcode = EFA_ADMIN_DESTROY_EVENT_COUNTER;
+ cmd.cntr_handle = params->cntr_handle;
+
+ err = efa_com_cmd_exec(aq, (struct efa_admin_aq_entry *)&cmd,
+ sizeof(cmd),
+ (struct efa_admin_acq_entry *)&resp,
+ sizeof(resp));
+ if (err) {
+ ibdev_err_ratelimited(edev->efa_dev,
+ "Failed to destroy event counter [%d]\n",
+ err);
+ return err;
+ }
+
+ return 0;
+}
+
+static int efa_com_attach_detach_event_counter(struct efa_com_dev *edev, u8 opcode,
+ u32 cntr_handle, u32 qp_handle,
+ u32 events)
+{
+ struct efa_admin_attach_detach_event_counter_cmd cmd = {};
+ struct efa_admin_attach_detach_event_counter_resp resp;
+ struct efa_com_admin_queue *aq = &edev->aq;
+ int err;
+
+ cmd.aq_common_descriptor.opcode = opcode;
+ cmd.cntr_handle = cntr_handle;
+ cmd.attach_type = EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS;
+ cmd.u.qp_events.qp_handle = qp_handle;
+ cmd.u.qp_events.events = events;
+
+ err = efa_com_cmd_exec(aq, (struct efa_admin_aq_entry *)&cmd,
+ sizeof(cmd),
+ (struct efa_admin_acq_entry *)&resp,
+ sizeof(resp));
+ if (err) {
+ ibdev_err_ratelimited(edev->efa_dev,
+ "Failed to %s event counter [%d]\n",
+ opcode == EFA_ADMIN_ATTACH_EVENT_COUNTER
+ ? "attach"
+ : "detach",
+ err);
+ return err;
+ }
+
+ return 0;
+}
+
+int efa_com_attach_event_counter(struct efa_com_dev *edev,
+ struct efa_com_attach_event_counter_params *params)
+{
+ return efa_com_attach_detach_event_counter(edev,
+ EFA_ADMIN_ATTACH_EVENT_COUNTER,
+ params->cntr_handle,
+ params->qp_handle,
+ params->events);
+}
+
+int efa_com_detach_event_counter(struct efa_com_dev *edev,
+ struct efa_com_detach_event_counter_params *params)
+{
+ return efa_com_attach_detach_event_counter(edev,
+ EFA_ADMIN_DETACH_EVENT_COUNTER,
+ params->cntr_handle,
+ params->qp_handle,
+ params->events);
+}
+
+int efa_com_modify_event_counter(struct efa_com_dev *edev,
+ struct efa_com_modify_event_counter_params *params)
+{
+ struct efa_admin_modify_event_counter_cmd cmd = {};
+ struct efa_admin_modify_event_counter_resp resp;
+ struct efa_com_admin_queue *aq = &edev->aq;
+ int err;
+
+ cmd.aq_common_descriptor.opcode = EFA_ADMIN_MODIFY_EVENT_COUNTER;
+ cmd.cntr_handle = params->cntr_handle;
+ cmd.operation = params->operation;
+ cmd.value = params->value;
+
+ err = efa_com_cmd_exec(aq, (struct efa_admin_aq_entry *)&cmd,
+ sizeof(cmd),
+ (struct efa_admin_acq_entry *)&resp,
+ sizeof(resp));
+ if (err) {
+ ibdev_err_ratelimited(edev->efa_dev,
+ "Failed to modify event counter [%d]\n",
+ err);
+ return err;
+ }
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/efa/efa_com_cmd.h b/drivers/infiniband/hw/efa/efa_com_cmd.h
index ef15b3c38429..3e7380fa0abb 100644
--- a/drivers/infiniband/hw/efa/efa_com_cmd.h
+++ b/drivers/infiniband/hw/efa/efa_com_cmd.h
@@ -106,6 +106,7 @@ struct efa_com_create_ah_result {
struct efa_com_destroy_ah_params {
u16 ah;
+ u8 gid[EFA_GID_SIZE];
u16 pdn;
};
@@ -145,6 +146,9 @@ struct efa_com_get_device_attr_result {
u16 min_sq_depth;
u16 max_link_speed_gbps;
u8 db_bar;
+ u32 max_event_counters;
+ u64 event_counter_max_val;
+ u32 supported_event_counter_qp_events;
};
struct efa_com_get_hw_hints_result {
@@ -300,6 +304,37 @@ union efa_com_get_stats_result {
struct efa_com_network_stats network_stats;
};
+struct efa_com_create_event_counter_params {
+ dma_addr_t dma_addr;
+ u16 uarn;
+};
+
+struct efa_com_create_event_counter_result {
+ u32 cntr_handle;
+};
+
+struct efa_com_destroy_event_counter_params {
+ u32 cntr_handle;
+};
+
+struct efa_com_attach_event_counter_params {
+ u32 cntr_handle;
+ u32 qp_handle;
+ u32 events;
+};
+
+struct efa_com_detach_event_counter_params {
+ u32 cntr_handle;
+ u32 qp_handle;
+ u32 events;
+};
+
+struct efa_com_modify_event_counter_params {
+ u32 cntr_handle;
+ u8 operation;
+ u64 value;
+};
+
int efa_com_create_qp(struct efa_com_dev *edev,
struct efa_com_create_qp_params *params,
struct efa_com_create_qp_result *res);
@@ -350,5 +385,16 @@ int efa_com_dealloc_uar(struct efa_com_dev *edev,
int efa_com_get_stats(struct efa_com_dev *edev,
struct efa_com_get_stats_params *params,
union efa_com_get_stats_result *result);
+int efa_com_create_event_counter(struct efa_com_dev *edev,
+ struct efa_com_create_event_counter_params *params,
+ struct efa_com_create_event_counter_result *result);
+int efa_com_destroy_event_counter(struct efa_com_dev *edev,
+ struct efa_com_destroy_event_counter_params *params);
+int efa_com_attach_event_counter(struct efa_com_dev *edev,
+ struct efa_com_attach_event_counter_params *params);
+int efa_com_detach_event_counter(struct efa_com_dev *edev,
+ struct efa_com_detach_event_counter_params *params);
+int efa_com_modify_event_counter(struct efa_com_dev *edev,
+ struct efa_com_modify_event_counter_params *params);
#endif /* _EFA_COM_CMD_H_ */
diff --git a/drivers/infiniband/hw/efa/efa_io_defs.h b/drivers/infiniband/hw/efa/efa_io_defs.h
index a4c9fd33da38..a849d92a6eb6 100644
--- a/drivers/infiniband/hw/efa/efa_io_defs.h
+++ b/drivers/infiniband/hw/efa/efa_io_defs.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
/*
- * Copyright 2018-2024 Amazon.com, Inc. or its affiliates. All rights reserved.
+ * Copyright 2018-2026 Amazon.com, Inc. or its affiliates. All rights reserved.
*/
#ifndef _EFA_IO_H_
@@ -65,6 +65,8 @@ enum efa_io_comp_status {
EFA_IO_COMP_STATUS_REMOTE_ERROR_UNKNOWN_PEER = 14,
/* Unreachable remote - never received a response */
EFA_IO_COMP_STATUS_LOCAL_ERROR_UNREACH_REMOTE = 15,
+ /* Remote feature mismatch */
+ EFA_IO_COMP_STATUS_REMOTE_ERROR_FEATURE_MISMATCH = 18,
};
enum efa_io_frwr_pbl_mode {
@@ -72,6 +74,11 @@ enum efa_io_frwr_pbl_mode {
EFA_IO_FRWR_DIRECT_PBL = 1,
};
+enum efa_io_processing_hint {
+ /* Optimize for throughput */
+ EFA_IO_PROCESSING_HINT_BURST_PPS_SENSITIVE = 1 << 0,
+};
+
struct efa_io_tx_meta_desc {
/* Verbs-generated Request ID */
u16 req_id;
@@ -121,7 +128,15 @@ struct efa_io_tx_meta_desc {
u16 ah;
- u16 reserved;
+ /*
+ * control flags
+ * 1:0 : processing_hints - Bitmask of enum
+ * efa_io_processing_hint
+ * 7:2 : reserved - MBZ
+ */
+ u8 ctrl3;
+
+ u8 reserved;
/* Queue key */
u32 qkey;
@@ -365,6 +380,7 @@ struct efa_io_rx_cdesc_ex {
#define EFA_IO_TX_META_DESC_FIRST_MASK BIT(2)
#define EFA_IO_TX_META_DESC_LAST_MASK BIT(3)
#define EFA_IO_TX_META_DESC_COMP_REQ_MASK BIT(4)
+#define EFA_IO_TX_META_DESC_PROCESSING_HINTS_MASK GENMASK(1, 0)
/* tx_buf_desc */
#define EFA_IO_TX_BUF_DESC_LKEY_MASK GENMASK(23, 0)
diff --git a/drivers/infiniband/hw/efa/efa_main.c b/drivers/infiniband/hw/efa/efa_main.c
index 97da8e828e34..4cd80727dcd2 100644
--- a/drivers/infiniband/hw/efa/efa_main.c
+++ b/drivers/infiniband/hw/efa/efa_main.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
/*
- * Copyright 2018-2025 Amazon.com, Inc. or its affiliates. All rights reserved.
+ * Copyright 2018-2026 Amazon.com, Inc. or its affiliates. All rights reserved.
*/
#include <linux/module.h>
@@ -17,12 +17,14 @@
#define PCI_DEV_ID_EFA1_VF 0xefa1
#define PCI_DEV_ID_EFA2_VF 0xefa2
#define PCI_DEV_ID_EFA3_VF 0xefa3
+#define PCI_DEV_ID_EFA4_VF 0xefa4
static const struct pci_device_id efa_pci_tbl[] = {
{ PCI_VDEVICE(AMAZON, PCI_DEV_ID_EFA0_VF) },
{ PCI_VDEVICE(AMAZON, PCI_DEV_ID_EFA1_VF) },
{ PCI_VDEVICE(AMAZON, PCI_DEV_ID_EFA2_VF) },
{ PCI_VDEVICE(AMAZON, PCI_DEV_ID_EFA3_VF) },
+ { PCI_VDEVICE(AMAZON, PCI_DEV_ID_EFA4_VF) },
{ }
};
@@ -372,20 +374,25 @@ static const struct ib_device_ops efa_dev_ops = {
.alloc_pd = efa_alloc_pd,
.alloc_ucontext = efa_alloc_ucontext,
.create_user_cq = efa_create_user_cq,
+ .create_comp_cntr = efa_create_comp_cntr,
.create_qp = efa_create_qp,
.create_user_ah = efa_create_ah,
.dealloc_pd = efa_dealloc_pd,
.dealloc_ucontext = efa_dealloc_ucontext,
.dereg_mr = efa_dereg_mr,
.destroy_ah = efa_destroy_ah,
+ .destroy_comp_cntr = efa_destroy_comp_cntr,
.destroy_cq = efa_destroy_cq,
.destroy_qp = efa_destroy_qp,
.get_hw_stats = efa_get_hw_stats,
.get_link_layer = efa_port_link_layer,
.get_port_immutable = efa_get_port_immutable,
+ .modify_comp_cntr = efa_modify_comp_cntr,
.mmap = efa_mmap,
.mmap_free = efa_mmap_free,
.modify_qp = efa_modify_qp,
+ .qp_attach_comp_cntr = efa_qp_attach_comp_cntr,
+ .query_comp_cntr_caps = efa_query_comp_cntr_caps,
.query_device = efa_query_device,
.query_gid = efa_query_gid,
.query_pkey = efa_query_pkey,
@@ -397,6 +404,7 @@ static const struct ib_device_ops efa_dev_ops = {
INIT_RDMA_OBJ_SIZE(ib_ah, efa_ah, ibah),
INIT_RDMA_OBJ_SIZE(ib_cq, efa_cq, ibcq),
+ INIT_RDMA_OBJ_SIZE(ib_comp_cntr, efa_comp_cntr, ibcc),
INIT_RDMA_OBJ_SIZE(ib_pd, efa_pd, ibpd),
INIT_RDMA_OBJ_SIZE(ib_qp, efa_qp, ibqp),
INIT_RDMA_OBJ_SIZE(ib_ucontext, efa_ucontext, ibucontext),
diff --git a/drivers/infiniband/hw/efa/efa_verbs.c b/drivers/infiniband/hw/efa/efa_verbs.c
index 06d3365aeb56..9bc8199b60bf 100644
--- a/drivers/infiniband/hw/efa/efa_verbs.c
+++ b/drivers/infiniband/hw/efa/efa_verbs.c
@@ -167,6 +167,11 @@ static inline struct efa_ah *to_eah(struct ib_ah *ibah)
return container_of(ibah, struct efa_ah, ibah);
}
+static inline struct efa_comp_cntr *to_ecc(struct ib_comp_cntr *ibcc)
+{
+ return container_of(ibcc, struct efa_comp_cntr, ibcc);
+}
+
static inline struct efa_user_mmap_entry *
to_emmap(struct rdma_user_mmap_entry *rdma_entry)
{
@@ -222,7 +227,6 @@ int efa_query_device(struct ib_device *ibdev,
dev_attr = &dev->dev_attr;
- memset(props, 0, sizeof(*props));
props->max_mr_size = dev_attr->max_mr_pages * PAGE_SIZE;
props->page_size_cap = dev_attr->page_size_cap;
props->vendor_id = dev->pdev->vendor;
@@ -265,6 +269,9 @@ int efa_query_device(struct ib_device *ibdev,
if (EFA_DEV_CAP(dev, UNSOLICITED_WRITE_RECV))
resp.device_caps |= EFA_QUERY_DEVICE_CAPS_UNSOLICITED_WRITE_RECV;
+ if (EFA_DEV_CAP(dev, EVENT_COUNTERS))
+ resp.device_caps |= EFA_QUERY_DEVICE_CAPS_COMP_CNTR;
+
if (dev->neqs)
resp.device_caps |= EFA_QUERY_DEVICE_CAPS_CQ_NOTIFICATIONS;
@@ -2054,10 +2061,11 @@ int efa_mmap(struct ib_ucontext *ibucontext,
static int efa_ah_destroy(struct efa_dev *dev, struct efa_ah *ah)
{
- struct efa_com_destroy_ah_params params = {
- .ah = ah->ah,
- .pdn = to_epd(ah->ibah.pd)->pdn,
- };
+ struct efa_com_destroy_ah_params params = {};
+
+ params.ah = ah->ah;
+ memcpy(params.gid, ah->id, sizeof(params.gid));
+ params.pdn = to_epd(ah->ibah.pd)->pdn;
return efa_com_destroy_ah(&dev->edev, &params);
}
@@ -2260,6 +2268,220 @@ enum rdma_link_layer efa_port_link_layer(struct ib_device *ibdev,
return IB_LINK_LAYER_UNSPECIFIED;
}
+int efa_query_comp_cntr_caps(struct ib_device *ibdev,
+ struct ib_comp_cntr_caps *caps,
+ struct uverbs_attr_bundle *attrs)
+{
+ struct efa_dev *dev = to_edev(ibdev);
+ u32 dev_ops = dev->dev_attr.supported_event_counter_qp_events;
+
+ caps->max_counters = dev->dev_attr.max_event_counters / 2;
+ caps->max_value = dev->dev_attr.event_counter_max_val;
+
+ caps->supported_qp_attach_ops = 0;
+ if (EFA_GET(&dev_ops, EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_SEND_COMP) &&
+ EFA_GET(&dev_ops, EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_SEND_COMP_ERR))
+ caps->supported_qp_attach_ops |= IB_QP_ATTACH_COMP_CNTR_OP_SEND;
+ if (EFA_GET(&dev_ops, EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_RECV_COMP) &&
+ EFA_GET(&dev_ops, EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_RECV_COMP_ERR))
+ caps->supported_qp_attach_ops |= IB_QP_ATTACH_COMP_CNTR_OP_RECV;
+ if (EFA_GET(&dev_ops, EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_READ_COMP) &&
+ EFA_GET(&dev_ops, EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_READ_COMP_ERR))
+ caps->supported_qp_attach_ops |= IB_QP_ATTACH_COMP_CNTR_OP_RDMA_READ;
+ if (EFA_GET(&dev_ops, EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_WRITE_COMP) &&
+ EFA_GET(&dev_ops, EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_WRITE_COMP_ERR))
+ caps->supported_qp_attach_ops |= IB_QP_ATTACH_COMP_CNTR_OP_RDMA_WRITE;
+ if (EFA_GET(&dev_ops, EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_REMOTE_READ_COMP))
+ caps->supported_qp_attach_ops |= IB_QP_ATTACH_COMP_CNTR_OP_REMOTE_RDMA_READ;
+ if (EFA_GET(&dev_ops, EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_REMOTE_WRITE_COMP))
+ caps->supported_qp_attach_ops |= IB_QP_ATTACH_COMP_CNTR_OP_REMOTE_RDMA_WRITE;
+
+ return 0;
+}
+
+static int efa_create_event_counter(struct efa_dev *dev, u16 uarn, dma_addr_t addr, u32 *handle)
+{
+ struct efa_com_create_event_counter_params params = {};
+ struct efa_com_create_event_counter_result result;
+ int err;
+
+ params.uarn = uarn;
+ params.dma_addr = addr;
+
+ err = efa_com_create_event_counter(&dev->edev, &params, &result);
+ if (err)
+ return err;
+
+ *handle = result.cntr_handle;
+ return 0;
+}
+
+static int efa_destroy_event_counter(struct efa_dev *dev, u32 handle)
+{
+ struct efa_com_destroy_event_counter_params params = {
+ .cntr_handle = handle,
+ };
+
+ return efa_com_destroy_event_counter(&dev->edev, &params);
+}
+
+int efa_create_comp_cntr(struct ib_comp_cntr *ibcc, struct uverbs_attr_bundle *attrs)
+{
+ struct efa_dev *dev = to_edev(ibcc->device);
+ struct efa_comp_cntr *cc = to_ecc(ibcc);
+ struct efa_ucontext *ucontext;
+ struct ib_umem *comp_umem;
+ struct ib_umem *err_umem;
+ dma_addr_t comp_addr;
+ dma_addr_t err_addr;
+ int err;
+
+ ucontext = rdma_udata_to_drv_context(&attrs->driver_udata, struct efa_ucontext,
+ ibucontext);
+
+ comp_umem = ib_umem_get_attr(ibcc->device, attrs, EFA_IB_ATTR_CREATE_COMP_CNTR_COMP_BUFFER,
+ sizeof(u64), IB_ACCESS_LOCAL_WRITE);
+ if (IS_ERR(comp_umem))
+ return PTR_ERR(comp_umem);
+
+ err_umem = ib_umem_get_attr(ibcc->device, attrs, EFA_IB_ATTR_CREATE_COMP_CNTR_ERR_BUFFER,
+ sizeof(u64), IB_ACCESS_LOCAL_WRITE);
+ if (IS_ERR(err_umem)) {
+ err = PTR_ERR(err_umem);
+ goto err_comp_umem;
+ }
+
+ comp_addr = ib_umem_start_dma_addr(comp_umem);
+ err_addr = ib_umem_start_dma_addr(err_umem);
+
+ if (!IS_ALIGNED(comp_addr, sizeof(u64)) || !IS_ALIGNED(err_addr, sizeof(u64))) {
+ ibdev_dbg(&dev->ibdev, "Completion Counter memory is unaligned\n");
+ err = -EINVAL;
+ goto err_err_umem;
+ }
+
+ err = efa_create_event_counter(dev, ucontext->uarn, comp_addr, &cc->comp_handle);
+ if (err) {
+ ibdev_dbg(&dev->ibdev, "Failed to create comp event counter [%d]\n", err);
+ goto err_err_umem;
+ }
+
+ err = efa_create_event_counter(dev, ucontext->uarn, err_addr, &cc->err_handle);
+ if (err) {
+ ibdev_dbg(&dev->ibdev, "Failed to create err event counter [%d]\n", err);
+ goto err_destroy_comp_event_cntr;
+ }
+
+ cc->comp_umem = comp_umem;
+ cc->err_umem = err_umem;
+
+ return 0;
+
+err_destroy_comp_event_cntr:
+ efa_destroy_event_counter(dev, cc->comp_handle);
+err_err_umem:
+ ib_umem_release(err_umem);
+err_comp_umem:
+ ib_umem_release(comp_umem);
+ return err;
+}
+
+int efa_destroy_comp_cntr(struct ib_comp_cntr *ibcc)
+{
+ struct efa_dev *dev = to_edev(ibcc->device);
+ struct efa_comp_cntr *cc = to_ecc(ibcc);
+
+ efa_destroy_event_counter(dev, cc->comp_handle);
+ efa_destroy_event_counter(dev, cc->err_handle);
+
+ ib_umem_release(cc->comp_umem);
+ ib_umem_release(cc->err_umem);
+ return 0;
+}
+
+int efa_modify_comp_cntr(struct ib_comp_cntr *ibcc, enum ib_comp_cntr_entry entry,
+ enum ib_comp_cntr_modify_op op, u64 value)
+{
+ struct efa_com_modify_event_counter_params params = {};
+ struct efa_comp_cntr *cc = to_ecc(ibcc);
+
+ params.cntr_handle = entry == IB_COMP_CNTR_ENTRY_ERR ? cc->err_handle : cc->comp_handle;
+ params.operation = op == IB_COMP_CNTR_MODIFY_OP_SET ?
+ EFA_ADMIN_EVENT_COUNTER_MODIFY_SET : EFA_ADMIN_EVENT_COUNTER_MODIFY_ADD;
+ params.value = value;
+
+ return efa_com_modify_event_counter(&to_edev(ibcc->device)->edev, &params);
+}
+
+static u32 efa_comp_cntr_op_to_comp_events(u32 op_mask)
+{
+ u32 events = 0;
+
+ if (op_mask & IB_QP_ATTACH_COMP_CNTR_OP_SEND)
+ EFA_SET(&events, EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_SEND_COMP, 1);
+ if (op_mask & IB_QP_ATTACH_COMP_CNTR_OP_RECV)
+ EFA_SET(&events, EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_RECV_COMP, 1);
+ if (op_mask & IB_QP_ATTACH_COMP_CNTR_OP_RDMA_READ)
+ EFA_SET(&events, EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_READ_COMP, 1);
+ if (op_mask & IB_QP_ATTACH_COMP_CNTR_OP_REMOTE_RDMA_READ)
+ EFA_SET(&events, EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_REMOTE_READ_COMP, 1);
+ if (op_mask & IB_QP_ATTACH_COMP_CNTR_OP_RDMA_WRITE)
+ EFA_SET(&events, EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_WRITE_COMP, 1);
+ if (op_mask & IB_QP_ATTACH_COMP_CNTR_OP_REMOTE_RDMA_WRITE)
+ EFA_SET(&events, EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_REMOTE_WRITE_COMP, 1);
+
+ return events;
+}
+
+static u32 efa_comp_cntr_op_to_err_events(u32 op_mask)
+{
+ u32 events = 0;
+
+ if (op_mask & IB_QP_ATTACH_COMP_CNTR_OP_SEND)
+ EFA_SET(&events, EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_SEND_COMP_ERR, 1);
+ if (op_mask & IB_QP_ATTACH_COMP_CNTR_OP_RECV)
+ EFA_SET(&events, EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_RECV_COMP_ERR, 1);
+ if (op_mask & IB_QP_ATTACH_COMP_CNTR_OP_RDMA_READ)
+ EFA_SET(&events, EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_READ_COMP_ERR, 1);
+ if (op_mask & IB_QP_ATTACH_COMP_CNTR_OP_RDMA_WRITE)
+ EFA_SET(&events, EFA_ADMIN_EVENT_COUNTER_ATTACH_QP_EVENTS_WRITE_COMP_ERR, 1);
+
+ return events;
+}
+
+int efa_qp_attach_comp_cntr(struct ib_qp *ibqp, struct ib_comp_cntr *ibcc,
+ struct ib_qp_attach_comp_cntr_attr *attr)
+{
+ struct efa_com_detach_event_counter_params detach_params = {};
+ struct efa_com_attach_event_counter_params params = {};
+ struct efa_dev *dev = to_edev(ibqp->device);
+ struct efa_comp_cntr *cc = to_ecc(ibcc);
+ struct efa_qp *qp = to_eqp(ibqp);
+ int err;
+
+ params.cntr_handle = cc->comp_handle;
+ params.qp_handle = qp->qp_handle;
+ params.events = efa_comp_cntr_op_to_comp_events(attr->op_mask);
+
+ err = efa_com_attach_event_counter(&dev->edev, &params);
+ if (err)
+ return err;
+
+ params.cntr_handle = cc->err_handle;
+ params.events = efa_comp_cntr_op_to_err_events(attr->op_mask);
+
+ err = efa_com_attach_event_counter(&dev->edev, &params);
+ if (err) {
+ detach_params.cntr_handle = cc->comp_handle;
+ detach_params.qp_handle = qp->qp_handle;
+ detach_params.events = efa_comp_cntr_op_to_comp_events(attr->op_mask);
+ efa_com_detach_event_counter(&dev->edev, &detach_params);
+ return err;
+ }
+
+ return 0;
+}
+
DECLARE_UVERBS_NAMED_METHOD(EFA_IB_METHOD_MR_QUERY,
UVERBS_ATTR_IDR(EFA_IB_ATTR_QUERY_MR_HANDLE,
UVERBS_OBJECT_MR,
@@ -2282,8 +2504,23 @@ ADD_UVERBS_METHODS(efa_mr,
UVERBS_OBJECT_MR,
&UVERBS_METHOD(EFA_IB_METHOD_MR_QUERY));
+ADD_UVERBS_ATTRIBUTES_SIMPLE(
+ efa_comp_cntr_create,
+ UVERBS_OBJECT_COMP_CNTR,
+ UVERBS_METHOD_COMP_CNTR_CREATE,
+ UVERBS_ATTR_PTR_IN(
+ EFA_IB_ATTR_CREATE_COMP_CNTR_COMP_BUFFER,
+ UVERBS_ATTR_STRUCT(struct ib_uverbs_buffer_desc, length),
+ UA_MANDATORY),
+ UVERBS_ATTR_PTR_IN(
+ EFA_IB_ATTR_CREATE_COMP_CNTR_ERR_BUFFER,
+ UVERBS_ATTR_STRUCT(struct ib_uverbs_buffer_desc, length),
+ UA_MANDATORY));
+
const struct uapi_definition efa_uapi_defs[] = {
UAPI_DEF_CHAIN_OBJ_TREE(UVERBS_OBJECT_MR,
&efa_mr),
+ UAPI_DEF_CHAIN_OBJ_TREE(UVERBS_OBJECT_COMP_CNTR,
+ &efa_comp_cntr_create),
{},
};
diff --git a/drivers/infiniband/hw/erdma/erdma_eq.c b/drivers/infiniband/hw/erdma/erdma_eq.c
index d5b9d19882b2..a8784e07acd6 100644
--- a/drivers/infiniband/hw/erdma/erdma_eq.c
+++ b/drivers/infiniband/hw/erdma/erdma_eq.c
@@ -220,6 +220,7 @@ static void erdma_free_ceq_irq(struct erdma_dev *dev, u16 ceqn)
irq_set_affinity_hint(eqc->irq.msix_vector, NULL);
free_irq(eqc->irq.msix_vector, eqc);
+ tasklet_kill(&eqc->tasklet);
}
static int create_eq_cmd(struct erdma_dev *dev, u32 eqn, struct erdma_eq *eq)
diff --git a/drivers/infiniband/hw/erdma/erdma_verbs.c b/drivers/infiniband/hw/erdma/erdma_verbs.c
index 74afe6eb18b0..71e3e8618a61 100644
--- a/drivers/infiniband/hw/erdma/erdma_verbs.c
+++ b/drivers/infiniband/hw/erdma/erdma_verbs.c
@@ -320,12 +320,10 @@ int erdma_query_device(struct ib_device *ibdev, struct ib_device_attr *attr,
struct erdma_dev *dev = to_edev(ibdev);
int err;
- err = ib_is_udata_in_empty(udata);
+ err = ib_no_udata_io(udata);
if (err)
return err;
- memset(attr, 0, sizeof(*attr));
-
attr->max_mr_size = dev->attrs.max_mr_size;
attr->vendor_id = PCI_VENDOR_ID_ALIBABA;
attr->vendor_part_id = dev->pdev->device;
@@ -363,7 +361,7 @@ int erdma_query_device(struct ib_device *ibdev, struct ib_device_attr *attr,
addrconf_addr_eui48((u8 *)&attr->sys_image_guid,
dev->netdev->dev_addr);
- return ib_respond_empty_udata(udata);
+ return 0;
}
int erdma_query_gid(struct ib_device *ibdev, u32 port, int idx,
diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c
index 44c524e45396..592e330e74bf 100644
--- a/drivers/infiniband/hw/hfi1/chip.c
+++ b/drivers/infiniband/hw/hfi1/chip.c
@@ -11929,26 +11929,27 @@ u8 encode_rcv_header_entry_size(u8 size)
/**
* hfi1_validate_rcvhdrcnt - validate hdrcnt
- * @dd: the device data
+ * @pdev: the PCI device
* @thecnt: the header count
*/
-int hfi1_validate_rcvhdrcnt(struct hfi1_devdata *dd, uint thecnt)
+int hfi1_validate_rcvhdrcnt(struct pci_dev *pdev, uint thecnt)
{
if (thecnt <= HFI1_MIN_HDRQ_EGRBUF_CNT) {
- dd_dev_err(dd, "Receive header queue count too small\n");
+ dev_err(&pdev->dev, "Receive header queue count too small\n");
return -EINVAL;
}
if (thecnt > HFI1_MAX_HDRQ_EGRBUF_CNT) {
- dd_dev_err(dd,
- "Receive header queue count cannot be greater than %u\n",
- HFI1_MAX_HDRQ_EGRBUF_CNT);
+ dev_err(&pdev->dev,
+ "Receive header queue count cannot be greater than %u\n",
+ HFI1_MAX_HDRQ_EGRBUF_CNT);
return -EINVAL;
}
if (thecnt % HDRQ_INCREMENT) {
- dd_dev_err(dd, "Receive header queue count %d must be divisible by %lu\n",
- thecnt, HDRQ_INCREMENT);
+ dev_err(&pdev->dev,
+ "Receive header queue count %u must be divisible by %lu\n",
+ thecnt, HDRQ_INCREMENT);
return -EINVAL;
}
@@ -15007,7 +15008,7 @@ int hfi1_init_dd(struct hfi1_devdata *dd)
*/
ret = hfi1_pcie_ddinit(dd, pdev);
if (ret < 0)
- goto bail_free;
+ goto bail;
/* Save PCI space registers to rewrite after device reset */
ret = save_pci_variables(dd);
@@ -15262,8 +15263,6 @@ bail_clear_intr:
bail_cleanup:
hfi1_free_rx(dd);
hfi1_pcie_ddcleanup(dd);
-bail_free:
- hfi1_free_devdata(dd);
bail:
return ret;
}
diff --git a/drivers/infiniband/hw/hfi1/chip.h b/drivers/infiniband/hw/hfi1/chip.h
index 56e03d486ace..bc1c9e1c3172 100644
--- a/drivers/infiniband/hw/hfi1/chip.h
+++ b/drivers/infiniband/hw/hfi1/chip.h
@@ -660,7 +660,7 @@ static inline u32 chip_rcv_array_count(struct hfi1_devdata *dd)
}
u8 encode_rcv_header_entry_size(u8 size);
-int hfi1_validate_rcvhdrcnt(struct hfi1_devdata *dd, uint thecnt);
+int hfi1_validate_rcvhdrcnt(struct pci_dev *pdev, uint thecnt);
void set_hdrq_regs(struct hfi1_devdata *dd, u8 ctxt, u8 entsize, u16 hdrcnt);
u64 create_pbc(struct hfi1_pportdata *ppd, u64 flags, int srate_mbs, u32 vl,
diff --git a/drivers/infiniband/hw/hfi1/device.c b/drivers/infiniband/hw/hfi1/device.c
index a98a4175e53b..adcfb80d52d4 100644
--- a/drivers/infiniband/hw/hfi1/device.c
+++ b/drivers/infiniband/hw/hfi1/device.c
@@ -10,18 +10,6 @@
#include "hfi.h"
#include "device.h"
-static char *hfi1_devnode(const struct device *dev, umode_t *mode)
-{
- if (mode)
- *mode = 0600;
- return kasprintf(GFP_KERNEL, "%s", dev_name(dev));
-}
-
-static const struct class class = {
- .name = "hfi1",
- .devnode = hfi1_devnode,
-};
-
static char *hfi1_user_devnode(const struct device *dev, umode_t *mode)
{
if (mode)
@@ -38,7 +26,6 @@ static dev_t hfi1_dev;
int hfi1_cdev_init(int minor, const char *name,
const struct file_operations *fops,
struct cdev *cdev, struct device **devp,
- bool user_accessible,
struct kobject *parent)
{
const dev_t dev = MKDEV(MAJOR(hfi1_dev), minor);
@@ -57,10 +44,7 @@ int hfi1_cdev_init(int minor, const char *name,
goto done;
}
- if (user_accessible)
- device = device_create(&user_class, NULL, dev, NULL, "%s", name);
- else
- device = device_create(&class, NULL, dev, NULL, "%s", name);
+ device = device_create(&user_class, NULL, dev, NULL, "%s", name);
if (IS_ERR(device)) {
ret = PTR_ERR(device);
@@ -100,33 +84,21 @@ int __init dev_init(void)
ret = alloc_chrdev_region(&hfi1_dev, 0, HFI1_NMINORS, DRIVER_NAME);
if (ret < 0) {
pr_err("Could not allocate chrdev region (err %d)\n", -ret);
- goto done;
- }
-
- ret = class_register(&class);
- if (ret) {
- pr_err("Could not create device class (err %d)\n", -ret);
- unregister_chrdev_region(hfi1_dev, HFI1_NMINORS);
- goto done;
+ return ret;
}
ret = class_register(&user_class);
if (ret) {
pr_err("Could not create device class for user accessible files (err %d)\n",
-ret);
- class_unregister(&class);
unregister_chrdev_region(hfi1_dev, HFI1_NMINORS);
- goto done;
}
-done:
return ret;
}
void dev_cleanup(void)
{
- class_unregister(&class);
class_unregister(&user_class);
-
unregister_chrdev_region(hfi1_dev, HFI1_NMINORS);
}
diff --git a/drivers/infiniband/hw/hfi1/device.h b/drivers/infiniband/hw/hfi1/device.h
index a91bea426ba5..3e2d21770e6c 100644
--- a/drivers/infiniband/hw/hfi1/device.h
+++ b/drivers/infiniband/hw/hfi1/device.h
@@ -9,7 +9,6 @@
int hfi1_cdev_init(int minor, const char *name,
const struct file_operations *fops,
struct cdev *cdev, struct device **devp,
- bool user_accessible,
struct kobject *parent);
void hfi1_cdev_cleanup(struct cdev *cdev, struct device **devp);
const char *class_name(void);
diff --git a/drivers/infiniband/hw/hfi1/file_ops.c b/drivers/infiniband/hw/hfi1/file_ops.c
index 56031becb273..dc548e6802e2 100644
--- a/drivers/infiniband/hw/hfi1/file_ops.c
+++ b/drivers/infiniband/hw/hfi1/file_ops.c
@@ -1689,7 +1689,7 @@ static int user_add(struct hfi1_devdata *dd)
snprintf(name, sizeof(name), "%s_%d", class_name(), dd->unit);
ret = hfi1_cdev_init(dd->unit, name, &hfi1_file_ops,
&dd->user_cdev, &dd->user_device,
- true, &dd->verbs_dev.rdi.ibdev.dev.kobj);
+ &dd->verbs_dev.rdi.ibdev.dev.kobj);
if (ret)
user_remove(dd);
diff --git a/drivers/infiniband/hw/hfi1/hfi.h b/drivers/infiniband/hw/hfi1/hfi.h
index 5a0310f758dc..80d480c4fc6a 100644
--- a/drivers/infiniband/hw/hfi1/hfi.h
+++ b/drivers/infiniband/hw/hfi1/hfi.h
@@ -2024,9 +2024,7 @@ struct cc_state *get_cc_state_protected(struct hfi1_pportdata *ppd)
/* waiting for an urgent packet to arrive */
#define HFI1_CTXT_WAITING_URG 4
-/* free up any allocated data at closes */
int hfi1_init_dd(struct hfi1_devdata *dd);
-void hfi1_free_devdata(struct hfi1_devdata *dd);
/* LED beaconing functions */
void hfi1_start_led_override(struct hfi1_pportdata *ppd, unsigned int timeon,
@@ -2132,7 +2130,7 @@ void hfi1_verbs_unregister_sysfs(struct hfi1_devdata *dd);
/* Hook for sysfs read of QSFP */
int qsfp_dump(struct hfi1_pportdata *ppd, char *buf, int len);
-int hfi1_pcie_init(struct hfi1_devdata *dd);
+int hfi1_pcie_init(struct pci_dev *pdev);
void hfi1_pcie_cleanup(struct pci_dev *pdev);
int hfi1_pcie_ddinit(struct hfi1_devdata *dd, struct pci_dev *pdev);
void hfi1_pcie_ddcleanup(struct hfi1_devdata *);
diff --git a/drivers/infiniband/hw/hfi1/init.c b/drivers/infiniband/hw/hfi1/init.c
index b7fd8b1fbbbd..f94d896e7212 100644
--- a/drivers/infiniband/hw/hfi1/init.c
+++ b/drivers/infiniband/hw/hfi1/init.c
@@ -629,8 +629,6 @@ void hfi1_init_pportdata(struct pci_dev *pdev, struct hfi1_pportdata *ppd,
ppd->sm_trap_qp = 0x0;
ppd->sa_qp = 0x1;
- ppd->hfi1_wq = NULL;
-
spin_lock_init(&ppd->cca_timer_lock);
for (i = 0; i < OPA_MAX_SLS; i++) {
@@ -740,31 +738,27 @@ static int create_workqueues(struct hfi1_devdata *dd)
for (pidx = 0; pidx < dd->num_pports; ++pidx) {
ppd = dd->pport + pidx;
- if (!ppd->hfi1_wq) {
- ppd->hfi1_wq =
- alloc_workqueue(
- "hfi%d_%d",
- WQ_SYSFS | WQ_HIGHPRI | WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM |
- WQ_PERCPU,
- HFI1_MAX_ACTIVE_WORKQUEUE_ENTRIES,
- dd->unit, pidx);
- if (!ppd->hfi1_wq)
- goto wq_error;
- }
- if (!ppd->link_wq) {
- /*
- * Make the link workqueue single-threaded to enforce
- * serialization.
- */
- ppd->link_wq =
- alloc_workqueue(
- "hfi_link_%d_%d",
- WQ_SYSFS | WQ_MEM_RECLAIM | WQ_UNBOUND,
- 1, /* max_active */
- dd->unit, pidx);
- if (!ppd->link_wq)
- goto wq_error;
- }
+ ppd->hfi1_wq =
+ alloc_workqueue(
+ "hfi%d_%d",
+ WQ_SYSFS | WQ_HIGHPRI | WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM |
+ WQ_PERCPU,
+ HFI1_MAX_ACTIVE_WORKQUEUE_ENTRIES,
+ dd->unit, pidx);
+ if (!ppd->hfi1_wq)
+ goto wq_error;
+ /*
+ * Make the link workqueue single-threaded to enforce
+ * serialization.
+ */
+ ppd->link_wq =
+ alloc_workqueue(
+ "hfi_link_%d_%d",
+ WQ_SYSFS | WQ_MEM_RECLAIM | WQ_UNBOUND,
+ 1, /* max_active */
+ dd->unit, pidx);
+ if (!ppd->link_wq)
+ goto wq_error;
}
return 0;
wq_error:
@@ -1161,7 +1155,7 @@ static void finalize_asic_data(struct hfi1_devdata *dd,
* It cleans up and frees all data structures set up by
* by hfi1_alloc_devdata().
*/
-void hfi1_free_devdata(struct hfi1_devdata *dd)
+static void hfi1_free_devdata(struct hfi1_devdata *dd)
{
struct hfi1_asic_data *ad;
unsigned long flags;
@@ -1225,8 +1219,9 @@ static struct hfi1_devdata *hfi1_alloc_devdata(struct pci_dev *pdev,
GFP_KERNEL);
if (ret < 0) {
dev_err(&pdev->dev,
- "Could not allocate unit ID: error %d\n", -ret);
- goto bail;
+ "Could not allocate unit ID: error %pe\n", ERR_PTR(ret));
+ rvt_dealloc_device(&dd->verbs_dev.rdi);
+ return ERR_PTR(ret);
}
/*
@@ -1554,50 +1549,28 @@ static void postinit_cleanup(struct hfi1_devdata *dd)
hfi1_dev_affinity_clean_up(dd);
hfi1_pcie_ddcleanup(dd);
- hfi1_pcie_cleanup(dd->pcidev);
cleanup_device_data(dd);
-
- hfi1_free_devdata(dd);
}
static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- int ret = 0, j, pidx, initfail;
+ int ret;
struct hfi1_devdata *dd;
- struct hfi1_pportdata *ppd;
/* First, lock the non-writable module parameters */
HFI1_CAP_LOCK();
- /* Validate dev ids */
- if (!(ent->device == PCI_DEVICE_ID_INTEL0 ||
- ent->device == PCI_DEVICE_ID_INTEL1)) {
- dev_err(&pdev->dev, "Failing on unknown Intel deviceid 0x%x\n",
- ent->device);
- ret = -ENODEV;
- goto bail;
- }
-
- /* Allocate the dd so we can get to work */
- dd = hfi1_alloc_devdata(pdev, NUM_IB_PORTS *
- sizeof(struct hfi1_pportdata));
- if (IS_ERR(dd)) {
- ret = PTR_ERR(dd);
- goto bail;
- }
-
/* Validate some global module parameters */
- ret = hfi1_validate_rcvhdrcnt(dd, rcvhdrcnt);
+ ret = hfi1_validate_rcvhdrcnt(pdev, rcvhdrcnt);
if (ret)
- goto bail;
+ return ret;
/* use the encoding function as a sanitization check */
if (!encode_rcv_header_entry_size(hfi1_hdrq_entsize)) {
- dd_dev_err(dd, "Invalid HdrQ Entry size %u\n",
- hfi1_hdrq_entsize);
- ret = -EINVAL;
- goto bail;
+ dev_err(&pdev->dev, "Invalid HdrQ Entry size %u\n",
+ hfi1_hdrq_entsize);
+ return -EINVAL;
}
/* The receive eager buffer size must be set before the receive
@@ -1617,87 +1590,75 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
clamp_val(eager_buffer_size,
MIN_EAGER_BUFFER * 8,
MAX_EAGER_BUFFER_TOTAL);
- dd_dev_info(dd, "Eager buffer size %u\n",
- eager_buffer_size);
+ pci_info(pdev, "Eager buffer size %u\n", eager_buffer_size);
} else {
- dd_dev_err(dd, "Invalid Eager buffer size of 0\n");
- ret = -EINVAL;
- goto bail;
+ dev_err(&pdev->dev, "Invalid Eager buffer size of 0\n");
+ return -EINVAL;
}
/* restrict value of hfi1_rcvarr_split */
hfi1_rcvarr_split = clamp_val(hfi1_rcvarr_split, 0, 100);
- ret = hfi1_pcie_init(dd);
+ ret = hfi1_pcie_init(pdev);
if (ret)
- goto bail;
+ return ret;
+
+ /* Allocate the dd so we can get to work */
+ dd = hfi1_alloc_devdata(pdev, NUM_IB_PORTS *
+ sizeof(struct hfi1_pportdata));
+ if (IS_ERR(dd)) {
+ ret = PTR_ERR(dd);
+ goto clean_pcie;
+ }
+
+ ret = create_workqueues(dd);
+ if (ret)
+ goto free_devdata;
/*
- * Do device-specific initialization, function table setup, dd
- * allocation, etc.
+ * Do device-specific initialization, function table setup, etc.
*/
ret = hfi1_init_dd(dd);
if (ret)
- goto clean_bail; /* error already printed */
-
- ret = create_workqueues(dd);
- if (ret)
- goto clean_bail;
+ goto destroy_workqueues; /* error already printed */
/* do the generic initialization */
- initfail = hfi1_init(dd, 0);
+ ret = hfi1_init(dd, 0);
+ if (ret)
+ goto free_rx;
ret = hfi1_register_ib_device(dd);
+ if (ret)
+ goto free_rx;
/*
* Now ready for use. this should be cleared whenever we
- * detect a reset, or initiate one. If earlier failure,
- * we still create devices, so diags, etc. can be used
- * to determine cause of problem.
+ * detect a reset, or initiate one.
*/
- if (!initfail && !ret) {
- dd->flags |= HFI1_INITTED;
- /* create debufs files after init and ib register */
- hfi1_dbg_ibdev_init(&dd->verbs_dev);
- }
+ dd->flags |= HFI1_INITTED;
- j = hfi1_device_create(dd);
- if (j)
- dd_dev_err(dd, "Failed to create /dev devices: %d\n", -j);
-
- if (initfail || ret) {
- msix_clean_up_interrupts(dd);
- stop_timers(dd);
- flush_workqueue(ib_wq);
- for (pidx = 0; pidx < dd->num_pports; ++pidx) {
- hfi1_quiet_serdes(dd->pport + pidx);
- ppd = dd->pport + pidx;
- if (ppd->hfi1_wq) {
- destroy_workqueue(ppd->hfi1_wq);
- ppd->hfi1_wq = NULL;
- }
- if (ppd->link_wq) {
- destroy_workqueue(ppd->link_wq);
- ppd->link_wq = NULL;
- }
- }
- if (!j)
- hfi1_device_remove(dd);
- if (!ret)
- hfi1_unregister_ib_device(dd);
- postinit_cleanup(dd);
- if (initfail)
- ret = initfail;
- goto bail; /* everything already cleaned */
- }
+ ret = hfi1_device_create(dd);
+ if (ret)
+ dd_dev_err(dd, "Failed to create /dev devices: %pe\n",
+ ERR_PTR(ret));
sdma_start(dd);
+ hfi1_dbg_ibdev_init(&dd->verbs_dev);
return 0;
-clean_bail:
+free_rx:
+ hfi1_free_rx(dd);
+ shutdown_device(dd);
+ stop_timers(dd);
+ postinit_cleanup(dd);
+
+destroy_workqueues:
+ destroy_workqueues(dd);
+free_devdata:
+ hfi1_free_devdata(dd);
+clean_pcie:
hfi1_pcie_cleanup(pdev);
-bail:
return ret;
}
@@ -1737,14 +1698,11 @@ static void remove_one(struct pci_dev *pdev)
* clear dma engines, etc.
*/
shutdown_device(dd);
- destroy_workqueues(dd);
-
stop_timers(dd);
-
- /* wait until all of our (qsfp) queue_work() calls complete */
- flush_workqueue(ib_wq);
-
postinit_cleanup(dd);
+ destroy_workqueues(dd);
+ hfi1_free_devdata(dd);
+ hfi1_pcie_cleanup(pdev);
}
static void shutdown_one(struct pci_dev *pdev)
diff --git a/drivers/infiniband/hw/hfi1/pcie.c b/drivers/infiniband/hw/hfi1/pcie.c
index 7133964749f8..1154b8cc713c 100644
--- a/drivers/infiniband/hw/hfi1/pcie.c
+++ b/drivers/infiniband/hw/hfi1/pcie.c
@@ -21,10 +21,9 @@
/*
* Do all the common PCIe setup and initialization.
*/
-int hfi1_pcie_init(struct hfi1_devdata *dd)
+int hfi1_pcie_init(struct pci_dev *pdev)
{
int ret;
- struct pci_dev *pdev = dd->pcidev;
ret = pci_enable_device(pdev);
if (ret) {
@@ -40,13 +39,15 @@ int hfi1_pcie_init(struct hfi1_devdata *dd)
* about that, it appears. If the original BAR was retained
* in the kernel data structures, this may be OK.
*/
- dd_dev_err(dd, "pci enable failed: error %d\n", -ret);
+ dev_err(&pdev->dev, "pci enable failed: error %pe\n",
+ ERR_PTR(ret));
return ret;
}
ret = pci_request_regions(pdev, DRIVER_NAME);
if (ret) {
- dd_dev_err(dd, "pci_request_regions fails: err %d\n", -ret);
+ dev_err(&pdev->dev, "pci_request_regions fails: err %pe\n",
+ ERR_PTR(ret));
goto bail;
}
@@ -59,7 +60,8 @@ int hfi1_pcie_init(struct hfi1_devdata *dd)
*/
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (ret) {
- dd_dev_err(dd, "Unable to set DMA mask: %d\n", ret);
+ dev_err(&pdev->dev, "Unable to set DMA mask: %pe\n",
+ ERR_PTR(ret));
goto bail;
}
}
@@ -512,29 +514,28 @@ pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
switch (state) {
case pci_channel_io_normal:
- dd_dev_info(dd, "State Normal, ignoring\n");
+ dev_info(&pdev->dev, "State Normal, ignoring\n");
break;
case pci_channel_io_frozen:
- dd_dev_info(dd, "State Frozen, requesting reset\n");
+ dev_info(&pdev->dev, "State Frozen, requesting reset\n");
pci_disable_device(pdev);
ret = PCI_ERS_RESULT_NEED_RESET;
break;
case pci_channel_io_perm_failure:
+ dev_info(&pdev->dev, "State Permanent Failure, disabling\n");
if (dd) {
- dd_dev_info(dd, "State Permanent Failure, disabling\n");
/* no more register accesses! */
dd->flags &= ~HFI1_PRESENT;
hfi1_disable_after_error(dd);
}
- /* else early, or other problem */
ret = PCI_ERS_RESULT_DISCONNECT;
break;
default: /* shouldn't happen */
- dd_dev_info(dd, "HFI1 PCI errors detected (state %d)\n",
- state);
+ dev_info(&pdev->dev, "HFI1 PCI errors detected (state %d)\n",
+ state);
break;
}
return ret;
@@ -561,9 +562,7 @@ pci_mmio_enabled(struct pci_dev *pdev)
static pci_ers_result_t
pci_slot_reset(struct pci_dev *pdev)
{
- struct hfi1_devdata *dd = pci_get_drvdata(pdev);
-
- dd_dev_info(dd, "HFI1 slot_reset function called, ignored\n");
+ dev_info(&pdev->dev, "HFI1 slot_reset function called, ignored\n");
return PCI_ERS_RESULT_CAN_RECOVER;
}
@@ -572,7 +571,10 @@ pci_resume(struct pci_dev *pdev)
{
struct hfi1_devdata *dd = pci_get_drvdata(pdev);
- dd_dev_info(dd, "HFI1 resume function called\n");
+ dev_info(&pdev->dev, "HFI1 resume function called\n");
+ if (!dd)
+ return;
+
/*
* Running jobs will fail, since it's asynchronous
* unlike sysfs-requested reset. Better than
diff --git a/drivers/infiniband/hw/hfi1/user_sdma.c b/drivers/infiniband/hw/hfi1/user_sdma.c
index 8ea5ed918a02..be6b82ba93af 100644
--- a/drivers/infiniband/hw/hfi1/user_sdma.c
+++ b/drivers/infiniband/hw/hfi1/user_sdma.c
@@ -1026,6 +1026,7 @@ static int set_txreq_header_ahg(struct user_sdma_request *req,
struct user_sdma_txreq *tx, u32 datalen)
{
u32 ahg[AHG_KDETH_ARRAY_SIZE];
+ int ret;
int idx = 0;
u8 omfactor; /* KDETH.OM */
struct hfi1_user_sdma_pkt_q *pq = req->pq;
@@ -1130,11 +1131,13 @@ static int set_txreq_header_ahg(struct user_sdma_request *req,
trace_hfi1_sdma_user_header_ahg(pq->dd, pq->ctxt, pq->subctxt,
req->info.comp_idx, req->sde->this_idx,
req->ahg_idx, ahg, idx, tidval);
- sdma_txinit_ahg(&tx->txreq,
- SDMA_TXREQ_F_USE_AHG,
- datalen, req->ahg_idx, idx,
- ahg, sizeof(req->hdr),
- user_sdma_txreq_cb);
+ ret = sdma_txinit_ahg(&tx->txreq,
+ SDMA_TXREQ_F_USE_AHG,
+ datalen, req->ahg_idx, idx,
+ ahg, sizeof(req->hdr),
+ user_sdma_txreq_cb);
+ if (ret)
+ return ret;
return idx;
}
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
index 2b3a1cafd1b2..27cc7df55ee7 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
@@ -4393,7 +4393,7 @@ static int hns_roce_v2_set_hem(struct hns_roce_dev *hr_dev,
struct hns_roce_hem_mhop mhop;
struct hns_roce_hem *hem;
unsigned long mhop_obj = obj;
- int i, j, k;
+ u64 i, j, k;
int ret = 0;
u64 hem_idx = 0;
u64 l1_idx = 0;
diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c
index c6f633bd5a34..662959efcf31 100644
--- a/drivers/infiniband/hw/hns/hns_roce_main.c
+++ b/drivers/infiniband/hw/hns/hns_roce_main.c
@@ -223,12 +223,10 @@ static int hns_roce_query_device(struct ib_device *ib_dev,
struct hns_roce_dev *hr_dev = to_hr_dev(ib_dev);
int ret;
- ret = ib_is_udata_in_empty(uhw);
+ ret = ib_no_udata_io(uhw);
if (ret)
return ret;
- memset(props, 0, sizeof(*props));
-
props->fw_ver = hr_dev->caps.fw_ver;
props->sys_image_guid = cpu_to_be64(hr_dev->sys_image_guid);
props->max_mr_size = (u64)(~(0ULL));
@@ -279,7 +277,7 @@ static int hns_roce_query_device(struct ib_device *ib_dev,
if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_XRC)
props->device_cap_flags |= IB_DEVICE_XRC;
- return ib_respond_empty_udata(uhw);
+ return 0;
}
static int hns_roce_query_port(struct ib_device *ib_dev, u32 port_num,
diff --git a/drivers/infiniband/hw/ionic/ionic_controlpath.c b/drivers/infiniband/hw/ionic/ionic_controlpath.c
index 9d91f7667d4f..a70ef59a8064 100644
--- a/drivers/infiniband/hw/ionic/ionic_controlpath.c
+++ b/drivers/infiniband/hw/ionic/ionic_controlpath.c
@@ -391,6 +391,16 @@ int ionic_alloc_ucontext(struct ib_ucontext *ibctx, struct ib_udata *udata)
goto err_mmap_dbell;
}
+ if (dev->lif_cfg.phc_state) {
+ ctx->mmap_phc = ionic_mmap_entry_insert(ctx, PAGE_SIZE, 0,
+ IONIC_MMAP_PHC,
+ &resp.phc_offset);
+ if (!ctx->mmap_phc) {
+ rc = -ENOMEM;
+ goto err_mmap_phc;
+ }
+ }
+
resp.page_shift = PAGE_SHIFT;
resp.dbell_offset = db_phys & ~PAGE_MASK;
@@ -421,6 +431,8 @@ int ionic_alloc_ucontext(struct ib_ucontext *ibctx, struct ib_udata *udata)
return 0;
err_resp:
+ rdma_user_mmap_entry_remove(ctx->mmap_phc);
+err_mmap_phc:
rdma_user_mmap_entry_remove(ctx->mmap_dbell);
err_mmap_dbell:
ionic_put_dbid(dev, ctx->dbid);
@@ -433,10 +445,26 @@ void ionic_dealloc_ucontext(struct ib_ucontext *ibctx)
struct ionic_ibdev *dev = to_ionic_ibdev(ibctx->device);
struct ionic_ctx *ctx = to_ionic_ctx(ibctx);
+ rdma_user_mmap_entry_remove(ctx->mmap_phc);
rdma_user_mmap_entry_remove(ctx->mmap_dbell);
ionic_put_dbid(dev, ctx->dbid);
}
+static int ionic_mmap_phc_state(struct ionic_ibdev *dev,
+ struct vm_area_struct *vma)
+{
+ if (!(vma->vm_flags & VM_SHARED))
+ return -EINVAL;
+
+ if (vma->vm_flags & (VM_WRITE | VM_EXEC))
+ return -EPERM;
+
+ vm_flags_clear(vma, VM_MAYWRITE);
+
+ return vm_insert_page(vma, vma->vm_start,
+ virt_to_page(dev->lif_cfg.phc_state));
+}
+
int ionic_mmap(struct ib_ucontext *ibctx, struct vm_area_struct *vma)
{
struct ionic_ibdev *dev = to_ionic_ibdev(ibctx->device);
@@ -455,6 +483,12 @@ int ionic_mmap(struct ib_ucontext *ibctx, struct vm_area_struct *vma)
ionic_entry = container_of(rdma_entry, struct ionic_mmap_entry,
rdma_entry);
+ if (ionic_entry->mmap_flags & IONIC_MMAP_PHC) {
+ rc = ionic_mmap_phc_state(dev, vma);
+ rdma_user_mmap_entry_put(rdma_entry);
+ return rc;
+ }
+
ibdev_dbg(&dev->ibdev, "writecombine? %d\n",
ionic_entry->mmap_flags & IONIC_MMAP_WC);
if (ionic_entry->mmap_flags & IONIC_MMAP_WC)
@@ -487,6 +521,11 @@ int ionic_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
{
struct ionic_ibdev *dev = to_ionic_ibdev(ibpd->device);
struct ionic_pd *pd = to_ionic_pd(ibpd);
+ int rc;
+
+ rc = ib_no_udata_io(udata);
+ if (rc)
+ return rc;
return ionic_get_pdid(dev, &pd->pdid);
}
@@ -495,6 +534,11 @@ int ionic_dealloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
{
struct ionic_ibdev *dev = to_ionic_ibdev(ibpd->device);
struct ionic_pd *pd = to_ionic_pd(ibpd);
+ int rc;
+
+ rc = ib_no_udata_io(udata);
+ if (rc)
+ return rc;
ionic_put_pdid(dev, pd->pdid);
@@ -741,6 +785,10 @@ int ionic_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *init_attr,
u32 flags = init_attr->flags;
int rc;
+ rc = ib_is_udata_in_empty(udata);
+ if (rc)
+ return rc;
+
rc = ionic_get_ahid(dev, &ah->ahid);
if (rc)
return rc;
@@ -877,6 +925,10 @@ struct ib_mr *ionic_reg_user_mr(struct ib_pd *ibpd, u64 start, u64 length,
unsigned long pg_sz;
int rc;
+ rc = ib_no_udata_io(udata);
+ if (rc)
+ return ERR_PTR(rc);
+
if (dmah)
return ERR_PTR(-EOPNOTSUPP);
@@ -1008,6 +1060,10 @@ int ionic_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
struct ionic_mr *mr = to_ionic_mr(ibmr);
int rc;
+ rc = ib_no_udata_io(udata);
+ if (rc)
+ return rc;
+
if (!mr->ibmr.lkey)
goto out;
@@ -1120,6 +1176,10 @@ int ionic_alloc_mw(struct ib_mw *ibmw, struct ib_udata *udata)
struct ionic_mr *mr = to_ionic_mw(ibmw);
int rc;
+ rc = ib_no_udata_io(udata);
+ if (rc)
+ return rc;
+
rc = ionic_get_mrid(dev, &mr->mrid);
if (rc)
return rc;
@@ -1292,6 +1352,10 @@ int ionic_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
struct ionic_vcq *vcq = to_ionic_vcq(ibcq);
int udma_idx, rc_tmp, rc = 0;
+ rc = ib_no_udata_io(udata);
+ if (rc)
+ return rc;
+
for (udma_idx = dev->lif_cfg.udma_count; udma_idx; ) {
--udma_idx;
@@ -2585,6 +2649,10 @@ int ionic_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int mask,
struct ionic_qp *qp = to_ionic_qp(ibqp);
int rc;
+ rc = ib_no_udata_io(udata);
+ if (rc)
+ return rc;
+
rc = ionic_check_modify_qp(qp, attr, mask);
if (rc)
return rc;
@@ -2658,6 +2726,10 @@ int ionic_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
struct ionic_cq *cq;
int rc;
+ rc = ib_no_udata_io(udata);
+ if (rc)
+ return rc;
+
rc = ionic_destroy_qp_cmd(dev, qp->qpid);
if (rc)
return rc;
diff --git a/drivers/infiniband/hw/ionic/ionic_datapath.c b/drivers/infiniband/hw/ionic/ionic_datapath.c
index aa2944887f23..3e2300f7ea10 100644
--- a/drivers/infiniband/hw/ionic/ionic_datapath.c
+++ b/drivers/infiniband/hw/ionic/ionic_datapath.c
@@ -32,6 +32,7 @@ static int ionic_flush_recv(struct ionic_qp *qp, struct ib_wc *wc)
{
struct ionic_rq_meta *meta;
struct ionic_v1_wqe *wqe;
+ u64 wqe_idx;
if (!qp->rq_flush)
return 0;
@@ -40,21 +41,22 @@ static int ionic_flush_recv(struct ionic_qp *qp, struct ib_wc *wc)
return 0;
wqe = ionic_queue_at_cons(&qp->rq);
+ wqe_idx = le64_to_cpu(wqe->base.wqe_idx);
- /* wqe_id must be a valid queue index */
- if (unlikely(wqe->base.wqe_id >> qp->rq.depth_log2)) {
+ /* wqe_idx must be a valid queue index */
+ if (unlikely(wqe_idx >> qp->rq.depth_log2)) {
ibdev_warn(qp->ibqp.device,
"flush qp %u recv index %llu invalid\n",
- qp->qpid, (unsigned long long)wqe->base.wqe_id);
+ qp->qpid, (unsigned long long)wqe_idx);
return -EIO;
}
- /* wqe_id must indicate a request that is outstanding */
- meta = &qp->rq_meta[wqe->base.wqe_id];
+ /* wqe_idx must indicate a request that is outstanding */
+ meta = &qp->rq_meta[wqe_idx];
if (unlikely(meta->next != IONIC_META_POSTED)) {
ibdev_warn(qp->ibqp.device,
"flush qp %u recv index %llu not posted\n",
- qp->qpid, (unsigned long long)wqe->base.wqe_id);
+ qp->qpid, (unsigned long long)wqe_idx);
return -EIO;
}
@@ -133,8 +135,8 @@ static int ionic_poll_recv(struct ionic_ibdev *dev, struct ionic_cq *cq,
{
struct ionic_qp *qp = NULL;
struct ionic_rq_meta *meta;
+ u16 vlan_tag, wqe_idx;
u32 src_qpn, st_len;
- u16 vlan_tag;
u8 op;
if (cqe_qp->rq_flush)
@@ -144,7 +146,7 @@ static int ionic_poll_recv(struct ionic_ibdev *dev, struct ionic_cq *cq,
st_len = be32_to_cpu(cqe->status_length);
- /* ignore wqe_id in case of flush error */
+ /* ignore wqe_idx in case of flush error */
if (ionic_v1_cqe_error(cqe) && st_len == IONIC_STS_WQE_FLUSHED_ERR) {
cqe_qp->rq_flush = true;
cq->flush = true;
@@ -160,20 +162,19 @@ static int ionic_poll_recv(struct ionic_ibdev *dev, struct ionic_cq *cq,
return -EIO;
}
- /* wqe_id must be a valid queue index */
- if (unlikely(cqe->recv.wqe_id >> qp->rq.depth_log2)) {
+ wqe_idx = le64_to_cpu(cqe->recv.wqe_idx_timestamp) & IONIC_V1_CQE_WQE_IDX_MASK;
+ /* wqe_idx must be a valid queue index */
+ if (unlikely(wqe_idx >> qp->rq.depth_log2)) {
ibdev_warn(&dev->ibdev,
- "qp %u recv index %llu invalid\n",
- qp->qpid, (unsigned long long)cqe->recv.wqe_id);
+ "qp %u recv index %u invalid\n", qp->qpid, wqe_idx);
return -EIO;
}
- /* wqe_id must indicate a request that is outstanding */
- meta = &qp->rq_meta[cqe->recv.wqe_id];
+ /* wqe_idx must indicate a request that is outstanding */
+ meta = &qp->rq_meta[wqe_idx];
if (unlikely(meta->next != IONIC_META_POSTED)) {
ibdev_warn(&dev->ibdev,
- "qp %u recv index %llu not posted\n",
- qp->qpid, (unsigned long long)cqe->recv.wqe_id);
+ "qp %u recv index %u not posted\n", qp->qpid, wqe_idx);
return -EIO;
}
@@ -408,7 +409,7 @@ static int ionic_comp_msn(struct ionic_qp *qp, struct ionic_v1_cqe *cqe)
static int ionic_comp_npg(struct ionic_qp *qp, struct ionic_v1_cqe *cqe)
{
struct ionic_sq_meta *meta;
- u16 cqe_idx;
+ u16 wqe_idx;
u32 st_len;
if (qp->sq_flush)
@@ -430,8 +431,8 @@ static int ionic_comp_npg(struct ionic_qp *qp, struct ionic_v1_cqe *cqe)
return 0;
}
- cqe_idx = cqe->send.npg_wqe_id & qp->sq.mask;
- meta = &qp->sq_meta[cqe_idx];
+ wqe_idx = le64_to_cpu(cqe->send.npg_wqe_idx_timestamp) & qp->sq.mask;
+ meta = &qp->sq_meta[wqe_idx];
meta->local_comp = true;
if (ionic_v1_cqe_error(cqe)) {
@@ -811,7 +812,7 @@ static void ionic_prep_base(struct ionic_qp *qp,
meta->signal = false;
meta->local_comp = false;
- wqe->base.wqe_id = qp->sq.prod;
+ wqe->base.wqe_idx = cpu_to_le64(qp->sq.prod);
if (wr->send_flags & IB_SEND_FENCE)
wqe->base.flags |= cpu_to_be16(IONIC_V1_FLAG_FENCE);
@@ -1205,7 +1206,7 @@ static int ionic_prep_recv(struct ionic_qp *qp,
meta->wrid = wr->wr_id;
- wqe->base.wqe_id = meta - qp->rq_meta;
+ wqe->base.wqe_idx = cpu_to_le64(meta - qp->rq_meta);
wqe->base.num_sge_key = wr->num_sge;
/* total length for recv goes in base imm_data_key */
diff --git a/drivers/infiniband/hw/ionic/ionic_fw.h b/drivers/infiniband/hw/ionic/ionic_fw.h
index adfbb89d856c..ee23062a1762 100644
--- a/drivers/infiniband/hw/ionic/ionic_fw.h
+++ b/drivers/infiniband/hw/ionic/ionic_fw.h
@@ -332,7 +332,7 @@ struct ionic_v1_cqe {
__le16 old_rq_cq_cindex;
} admin;
struct {
- __u64 wqe_id;
+ __le64 wqe_idx_timestamp;
__be32 src_qpn_op;
__u8 src_mac[6];
__be16 vlan_tag;
@@ -342,13 +342,19 @@ struct ionic_v1_cqe {
__u8 rsvd[4];
__be32 msg_msn;
__u8 rsvd2[8];
- __u64 npg_wqe_id;
+ __le64 npg_wqe_idx_timestamp;
} send;
};
__be32 status_length;
__be32 qid_type_flags;
};
+/* bits for cqe wqe_idx and timestamp */
+enum ionic_v1_cqe_wqe_idx_timestamp_bits {
+ IONIC_V1_CQE_WQE_IDX_MASK = 0xffff,
+ IONIC_V1_CQE_TIMESTAMP_SHIFT = 16,
+};
+
/* bits for cqe recv */
enum ionic_v1_cqe_src_qpn_bits {
IONIC_V1_CQE_RECV_QPN_MASK = 0xffffff,
@@ -423,7 +429,7 @@ static inline u32 ionic_v1_cqe_qtf_qid(u32 qtf)
/* v1 base wqe header */
struct ionic_v1_base_hdr {
- __u64 wqe_id;
+ __le64 wqe_idx;
__u8 op;
__u8 num_sge_key;
__be16 flags;
diff --git a/drivers/infiniband/hw/ionic/ionic_ibdev.c b/drivers/infiniband/hw/ionic/ionic_ibdev.c
index b0449c75f893..cba7809ec3d9 100644
--- a/drivers/infiniband/hw/ionic/ionic_ibdev.c
+++ b/drivers/infiniband/hw/ionic/ionic_ibdev.c
@@ -27,7 +27,7 @@ static int ionic_query_device(struct ib_device *ibdev,
struct net_device *ndev;
int err;
- err = ib_is_udata_in_empty(udata);
+ err = ib_no_udata_io(udata);
if (err)
return err;
@@ -74,7 +74,7 @@ static int ionic_query_device(struct ib_device *ibdev,
attr->max_fast_reg_page_list_len = dev->lif_cfg.npts_per_lif / 2;
attr->max_pkeys = IONIC_PKEY_TBL_LEN;
- return ib_respond_empty_udata(udata);
+ return 0;
}
static int ionic_query_port(struct ib_device *ibdev, u32 port,
@@ -216,6 +216,7 @@ static const struct ib_device_ops ionic_dev_ops = {
.owner = THIS_MODULE,
.driver_id = RDMA_DRIVER_IONIC,
.uverbs_abi_ver = IONIC_ABI_VERSION,
+ .uverbs_robust_udata = true,
.alloc_ucontext = ionic_alloc_ucontext,
.dealloc_ucontext = ionic_dealloc_ucontext,
diff --git a/drivers/infiniband/hw/ionic/ionic_ibdev.h b/drivers/infiniband/hw/ionic/ionic_ibdev.h
index 63828240d659..d7adaa161e6f 100644
--- a/drivers/infiniband/hw/ionic/ionic_ibdev.h
+++ b/drivers/infiniband/hw/ionic/ionic_ibdev.h
@@ -33,7 +33,6 @@
#define IONIC_MAX_QPID 0xffffff
#define IONIC_SPEC_HIGH 8
#define IONIC_MAX_PD 1024
-#define IONIC_SPEC_HIGH 8
#define IONIC_SQCMB_ORDER 5
#define IONIC_RQCMB_ORDER 0
@@ -72,6 +71,7 @@ enum ionic_admin_flags {
enum ionic_mmap_flag {
IONIC_MMAP_WC = BIT(0),
+ IONIC_MMAP_PHC = BIT(1),
};
struct ionic_mmap_entry {
@@ -173,6 +173,7 @@ struct ionic_ctx {
struct ib_ucontext ibctx;
u32 dbid;
struct rdma_user_mmap_entry *mmap_dbell;
+ struct rdma_user_mmap_entry *mmap_phc;
};
struct ionic_tbl_buf {
diff --git a/drivers/infiniband/hw/ionic/ionic_lif_cfg.c b/drivers/infiniband/hw/ionic/ionic_lif_cfg.c
index f3cd281c3a2f..f827dce59973 100644
--- a/drivers/infiniband/hw/ionic/ionic_lif_cfg.c
+++ b/drivers/infiniband/hw/ionic/ionic_lif_cfg.c
@@ -40,6 +40,8 @@ void ionic_fill_lif_cfg(struct ionic_lif *lif, struct ionic_lif_cfg *cfg)
cfg->dbid_count = le32_to_cpu(lif->ionic->ident.dev.ndbpgs_per_lif);
cfg->dbpage = lif->kern_dbpage;
cfg->intr_ctrl = lif->ionic->idev.intr_ctrl;
+ if (lif->phc)
+ cfg->phc_state = lif->phc->state_page;
cfg->db_phys = lif->ionic->bars[IONIC_PCI_BAR_DBELL].bus_addr;
diff --git a/drivers/infiniband/hw/ionic/ionic_lif_cfg.h b/drivers/infiniband/hw/ionic/ionic_lif_cfg.h
index 20853429f623..2b29e646c193 100644
--- a/drivers/infiniband/hw/ionic/ionic_lif_cfg.h
+++ b/drivers/infiniband/hw/ionic/ionic_lif_cfg.h
@@ -23,6 +23,7 @@ struct ionic_lif_cfg {
u64 __iomem *dbpage;
struct ionic_intr __iomem *intr_ctrl;
phys_addr_t db_phys;
+ void *phc_state;
u64 page_size_supported;
u32 npts_per_lif;
diff --git a/drivers/infiniband/hw/irdma/i40iw_hw.c b/drivers/infiniband/hw/irdma/i40iw_hw.c
index 60c1f2b1811d..8301938b4543 100644
--- a/drivers/infiniband/hw/irdma/i40iw_hw.c
+++ b/drivers/infiniband/hw/irdma/i40iw_hw.c
@@ -29,7 +29,9 @@ static u32 i40iw_regs[IRDMA_MAX_REGS] = {
I40E_PFHMC_PDINV,
I40E_GLHMC_VFPDINV(0),
I40E_GLPE_CRITERR,
- 0xffffffff /* PFINT_RATEN not used in FPK */
+ 0xffffffff, /* PFINT_RATEN not used in FPK */
+ 0xffffffff, /* PFHMC_ERRORINFO not used in FPK */
+ 0xffffffff /* PFHMC_ERRORDATA not used in FPK */
};
static u32 i40iw_stat_offsets[] = {
diff --git a/drivers/infiniband/hw/irdma/icrdma_hw.c b/drivers/infiniband/hw/irdma/icrdma_hw.c
index 32f26284a788..b1f1b5485762 100644
--- a/drivers/infiniband/hw/irdma/icrdma_hw.c
+++ b/drivers/infiniband/hw/irdma/icrdma_hw.c
@@ -29,6 +29,8 @@ static u32 icrdma_regs[IRDMA_MAX_REGS] = {
GLHMC_VFPDINV(0),
GLPE_CRITERR,
GLINT_RATE(0),
+ PFHMC_ERRORINFO,
+ PFHMC_ERRORDATA,
};
static u64 icrdma_masks[IRDMA_MAX_MASKS] = {
diff --git a/drivers/infiniband/hw/irdma/icrdma_hw.h b/drivers/infiniband/hw/irdma/icrdma_hw.h
index d97944ab45da..0acdeda1236d 100644
--- a/drivers/infiniband/hw/irdma/icrdma_hw.h
+++ b/drivers/infiniband/hw/irdma/icrdma_hw.h
@@ -40,6 +40,8 @@
#define GLHMC_VFPDINV(_i) (0x00528300 + ((_i) * 4)) /* _i=0...31 */
#define GLPE_CRITERR 0x00534000
#define GLINT_RATE(_INT) (0x0015A000 + ((_INT) * 4)) /* _i=0...2047 */ /* Reset Source: CORER */
+#define PFHMC_ERRORINFO 0x00520400
+#define PFHMC_ERRORDATA 0x00520500
#define ICRDMA_DB_ADDR_OFFSET (8 * 1024 * 1024 - 64 * 1024)
diff --git a/drivers/infiniband/hw/irdma/icrdma_if.c b/drivers/infiniband/hw/irdma/icrdma_if.c
index 2172a2092e3f..4b451d8482a4 100644
--- a/drivers/infiniband/hw/irdma/icrdma_if.c
+++ b/drivers/infiniband/hw/irdma/icrdma_if.c
@@ -91,8 +91,12 @@ static void icrdma_iidc_event_handler(struct iidc_rdma_core_dev_info *cdev_info,
}
}
if (event->reg & IRDMAPFINT_OICR_HMC_ERR_M) {
- ibdev_err(&iwdev->ibdev, "HMC Error\n");
- iwdev->rf->reset = true;
+ u32 hmc_errinfo = readl(iwdev->rf->sc_dev.hw_regs[IRDMA_PFHMC_ERRORINFO]);
+ u32 hmc_errdata = readl(iwdev->rf->sc_dev.hw_regs[IRDMA_PFHMC_ERRORDATA]);
+
+ /* Log diagnostics; do not reset here. */
+ ibdev_warn(&iwdev->ibdev, "HMC Error: errinfo=0x%08x errdata=0x%08x\n",
+ hmc_errinfo, hmc_errdata);
}
if (event->reg & IRDMAPFINT_OICR_PE_PUSH_M) {
ibdev_err(&iwdev->ibdev, "PE Push Error\n");
diff --git a/drivers/infiniband/hw/irdma/irdma.h b/drivers/infiniband/hw/irdma/irdma.h
index b5ce515f4ee8..d4530520e39f 100644
--- a/drivers/infiniband/hw/irdma/irdma.h
+++ b/drivers/infiniband/hw/irdma/irdma.h
@@ -66,6 +66,8 @@ enum irdma_registers {
IRDMA_GLHMC_VFPDINV,
IRDMA_GLPE_CRITERR,
IRDMA_GLINT_RATE,
+ IRDMA_PFHMC_ERRORINFO,
+ IRDMA_PFHMC_ERRORDATA,
IRDMA_MAX_REGS, /* Must be last entry */
};
diff --git a/drivers/infiniband/hw/irdma/utils.c b/drivers/infiniband/hw/irdma/utils.c
index e4037d5ef899..290ad02ed657 100644
--- a/drivers/infiniband/hw/irdma/utils.c
+++ b/drivers/infiniband/hw/irdma/utils.c
@@ -1168,6 +1168,12 @@ void irdma_free_qp_rsrc(struct irdma_qp *iwqp)
iwqp->kqp.dma_mem.va = NULL;
kfree(iwqp->kqp.sq_wrid_mem);
kfree(iwqp->kqp.rq_wrid_mem);
+
+ if (iwqp->user_mode && iwqp->iwpbl) {
+ struct irdma_mr *iwmr = iwqp->iwpbl->iwmr;
+
+ refcount_dec(&iwmr->user_ring_refs);
+ }
}
/**
diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c
index b7388b41ed95..8e094e6568b3 100644
--- a/drivers/infiniband/hw/irdma/verbs.c
+++ b/drivers/infiniband/hw/irdma/verbs.c
@@ -18,11 +18,10 @@ static int irdma_query_device(struct ib_device *ibdev,
struct irdma_hw_attrs *hw_attrs = &rf->sc_dev.hw_attrs;
int err;
- err = ib_is_udata_in_empty(udata);
+ err = ib_no_udata_io(udata);
if (err)
return err;
- memset(props, 0, sizeof(*props));
addrconf_addr_eui48((u8 *)&props->sys_image_guid,
iwdev->netdev->dev_addr);
props->fw_ver = (u64)irdma_fw_major_ver(&rf->sc_dev) << 32 |
@@ -76,7 +75,7 @@ static int irdma_query_device(struct ib_device *ibdev,
if (hw_attrs->uk_attrs.hw_rev >= IRDMA_GEN_3)
props->device_cap_flags |= IB_DEVICE_MEM_WINDOW_TYPE_2B;
- return ib_respond_empty_udata(udata);
+ return 0;
}
/**
@@ -407,6 +406,10 @@ static int irdma_alloc_pd(struct ib_pd *pd, struct ib_udata *udata)
u32 pd_id = 0;
int err;
+ err = ib_is_udata_in_empty(udata);
+ if (err)
+ return err;
+
if (udata && udata->outlen < IRDMA_ALLOC_PD_MIN_RESP_LEN)
return -EINVAL;
@@ -445,6 +448,11 @@ static int irdma_dealloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
{
struct irdma_pd *iwpd = to_iwpd(ibpd);
struct irdma_device *iwdev = to_iwdev(ibpd->device);
+ int ret;
+
+ ret = ib_no_udata_io(udata);
+ if (ret)
+ return ret;
irdma_free_rsrc(iwdev->rf, iwdev->rf->allocated_pds, iwpd->sc_pd.pd_id);
@@ -464,6 +472,9 @@ static struct irdma_pbl *irdma_get_pbl(unsigned long va,
list_for_each_entry (iwpbl, pbl_list, list) {
if (iwpbl->user_base == va) {
+ struct irdma_mr *iwmr = iwpbl->iwmr;
+
+ refcount_inc(&iwmr->user_ring_refs);
list_del(&iwpbl->list);
iwpbl->on_list = false;
return iwpbl;
@@ -534,11 +545,10 @@ static int irdma_setup_push_mmap_entries(struct irdma_ucontext *ucontext,
}
/**
- * irdma_destroy_qp - destroy qp
+ * _irdma_destroy_qp - destroy qp
* @ibqp: qp's ib pointer also to get to device's qp address
- * @udata: user data
*/
-static int irdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
+static void _irdma_destroy_qp(struct ib_qp *ibqp)
{
struct irdma_qp *iwqp = to_iwqp(ibqp);
struct irdma_device *iwdev = iwqp->iwdev;
@@ -570,6 +580,22 @@ static int irdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
if (iwqp->sc_qp.qp_uk.qp_id == 1)
iwdev->rf->hwqp1_rsvd = false;
irdma_free_qp_rsrc(iwqp);
+}
+
+/**
+ * irdma_destroy_qp - destroy qp
+ * @ibqp: qp's ib pointer also to get to device's qp address
+ * @udata: user data
+ */
+static int irdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
+{
+ int ret;
+
+ ret = ib_no_udata_io(udata);
+ if (ret)
+ return ret;
+
+ _irdma_destroy_qp(ibqp);
return 0;
}
@@ -605,37 +631,29 @@ static void irdma_setup_virt_qp(struct irdma_device *iwdev,
/**
* irdma_setup_umode_qp - setup sq and rq size in user mode qp
- * @udata: udata
+ * @ucontext: user context
+ * @req: user request pointer
* @iwdev: iwarp device
* @iwqp: qp ptr (user or kernel)
* @info: initialize info to return
* @init_attr: Initial QP create attributes
*/
-static int irdma_setup_umode_qp(struct ib_udata *udata,
+static int irdma_setup_umode_qp(struct irdma_ucontext *ucontext,
+ struct irdma_create_qp_req *req,
struct irdma_device *iwdev,
struct irdma_qp *iwqp,
struct irdma_qp_init_info *info,
struct ib_qp_init_attr *init_attr)
{
- struct irdma_ucontext *ucontext = rdma_udata_to_drv_context(udata,
- struct irdma_ucontext, ibucontext);
struct irdma_qp_uk_init_info *ukinfo = &info->qp_uk_init_info;
- struct irdma_create_qp_req req;
unsigned long flags;
int ret;
- ret = ib_copy_from_udata(&req, udata,
- min(sizeof(req), udata->inlen));
- if (ret) {
- ibdev_dbg(&iwdev->ibdev, "VERBS: ib_copy_from_data fail\n");
- return ret;
- }
-
- iwqp->ctx_info.qp_compl_ctx = req.user_compl_ctx;
+ iwqp->ctx_info.qp_compl_ctx = req->user_compl_ctx;
iwqp->user_mode = 1;
spin_lock_irqsave(&ucontext->qp_reg_mem_list_lock, flags);
- iwqp->iwpbl = irdma_get_pbl((unsigned long)req.user_wqe_bufs,
+ iwqp->iwpbl = irdma_get_pbl((unsigned long)req->user_wqe_bufs,
&ucontext->qp_reg_mem_list);
spin_unlock_irqrestore(&ucontext->qp_reg_mem_list_lock, flags);
@@ -962,6 +980,7 @@ static int irdma_create_qp(struct ib_qp *ibqp,
struct irdma_uk_attrs *uk_attrs = &dev->hw_attrs.uk_attrs;
struct irdma_qp_init_info init_info = {};
struct irdma_qp_host_ctx_info *ctx_info;
+ struct irdma_create_qp_req ureq = {};
struct irdma_srq *iwsrq;
bool srq_valid = false;
u32 srq_id = 0;
@@ -979,9 +998,14 @@ static int irdma_create_qp(struct ib_qp *ibqp,
if (err_code)
return err_code;
- if (udata && (udata->inlen < IRDMA_CREATE_QP_MIN_REQ_LEN ||
- udata->outlen < IRDMA_CREATE_QP_MIN_RESP_LEN))
- return -EINVAL;
+ if (udata) {
+ if (udata->outlen < IRDMA_CREATE_QP_MIN_RESP_LEN)
+ return -EINVAL;
+
+ err_code = ib_copy_validate_udata_in(udata, ureq, user_compl_ctx);
+ if (err_code)
+ return err_code;
+ }
init_info.vsi = &iwdev->vsi;
init_info.qp_uk_init_info.uk_attrs = uk_attrs;
@@ -1040,9 +1064,14 @@ static int irdma_create_qp(struct ib_qp *ibqp,
init_waitqueue_head(&iwqp->mod_qp_waitq);
if (udata) {
+ struct irdma_ucontext *ucontext =
+ rdma_udata_to_drv_context(udata,
+ struct irdma_ucontext,
+ ibucontext);
+
init_info.qp_uk_init_info.abi_ver = iwpd->sc_pd.abi_ver;
- err_code = irdma_setup_umode_qp(udata, iwdev, iwqp, &init_info,
- init_attr);
+ err_code = irdma_setup_umode_qp(ucontext, &ureq, iwdev, iwqp,
+ &init_info, init_attr);
} else {
INIT_DELAYED_WORK(&iwqp->dwork_flush, irdma_flush_worker);
init_info.qp_uk_init_info.abi_ver = IRDMA_ABI_VER;
@@ -1109,8 +1138,12 @@ static int irdma_create_qp(struct ib_qp *ibqp,
init_completion(&iwqp->free_qp);
if (udata) {
- /* GEN_1 legacy support with libi40iw does not have expanded uresp struct */
- if (udata->outlen < sizeof(uresp)) {
+ /* GEN_1 legacy support with libi40iw does not have expanded
+ * uresp struct. Check for the exact legacy size (20 bytes) to
+ * ensure that newer expanded uresp structs don't accidentally
+ * trigger the legacy fallback.
+ */
+ if (udata->outlen == IRDMA_CREATE_QP_MIN_RESP_LEN) {
uresp.lsmm = 1;
uresp.push_idx = IRDMA_INVALID_PUSH_PAGE_INDEX_GEN_1;
} else {
@@ -1124,7 +1157,7 @@ static int irdma_create_qp(struct ib_qp *ibqp,
err_code = ib_respond_udata(udata, uresp);
if (err_code) {
- irdma_destroy_qp(&iwqp->ibqp, udata);
+ _irdma_destroy_qp(&iwqp->ibqp);
return err_code;
}
}
@@ -1273,7 +1306,6 @@ static int irdma_wait_for_suspend(struct irdma_qp *iwqp)
int irdma_modify_qp_roce(struct ib_qp *ibqp, struct ib_qp_attr *attr,
int attr_mask, struct ib_udata *udata)
{
-#define IRDMA_MODIFY_QP_MIN_REQ_LEN offsetofend(struct irdma_modify_qp_req, rq_flush)
#define IRDMA_MODIFY_QP_MIN_RESP_LEN offsetofend(struct irdma_modify_qp_resp, push_valid)
struct irdma_pd *iwpd = to_iwpd(ibqp->pd);
struct irdma_qp *iwqp = to_iwqp(ibqp);
@@ -1289,15 +1321,26 @@ int irdma_modify_qp_roce(struct ib_qp *ibqp, struct ib_qp_attr *attr,
u8 issue_modify_qp = 0;
int ret = 0;
+ /* Clear the response buffer (if any). It may be updated again later. */
+ ret = ib_respond_empty_udata(udata);
+ if (ret)
+ return ret;
+
ctx_info = &iwqp->ctx_info;
roce_info = &iwqp->roce_info;
udp_info = &iwqp->udp_info;
if (udata) {
/* udata inlen/outlen can be 0 when supporting legacy libi40iw */
- if ((udata->inlen && udata->inlen < IRDMA_MODIFY_QP_MIN_REQ_LEN) ||
- (udata->outlen && udata->outlen < IRDMA_MODIFY_QP_MIN_RESP_LEN))
+ if (udata->outlen && udata->outlen < IRDMA_MODIFY_QP_MIN_RESP_LEN)
return -EINVAL;
+
+ /* For current irdma, validate against ABI def. */
+ if (udata->inlen) {
+ ret = ib_copy_validate_udata_in(udata, ureq, rsvd);
+ if (ret)
+ return ret;
+ }
}
if (attr_mask & ~IB_QP_ATTR_STANDARD_BITS)
@@ -1540,10 +1583,6 @@ int irdma_modify_qp_roce(struct ib_qp *ibqp, struct ib_qp_attr *attr,
iwqp->ibqp_state = attr->qp_state;
spin_unlock_irqrestore(&iwqp->lock, flags);
if (udata && udata->inlen) {
- if (ib_copy_from_udata(&ureq, udata,
- min(sizeof(ureq), udata->inlen)))
- return -EINVAL;
-
irdma_flush_wqes(iwqp,
(ureq.sq_flush ? IRDMA_FLUSH_SQ : 0) |
(ureq.rq_flush ? IRDMA_FLUSH_RQ : 0) |
@@ -1633,7 +1672,6 @@ exit:
int irdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
struct ib_udata *udata)
{
-#define IRDMA_MODIFY_QP_MIN_REQ_LEN offsetofend(struct irdma_modify_qp_req, rq_flush)
#define IRDMA_MODIFY_QP_MIN_RESP_LEN offsetofend(struct irdma_modify_qp_resp, push_valid)
struct irdma_qp *iwqp = to_iwqp(ibqp);
struct irdma_device *iwdev = iwqp->iwdev;
@@ -1649,11 +1687,20 @@ int irdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
int err;
unsigned long flags;
+ err = ib_respond_empty_udata(udata);
+ if (err)
+ return err;
+
if (udata) {
/* udata inlen/outlen can be 0 when supporting legacy libi40iw */
- if ((udata->inlen && udata->inlen < IRDMA_MODIFY_QP_MIN_REQ_LEN) ||
- (udata->outlen && udata->outlen < IRDMA_MODIFY_QP_MIN_RESP_LEN))
+ if (udata->outlen && udata->outlen < IRDMA_MODIFY_QP_MIN_RESP_LEN)
return -EINVAL;
+
+ if (udata->inlen) {
+ err = ib_copy_validate_udata_in(udata, ureq, rsvd);
+ if (err)
+ return err;
+ }
}
if (attr_mask & ~IB_QP_ATTR_STANDARD_BITS)
@@ -1743,10 +1790,6 @@ int irdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
iwqp->ibqp_state = attr->qp_state;
spin_unlock_irqrestore(&iwqp->lock, flags);
if (udata && udata->inlen) {
- if (ib_copy_from_udata(&ureq, udata,
- min(sizeof(ureq), udata->inlen)))
- return -EINVAL;
-
irdma_flush_wqes(iwqp,
(ureq.sq_flush ? IRDMA_FLUSH_SQ : 0) |
(ureq.rq_flush ? IRDMA_FLUSH_RQ : 0) |
@@ -1880,6 +1923,11 @@ static void irdma_srq_free_rsrc(struct irdma_pci_f *rf, struct irdma_srq *iwsrq)
dma_free_coherent(rf->sc_dev.hw->device, iwsrq->kmem.size,
iwsrq->kmem.va, iwsrq->kmem.pa);
iwsrq->kmem.va = NULL;
+ } else {
+ /* Not called in any failure path, so iwpbl is valid. */
+ struct irdma_mr *iwmr = iwsrq->iwpbl->iwmr;
+
+ refcount_dec(&iwmr->user_ring_refs);
}
irdma_free_rsrc(rf, rf->allocated_srqs, srq->srq_uk.srq_id);
@@ -1902,6 +1950,21 @@ static void irdma_cq_free_rsrc(struct irdma_pci_f *rf, struct irdma_cq *iwcq)
iwcq->kmem_shadow.size,
iwcq->kmem_shadow.va, iwcq->kmem_shadow.pa);
iwcq->kmem_shadow.va = NULL;
+ } else {
+ struct irdma_mr *iwmr;
+
+ /* May be called in a failure path before iwpbl is valid. */
+ if (iwcq->iwpbl) {
+ iwmr = iwcq->iwpbl->iwmr;
+
+ refcount_dec(&iwmr->user_ring_refs);
+ }
+
+ if (iwcq->iwpbl_shadow) {
+ iwmr = iwcq->iwpbl_shadow->iwmr;
+
+ refcount_dec(&iwmr->user_ring_refs);
+ }
}
irdma_free_rsrc(rf, rf->allocated_cqs, cq->cq_uk.cq_id);
@@ -1958,6 +2021,11 @@ static int irdma_destroy_srq(struct ib_srq *ibsrq, struct ib_udata *udata)
struct irdma_device *iwdev = to_iwdev(ibsrq->device);
struct irdma_srq *iwsrq = to_iwsrq(ibsrq);
struct irdma_sc_srq *srq = &iwsrq->sc_srq;
+ int ret;
+
+ ret = ib_no_udata_io(udata);
+ if (ret)
+ return ret;
irdma_srq_wq_destroy(iwdev->rf, srq);
irdma_srq_free_rsrc(iwdev->rf, iwsrq);
@@ -1978,6 +2046,11 @@ static int irdma_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
struct irdma_sc_ceq *ceq = dev->ceq[cq->ceq_id];
struct irdma_ceq *iwceq = container_of(ceq, struct irdma_ceq, sc_ceq);
unsigned long flags;
+ int ret;
+
+ ret = ib_no_udata_io(udata);
+ if (ret)
+ return ret;
spin_lock_irqsave(&iwcq->lock, flags);
if (!list_empty(&iwcq->cmpl_generated))
@@ -2008,7 +2081,6 @@ static int irdma_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
static int irdma_resize_cq(struct ib_cq *ibcq, unsigned int entries,
struct ib_udata *udata)
{
-#define IRDMA_RESIZE_CQ_MIN_REQ_LEN offsetofend(struct irdma_resize_cq_req, user_cq_buffer)
struct irdma_cq *iwcq = to_iwcq(ibcq);
struct irdma_sc_dev *dev = iwcq->sc_cq.dev;
struct irdma_cqp_request *cqp_request;
@@ -2017,7 +2089,7 @@ static int irdma_resize_cq(struct ib_cq *ibcq, unsigned int entries,
struct irdma_modify_cq_info info = {};
struct irdma_dma_mem kmem_buf;
struct irdma_cq_mr *cqmr_buf;
- struct irdma_pbl *iwpbl_buf;
+ struct irdma_pbl *iwpbl_buf = NULL;
struct irdma_device *iwdev;
struct irdma_pci_f *rf;
struct irdma_cq_buf *cq_buf = NULL;
@@ -2032,12 +2104,13 @@ static int irdma_resize_cq(struct ib_cq *ibcq, unsigned int entries,
IRDMA_FEATURE_CQ_RESIZE))
return -EOPNOTSUPP;
- if (udata && udata->inlen < IRDMA_RESIZE_CQ_MIN_REQ_LEN)
- return -EINVAL;
-
if (entries > rf->max_cqe)
return -EINVAL;
+ ret = ib_respond_empty_udata(udata);
+ if (ret)
+ return ret;
+
if (!iwcq->user_mode) {
entries += 2;
@@ -2064,9 +2137,9 @@ static int irdma_resize_cq(struct ib_cq *ibcq, unsigned int entries,
rdma_udata_to_drv_context(udata, struct irdma_ucontext,
ibucontext);
- if (ib_copy_from_udata(&req, udata,
- min(sizeof(req), udata->inlen)))
- return -EINVAL;
+ ret = ib_copy_validate_udata_in(udata, req, user_cq_buffer);
+ if (ret)
+ return ret;
spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags);
iwpbl_buf = irdma_get_pbl((unsigned long)req.user_cq_buffer,
@@ -2128,6 +2201,19 @@ static int irdma_resize_cq(struct ib_cq *ibcq, unsigned int entries,
goto error;
spin_lock_irqsave(&iwcq->lock, flags);
+ if (udata) {
+ struct irdma_pbl *old_iwpbl = iwcq->iwpbl;
+
+ /* Only update if the resize was successful. Otherwise, HW is
+ * still pointing to the old PBL.
+ */
+ iwcq->iwpbl = iwpbl_buf;
+ if (old_iwpbl) {
+ struct irdma_mr *old_iwmr = old_iwpbl->iwmr;
+
+ refcount_dec(&old_iwmr->user_ring_refs);
+ }
+ }
if (cq_buf) {
cq_buf->kmem_buf = iwcq->kmem;
cq_buf->hw = dev->hw;
@@ -2143,6 +2229,11 @@ static int irdma_resize_cq(struct ib_cq *ibcq, unsigned int entries,
return 0;
error:
+ if (iwpbl_buf) {
+ struct irdma_mr *iwmr = iwpbl_buf->iwmr;
+
+ refcount_dec(&iwmr->user_ring_refs);
+ }
if (!udata) {
dma_free_coherent(dev->hw->device, kmem_buf.size, kmem_buf.va,
kmem_buf.pa);
@@ -2194,6 +2285,10 @@ static int irdma_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
struct cqp_cmds_info *cqp_info;
int status;
+ status = ib_no_udata_io(udata);
+ if (status)
+ return status;
+
if (attr_mask & IB_SRQ_MAX_WR)
return -EINVAL;
@@ -2236,24 +2331,20 @@ static int irdma_setup_umode_srq(struct irdma_device *iwdev,
struct irdma_srq_init_info *info,
struct ib_udata *udata)
{
-#define IRDMA_CREATE_SRQ_MIN_REQ_LEN \
- offsetofend(struct irdma_create_srq_req, user_shadow_area)
struct irdma_create_srq_req req = {};
struct irdma_ucontext *ucontext;
struct irdma_srq_mr *srqmr;
struct irdma_pbl *iwpbl;
unsigned long flags;
+ int ret;
iwsrq->user_mode = true;
ucontext = rdma_udata_to_drv_context(udata, struct irdma_ucontext,
ibucontext);
- if (udata->inlen < IRDMA_CREATE_SRQ_MIN_REQ_LEN)
- return -EINVAL;
-
- if (ib_copy_from_udata(&req, udata,
- min(sizeof(req), udata->inlen)))
- return -EFAULT;
+ ret = ib_copy_validate_udata_in(udata, req, user_shadow_area);
+ if (ret)
+ return ret;
spin_lock_irqsave(&ucontext->srq_reg_mem_list_lock, flags);
iwpbl = irdma_get_pbl((unsigned long)req.user_srq_buf,
@@ -2316,6 +2407,7 @@ static int irdma_create_srq(struct ib_srq *ibsrq,
struct ib_srq_init_attr *initattrs,
struct ib_udata *udata)
{
+#define IRDMA_CREATE_SRQ_MIN_RESP_LEN offsetofend(struct irdma_create_srq_resp, srq_size)
struct irdma_device *iwdev = to_iwdev(ibsrq->device);
struct ib_srq_attr *attr = &initattrs->attr;
struct irdma_pd *iwpd = to_iwpd(ibsrq->pd);
@@ -2336,6 +2428,9 @@ static int irdma_create_srq(struct ib_srq *ibsrq,
if (initattrs->srq_type != IB_SRQT_BASIC)
return -EOPNOTSUPP;
+ if (udata && udata->outlen < IRDMA_CREATE_SRQ_MIN_RESP_LEN)
+ return -EINVAL;
+
if (!(uk_attrs->feature_flags & IRDMA_FEATURE_SRQ) ||
attr->max_sge > uk_attrs->max_hw_wq_frags)
return -EINVAL;
@@ -2419,6 +2514,11 @@ free_dmem:
dma_free_coherent(rf->hw.device, iwsrq->kmem.size,
iwsrq->kmem.va, iwsrq->kmem.pa);
free_rsrc:
+ if (iwsrq->user_mode && iwsrq->iwpbl) {
+ struct irdma_mr *iwmr = iwsrq->iwpbl->iwmr;
+
+ refcount_dec(&iwmr->user_ring_refs);
+ }
irdma_free_rsrc(rf, rf->allocated_srqs, iwsrq->srq_num);
return err_code;
}
@@ -2458,7 +2558,6 @@ static int irdma_create_cq(struct ib_cq *ibcq,
const struct ib_cq_init_attr *attr,
struct uverbs_attr_bundle *attrs)
{
-#define IRDMA_CREATE_CQ_MIN_REQ_LEN offsetofend(struct irdma_create_cq_req, user_cq_buf)
#define IRDMA_CREATE_CQ_MIN_RESP_LEN offsetofend(struct irdma_create_cq_resp, cq_size)
struct ib_udata *udata = &attrs->driver_udata;
struct ib_device *ibdev = ibcq->device;
@@ -2482,8 +2581,7 @@ static int irdma_create_cq(struct ib_cq *ibcq,
if (err_code)
return err_code;
- if (udata && (udata->inlen < IRDMA_CREATE_CQ_MIN_REQ_LEN ||
- udata->outlen < IRDMA_CREATE_CQ_MIN_RESP_LEN))
+ if (udata && udata->outlen < IRDMA_CREATE_CQ_MIN_RESP_LEN)
return -EINVAL;
err_code = irdma_alloc_rsrc(rf, rf->allocated_cqs, rf->max_cq, &cq_num,
@@ -2498,6 +2596,8 @@ static int irdma_create_cq(struct ib_cq *ibcq,
INIT_LIST_HEAD(&iwcq->resize_list);
INIT_LIST_HEAD(&iwcq->cmpl_generated);
iwcq->cq_num = cq_num;
+ iwcq->iwpbl = NULL;
+ iwcq->iwpbl_shadow = NULL;
info.dev = dev;
ukinfo->cq_size = max(entries, 4);
ukinfo->cq_id = cq_num;
@@ -2517,49 +2617,50 @@ static int irdma_create_cq(struct ib_cq *ibcq,
struct irdma_ucontext *ucontext;
struct irdma_create_cq_req req = {};
struct irdma_cq_mr *cqmr;
- struct irdma_pbl *iwpbl;
- struct irdma_pbl *iwpbl_shadow;
struct irdma_cq_mr *cqmr_shadow;
iwcq->user_mode = true;
ucontext =
rdma_udata_to_drv_context(udata, struct irdma_ucontext,
ibucontext);
- if (ib_copy_from_udata(&req, udata,
- min(sizeof(req), udata->inlen))) {
- err_code = -EFAULT;
+ /* Even though the last member of struct irdma_create_cq_req
+ * was always user_shadow_area, we need backwards compat with
+ * the legacy i40iw struct i40iw_ucreate_cq which stopped
+ * at user_cq_buffer.
+ */
+ err_code = ib_copy_validate_udata_in(udata, req, user_cq_buf);
+ if (err_code)
goto cq_free_rsrc;
- }
spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags);
- iwpbl = irdma_get_pbl((unsigned long)req.user_cq_buf,
- &ucontext->cq_reg_mem_list);
+ iwcq->iwpbl = irdma_get_pbl((unsigned long)req.user_cq_buf,
+ &ucontext->cq_reg_mem_list);
spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags);
- if (!iwpbl) {
+ if (!iwcq->iwpbl) {
err_code = -EPROTO;
goto cq_free_rsrc;
}
- cqmr = &iwpbl->cq_mr;
+ cqmr = &iwcq->iwpbl->cq_mr;
if (rf->sc_dev.hw_attrs.uk_attrs.feature_flags &
IRDMA_FEATURE_CQ_RESIZE) {
spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags);
- iwpbl_shadow = irdma_get_pbl(
+ iwcq->iwpbl_shadow = irdma_get_pbl(
(unsigned long)req.user_shadow_area,
&ucontext->cq_reg_mem_list);
spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags);
- if (!iwpbl_shadow) {
+ if (!iwcq->iwpbl_shadow) {
err_code = -EPROTO;
goto cq_free_rsrc;
}
- cqmr_shadow = &iwpbl_shadow->cq_mr;
+ cqmr_shadow = &iwcq->iwpbl_shadow->cq_mr;
info.shadow_area_pa = cqmr_shadow->cq_pbl.addr;
} else {
info.shadow_area_pa = cqmr->shadow;
}
- if (iwpbl->pbl_allocated) {
+ if (iwcq->iwpbl->pbl_allocated) {
info.virtual_map = true;
info.pbl_chunk_size = 1;
info.first_pm_pbl_idx = cqmr->cq_pbl.idx;
@@ -3034,6 +3135,10 @@ static int irdma_alloc_mw(struct ib_mw *ibmw, struct ib_udata *udata)
int err_code;
u32 stag;
+ err_code = ib_no_udata_io(udata);
+ if (err_code)
+ return err_code;
+
stag = irdma_create_stag(iwdev);
if (!stag)
return -ENOMEM;
@@ -3362,6 +3467,7 @@ static struct irdma_mr *irdma_alloc_iwmr(struct ib_umem *region,
if (!iwmr)
return ERR_PTR(-ENOMEM);
+ refcount_set(&iwmr->user_ring_refs, 1);
iwpbl = &iwmr->iwpbl;
iwpbl->iwmr = iwmr;
iwmr->region = region;
@@ -3508,7 +3614,6 @@ static struct ib_mr *irdma_reg_user_mr(struct ib_pd *pd, u64 start, u64 len,
struct ib_dmah *dmah,
struct ib_udata *udata)
{
-#define IRDMA_MEM_REG_MIN_REQ_LEN offsetofend(struct irdma_mem_reg_req, sq_pages)
struct irdma_device *iwdev = to_iwdev(pd->device);
struct irdma_mem_reg_req req = {};
struct ib_umem *region = NULL;
@@ -3518,10 +3623,15 @@ static struct ib_mr *irdma_reg_user_mr(struct ib_pd *pd, u64 start, u64 len,
if (dmah)
return ERR_PTR(-EOPNOTSUPP);
- if (len > iwdev->rf->sc_dev.hw_attrs.max_mr_size)
- return ERR_PTR(-EINVAL);
+ err = ib_copy_validate_udata_in(udata, req, sq_pages);
+ if (err)
+ return ERR_PTR(err);
+
+ err = ib_respond_empty_udata(udata);
+ if (err)
+ return ERR_PTR(err);
- if (udata->inlen < IRDMA_MEM_REG_MIN_REQ_LEN)
+ if (len > iwdev->rf->sc_dev.hw_attrs.max_mr_size)
return ERR_PTR(-EINVAL);
region = ib_umem_get_va(pd->device, start, len, access);
@@ -3532,11 +3642,6 @@ static struct ib_mr *irdma_reg_user_mr(struct ib_pd *pd, u64 start, u64 len,
return (struct ib_mr *)region;
}
- if (ib_copy_from_udata(&req, udata, min(sizeof(req), udata->inlen))) {
- ib_umem_release(region);
- return ERR_PTR(-EFAULT);
- }
-
iwmr = irdma_alloc_iwmr(region, pd, virt, req.reg_type);
if (IS_ERR(iwmr)) {
ib_umem_release(region);
@@ -3784,6 +3889,10 @@ static struct ib_mr *irdma_rereg_user_mr(struct ib_mr *ib_mr, int flags,
struct ib_umem_dmabuf *umem_dmabuf;
int ret;
+ ret = ib_no_udata_io(udata);
+ if (ret)
+ return ERR_PTR(ret);
+
if (len > iwdev->rf->sc_dev.hw_attrs.max_mr_size)
return ERR_PTR(-EINVAL);
@@ -3929,41 +4038,41 @@ static struct ib_mr *irdma_get_dma_mr(struct ib_pd *pd, int acc)
* irdma_del_memlist - Deleting pbl list entries for CQ/QP
* @iwmr: iwmr for IB's user page addresses
* @ucontext: ptr to user context
+ *
+ * Return: True if the MR is currently in-use by a QP/CQ/SRQ ring.
*/
-static void irdma_del_memlist(struct irdma_mr *iwmr,
+static bool irdma_del_memlist(struct irdma_mr *iwmr,
struct irdma_ucontext *ucontext)
{
struct irdma_pbl *iwpbl = &iwmr->iwpbl;
unsigned long flags;
+ spinlock_t *lock;
+ bool in_use = false;
switch (iwmr->type) {
case IRDMA_MEMREG_TYPE_CQ:
- spin_lock_irqsave(&ucontext->cq_reg_mem_list_lock, flags);
- if (iwpbl->on_list) {
- iwpbl->on_list = false;
- list_del(&iwpbl->list);
- }
- spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags);
+ lock = &ucontext->cq_reg_mem_list_lock;
break;
case IRDMA_MEMREG_TYPE_QP:
- spin_lock_irqsave(&ucontext->qp_reg_mem_list_lock, flags);
- if (iwpbl->on_list) {
- iwpbl->on_list = false;
- list_del(&iwpbl->list);
- }
- spin_unlock_irqrestore(&ucontext->qp_reg_mem_list_lock, flags);
+ lock = &ucontext->qp_reg_mem_list_lock;
break;
case IRDMA_MEMREG_TYPE_SRQ:
- spin_lock_irqsave(&ucontext->srq_reg_mem_list_lock, flags);
- if (iwpbl->on_list) {
- iwpbl->on_list = false;
- list_del(&iwpbl->list);
- }
- spin_unlock_irqrestore(&ucontext->srq_reg_mem_list_lock, flags);
+ lock = &ucontext->srq_reg_mem_list_lock;
break;
default:
- break;
+ return false;
}
+
+ spin_lock_irqsave(lock, flags);
+ if (!refcount_dec_if_one(&iwmr->user_ring_refs)) {
+ in_use = true;
+ } else if (iwpbl->on_list) {
+ iwpbl->on_list = false;
+ list_del(&iwpbl->list);
+ }
+ spin_unlock_irqrestore(lock, flags);
+
+ return in_use;
}
/**
@@ -3979,6 +4088,10 @@ static int irdma_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata)
bool dmabuf_revocable = iwmr->region && iwmr->region->is_dmabuf;
int ret;
+ ret = ib_no_udata_io(udata);
+ if (ret)
+ return ret;
+
if (iwmr->type != IRDMA_MEMREG_TYPE_MEM) {
if (iwmr->region) {
struct irdma_ucontext *ucontext;
@@ -3986,7 +4099,12 @@ static int irdma_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata)
ucontext = rdma_udata_to_drv_context(udata,
struct irdma_ucontext,
ibucontext);
- irdma_del_memlist(iwmr, ucontext);
+
+ /* Do not allow the MR to be unpinned if it is still
+ * backing a user ring.
+ */
+ if (irdma_del_memlist(iwmr, ucontext))
+ return -EBUSY;
}
goto done;
}
@@ -5295,6 +5413,10 @@ static int irdma_create_user_ah(struct ib_ah *ibah,
struct irdma_ah *parent_ah;
int err;
+ err = ib_is_udata_in_empty(udata);
+ if (err)
+ return err;
+
if (udata->outlen < IRDMA_CREATE_AH_MIN_RESP_LEN)
return -EINVAL;
@@ -5346,6 +5468,10 @@ static int irdma_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *attr,
struct irdma_device *iwdev = to_iwdev(ibah->pd->device);
int err;
+ err = ib_no_udata_io(udata);
+ if (err)
+ return err;
+
err = irdma_setup_ah(ibah, attr);
if (err)
return err;
@@ -5428,6 +5554,7 @@ static const struct ib_device_ops irdma_dev_ops = {
.owner = THIS_MODULE,
.driver_id = RDMA_DRIVER_IRDMA,
.uverbs_abi_ver = IRDMA_ABI_VER,
+ .uverbs_robust_udata = true,
.alloc_hw_port_stats = irdma_alloc_hw_port_stats,
.alloc_mr = irdma_alloc_mr,
diff --git a/drivers/infiniband/hw/irdma/verbs.h b/drivers/infiniband/hw/irdma/verbs.h
index 289ebc9b23ca..a1651641eb71 100644
--- a/drivers/infiniband/hw/irdma/verbs.h
+++ b/drivers/infiniband/hw/irdma/verbs.h
@@ -120,6 +120,7 @@ struct irdma_mr {
u64 len;
u64 pgaddrmem[IRDMA_MAX_SAVED_PHY_PGADDR];
struct irdma_pbl iwpbl;
+ refcount_t user_ring_refs;
};
struct irdma_srq {
@@ -152,6 +153,8 @@ struct irdma_cq {
struct list_head resize_list;
struct irdma_cq_poll_info cur_cqe;
struct list_head cmpl_generated;
+ struct irdma_pbl *iwpbl;
+ struct irdma_pbl *iwpbl_shadow;
};
struct irdma_cmpl_gen {
diff --git a/drivers/infiniband/hw/mana/cq.c b/drivers/infiniband/hw/mana/cq.c
index f2547989f422..d4e5e3f91268 100644
--- a/drivers/infiniband/hw/mana/cq.c
+++ b/drivers/infiniband/hw/mana/cq.c
@@ -27,7 +27,8 @@ int mana_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
is_rnic_cq = mana_ib_is_rnic(mdev);
if (udata) {
- err = ib_copy_validate_udata_in(udata, ucmd, buf_addr);
+ err = ib_copy_validate_udata_in_cm(udata, ucmd, buf_addr,
+ MANA_IB_CREATE_RNIC_CQ);
if (err)
return err;
@@ -105,6 +106,11 @@ int mana_ib_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
struct mana_ib_cq *cq = container_of(ibcq, struct mana_ib_cq, ibcq);
struct ib_device *ibdev = ibcq->device;
struct mana_ib_dev *mdev;
+ int err;
+
+ err = ib_no_udata_io(udata);
+ if (err)
+ return err;
mdev = container_of(ibdev, struct mana_ib_dev, ib_dev);
diff --git a/drivers/infiniband/hw/mana/device.c b/drivers/infiniband/hw/mana/device.c
index 9811570ab8f8..a8d19586a78a 100644
--- a/drivers/infiniband/hw/mana/device.c
+++ b/drivers/infiniband/hw/mana/device.c
@@ -15,6 +15,7 @@ static const struct ib_device_ops mana_ib_dev_ops = {
.owner = THIS_MODULE,
.driver_id = RDMA_DRIVER_MANA,
.uverbs_abi_ver = MANA_IB_UVERBS_ABI_VERSION,
+ .uverbs_robust_udata = true,
.add_gid = mana_ib_gd_add_gid,
.alloc_mw = mana_ib_alloc_mw,
diff --git a/drivers/infiniband/hw/mana/main.c b/drivers/infiniband/hw/mana/main.c
index efe2935bda29..0bfb1883a186 100644
--- a/drivers/infiniband/hw/mana/main.c
+++ b/drivers/infiniband/hw/mana/main.c
@@ -101,6 +101,10 @@ int mana_ib_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
struct gdma_context *gc;
int err;
+ err = ib_no_udata_io(udata);
+ if (err)
+ return err;
+
dev = container_of(ibdev, struct mana_ib_dev, ib_dev);
gc = mdev_to_gc(dev);
@@ -133,6 +137,11 @@ int mana_ib_dealloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
struct gdma_destroy_pd_req req = {};
struct mana_ib_dev *dev;
struct gdma_context *gc;
+ int err;
+
+ err = ib_no_udata_io(udata);
+ if (err)
+ return err;
dev = container_of(ibdev, struct mana_ib_dev, ib_dev);
gc = mdev_to_gc(dev);
@@ -142,7 +151,11 @@ int mana_ib_dealloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
req.pd_handle = pd->pd_handle;
- return mana_gd_send_request(gc, sizeof(req), &req, sizeof(resp), &resp);
+ err = mana_gd_send_request(gc, sizeof(req), &req, sizeof(resp), &resp);
+ if (err)
+ return err;
+
+ return 0;
}
static int mana_gd_destroy_doorbell_page(struct gdma_context *gc,
@@ -198,17 +211,17 @@ int mana_ib_alloc_ucontext(struct ib_ucontext *ibcontext,
int doorbell_page;
int ret;
+ ret = ib_no_udata_io(udata);
+ if (ret)
+ return ret;
+
mdev = container_of(ibdev, struct mana_ib_dev, ib_dev);
gc = mdev_to_gc(mdev);
/* Allocate a doorbell page index */
ret = mana_gd_allocate_doorbell_page(gc, &doorbell_page);
- if (ret) {
- ibdev_dbg(ibdev, "Failed to allocate doorbell page %d\n", ret);
+ if (ret)
return ret;
- }
-
- ibdev_dbg(ibdev, "Doorbell page allocated %d\n", doorbell_page);
ucontext->doorbell = doorbell_page;
@@ -575,11 +588,10 @@ int mana_ib_query_device(struct ib_device *ibdev, struct ib_device_attr *props,
struct pci_dev *pdev = to_pci_dev(mdev_to_gc(dev)->dev);
int err;
- err = ib_is_udata_in_empty(uhw);
+ err = ib_no_udata_io(uhw);
if (err)
return err;
- memset(props, 0, sizeof(*props));
props->vendor_id = pdev->vendor;
props->vendor_part_id = dev->gdma_dev->dev_id.type;
props->max_mr_size = MANA_IB_MAX_MR_SIZE;
@@ -605,7 +617,7 @@ int mana_ib_query_device(struct ib_device *ibdev, struct ib_device_attr *props,
if (!mana_ib_is_rnic(dev))
props->raw_packet_caps = IB_RAW_PACKET_CAP_IP_CSUM;
- return ib_respond_empty_udata(uhw);
+ return 0;
}
int mana_ib_query_port(struct ib_device *ibdev, u32 port,
diff --git a/drivers/infiniband/hw/mana/mr.c b/drivers/infiniband/hw/mana/mr.c
index 030bfdcfff3c..1233685b4b89 100644
--- a/drivers/infiniband/hw/mana/mr.c
+++ b/drivers/infiniband/hw/mana/mr.c
@@ -113,6 +113,10 @@ struct ib_mr *mana_ib_reg_user_mr(struct ib_pd *ibpd, u64 start, u64 length,
if (dmah)
return ERR_PTR(-EOPNOTSUPP);
+ err = ib_no_udata_io(udata);
+ if (err)
+ return ERR_PTR(err);
+
dev = container_of(ibdev, struct mana_ib_dev, ib_dev);
ibdev_dbg(ibdev,
@@ -327,6 +331,11 @@ int mana_ib_alloc_mw(struct ib_mw *ibmw, struct ib_udata *udata)
{
struct mana_ib_dev *mdev = container_of(ibmw->device, struct mana_ib_dev, ib_dev);
struct mana_ib_pd *pd = container_of(ibmw->pd, struct mana_ib_pd, ibpd);
+ int err;
+
+ err = ib_no_udata_io(udata);
+ if (err)
+ return err;
return mana_ib_gd_create_mw(mdev, pd, ibmw);
}
@@ -346,6 +355,10 @@ int mana_ib_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
struct mana_ib_dev *dev;
int err;
+ err = ib_no_udata_io(udata);
+ if (err)
+ return err;
+
dev = container_of(ibdev, struct mana_ib_dev, ib_dev);
err = mana_ib_gd_destroy_mr(dev, mr->mr_handle);
diff --git a/drivers/infiniband/hw/mana/qp.c b/drivers/infiniband/hw/mana/qp.c
index 60926f39ab9d..c52f3ec14032 100644
--- a/drivers/infiniband/hw/mana/qp.c
+++ b/drivers/infiniband/hw/mana/qp.c
@@ -472,6 +472,12 @@ static void mana_table_remove_rc_qp(struct mana_ib_dev *mdev, struct mana_ib_qp
xa_erase_irq(&mdev->qp_table_wq, qp->ibqp.qp_num);
}
+static void mana_table_drain_qp_ref(struct mana_ib_qp *qp)
+{
+ mana_put_qp_ref(qp);
+ wait_for_completion(&qp->free);
+}
+
static int mana_table_store_ud_qp(struct mana_ib_dev *mdev, struct mana_ib_qp *qp)
{
u32 qids = qp->ud_qp.queues[MANA_UD_SEND_QUEUE].id | MANA_SENDQ_MASK;
@@ -490,6 +496,7 @@ static int mana_table_store_ud_qp(struct mana_ib_dev *mdev, struct mana_ib_qp *q
remove_sq:
xa_erase_irq(&mdev->qp_table_wq, qids);
+ mana_table_drain_qp_ref(qp);
return err;
}
@@ -537,8 +544,7 @@ static void mana_table_remove_qp(struct mana_ib_dev *mdev,
qp->ibqp.qp_type);
return;
}
- mana_put_qp_ref(qp);
- wait_for_completion(&qp->free);
+ mana_table_drain_qp_ref(qp);
}
static int mana_ib_create_rc_qp(struct ib_qp *ibqp, struct ib_pd *ibpd,
@@ -651,10 +657,8 @@ static int mana_ib_create_ud_qp(struct ib_qp *ibqp, struct ib_pd *ibpd,
u32 doorbell, queue_size;
int i, err;
- if (udata) {
- ibdev_dbg(&mdev->ib_dev, "User-level UD QPs are not supported\n");
+ if (udata)
return -EOPNOTSUPP;
- }
for (i = 0; i < MANA_UD_QUEUE_TYPE_MAX; ++i) {
queue_size = mana_ib_queue_size(attr, i);
@@ -745,6 +749,11 @@ static int mana_ib_gd_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
struct gdma_context *gc = mdev_to_gc(mdev);
struct mana_port_context *mpc;
struct net_device *ndev;
+ int err;
+
+ err = ib_no_udata_io(udata);
+ if (err)
+ return err;
mana_gd_init_req_hdr(&req.hdr, MANA_IB_SET_QP_STATE, sizeof(req), sizeof(resp));
@@ -797,7 +806,11 @@ static int mana_ib_gd_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
req.ah_attr.flow_label = attr->ah_attr.grh.flow_label;
}
- return mana_gd_send_request(gc, sizeof(req), &req, sizeof(resp), &resp);
+ err = mana_gd_send_request(gc, sizeof(req), &req, sizeof(resp), &resp);
+ if (err)
+ return err;
+
+ return 0;
}
int mana_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
@@ -826,7 +839,11 @@ static int mana_ib_destroy_qp_rss(struct mana_ib_qp *qp,
struct mana_ib_pd *pd;
struct mana_ib_wq *wq;
struct ib_wq *ibwq;
- int i;
+ int i, err;
+
+ err = ib_no_udata_io(udata);
+ if (err)
+ return err;
ndev = mana_ib_get_netdev(qp->ibqp.device, qp->port);
mpc = netdev_priv(ndev);
@@ -872,6 +889,11 @@ static int mana_ib_destroy_qp_raw(struct mana_ib_qp *qp, struct ib_udata *udata)
struct mana_port_context *mpc;
struct net_device *ndev;
struct mana_ib_pd *pd;
+ int err;
+
+ err = ib_no_udata_io(udata);
+ if (err)
+ return err;
ndev = mana_ib_get_netdev(qp->ibqp.device, qp->port);
mpc = netdev_priv(ndev);
@@ -890,7 +912,11 @@ static int mana_ib_destroy_rc_qp(struct mana_ib_qp *qp, struct ib_udata *udata)
{
struct mana_ib_dev *mdev =
container_of(qp->ibqp.device, struct mana_ib_dev, ib_dev);
- int i;
+ int i, err;
+
+ err = ib_no_udata_io(udata);
+ if (err)
+ return err;
mana_table_remove_qp(mdev, qp);
@@ -908,7 +934,11 @@ static int mana_ib_destroy_ud_qp(struct mana_ib_qp *qp, struct ib_udata *udata)
{
struct mana_ib_dev *mdev =
container_of(qp->ibqp.device, struct mana_ib_dev, ib_dev);
- int i;
+ int i, err;
+
+ err = ib_no_udata_io(udata);
+ if (err)
+ return err;
mana_remove_qp_from_cqs(qp);
mana_table_remove_qp(mdev, qp);
diff --git a/drivers/infiniband/hw/mana/wq.c b/drivers/infiniband/hw/mana/wq.c
index 5c2134a0b1a1..6b066d605dcb 100644
--- a/drivers/infiniband/hw/mana/wq.c
+++ b/drivers/infiniband/hw/mana/wq.c
@@ -55,6 +55,11 @@ int mana_ib_destroy_wq(struct ib_wq *ibwq, struct ib_udata *udata)
struct mana_ib_wq *wq = container_of(ibwq, struct mana_ib_wq, ibwq);
struct ib_device *ib_dev = ibwq->device;
struct mana_ib_dev *mdev;
+ int err;
+
+ err = ib_no_udata_io(udata);
+ if (err)
+ return err;
mdev = container_of(ib_dev, struct mana_ib_dev, ib_dev);
@@ -69,10 +74,17 @@ int mana_ib_create_rwq_ind_table(struct ib_rwq_ind_table *ib_rwq_ind_table,
struct ib_rwq_ind_table_init_attr *init_attr,
struct ib_udata *udata)
{
+ int err;
+
+ err = ib_no_udata_io(udata);
+ if (err)
+ return err;
+
/*
* There is no additional data in ind_table to be maintained by this
* driver, do nothing
*/
+
return 0;
}
diff --git a/drivers/infiniband/hw/mlx4/cm.c b/drivers/infiniband/hw/mlx4/cm.c
index 63a868a3822f..1e5e525fea73 100644
--- a/drivers/infiniband/hw/mlx4/cm.c
+++ b/drivers/infiniband/hw/mlx4/cm.c
@@ -40,6 +40,7 @@
#include "mlx4_ib.h"
#define CM_CLEANUP_CACHE_TIMEOUT (30 * HZ)
+#define CM_RTU_TIMEOUT (60 * HZ)
struct id_map_entry {
struct rb_node node;
@@ -48,6 +49,7 @@ struct id_map_entry {
u32 pv_cm_id;
int slave_id;
int scheduled_delete;
+ bool rtu_timeout;
struct mlx4_ib_dev *dev;
struct list_head list;
@@ -184,6 +186,10 @@ static void id_map_ent_timeout(struct work_struct *work)
struct rb_root *sl_id_map = &sriov->sl_id_map;
spin_lock(&sriov->id_map_lock);
+ if (!ent->scheduled_delete) {
+ spin_unlock(&sriov->id_map_lock);
+ return;
+ }
if (!xa_erase(&sriov->pv_id_table, ent->pv_cm_id))
goto out;
found_ent = id_map_find_by_sl_id(&dev->ib_dev, ent->slave_id, ent->sl_cm_id);
@@ -228,8 +234,12 @@ static void sl_id_map_add(struct ib_device *ibdev, struct id_map_entry *new)
rb_insert_color(&new->node, sl_id_map);
}
+static void schedule_delayed(struct ib_device *ibdev, struct id_map_entry *id,
+ unsigned long timeout, bool rtu_timeout);
+
static struct id_map_entry *
-id_map_alloc(struct ib_device *ibdev, int slave_id, u32 sl_cm_id)
+id_map_alloc(struct ib_device *ibdev, int slave_id, u32 sl_cm_id,
+ u32 *pv_cm_id)
{
int ret;
struct id_map_entry *ent;
@@ -242,6 +252,7 @@ id_map_alloc(struct ib_device *ibdev, int slave_id, u32 sl_cm_id)
ent->sl_cm_id = sl_cm_id;
ent->slave_id = slave_id;
ent->scheduled_delete = 0;
+ ent->rtu_timeout = false;
ent->dev = to_mdev(ibdev);
INIT_DELAYED_WORK(&ent->timeout, id_map_ent_timeout);
@@ -251,6 +262,8 @@ id_map_alloc(struct ib_device *ibdev, int slave_id, u32 sl_cm_id)
spin_lock(&sriov->id_map_lock);
sl_id_map_add(ibdev, ent);
list_add_tail(&ent->list, &sriov->cm_list);
+ *pv_cm_id = ent->pv_cm_id;
+ schedule_delayed(ibdev, ent, CM_RTU_TIMEOUT, true);
spin_unlock(&sriov->id_map_lock);
return ent;
}
@@ -267,42 +280,41 @@ id_map_get(struct ib_device *ibdev, int *pv_cm_id, int slave_id, int sl_cm_id)
struct id_map_entry *ent;
struct mlx4_ib_sriov *sriov = &to_mdev(ibdev)->sriov;
- spin_lock(&sriov->id_map_lock);
+ lockdep_assert_held(&sriov->id_map_lock);
if (*pv_cm_id == -1) {
ent = id_map_find_by_sl_id(ibdev, slave_id, sl_cm_id);
if (ent)
*pv_cm_id = (int) ent->pv_cm_id;
} else
ent = xa_load(&sriov->pv_id_table, *pv_cm_id);
- spin_unlock(&sriov->id_map_lock);
return ent;
}
-static void schedule_delayed(struct ib_device *ibdev, struct id_map_entry *id)
+static void schedule_delayed(struct ib_device *ibdev, struct id_map_entry *id,
+ unsigned long timeout, bool rtu_timeout)
{
struct mlx4_ib_sriov *sriov = &to_mdev(ibdev)->sriov;
unsigned long flags;
- spin_lock(&sriov->id_map_lock);
+ lockdep_assert_held(&sriov->id_map_lock);
spin_lock_irqsave(&sriov->going_down_lock, flags);
/*make sure that there is no schedule inside the scheduled work.*/
- if (!sriov->is_going_down && !id->scheduled_delete) {
+ if (!sriov->is_going_down || id->scheduled_delete) {
id->scheduled_delete = 1;
- queue_delayed_work(cm_wq, &id->timeout, CM_CLEANUP_CACHE_TIMEOUT);
- } else if (id->scheduled_delete) {
- /* Adjust timeout if already scheduled */
- mod_delayed_work(cm_wq, &id->timeout, CM_CLEANUP_CACHE_TIMEOUT);
+ id->rtu_timeout = rtu_timeout;
+ mod_delayed_work(cm_wq, &id->timeout, timeout);
}
spin_unlock_irqrestore(&sriov->going_down_lock, flags);
- spin_unlock(&sriov->id_map_lock);
}
#define REJ_REASON(m) be16_to_cpu(((struct cm_generic_msg *)(m))->rej_reason)
int mlx4_ib_multiplex_cm_handler(struct ib_device *ibdev, int port, int slave_id,
struct ib_mad *mad)
{
+ struct mlx4_ib_sriov *sriov = &to_mdev(ibdev)->sriov;
struct id_map_entry *id;
+ u32 pv_cm_id_to_set = 0;
u32 sl_cm_id;
int pv_cm_id = -1;
@@ -312,21 +324,62 @@ int mlx4_ib_multiplex_cm_handler(struct ib_device *ibdev, int port, int slave_id
mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID ||
(mad->mad_hdr.attr_id == CM_REJ_ATTR_ID && REJ_REASON(mad) == IB_CM_REJ_TIMEOUT)) {
sl_cm_id = get_local_comm_id(mad);
+ spin_lock(&sriov->id_map_lock);
id = id_map_get(ibdev, &pv_cm_id, slave_id, sl_cm_id);
+ if (id) {
+ pv_cm_id_to_set = id->pv_cm_id;
+ if (mad->mad_hdr.attr_id == CM_REJ_ATTR_ID)
+ schedule_delayed(ibdev, id,
+ CM_CLEANUP_CACHE_TIMEOUT,
+ false);
+ }
+ spin_unlock(&sriov->id_map_lock);
if (id)
goto cont;
- id = id_map_alloc(ibdev, slave_id, sl_cm_id);
+ if (mad->mad_hdr.attr_id == CM_REJ_ATTR_ID)
+ return 0;
+ id = id_map_alloc(ibdev, slave_id, sl_cm_id,
+ &pv_cm_id_to_set);
if (IS_ERR(id)) {
mlx4_ib_warn(ibdev, "%s: id{slave: %d, sl_cm_id: 0x%x} Failed to id_map_alloc\n",
__func__, slave_id, sl_cm_id);
return PTR_ERR(id);
}
- } else if (mad->mad_hdr.attr_id == CM_REJ_ATTR_ID ||
- mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) {
+ } else if (mad->mad_hdr.attr_id == CM_REJ_ATTR_ID) {
+ sl_cm_id = get_local_comm_id(mad);
+ spin_lock(&sriov->id_map_lock);
+ id = id_map_get(ibdev, &pv_cm_id, slave_id, sl_cm_id);
+ if (id) {
+ pv_cm_id_to_set = id->pv_cm_id;
+ schedule_delayed(ibdev, id, CM_CLEANUP_CACHE_TIMEOUT,
+ false);
+ }
+ spin_unlock(&sriov->id_map_lock);
+ if (!id)
+ return 0;
+ } else if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) {
return 0;
} else {
sl_cm_id = get_local_comm_id(mad);
+ spin_lock(&sriov->id_map_lock);
id = id_map_get(ibdev, &pv_cm_id, slave_id, sl_cm_id);
+ if (id) {
+ if (mad->mad_hdr.attr_id == CM_RTU_ATTR_ID &&
+ id->rtu_timeout) {
+ id->rtu_timeout = false;
+ if (cancel_delayed_work(&id->timeout))
+ id->scheduled_delete = 0;
+ else
+ id = NULL;
+ }
+ if (id)
+ pv_cm_id_to_set = id->pv_cm_id;
+ if (id && mad->mad_hdr.attr_id == CM_DREQ_ATTR_ID)
+ schedule_delayed(ibdev, id,
+ CM_CLEANUP_CACHE_TIMEOUT,
+ false);
+ }
+ spin_unlock(&sriov->id_map_lock);
}
if (!id) {
@@ -336,10 +389,7 @@ int mlx4_ib_multiplex_cm_handler(struct ib_device *ibdev, int port, int slave_id
}
cont:
- set_local_comm_id(mad, id->pv_cm_id);
-
- if (mad->mad_hdr.attr_id == CM_DREQ_ATTR_ID)
- schedule_delayed(ibdev, id);
+ set_local_comm_id(mad, pv_cm_id_to_set);
return 0;
}
@@ -429,7 +479,10 @@ int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave,
struct mlx4_ib_sriov *sriov = &to_mdev(ibdev)->sriov;
u32 rem_pv_cm_id = get_local_comm_id(mad);
u32 pv_cm_id;
+ u32 sl_cm_id = 0;
struct id_map_entry *id;
+ int pv_cm_id_int;
+ int slave_id = 0;
int sts;
if (mad->mad_hdr.attr_id == CM_REQ_ATTR_ID ||
@@ -457,7 +510,28 @@ int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave,
}
pv_cm_id = get_remote_comm_id(mad);
- id = id_map_get(ibdev, (int *)&pv_cm_id, -1, -1);
+ pv_cm_id_int = pv_cm_id;
+ spin_lock(&sriov->id_map_lock);
+ id = id_map_get(ibdev, &pv_cm_id_int, -1, -1);
+ if (id) {
+ if (mad->mad_hdr.attr_id == CM_RTU_ATTR_ID &&
+ id->rtu_timeout) {
+ id->rtu_timeout = false;
+ if (cancel_delayed_work(&id->timeout))
+ id->scheduled_delete = 0;
+ else
+ id = NULL;
+ }
+ if (id && slave)
+ slave_id = id->slave_id;
+ if (id)
+ sl_cm_id = id->sl_cm_id;
+ if (id && (mad->mad_hdr.attr_id == CM_DREQ_ATTR_ID ||
+ mad->mad_hdr.attr_id == CM_REJ_ATTR_ID))
+ schedule_delayed(ibdev, id,
+ CM_CLEANUP_CACHE_TIMEOUT, false);
+ }
+ spin_unlock(&sriov->id_map_lock);
if (!id) {
if (mad->mad_hdr.attr_id == CM_REJ_ATTR_ID &&
@@ -472,12 +546,8 @@ int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave,
}
if (slave)
- *slave = id->slave_id;
- set_remote_comm_id(mad, id->sl_cm_id);
-
- if (mad->mad_hdr.attr_id == CM_DREQ_ATTR_ID ||
- mad->mad_hdr.attr_id == CM_REJ_ATTR_ID)
- schedule_delayed(ibdev, id);
+ *slave = slave_id;
+ set_remote_comm_id(mad, sl_cm_id);
return 0;
}
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index 17073e8f105a..7266a6141944 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -471,8 +471,6 @@ static int mlx4_ib_query_device(struct ib_device *ibdev,
if (err)
goto out;
- memset(props, 0, sizeof *props);
-
have_ib_ports = num_ib_ports(dev->dev);
props->fw_ver = dev->dev->caps.fw_ver;
diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c
index 761e2c05dd0f..a6b4abce1bfe 100644
--- a/drivers/infiniband/hw/mlx4/mr.c
+++ b/drivers/infiniband/hw/mlx4/mr.c
@@ -313,7 +313,7 @@ mlx4_alloc_priv_pages(struct ib_device *device,
MLX4_MR_PAGES_ALIGN);
/* Prevent cross page boundary allocation. */
- mr->pages = (__be64 *)get_zeroed_page(GFP_KERNEL);
+ mr->pages = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!mr->pages)
return -ENOMEM;
@@ -328,7 +328,7 @@ mlx4_alloc_priv_pages(struct ib_device *device,
return 0;
err:
- free_page((unsigned long)mr->pages);
+ kfree(mr->pages);
return ret;
}
@@ -340,7 +340,7 @@ mlx4_free_priv_pages(struct mlx4_ib_mr *mr)
dma_unmap_single(device->dev.parent, mr->page_map,
mr->page_map_size, DMA_TO_DEVICE);
- free_page((unsigned long)mr->pages);
+ kfree(mr->pages);
mr->pages = NULL;
}
}
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index 4ff6cca7e581..711abd650ecd 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -969,7 +969,6 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,
if (err)
return err;
- memset(props, 0, sizeof(*props));
err = mlx5_query_system_image_guid(ibdev,
&props->sys_image_guid);
if (err)
@@ -5501,13 +5500,13 @@ static int __init mlx5_ib_init(void)
{
int ret;
- xlt_emergency_page = (void *)__get_free_page(GFP_KERNEL);
+ xlt_emergency_page = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!xlt_emergency_page)
return -ENOMEM;
mlx5_ib_event_wq = alloc_ordered_workqueue("mlx5_ib_event_wq", 0);
if (!mlx5_ib_event_wq) {
- free_page((unsigned long)xlt_emergency_page);
+ kfree(xlt_emergency_page);
return -ENOMEM;
}
@@ -5542,7 +5541,7 @@ rep_err:
mlx5_ib_qp_event_cleanup();
qp_event_err:
destroy_workqueue(mlx5_ib_event_wq);
- free_page((unsigned long)xlt_emergency_page);
+ kfree(xlt_emergency_page);
return ret;
}
@@ -5556,7 +5555,7 @@ static void __exit mlx5_ib_cleanup(void)
mlx5_ib_qp_event_cleanup();
destroy_workqueue(mlx5_ib_event_wq);
- free_page((unsigned long)xlt_emergency_page);
+ kfree(xlt_emergency_page);
}
module_init(mlx5_ib_init);
diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c
index e6b74955d95d..00e13028762a 100644
--- a/drivers/infiniband/hw/mlx5/mr.c
+++ b/drivers/infiniband/hw/mlx5/mr.c
@@ -339,7 +339,7 @@ static int mlx5r_build_frmr_key(struct ib_device *device,
return 0;
}
-static struct ib_frmr_pool_ops mlx5r_frmr_pool_ops = {
+static const struct ib_frmr_pool_ops mlx5r_frmr_pool_ops = {
.create_frmrs = mlx5r_create_mkeys,
.destroy_frmrs = mlx5r_destroy_mkeys,
.build_key = mlx5r_build_frmr_key,
@@ -898,8 +898,8 @@ static void mlx5_ib_dmabuf_invalidate_cb(struct dma_buf_attachment *attach)
ib_umem_dmabuf_unmap_pages(umem_dmabuf);
}
-static struct dma_buf_attach_ops mlx5_ib_dmabuf_attach_ops = {
- .allow_peer2peer = 1,
+static const struct dma_buf_attach_ops mlx5_ib_dmabuf_attach_ops = {
+ .allow_peer2peer = true,
.invalidate_mappings = mlx5_ib_dmabuf_invalidate_cb,
};
diff --git a/drivers/infiniband/hw/mlx5/odp.c b/drivers/infiniband/hw/mlx5/odp.c
index 1badec9bf527..b8618610737a 100644
--- a/drivers/infiniband/hw/mlx5/odp.c
+++ b/drivers/infiniband/hw/mlx5/odp.c
@@ -37,6 +37,7 @@
#include <linux/hmm.h>
#include <linux/hmm-dma.h>
#include <linux/pci-p2pdma.h>
+#include <linux/slab.h>
#include "mlx5_ib.h"
#include "cmd.h"
@@ -1414,7 +1415,8 @@ static void mlx5_ib_mr_wqe_pfault_handler(struct mlx5_ib_dev *dev,
goto resolve_page_fault;
}
- wqe_start = (void *)__get_free_page(GFP_KERNEL);
+ /* TODO: switch to "fast and as large as possible" allocation helper */
+ wqe_start = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!wqe_start) {
mlx5_ib_err(dev, "Error allocating memory for IO page fault handling.\n");
goto resolve_page_fault;
@@ -1475,7 +1477,7 @@ resolve_page_fault:
pfault->wqe.wq_num, resume_with_error,
pfault->type);
mlx5_core_res_put(res);
- free_page((unsigned long)wqe_start);
+ kfree(wqe_start);
}
static void mlx5_ib_mr_rdma_pfault_handler(struct mlx5_ib_dev *dev,
diff --git a/drivers/infiniband/hw/mlx5/umr.c b/drivers/infiniband/hw/mlx5/umr.c
index 48cae5cc1c1b..80d0d190b26c 100644
--- a/drivers/infiniband/hw/mlx5/umr.c
+++ b/drivers/infiniband/hw/mlx5/umr.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. */
+#include <linux/slab.h>
#include <rdma/ib_umem_odp.h>
#include <rdma/iter.h>
#include "mlx5_ib.h"
@@ -517,22 +518,20 @@ static void *mlx5r_umr_alloc_xlt(size_t *nents, size_t ent_size, gfp_t gfp_mask)
size = min_t(size_t, ent_size * ALIGN(*nents, xlt_chunk_align),
MLX5_MAX_UMR_CHUNK);
*nents = size / ent_size;
- res = (void *)__get_free_pages(gfp_mask | __GFP_NOWARN,
- get_order(size));
+ res = kmalloc(size, gfp_mask | __GFP_NOWARN);
if (res)
return res;
if (size > MLX5_SPARE_UMR_CHUNK) {
size = MLX5_SPARE_UMR_CHUNK;
*nents = size / ent_size;
- res = (void *)__get_free_pages(gfp_mask | __GFP_NOWARN,
- get_order(size));
+ res = kmalloc(size, gfp_mask | __GFP_NOWARN);
if (res)
return res;
}
*nents = PAGE_SIZE / ent_size;
- res = (void *)__get_free_page(gfp_mask);
+ res = kmalloc(PAGE_SIZE, gfp_mask);
if (res)
return res;
@@ -548,7 +547,7 @@ static void mlx5r_umr_free_xlt(void *xlt, size_t length)
return;
}
- free_pages((unsigned long)xlt, get_order(length));
+ kfree(xlt);
}
static void mlx5r_umr_unmap_free_xlt(struct mlx5_ib_dev *dev, void *xlt,
@@ -978,7 +977,7 @@ static inline int _mlx5r_dmabuf_umr_update_pas(struct mlx5_ib_mr *mr,
start_block, nblocks);
}
-/**
+/*
* This function makes an mkey non-present by zapping the translation entries of
* the mkey by zapping (zeroing out) the first N entries, where N is determined
* by the largest page size supported by the device and the MR length.
diff --git a/drivers/infiniband/hw/mthca/mthca_allocator.c b/drivers/infiniband/hw/mthca/mthca_allocator.c
index dedc301235a0..117a070e784e 100644
--- a/drivers/infiniband/hw/mthca/mthca_allocator.c
+++ b/drivers/infiniband/hw/mthca/mthca_allocator.c
@@ -126,7 +126,7 @@ int mthca_array_set(struct mthca_array *array, int index, void *value)
/* Allocate with GFP_ATOMIC because we'll be called with locks held. */
if (!array->page_list[p].page)
- array->page_list[p].page = (void **) get_zeroed_page(GFP_ATOMIC);
+ array->page_list[p].page = kzalloc(PAGE_SIZE, GFP_ATOMIC);
if (!array->page_list[p].page)
return -ENOMEM;
@@ -142,7 +142,7 @@ void mthca_array_clear(struct mthca_array *array, int index)
int p = (index * sizeof (void *)) >> PAGE_SHIFT;
if (--array->page_list[p].used == 0) {
- free_page((unsigned long) array->page_list[p].page);
+ kfree(array->page_list[p].page);
array->page_list[p].page = NULL;
} else
array->page_list[p].page[index & MTHCA_ARRAY_MASK] = NULL;
@@ -174,7 +174,7 @@ void mthca_array_cleanup(struct mthca_array *array, int nent)
int i;
for (i = 0; i < (nent * sizeof (void *) + PAGE_SIZE - 1) / PAGE_SIZE; ++i)
- free_page((unsigned long) array->page_list[i].page);
+ kfree(array->page_list[i].page);
kfree(array->page_list);
}
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index f90f67afc8fa..8989e572e32c 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -58,7 +58,7 @@ static int mthca_query_device(struct ib_device *ibdev, struct ib_device_attr *pr
int err;
struct mthca_dev *mdev = to_mdev(ibdev);
- err = ib_is_udata_in_empty(uhw);
+ err = ib_no_udata_io(uhw);
if (err)
return err;
@@ -69,8 +69,6 @@ static int mthca_query_device(struct ib_device *ibdev, struct ib_device_attr *pr
goto out;
}
- memset(props, 0, sizeof *props);
-
props->fw_ver = mdev->fw_ver;
ib_init_query_mad(in_mad);
@@ -114,7 +112,6 @@ static int mthca_query_device(struct ib_device *ibdev, struct ib_device_attr *pr
props->max_total_mcast_qp_attach = props->max_mcast_qp_attach *
props->max_mcast_grp;
- err = ib_respond_empty_udata(uhw);
out:
kfree(in_mad);
kfree(out_mad);
@@ -895,7 +892,8 @@ static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
goto err_umem;
}
- pages = (u64 *) __get_free_page(GFP_KERNEL);
+ /* TODO: switch to "fast and as large as possible" allocation helper */
+ pages = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!pages) {
err = -ENOMEM;
goto err_mtt;
@@ -924,7 +922,7 @@ static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
if (i)
err = mthca_write_mtt(dev, mr->mtt, n, pages, i);
mtt_done:
- free_page((unsigned long) pages);
+ kfree(pages);
if (err)
goto err_mtt;
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
index 53ba32d168a1..cfe3d19b73b3 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
@@ -70,11 +70,10 @@ int ocrdma_query_device(struct ib_device *ibdev, struct ib_device_attr *attr,
struct ocrdma_dev *dev = get_ocrdma_dev(ibdev);
int err;
- err = ib_is_udata_in_empty(uhw);
+ err = ib_no_udata_io(uhw);
if (err)
return err;
- memset(attr, 0, sizeof *attr);
memcpy(&attr->fw_ver, &dev->attr.fw_ver[0],
min(sizeof(dev->attr.fw_ver), sizeof(attr->fw_ver)));
addrconf_addr_eui48((u8 *)&attr->sys_image_guid,
@@ -112,7 +111,7 @@ int ocrdma_query_device(struct ib_device *ibdev, struct ib_device_attr *attr,
attr->local_ca_ack_delay = dev->attr.local_ca_ack_delay;
attr->max_fast_reg_page_list_len = dev->attr.max_pages_per_frmr;
attr->max_pkeys = 1;
- return ib_respond_empty_udata(uhw);
+ return 0;
}
static inline void get_link_speed_and_width(struct ocrdma_dev *dev,
diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c
index c90a1b5c8ee7..012a0ab98d6b 100644
--- a/drivers/infiniband/hw/qedr/verbs.c
+++ b/drivers/infiniband/hw/qedr/verbs.c
@@ -114,12 +114,10 @@ int qedr_query_device(struct ib_device *ibdev,
return -EINVAL;
}
- rc = ib_is_udata_in_empty(udata);
+ rc = ib_no_udata_io(udata);
if (rc)
return rc;
- memset(attr, 0, sizeof(*attr));
-
attr->fw_ver = qattr->fw_ver;
attr->sys_image_guid = qattr->sys_image_guid;
attr->max_mr_size = qattr->max_mr_size;
@@ -148,7 +146,7 @@ int qedr_query_device(struct ib_device *ibdev,
attr->max_qp_init_rd_atom =
1 << (fls(qattr->max_qp_req_rd_atomic_resc) - 1);
attr->max_qp_rd_atom =
- min(1 << (fls(qattr->max_qp_resp_rd_atomic_resc) - 1),
+ min(1U << (fls(qattr->max_qp_resp_rd_atomic_resc) - 1),
attr->max_qp_init_rd_atom);
attr->max_srq = qattr->max_srq;
@@ -160,7 +158,7 @@ int qedr_query_device(struct ib_device *ibdev,
attr->max_pkeys = qattr->max_pkey;
attr->max_ah = qattr->max_ah;
- return ib_respond_empty_udata(udata);
+ return 0;
}
static inline void get_link_speed_and_width(int speed, u16 *ib_speed,
diff --git a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c
index dc355b00f61c..1a1647d0e345 100644
--- a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c
+++ b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c
@@ -278,13 +278,12 @@ int usnic_ib_query_device(struct ib_device *ibdev,
int err;
usnic_dbg("\n");
- err = ib_is_udata_in_empty(uhw);
+ err = ib_no_udata_io(uhw);
if (err)
return err;
mutex_lock(&us_ibdev->usdev_lock);
us_ibdev->netdev->ethtool_ops->get_drvinfo(us_ibdev->netdev, &info);
- memset(props, 0, sizeof(*props));
usnic_mac_ip_to_gid(us_ibdev->ufdev->mac, us_ibdev->ufdev->inaddr,
&gid.raw[0]);
memcpy(&props->sys_image_guid, &gid.global.interface_id,
@@ -324,7 +323,7 @@ int usnic_ib_query_device(struct ib_device *ibdev,
* max_qp_wr, max_sge, max_sge_rd, max_cqe */
mutex_unlock(&us_ibdev->usdev_lock);
- return ib_respond_empty_udata(uhw);
+ return 0;
}
int usnic_ib_query_port(struct ib_device *ibdev, u32 port,
diff --git a/drivers/infiniband/hw/usnic/usnic_uiom.c b/drivers/infiniband/hw/usnic/usnic_uiom.c
index 691c64a73516..201c35039a74 100644
--- a/drivers/infiniband/hw/usnic/usnic_uiom.c
+++ b/drivers/infiniband/hw/usnic/usnic_uiom.c
@@ -114,7 +114,7 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable,
INIT_LIST_HEAD(chunk_list);
- page_list = (struct page **) __get_free_page(GFP_KERNEL);
+ page_list = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!page_list)
return -ENOMEM;
@@ -182,7 +182,7 @@ out:
mmgrab(uiomr->owning_mm);
mmap_read_unlock(mm);
- free_page((unsigned long) page_list);
+ kfree(page_list);
return ret;
}
diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c
index 1d29a535f76a..59c2a88c158a 100644
--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c
+++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c
@@ -69,7 +69,7 @@ int pvrdma_query_device(struct ib_device *ibdev,
struct pvrdma_dev *dev = to_vdev(ibdev);
int err;
- err = ib_is_udata_in_empty(uhw);
+ err = ib_no_udata_io(uhw);
if (err)
return err;
@@ -116,7 +116,7 @@ int pvrdma_query_device(struct ib_device *ibdev,
props->device_cap_flags |= IB_DEVICE_PORT_ACTIVE_EVENT |
IB_DEVICE_RC_RNR_NAK_GEN;
- return ib_respond_empty_udata(uhw);
+ return 0;
}
/**
diff --git a/drivers/infiniband/sw/rdmavt/qp.c b/drivers/infiniband/sw/rdmavt/qp.c
index 70e7d08fdce6..c40cce69e945 100644
--- a/drivers/infiniband/sw/rdmavt/qp.c
+++ b/drivers/infiniband/sw/rdmavt/qp.c
@@ -263,7 +263,7 @@ static inline bool wss_exceeds_threshold(struct rvt_wss *wss)
static void get_map_page(struct rvt_qpn_table *qpt,
struct rvt_qpn_map *map)
{
- unsigned long page = get_zeroed_page(GFP_KERNEL);
+ void *page = kzalloc(PAGE_SIZE, GFP_KERNEL);
/*
* Free the page if someone raced with us installing it.
@@ -271,9 +271,9 @@ static void get_map_page(struct rvt_qpn_table *qpt,
spin_lock(&qpt->lock);
if (map->page)
- free_page(page);
+ kfree(page);
else
- map->page = (void *)page;
+ map->page = page;
spin_unlock(&qpt->lock);
}
@@ -343,7 +343,7 @@ static void free_qpn_table(struct rvt_qpn_table *qpt)
int i;
for (i = 0; i < ARRAY_SIZE(qpt->map); i++)
- free_page((unsigned long)qpt->map[i].page);
+ kfree(qpt->map[i].page);
}
/**
diff --git a/drivers/infiniband/sw/rdmavt/vt.c b/drivers/infiniband/sw/rdmavt/vt.c
index 5fa3a1f33326..1c112f4dc994 100644
--- a/drivers/infiniband/sw/rdmavt/vt.c
+++ b/drivers/infiniband/sw/rdmavt/vt.c
@@ -55,8 +55,10 @@ struct rvt_dev_info *rvt_alloc_device(size_t size, int nports)
return rdi;
rdi->ports = kzalloc_objs(*rdi->ports, nports);
- if (!rdi->ports)
+ if (!rdi->ports) {
ib_dealloc_device(&rdi->ibdev);
+ return NULL;
+ }
return rdi;
}
@@ -82,14 +84,14 @@ static int rvt_query_device(struct ib_device *ibdev,
struct rvt_dev_info *rdi = ib_to_rvt(ibdev);
int err;
- err = ib_is_udata_in_empty(uhw);
+ err = ib_no_udata_io(uhw);
if (err)
return err;
/*
* Return rvt_dev_info.dparms.props contents
*/
*props = rdi->dparms.props;
- return ib_respond_empty_udata(uhw);
+ return 0;
}
static int rvt_get_numa_node(struct ib_device *ibdev)
diff --git a/drivers/infiniband/sw/rxe/rxe_mw.c b/drivers/infiniband/sw/rxe/rxe_mw.c
index 379e65bfcd49..bddb7a257831 100644
--- a/drivers/infiniband/sw/rxe/rxe_mw.c
+++ b/drivers/infiniband/sw/rxe/rxe_mw.c
@@ -72,13 +72,6 @@ static int rxe_check_bind_mw(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
return -EINVAL;
}
- /* C10-72 */
- if (unlikely(qp->pd != to_rpd(mw->ibmw.pd))) {
- rxe_dbg_mw(mw,
- "attempt to bind type 2 MW with qp with different PD\n");
- return -EINVAL;
- }
-
/* o10-37.2.40 */
if (unlikely(!mr || wqe->wr.wr.mw.length == 0)) {
rxe_dbg_mw(mw,
@@ -87,10 +80,21 @@ static int rxe_check_bind_mw(struct rxe_qp *qp, struct rxe_send_wqe *wqe,
}
}
- /* remaining checks only apply to a nonzero MR */
+ /* C10-72 */
+ if (unlikely(qp->pd != rxe_mw_pd(mw))) {
+ rxe_dbg_mw(mw, "attempt to bind MW with qp with different PD\n");
+ return -EINVAL;
+ }
+
if (!mr)
return 0;
+ /* remaining checks only apply to a nonzero MR */
+ if (unlikely(qp->pd != mr_pd(mr))) {
+ rxe_dbg_mw(mw, "attempt to bind MW/QP to MR with different PD\n");
+ return -EINVAL;
+ }
+
if (unlikely(mr->access & IB_ZERO_BASED)) {
rxe_dbg_mw(mw, "attempt to bind MW to zero based MR\n");
return -EINVAL;
diff --git a/drivers/infiniband/sw/rxe/rxe_odp.c b/drivers/infiniband/sw/rxe/rxe_odp.c
index ff904d5e54a7..c189c033175d 100644
--- a/drivers/infiniband/sw/rxe/rxe_odp.c
+++ b/drivers/infiniband/sw/rxe/rxe_odp.c
@@ -87,14 +87,9 @@ int rxe_odp_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length,
rxe_mr_init(access_flags, mr);
- if (!start && length == U64_MAX) {
- if (iova != 0)
- return -EINVAL;
- if (!(rxe->attr.odp_caps.general_caps & IB_ODP_SUPPORT_IMPLICIT))
- return -EINVAL;
-
- /* Never reach here, for implicit ODP is not implemented. */
- }
+ /* Implicit ODP (start=0, length=U64_MAX) is not implemented. */
+ if (!start && length == U64_MAX)
+ return -EOPNOTSUPP;
umem_odp = ib_umem_odp_get(&rxe->ib_dev, start, length, access_flags,
&rxe_mn_ops);
diff --git a/drivers/infiniband/sw/rxe/rxe_qp.c b/drivers/infiniband/sw/rxe/rxe_qp.c
index f3dff1aea96a..ec2cfb12559a 100644
--- a/drivers/infiniband/sw/rxe/rxe_qp.c
+++ b/drivers/infiniband/sw/rxe/rxe_qp.c
@@ -67,27 +67,27 @@ static int rxe_qp_chk_cap(struct rxe_dev *rxe, struct ib_qp_cap *cap,
int has_srq)
{
if (cap->max_send_wr > rxe->attr.max_qp_wr) {
- rxe_dbg_dev(rxe, "invalid send wr = %u > %d\n",
- cap->max_send_wr, rxe->attr.max_qp_wr);
+ rxe_dbg_dev(rxe, "invalid send wr = %u > %u\n",
+ cap->max_send_wr, rxe->attr.max_qp_wr);
goto err1;
}
if (cap->max_send_sge > rxe->attr.max_send_sge) {
- rxe_dbg_dev(rxe, "invalid send sge = %u > %d\n",
- cap->max_send_sge, rxe->attr.max_send_sge);
+ rxe_dbg_dev(rxe, "invalid send sge = %u > %u\n",
+ cap->max_send_sge, rxe->attr.max_send_sge);
goto err1;
}
if (!has_srq) {
if (cap->max_recv_wr > rxe->attr.max_qp_wr) {
- rxe_dbg_dev(rxe, "invalid recv wr = %u > %d\n",
- cap->max_recv_wr, rxe->attr.max_qp_wr);
+ rxe_dbg_dev(rxe, "invalid recv wr = %u > %u\n",
+ cap->max_recv_wr, rxe->attr.max_qp_wr);
goto err1;
}
if (cap->max_recv_sge > rxe->attr.max_recv_sge) {
- rxe_dbg_dev(rxe, "invalid recv sge = %u > %d\n",
- cap->max_recv_sge, rxe->attr.max_recv_sge);
+ rxe_dbg_dev(rxe, "invalid recv sge = %u > %u\n",
+ cap->max_recv_sge, rxe->attr.max_recv_sge);
goto err1;
}
}
@@ -172,6 +172,7 @@ static void free_rd_atomic_resources(struct rxe_qp *qp)
}
kfree(qp->resp.resources);
qp->resp.resources = NULL;
+ qp->resp.res = NULL;
}
}
@@ -537,9 +538,9 @@ int rxe_qp_chk_attr(struct rxe_dev *rxe, struct rxe_qp *qp,
if (mask & IB_QP_MAX_QP_RD_ATOMIC) {
if (attr->max_rd_atomic > rxe->attr.max_qp_rd_atom) {
- rxe_dbg_qp(qp, "invalid max_rd_atomic %d > %d\n",
- attr->max_rd_atomic,
- rxe->attr.max_qp_rd_atom);
+ rxe_dbg_qp(qp, "invalid max_rd_atomic %u > %u\n",
+ attr->max_rd_atomic,
+ rxe->attr.max_qp_rd_atom);
goto err1;
}
}
@@ -709,11 +710,23 @@ int rxe_qp_from_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask,
qp->attr.max_dest_rd_atomic = max_dest_rd_atomic;
+ /*
+ * Not gated by IB_QP_STATE, so the responder task is live.
+ * Quiesce recv_task like rxe_qp_reset() before swapping the
+ * rd_atomic array, so rxe_receiver() cannot race the free/
+ * realloc.
+ */
+ rxe_disable_task(&qp->recv_task);
free_rd_atomic_resources(qp);
-
err = alloc_rd_atomic_resources(qp, max_dest_rd_atomic);
+ /*
+ * On ENOMEM leave recv_task quiesced: qp->resp.resources is
+ * NULL and rxe_prepare_res()/find_resource() would deref it.
+ * Re-enable only after a fresh array is installed.
+ */
if (err)
return err;
+ rxe_enable_task(&qp->recv_task);
}
if (mask & IB_QP_EN_SQD_ASYNC_NOTIFY)
diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c
index 12d03f390b09..24f5c044363f 100644
--- a/drivers/infiniband/sw/rxe/rxe_req.c
+++ b/drivers/infiniband/sw/rxe/rxe_req.c
@@ -701,6 +701,21 @@ int rxe_requester(struct rxe_qp *qp)
if (unlikely(!wqe))
goto exit;
+ /*
+ * Don't trust user space data: a user QP's WQE comes from an mmap'd
+ * ring, so num_sge/cur_sge are attacker-controlled. Bound num_sge like
+ * get_srq_wqe(); bound cur_sge only when payload exists (dma.resid),
+ * since copy_data() skips dma->sge[] on a zero-length copy (all a
+ * max_sge == 0 QP can post).
+ */
+ if (unlikely(wqe->dma.num_sge > qp->sq.max_sge ||
+ (wqe->dma.resid &&
+ wqe->dma.cur_sge >= qp->sq.max_sge))) {
+ rxe_dbg_qp(qp, "invalid num_sge/cur_sge in send wqe\n");
+ wqe->status = IB_WC_LOC_QP_OP_ERR;
+ goto err;
+ }
+
if (rxe_wqe_is_fenced(qp, wqe)) {
qp->req.wait_fence = 1;
goto exit;
diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c
index d8cbdfa70cdb..02b16e2b49b8 100644
--- a/drivers/infiniband/sw/rxe/rxe_resp.c
+++ b/drivers/infiniband/sw/rxe/rxe_resp.c
@@ -1217,7 +1217,14 @@ finish:
spin_lock_irqsave(&qp->state_lock, flags);
if (unlikely(qp_state(qp) == IB_QPS_ERR)) {
spin_unlock_irqrestore(&qp->state_lock, flags);
- return RESPST_CHK_RESOURCE;
+ /* The packet was executed and completed before the QP
+ * moved to ERROR; it must be consumed exactly once.
+ * Re-entering the request chain with the stale packet
+ * would copy it into every remaining recv WQE as a new
+ * completion. Remaining WQEs are flushed by the drain
+ * path at rxe_receiver() entry.
+ */
+ return pkt ? RESPST_CLEANUP : RESPST_CHK_RESOURCE;
}
spin_unlock_irqrestore(&qp->state_lock, flags);
diff --git a/drivers/infiniband/sw/rxe/rxe_srq.c b/drivers/infiniband/sw/rxe/rxe_srq.c
index c9a7cd38953d..74904a6fdf2b 100644
--- a/drivers/infiniband/sw/rxe/rxe_srq.c
+++ b/drivers/infiniband/sw/rxe/rxe_srq.c
@@ -13,8 +13,8 @@ int rxe_srq_chk_init(struct rxe_dev *rxe, struct ib_srq_init_attr *init)
struct ib_srq_attr *attr = &init->attr;
if (attr->max_wr > rxe->attr.max_srq_wr) {
- rxe_dbg_dev(rxe, "max_wr(%d) > max_srq_wr(%d)\n",
- attr->max_wr, rxe->attr.max_srq_wr);
+ rxe_dbg_dev(rxe, "max_wr(%u) > max_srq_wr(%u)\n",
+ attr->max_wr, rxe->attr.max_srq_wr);
goto err1;
}
@@ -27,8 +27,8 @@ int rxe_srq_chk_init(struct rxe_dev *rxe, struct ib_srq_init_attr *init)
attr->max_wr = RXE_MIN_SRQ_WR;
if (attr->max_sge > rxe->attr.max_srq_sge) {
- rxe_dbg_dev(rxe, "max_sge(%d) > max_srq_sge(%d)\n",
- attr->max_sge, rxe->attr.max_srq_sge);
+ rxe_dbg_dev(rxe, "max_sge(%u) > max_srq_sge(%u)\n",
+ attr->max_sge, rxe->attr.max_srq_sge);
goto err1;
}
@@ -107,8 +107,8 @@ int rxe_srq_chk_attr(struct rxe_dev *rxe, struct rxe_srq *srq,
if (mask & IB_SRQ_MAX_WR) {
if (attr->max_wr > rxe->attr.max_srq_wr) {
- rxe_dbg_srq(srq, "max_wr(%d) > max_srq_wr(%d)\n",
- attr->max_wr, rxe->attr.max_srq_wr);
+ rxe_dbg_srq(srq, "max_wr(%u) > max_srq_wr(%u)\n",
+ attr->max_wr, rxe->attr.max_srq_wr);
goto err1;
}
@@ -129,8 +129,8 @@ int rxe_srq_chk_attr(struct rxe_dev *rxe, struct rxe_srq *srq,
if (mask & IB_SRQ_LIMIT) {
if (attr->srq_limit > rxe->attr.max_srq_wr) {
- rxe_dbg_srq(srq, "srq_limit(%d) > max_srq_wr(%d)\n",
- attr->srq_limit, rxe->attr.max_srq_wr);
+ rxe_dbg_srq(srq, "srq_limit(%u) > max_srq_wr(%u)\n",
+ attr->srq_limit, rxe->attr.max_srq_wr);
goto err1;
}
diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c
index 1ec130fee8ea..c8562866e21f 100644
--- a/drivers/infiniband/sw/rxe/rxe_verbs.c
+++ b/drivers/infiniband/sw/rxe/rxe_verbs.c
@@ -22,13 +22,13 @@ static int rxe_query_device(struct ib_device *ibdev,
struct rxe_dev *rxe = to_rdev(ibdev);
int err;
- err = ib_is_udata_in_empty(udata);
+ err = ib_no_udata_io(udata);
if (err)
return err;
memcpy(attr, &rxe->attr, sizeof(*attr));
- return ib_respond_empty_udata(udata);
+ return 0;
}
static int rxe_query_port(struct ib_device *ibdev,
diff --git a/drivers/infiniband/sw/siw/siw_verbs.c b/drivers/infiniband/sw/siw/siw_verbs.c
index 2349c08c32ed..80ef4cb95fc3 100644
--- a/drivers/infiniband/sw/siw/siw_verbs.c
+++ b/drivers/infiniband/sw/siw/siw_verbs.c
@@ -132,12 +132,10 @@ int siw_query_device(struct ib_device *base_dev, struct ib_device_attr *attr,
struct siw_device *sdev = to_siw_dev(base_dev);
int rv;
- rv = ib_is_udata_in_empty(udata);
+ rv = ib_no_udata_io(udata);
if (rv)
return rv;
- memset(attr, 0, sizeof(*attr));
-
/* Revisit atomic caps if RFC 7306 gets supported */
attr->atomic_cap = 0;
attr->device_cap_flags = IB_DEVICE_MEM_MGT_EXTENSIONS;
@@ -167,7 +165,7 @@ int siw_query_device(struct ib_device *base_dev, struct ib_device_attr *attr,
addrconf_addr_eui48((u8 *)&attr->sys_image_guid,
sdev->raw_gid);
- return ib_respond_empty_udata(udata);
+ return 0;
}
int siw_query_port(struct ib_device *base_dev, u32 port,
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 57fec88a1629..ed0592898384 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -1071,8 +1071,7 @@ static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ipoib_
struct ib_qp *tx_qp;
if (dev->features & NETIF_F_SG)
- attr.cap.max_send_sge = min_t(u32, priv->ca->attrs.max_send_sge,
- MAX_SKB_FRAGS + 1);
+ attr.cap.max_send_sge = min(priv->ca->attrs.max_send_sge, MAX_SKB_FRAGS + 1);
tx_qp = ib_create_qp(priv->pd, &attr);
tx->max_send_sge = attr.cap.max_send_sge;
@@ -1582,7 +1581,8 @@ static void ipoib_cm_create_srq(struct net_device *dev, int max_sge)
int ipoib_cm_dev_init(struct net_device *dev)
{
struct ipoib_dev_priv *priv = ipoib_priv(dev);
- int max_srq_sge, i;
+ u32 max_srq_sge;
+ int i;
u8 addr;
INIT_LIST_HEAD(&priv->cm.passive_ids);
@@ -1600,9 +1600,9 @@ int ipoib_cm_dev_init(struct net_device *dev)
skb_queue_head_init(&priv->cm.skb_queue);
- ipoib_dbg(priv, "max_srq_sge=%d\n", priv->ca->attrs.max_srq_sge);
+ ipoib_dbg(priv, "max_srq_sge=%u\n", priv->ca->attrs.max_srq_sge);
- max_srq_sge = min_t(int, IPOIB_CM_RX_SG, priv->ca->attrs.max_srq_sge);
+ max_srq_sge = min(priv->ca->attrs.max_srq_sge, IPOIB_CM_RX_SG);
ipoib_cm_create_srq(dev, max_srq_sge);
if (ipoib_cm_has_srq(dev)) {
priv->cm.max_cm_mtu = max_srq_sge * PAGE_SIZE - 0x10;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
index 3ed1ea566690..2490696a1aab 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
@@ -147,8 +147,7 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
.cap = {
.max_send_wr = ipoib_sendq_size,
.max_recv_wr = ipoib_recvq_size,
- .max_send_sge = min_t(u32, priv->ca->attrs.max_send_sge,
- MAX_SKB_FRAGS + 1),
+ .max_send_sge = min(priv->ca->attrs.max_send_sge, MAX_SKB_FRAGS + 1),
.max_recv_sge = IPOIB_UD_RX_SG
},
.sq_sig_type = IB_SIGNAL_ALL_WR,
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index f03b3bb3c0c4..55fe68e5b837 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -244,8 +244,7 @@ static int iser_create_ib_conn_res(struct ib_conn *ib_conn)
max_send_wr = ISER_QP_SIG_MAX_REQ_DTOS + 1;
else
max_send_wr = ISER_QP_MAX_REQ_DTOS + 1;
- max_send_wr = min_t(unsigned int, max_send_wr,
- (unsigned int)ib_dev->attrs.max_qp_wr);
+ max_send_wr = min(max_send_wr, ib_dev->attrs.max_qp_wr);
cq_size = max_send_wr + ISER_QP_MAX_RECV_DTOS;
ib_conn->cq = ib_cq_pool_get(ib_dev, cq_size, -1, IB_POLL_SOFTIRQ);
@@ -589,7 +588,7 @@ static void iser_route_handler(struct rdma_cm_id *cma_id)
goto failure;
memset(&conn_param, 0, sizeof conn_param);
- conn_param.responder_resources = ib_dev->attrs.max_qp_rd_atom;
+ conn_param.responder_resources = min(ib_dev->attrs.max_qp_rd_atom, U8_MAX);
conn_param.initiator_depth = 1;
conn_param.retry_count = 7;
conn_param.rnr_retry_count = 6;
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
index 1015a51f750a..4691845bf815 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -214,9 +214,9 @@ isert_create_device_ib_res(struct isert_device *device)
struct ib_device *ib_dev = device->ib_device;
int ret;
- isert_dbg("devattr->max_send_sge: %d devattr->max_recv_sge %d\n",
+ isert_dbg("devattr->max_send_sge: %u devattr->max_recv_sge %u\n",
ib_dev->attrs.max_send_sge, ib_dev->attrs.max_recv_sge);
- isert_dbg("devattr->max_sge_rd: %d\n", ib_dev->attrs.max_sge_rd);
+ isert_dbg("devattr->max_sge_rd: %u\n", ib_dev->attrs.max_sge_rd);
device->pd = ib_alloc_pd(ib_dev, 0);
if (IS_ERR(device->pd)) {
@@ -381,8 +381,7 @@ isert_set_nego_params(struct isert_conn *isert_conn,
struct ib_device_attr *attr = &isert_conn->device->ib_device->attrs;
/* Set max inflight RDMA READ requests */
- isert_conn->initiator_depth = min_t(u8, param->initiator_depth,
- attr->max_qp_init_rd_atom);
+ isert_conn->initiator_depth = min(param->initiator_depth, attr->max_qp_init_rd_atom);
isert_dbg("Using initiator_depth: %u\n", isert_conn->initiator_depth);
if (param->private_data) {
diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt.c b/drivers/infiniband/ulp/rtrs/rtrs-clt.c
index d34d7e5f34d6..7b2c51ae614f 100644
--- a/drivers/infiniband/ulp/rtrs/rtrs-clt.c
+++ b/drivers/infiniband/ulp/rtrs/rtrs-clt.c
@@ -1675,8 +1675,7 @@ static int create_con_cq_qp(struct rtrs_clt_con *con)
* + 2 for drain and heartbeat
* in case qp gets into error state.
*/
- max_send_wr =
- min_t(int, wr_limit, SERVICE_CON_QUEUE_DEPTH * 2 + 2);
+ max_send_wr = min(wr_limit, SERVICE_CON_QUEUE_DEPTH * 2 + 2);
max_recv_wr = max_send_wr;
} else {
/*
@@ -1692,11 +1691,9 @@ static int create_con_cq_qp(struct rtrs_clt_con *con)
wr_limit = clt_path->s.dev->ib_dev->attrs.max_qp_wr;
/* Shared between connections */
clt_path->s.dev_ref++;
- max_send_wr = min_t(int, wr_limit,
- /* QD * (REQ + RSP + FR REGS or INVS) + drain */
- clt_path->queue_depth * 4 + 1);
- max_recv_wr = min_t(int, wr_limit,
- clt_path->queue_depth * 3 + 1);
+ /* QD * (REQ + RSP + FR REGS or INVS) + drain */
+ max_send_wr = min(wr_limit, clt_path->queue_depth * 4 + 1);
+ max_recv_wr = min(wr_limit, clt_path->queue_depth * 3 + 1);
max_send_sge = 2;
}
atomic_set(&con->c.sq_wr_avail, max_send_wr);
diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c
index 7d8e4422cc57..5314599d29fe 100644
--- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c
+++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c
@@ -1740,21 +1740,16 @@ static int create_con(struct rtrs_srv_path *srv_path,
* All receive and all send (each requiring invalidate)
* + 2 for drain and heartbeat
*/
- max_send_wr = min_t(int, wr_limit,
- SERVICE_CON_QUEUE_DEPTH * 2 + 2);
+ max_send_wr = min(wr_limit, SERVICE_CON_QUEUE_DEPTH * 2 + 2);
max_recv_wr = max_send_wr;
s->signal_interval = min_not_zero(srv->queue_depth,
(size_t)SERVICE_CON_QUEUE_DEPTH);
} else {
/* when always_invlaidate enalbed, we need linv+rinv+mr+imm */
if (always_invalidate)
- max_send_wr =
- min_t(int, wr_limit,
- srv->queue_depth * (1 + 4) + 1);
+ max_send_wr = min(wr_limit, srv->queue_depth * (1 + 4) + 1);
else
- max_send_wr =
- min_t(int, wr_limit,
- srv->queue_depth * (1 + 2) + 1);
+ max_send_wr = min(wr_limit, srv->queue_depth * (1 + 2) + 1);
max_recv_wr = srv->queue_depth + 1;
}
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index acbd787de265..0caebbc2810f 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -557,7 +557,7 @@ static int srp_create_ch_ib(struct srp_rdma_ch *ch)
init_attr->cap.max_send_wr = m * target->queue_size;
init_attr->cap.max_recv_wr = target->queue_size + 1;
init_attr->cap.max_recv_sge = 1;
- init_attr->cap.max_send_sge = min(SRP_MAX_SGE, attr->max_send_sge);
+ init_attr->cap.max_send_sge = min(attr->max_send_sge, SRP_MAX_SGE);
init_attr->sq_sig_type = IB_SIGNAL_REQ_WR;
init_attr->qp_type = IB_QPT_RC;
init_attr->send_cq = send_cq;
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index f66cfd70c263..7197d95f2216 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -77,8 +77,8 @@ module_param(srp_max_req_size, int, 0444);
MODULE_PARM_DESC(srp_max_req_size,
"Maximum size of SRP request messages in bytes.");
-static int srpt_srq_size = DEFAULT_SRPT_SRQ_SIZE;
-module_param(srpt_srq_size, int, 0444);
+static unsigned int srpt_srq_size = DEFAULT_SRPT_SRQ_SIZE;
+module_param(srpt_srq_size, uint, 0444);
MODULE_PARM_DESC(srpt_srq_size,
"Shared receive queue (SRQ) size.");
@@ -405,8 +405,7 @@ static void srpt_get_ioc(struct srpt_port *sport, u32 slot,
if (sdev->use_srq)
send_queue_depth = sdev->srq_size;
else
- send_queue_depth = min(MAX_SRPT_RQ_SIZE,
- sdev->device->attrs.max_qp_wr);
+ send_queue_depth = min(sdev->device->attrs.max_qp_wr, MAX_SRPT_RQ_SIZE);
memset(iocp, 0, sizeof(*iocp));
strcpy(iocp->id_string, SRPT_ID_STRING);
@@ -960,6 +959,7 @@ static int srpt_alloc_rw_ctxs(struct srpt_send_ioctx *ioctx,
struct srpt_rdma_ch *ch = ioctx->ch;
struct scatterlist *prev = NULL;
unsigned prev_nents;
+ u8 n_rdma, n_rw_ctx;
int ret, i;
if (nbufs == 1) {
@@ -970,6 +970,9 @@ static int srpt_alloc_rw_ctxs(struct srpt_send_ioctx *ioctx,
return -ENOMEM;
}
+ n_rw_ctx = ioctx->n_rw_ctx;
+ n_rdma = ioctx->n_rdma;
+
for (i = ioctx->n_rw_ctx; i < nbufs; i++, db++) {
struct srpt_rw_ctx *ctx = &ioctx->rw_ctxs[i];
u64 remote_addr = be64_to_cpu(db->va);
@@ -1016,6 +1019,9 @@ unwind:
}
if (ioctx->rw_ctxs != &ioctx->s_rw_ctx)
kfree(ioctx->rw_ctxs);
+ ioctx->rw_ctxs = NULL;
+ ioctx->n_rw_ctx = n_rw_ctx;
+ ioctx->n_rdma = n_rdma;
return ret;
}
@@ -1596,7 +1602,7 @@ static void srpt_handle_cmd(struct srpt_rdma_ch *ch,
rc = target_init_cmd(cmd, ch->sess, &send_ioctx->sense_data[0],
scsilun_to_int(&srp_cmd->lun), data_len,
- TCM_SIMPLE_TAG, dir, TARGET_SCF_ACK_KREF);
+ cmd->sam_task_attr, dir, TARGET_SCF_ACK_KREF);
if (rc != 0) {
pr_debug("target_submit_cmd() returned %d for tag %#llx\n", rc,
srp_cmd->tag);
@@ -1851,7 +1857,7 @@ static int srpt_create_ch_ib(struct srpt_rdma_ch *ch)
struct srpt_port *sport = ch->sport;
struct srpt_device *sdev = sport->sdev;
const struct ib_device_attr *attrs = &sdev->device->attrs;
- int sq_size = sport->port_attrib.srp_sq_size;
+ u32 sq_size = sport->port_attrib.srp_sq_size;
int i, ret;
WARN_ON(ch->rq_size < 1);
@@ -1912,13 +1918,13 @@ retry:
bool retry = sq_size > MIN_SRPT_SQ_SIZE;
if (retry) {
- pr_debug("failed to create queue pair with sq_size = %d (%d) - retrying\n",
+ pr_debug("failed to create queue pair with sq_size = %u (%d) - retrying\n",
sq_size, ret);
ib_cq_pool_put(ch->cq, ch->cq_size);
sq_size = max(sq_size / 2, MIN_SRPT_SQ_SIZE);
goto retry;
} else {
- pr_err("failed to create queue pair with sq_size = %d (%d)\n",
+ pr_err("failed to create queue pair with sq_size = %u (%d)\n",
sq_size, ret);
goto err_destroy_cq;
}
@@ -1926,7 +1932,7 @@ retry:
atomic_set(&ch->sq_wr_avail, qp_init->cap.max_send_wr);
- pr_debug("%s: max_cqe= %d max_sge= %d sq_size = %d ch= %p\n",
+ pr_debug("%s: max_cqe= %d max_sge= %d sq_size = %u ch= %p\n",
__func__, ch->cq->cqe, qp_init->cap.max_send_sge,
qp_init->cap.max_send_wr, ch);
@@ -2299,7 +2305,7 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev,
* depth to avoid that the initiator driver has to report QUEUE_FULL
* to the SCSI mid-layer.
*/
- ch->rq_size = min(MAX_SRPT_RQ_SIZE, sdev->device->attrs.max_qp_wr);
+ ch->rq_size = min(sdev->device->attrs.max_qp_wr, MAX_SRPT_RQ_SIZE);
spin_lock_init(&ch->spinlock);
ch->state = CH_CONNECTING;
INIT_LIST_HEAD(&ch->cmd_wait_list);
@@ -3137,7 +3143,7 @@ static int srpt_alloc_srq(struct srpt_device *sdev)
return PTR_ERR(srq);
}
- pr_debug("create SRQ #wr= %d max_allow=%d dev= %s\n", sdev->srq_size,
+ pr_debug("create SRQ #wr= %d max_allow=%u dev= %s\n", sdev->srq_size,
sdev->device->attrs.max_srq_wr, dev_name(&device->dev));
sdev->req_buf_cache = srpt_cache_get(srp_max_req_size);
@@ -3952,7 +3958,7 @@ static int __init srpt_init_module(void)
if (srpt_srq_size < MIN_SRPT_SRQ_SIZE
|| srpt_srq_size > MAX_SRPT_SRQ_SIZE) {
- pr_err("invalid value %d for kernel module parameter srpt_srq_size -- must be in the range [%d..%d].\n",
+ pr_err("invalid value %u for kernel module parameter srpt_srq_size -- must be in the range [%d..%d].\n",
srpt_srq_size, MIN_SRPT_SRQ_SIZE, MAX_SRPT_SRQ_SIZE);
goto out;
}
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
index c4ab4b5caa0a..fc8c50e8f365 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
@@ -1041,10 +1041,14 @@ static int ionic_get_ts_info(struct net_device *netdev,
info->phc_index = ptp_clock_index(lif->phc->ptp);
- info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
- SOF_TIMESTAMPING_TX_HARDWARE |
- SOF_TIMESTAMPING_RX_HARDWARE |
- SOF_TIMESTAMPING_RAW_HARDWARE;
+ info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE;
+
+ if (!(lif->hw_features & IONIC_ETH_HW_TIMESTAMP))
+ return 0;
+
+ info->so_timestamping |= SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
/* tx modes */
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_if.h b/drivers/net/ethernet/pensando/ionic/ionic_if.h
index 0a201422d0c5..6afc1fc3c7ed 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_if.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic_if.h
@@ -1181,6 +1181,7 @@ enum ionic_eth_hw_features {
IONIC_ETH_HW_TX_CSUM_GENEVE = BIT(18),
IONIC_ETH_HW_TSO_GENEVE = BIT(19),
IONIC_ETH_HW_TIMESTAMP = BIT(20),
+ IONIC_ETH_HW_RDMA_TIMESTAMP = BIT(21),
};
/**
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
index fd3ee9820531..af4aadd96cb9 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
@@ -1500,7 +1500,8 @@ static int ionic_set_nic_features(struct ionic_lif *lif,
ctx.cmd.lif_setattr.features = ionic_netdev_features_to_nic(features);
if (lif->phc)
- ctx.cmd.lif_setattr.features |= cpu_to_le64(IONIC_ETH_HW_TIMESTAMP);
+ ctx.cmd.lif_setattr.features |= lif->ionic->ident.lif.eth.config.features &
+ cpu_to_le64(IONIC_ETH_HW_TIMESTAMP | IONIC_ETH_HW_RDMA_TIMESTAMP);
err = ionic_adminq_post_wait(lif, &ctx);
if (err)
@@ -1551,6 +1552,8 @@ static int ionic_set_nic_features(struct ionic_lif *lif,
dev_dbg(dev, "feature ETH_HW_TSO_UDP_CSUM\n");
if (lif->hw_features & IONIC_ETH_HW_TIMESTAMP)
dev_dbg(dev, "feature ETH_HW_TIMESTAMP\n");
+ if (lif->hw_features & IONIC_ETH_HW_RDMA_TIMESTAMP)
+ dev_dbg(dev, "feature ETH_HW_RDMA_TIMESTAMP\n");
return 0;
}
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.h b/drivers/net/ethernet/pensando/ionic/ionic_lif.h
index d34692462036..e790f6b9441e 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h
@@ -248,7 +248,7 @@ struct ionic_lif {
};
struct ionic_phc {
- spinlock_t lock; /* lock for cc and tc */
+ spinlock_t lock; /* lock for state_page, cc and tc */
struct cyclecounter cc;
struct timecounter tc;
@@ -261,6 +261,7 @@ struct ionic_phc {
long aux_work_delay;
struct ptp_clock_info ptp_info;
+ struct ib_uverbs_clock_info *state_page;
struct ptp_clock *ptp;
struct ionic_lif *lif;
};
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_phc.c b/drivers/net/ethernet/pensando/ionic/ionic_phc.c
index 05b44fc482f8..4b8d80a55b72 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_phc.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_phc.c
@@ -3,6 +3,7 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <uapi/rdma/ib_user_verbs.h>
#include "ionic.h"
#include "ionic_bus.h"
@@ -77,7 +78,8 @@ static int ionic_lif_hwstamp_set_ts_config(struct ionic_lif *lif,
bool rx_all;
__le64 mask;
- if (!lif->phc || !lif->phc->ptp)
+ if (!lif->phc || !lif->phc->ptp ||
+ !(lif->hw_features & IONIC_ETH_HW_TIMESTAMP))
return -EOPNOTSUPP;
mutex_lock(&lif->phc->config_lock);
@@ -210,7 +212,8 @@ int ionic_hwstamp_set(struct net_device *netdev,
struct ionic_lif *lif = netdev_priv(netdev);
int err;
- if (!lif->phc || !lif->phc->ptp)
+ if (!lif->phc || !lif->phc->ptp ||
+ !(lif->hw_features & IONIC_ETH_HW_TIMESTAMP))
return -EOPNOTSUPP;
mutex_lock(&lif->queue_lock);
@@ -228,7 +231,8 @@ void ionic_lif_hwstamp_replay(struct ionic_lif *lif)
{
int err;
- if (!lif->phc || !lif->phc->ptp)
+ if (!lif->phc || !lif->phc->ptp ||
+ !(lif->hw_features & IONIC_ETH_HW_TIMESTAMP))
return;
mutex_lock(&lif->queue_lock);
@@ -242,7 +246,8 @@ void ionic_lif_hwstamp_recreate_queues(struct ionic_lif *lif)
{
int err;
- if (!lif->phc || !lif->phc->ptp)
+ if (!lif->phc || !lif->phc->ptp ||
+ !(lif->hw_features & IONIC_ETH_HW_TIMESTAMP))
return;
mutex_lock(&lif->phc->config_lock);
@@ -267,7 +272,8 @@ int ionic_hwstamp_get(struct net_device *netdev,
{
struct ionic_lif *lif = netdev_priv(netdev);
- if (!lif->phc || !lif->phc->ptp)
+ if (!lif->phc || !lif->phc->ptp ||
+ !(lif->hw_features & IONIC_ETH_HW_TIMESTAMP))
return -EOPNOTSUPP;
mutex_lock(&lif->phc->config_lock);
@@ -329,6 +335,26 @@ static int ionic_setphc_cmd(struct ionic_phc *phc, struct ionic_admin_ctx *ctx)
return ionic_adminq_post(phc->lif, ctx);
}
+static void ionic_phc_state_page_update(struct ionic_phc *phc)
+{
+ struct ib_uverbs_clock_info *state = phc->state_page;
+ u32 sign;
+
+ /* read current sign */
+ sign = smp_load_acquire(&state->sign) & ~1;
+
+ /* make sign odd for updating */
+ smp_store_mb(state->sign, sign | 1);
+
+ state->cycles = phc->tc.cycle_last;
+ state->nsec = phc->tc.nsec;
+ state->frac = phc->tc.frac;
+ state->mult = phc->cc.mult;
+
+ /* make sign the next even number for update completed */
+ smp_store_release(&state->sign, sign + 2);
+}
+
static int ionic_phc_adjfine(struct ptp_clock_info *info, long scaled_ppm)
{
struct ionic_phc *phc = container_of(info, struct ionic_phc, ptp_info);
@@ -356,6 +382,8 @@ static int ionic_phc_adjfine(struct ptp_clock_info *info, long scaled_ppm)
timecounter_read(&phc->tc);
phc->cc.mult = adj;
+ ionic_phc_state_page_update(phc);
+
/* Setphc commands are posted in-order, sequenced by phc->lock. We
* need to drop the lock before waiting for the command to complete.
*/
@@ -381,6 +409,8 @@ static int ionic_phc_adjtime(struct ptp_clock_info *info, s64 delta)
timecounter_adjtime(&phc->tc, delta);
+ ionic_phc_state_page_update(phc);
+
/* Setphc commands are posted in-order, sequenced by phc->lock. We
* need to drop the lock before waiting for the command to complete.
*/
@@ -410,6 +440,8 @@ static int ionic_phc_settime64(struct ptp_clock_info *info,
timecounter_init(&phc->tc, &phc->cc, ns);
+ ionic_phc_state_page_update(phc);
+
/* Setphc commands are posted in-order, sequenced by phc->lock. We
* need to drop the lock before waiting for the command to complete.
*/
@@ -467,6 +499,8 @@ static long ionic_phc_aux_work(struct ptp_clock_info *info)
/* update point-in-time basis to now */
timecounter_read(&phc->tc);
+ ionic_phc_state_page_update(phc);
+
/* Setphc commands are posted in-order, sequenced by phc->lock. We
* need to drop the lock before waiting for the command to complete.
*/
@@ -506,7 +540,8 @@ static const struct ptp_clock_info ionic_ptp_info = {
void ionic_lif_register_phc(struct ionic_lif *lif)
{
- if (!lif->phc || !(lif->hw_features & IONIC_ETH_HW_TIMESTAMP))
+ if (!lif->phc ||
+ !(lif->hw_features & (IONIC_ETH_HW_TIMESTAMP | IONIC_ETH_HW_RDMA_TIMESTAMP)))
return;
lif->phc->ptp = ptp_clock_register(&lif->phc->ptp_info, lif->ionic->dev);
@@ -545,13 +580,19 @@ void ionic_lif_alloc_phc(struct ionic_lif *lif)
return;
features = le64_to_cpu(ionic->ident.lif.eth.config.features);
- if (!(features & IONIC_ETH_HW_TIMESTAMP))
+ if (!(features & (IONIC_ETH_HW_TIMESTAMP | IONIC_ETH_HW_RDMA_TIMESTAMP)))
return;
phc = devm_kzalloc(ionic->dev, sizeof(*phc), GFP_KERNEL);
if (!phc)
return;
+ phc->state_page = (void *)get_zeroed_page(GFP_KERNEL);
+ if (!phc->state_page) {
+ devm_kfree(ionic->dev, phc);
+ return;
+ }
+
phc->lif = lif;
phc->cc.read = ionic_cc_read;
@@ -563,6 +604,7 @@ void ionic_lif_alloc_phc(struct ionic_lif *lif)
dev_err(lif->ionic->dev,
"Invalid device PHC mask multiplier %u, disabling HW timestamp support\n",
phc->cc.mult);
+ free_page((unsigned long)phc->state_page);
devm_kfree(lif->ionic->dev, phc);
lif->phc = NULL;
return;
@@ -646,6 +688,12 @@ void ionic_lif_alloc_phc(struct ionic_lif *lif)
*/
phc->ptp_info.max_adj = NORMAL_PPB;
+ phc->state_page->mask = phc->cc.mask;
+ phc->state_page->shift = phc->cc.shift;
+ phc->state_page->overflow_period = delay;
+
+ ionic_phc_state_page_update(phc);
+
lif->phc = phc;
}
@@ -656,6 +704,7 @@ void ionic_lif_free_phc(struct ionic_lif *lif)
mutex_destroy(&lif->phc->config_lock);
+ free_page((unsigned long)lif->phc->state_page);
devm_kfree(lif->ionic->dev, lif->phc);
lif->phc = NULL;
}
diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index 6909e3542794..56cd228af1d5 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -394,8 +394,10 @@ nvme_rdma_find_get_device(struct rdma_cm_id *cm_id)
goto out_free_pd;
}
- ndev->num_inline_segments = min(NVME_RDMA_MAX_INLINE_SEGMENTS,
- ndev->dev->attrs.max_send_sge - 1);
+ ndev->num_inline_segments = ndev->dev->attrs.max_send_sge;
+ if (ndev->num_inline_segments)
+ ndev->num_inline_segments--;
+ ndev->num_inline_segments = min(ndev->num_inline_segments, NVME_RDMA_MAX_INLINE_SEGMENTS);
list_add(&ndev->entry, &device_list);
out_unlock:
mutex_unlock(&device_list_mutex);
@@ -1847,7 +1849,7 @@ static int nvme_rdma_route_resolved(struct nvme_rdma_queue *queue)
param.qp_num = queue->qp->qp_num;
param.flow_control = 1;
- param.responder_resources = queue->device->dev->attrs.max_qp_rd_atom;
+ param.responder_resources = min(queue->device->dev->attrs.max_qp_rd_atom, U8_MAX);
/* maximum retry count */
param.retry_count = 7;
param.rnr_retry_count = 7;
diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c
index ea1185b8267e..bdd28ce99faa 100644
--- a/drivers/nvme/target/rdma.c
+++ b/drivers/nvme/target/rdma.c
@@ -149,10 +149,10 @@ MODULE_PARM_DESC(use_srq, "Use shared receive queue.");
static int srq_size_set(const char *val, const struct kernel_param *kp);
static const struct kernel_param_ops srq_size_ops = {
.set = srq_size_set,
- .get = param_get_int,
+ .get = param_get_uint,
};
-static int nvmet_rdma_srq_size = 1024;
+static unsigned int nvmet_rdma_srq_size = 1024;
module_param_cb(srq_size, &srq_size_ops, &nvmet_rdma_srq_size, 0644);
MODULE_PARM_DESC(srq_size, "set Shared Receive Queue (SRQ) size, should >= 256 (default: 1024)");
@@ -180,13 +180,14 @@ static const struct nvmet_fabrics_ops nvmet_rdma_ops;
static int srq_size_set(const char *val, const struct kernel_param *kp)
{
- int n = 0, ret;
+ unsigned int n;
+ int ret;
- ret = kstrtoint(val, 10, &n);
+ ret = kstrtouint(val, 10, &n);
if (ret != 0 || n < 256)
return -EINVAL;
- return param_set_int(val, kp);
+ return param_set_uint(val, kp);
}
static int num_pages(int len)
@@ -1153,8 +1154,8 @@ static int nvmet_rdma_init_srqs(struct nvmet_rdma_device *ndev)
ndev->srq_size = min(ndev->device->attrs.max_srq_wr,
nvmet_rdma_srq_size);
- ndev->srq_count = min(ndev->device->num_comp_vectors,
- ndev->device->attrs.max_srq);
+ ndev->srq_count = min_t(u32, ndev->device->num_comp_vectors,
+ ndev->device->attrs.max_srq);
ndev->srqs = kzalloc_objs(*ndev->srqs, ndev->srq_count);
if (!ndev->srqs)
@@ -1199,7 +1200,7 @@ nvmet_rdma_find_get_device(struct rdma_cm_id *cm_id)
struct nvmet_port *nport = port->nport;
struct nvmet_rdma_device *ndev;
int inline_page_count;
- int inline_sge_count;
+ u32 inline_sge_count;
int ret;
mutex_lock(&device_list_mutex);
@@ -1215,7 +1216,9 @@ nvmet_rdma_find_get_device(struct rdma_cm_id *cm_id)
inline_page_count = num_pages(nport->inline_data_size);
inline_sge_count = max(cm_id->device->attrs.max_sge_rd,
- cm_id->device->attrs.max_recv_sge) - 1;
+ cm_id->device->attrs.max_recv_sge);
+ if (inline_sge_count)
+ inline_sge_count--;
if (inline_page_count > inline_sge_count) {
pr_warn("inline_data_size %d cannot be supported by device %s. Reducing to %lu.\n",
nport->inline_data_size, cm_id->device->name,
@@ -1555,8 +1558,9 @@ static int nvmet_rdma_cm_accept(struct rdma_cm_id *cm_id,
param.rnr_retry_count = 7;
param.flow_control = 1;
- param.initiator_depth = min_t(u8, p->initiator_depth,
- queue->dev->device->attrs.max_qp_init_rd_atom);
+ param.initiator_depth = min3(p->initiator_depth,
+ queue->dev->device->attrs.max_qp_init_rd_atom,
+ U8_MAX);
param.private_data = &priv;
param.private_data_len = sizeof(priv);
priv.recfmt = cpu_to_le16(NVME_RDMA_CM_FMT_1_0);
diff --git a/fs/smb/smbdirect/accept.c b/fs/smb/smbdirect/accept.c
index 529740005838..44b681a20725 100644
--- a/fs/smb/smbdirect/accept.c
+++ b/fs/smb/smbdirect/accept.c
@@ -32,8 +32,9 @@ int smbdirect_accept_connect_request(struct smbdirect_socket *sc,
/*
* First set what the we as server are able to support
*/
- sp->initiator_depth = min_t(u8, sp->initiator_depth,
- sc->ib.dev->attrs.max_qp_rd_atom);
+ sp->initiator_depth = min3(sp->initiator_depth,
+ sc->ib.dev->attrs.max_qp_rd_atom,
+ U8_MAX);
peer_initiator_depth = param->initiator_depth;
peer_responder_resources = param->responder_resources;
diff --git a/fs/smb/smbdirect/connect.c b/fs/smb/smbdirect/connect.c
index cd726b399afe..34a3e72c38fb 100644
--- a/fs/smb/smbdirect/connect.c
+++ b/fs/smb/smbdirect/connect.c
@@ -182,8 +182,9 @@ static int smbdirect_connect_rdma_connect(struct smbdirect_socket *sc)
if (sc->ib.dev->attrs.kernel_cap_flags & IBK_SG_GAPS_REG)
sc->mr_io.type = IB_MR_TYPE_SG_GAPS;
- sp->responder_resources = min_t(u8, sp->responder_resources,
- sc->ib.dev->attrs.max_qp_rd_atom);
+ sp->responder_resources = min3(sp->responder_resources,
+ sc->ib.dev->attrs.max_qp_rd_atom,
+ U8_MAX);
smbdirect_log_rdma_mr(sc, SMBDIRECT_LOG_INFO,
"responder_resources=%d\n",
sp->responder_resources);
diff --git a/fs/smb/smbdirect/connection.c b/fs/smb/smbdirect/connection.c
index 8adf58097534..690acb84e1b5 100644
--- a/fs/smb/smbdirect/connection.c
+++ b/fs/smb/smbdirect/connection.c
@@ -287,7 +287,7 @@ int smbdirect_connection_create_qp(struct smbdirect_socket *sc)
qp_cap.max_send_wr > sc->ib.dev->attrs.max_qp_wr) {
pr_err("Possible CQE overrun: max_send_wr %d\n",
qp_cap.max_send_wr);
- pr_err("device %.*s reporting max_cqe %d max_qp_wr %d\n",
+ pr_err("device %.*s reporting max_cqe %u max_qp_wr %u\n",
IB_DEVICE_NAME_MAX,
sc->ib.dev->name,
sc->ib.dev->attrs.max_cqe,
@@ -302,7 +302,7 @@ int smbdirect_connection_create_qp(struct smbdirect_socket *sc)
max_send_wr >= sc->ib.dev->attrs.max_qp_wr)) {
pr_err("Possible CQE overrun: rdma_send_wr %d + max_send_wr %d = %d\n",
rdma_send_wr, qp_cap.max_send_wr, max_send_wr);
- pr_err("device %.*s reporting max_cqe %d max_qp_wr %d\n",
+ pr_err("device %.*s reporting max_cqe %u max_qp_wr %u\n",
IB_DEVICE_NAME_MAX,
sc->ib.dev->name,
sc->ib.dev->attrs.max_cqe,
@@ -316,7 +316,7 @@ int smbdirect_connection_create_qp(struct smbdirect_socket *sc)
qp_cap.max_recv_wr > sc->ib.dev->attrs.max_qp_wr) {
pr_err("Possible CQE overrun: max_recv_wr %d\n",
qp_cap.max_recv_wr);
- pr_err("device %.*s reporting max_cqe %d max_qp_wr %d\n",
+ pr_err("device %.*s reporting max_cqe %u max_qp_wr %u\n",
IB_DEVICE_NAME_MAX,
sc->ib.dev->name,
sc->ib.dev->attrs.max_cqe,
@@ -328,7 +328,7 @@ int smbdirect_connection_create_qp(struct smbdirect_socket *sc)
if (qp_cap.max_send_sge > sc->ib.dev->attrs.max_send_sge ||
qp_cap.max_recv_sge > sc->ib.dev->attrs.max_recv_sge) {
- pr_err("device %.*s max_send_sge/max_recv_sge = %d/%d too small\n",
+ pr_err("device %.*s max_send_sge/max_recv_sge = %u/%u too small\n",
IB_DEVICE_NAME_MAX,
sc->ib.dev->name,
sc->ib.dev->attrs.max_send_sge,
diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h
index 5aadb47b3b0e..76aa5ec4ab40 100644
--- a/include/linux/sunrpc/svc_rdma.h
+++ b/include/linux/sunrpc/svc_rdma.h
@@ -77,8 +77,8 @@ struct svcxprt_rdma {
struct rdma_cm_id *sc_cm_id; /* RDMA connection id */
struct list_head sc_accept_q; /* Conn. waiting accept */
struct rpcrdma_notification sc_rn; /* removal notification */
- int sc_ord; /* RDMA read limit */
- int sc_max_send_sges;
+ u32 sc_ord; /* RDMA read limit */
+ unsigned int sc_max_send_sges;
bool sc_snd_w_inv; /* OK to use Send With Invalidate */
atomic_t sc_sq_avail; /* SQEs ready to be consumed */
diff --git a/include/rdma/ib_umem.h b/include/rdma/ib_umem.h
index 31b3a86fe73a..1fe87fd1d769 100644
--- a/include/rdma/ib_umem.h
+++ b/include/rdma/ib_umem.h
@@ -250,7 +250,7 @@ struct ib_umem_dmabuf *ib_umem_dmabuf_get(struct ib_device *device,
unsigned long offset,
size_t size, int fd,
int access,
- struct dma_buf_attach_ops *ops)
+ const struct dma_buf_attach_ops *ops)
{
return ERR_PTR(-EOPNOTSUPP);
}
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index 794746de8db0..cb3b6163961b 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -407,36 +407,36 @@ struct ib_device_attr {
u32 vendor_id;
u32 vendor_part_id;
u32 hw_ver;
- int max_qp;
- int max_qp_wr;
+ u32 max_qp;
+ u32 max_qp_wr;
u64 device_cap_flags;
u64 kernel_cap_flags;
- int max_send_sge;
- int max_recv_sge;
- int max_sge_rd;
- int max_cq;
- int max_cqe;
- int max_mr;
- int max_pd;
- int max_qp_rd_atom;
- int max_ee_rd_atom;
- int max_res_rd_atom;
- int max_qp_init_rd_atom;
- int max_ee_init_rd_atom;
+ u32 max_send_sge;
+ u32 max_recv_sge;
+ u32 max_sge_rd;
+ u32 max_cq;
+ u32 max_cqe;
+ u32 max_mr;
+ u32 max_pd;
+ u32 max_qp_rd_atom;
+ u32 max_ee_rd_atom;
+ u32 max_res_rd_atom;
+ u32 max_qp_init_rd_atom;
+ u32 max_ee_init_rd_atom;
enum ib_atomic_cap atomic_cap;
enum ib_atomic_cap masked_atomic_cap;
- int max_ee;
- int max_rdd;
- int max_mw;
- int max_raw_ipv6_qp;
- int max_raw_ethy_qp;
- int max_mcast_grp;
- int max_mcast_qp_attach;
- int max_total_mcast_qp_attach;
- int max_ah;
- int max_srq;
- int max_srq_wr;
- int max_srq_sge;
+ u32 max_ee;
+ u32 max_rdd;
+ u32 max_mw;
+ u32 max_raw_ipv6_qp;
+ u32 max_raw_ethy_qp;
+ u32 max_mcast_grp;
+ u32 max_mcast_qp_attach;
+ u32 max_total_mcast_qp_attach;
+ u32 max_ah;
+ u32 max_srq;
+ u32 max_srq_wr;
+ u32 max_srq_sge;
unsigned int max_fast_reg_page_list_len;
unsigned int max_pi_fast_reg_page_list_len;
u16 max_pkeys;
@@ -1746,6 +1746,42 @@ struct ib_cq {
struct rdma_restrack_entry res;
};
+enum ib_qp_attach_comp_cntr_op {
+ IB_QP_ATTACH_COMP_CNTR_OP_SEND = IB_UVERBS_QP_ATTACH_COMP_CNTR_OP_SEND,
+ IB_QP_ATTACH_COMP_CNTR_OP_RECV = IB_UVERBS_QP_ATTACH_COMP_CNTR_OP_RECV,
+ IB_QP_ATTACH_COMP_CNTR_OP_RDMA_READ = IB_UVERBS_QP_ATTACH_COMP_CNTR_OP_RDMA_READ,
+ IB_QP_ATTACH_COMP_CNTR_OP_REMOTE_RDMA_READ = IB_UVERBS_QP_ATTACH_COMP_CNTR_OP_REMOTE_RDMA_READ,
+ IB_QP_ATTACH_COMP_CNTR_OP_RDMA_WRITE = IB_UVERBS_QP_ATTACH_COMP_CNTR_OP_RDMA_WRITE,
+ IB_QP_ATTACH_COMP_CNTR_OP_REMOTE_RDMA_WRITE = IB_UVERBS_QP_ATTACH_COMP_CNTR_OP_REMOTE_RDMA_WRITE,
+};
+
+struct ib_comp_cntr_caps {
+ u64 max_value;
+ u32 max_counters;
+ u32 supported_qp_attach_ops; /* Bitmask of enum ib_qp_attach_comp_cntr_op */
+};
+
+struct ib_comp_cntr {
+ struct ib_device *device;
+ struct ib_uobject *uobject;
+ atomic_t usecnt;
+ struct rdma_restrack_entry res;
+};
+
+enum ib_comp_cntr_entry {
+ IB_COMP_CNTR_ENTRY_COMP = IB_UVERBS_COMP_CNTR_ENTRY_COMP,
+ IB_COMP_CNTR_ENTRY_ERR = IB_UVERBS_COMP_CNTR_ENTRY_ERR,
+};
+
+enum ib_comp_cntr_modify_op {
+ IB_COMP_CNTR_MODIFY_OP_SET = IB_UVERBS_COMP_CNTR_MODIFY_OP_SET,
+ IB_COMP_CNTR_MODIFY_OP_INC = IB_UVERBS_COMP_CNTR_MODIFY_OP_INC,
+};
+
+struct ib_qp_attach_comp_cntr_attr {
+ u32 op_mask; /* Bitmask of enum ib_qp_attach_comp_cntr_op */
+};
+
struct ib_srq {
struct ib_device *device;
struct ib_pd *pd;
@@ -1916,6 +1952,8 @@ struct ib_qp {
struct completion srq_completion;
struct ib_xrcd *xrcd; /* XRC TGT QPs only */
struct list_head xrcd_list;
+ struct xarray comp_cntrs; /* op_mask -> comp_cntr */
+ u32 comp_cntr_op_mask;
/* count times opened, mcast attaches, flow attaches */
atomic_t usecnt;
@@ -2629,6 +2667,8 @@ struct ib_device_ops {
struct ib_udata *udata);
int (*modify_qp)(struct ib_qp *qp, struct ib_qp_attr *qp_attr,
int qp_attr_mask, struct ib_udata *udata);
+ int (*qp_attach_comp_cntr)(struct ib_qp *qp, struct ib_comp_cntr *cc,
+ struct ib_qp_attach_comp_cntr_attr *attr);
int (*query_qp)(struct ib_qp *qp, struct ib_qp_attr *qp_attr,
int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr);
int (*destroy_qp)(struct ib_qp *qp, struct ib_udata *udata);
@@ -2650,6 +2690,15 @@ struct ib_device_ops {
* post_destroy_cq - Free all kernel resources
*/
void (*post_destroy_cq)(struct ib_cq *cq);
+ int (*create_comp_cntr)(struct ib_comp_cntr *cc,
+ struct uverbs_attr_bundle *attrs);
+ int (*destroy_comp_cntr)(struct ib_comp_cntr *cc);
+ int (*modify_comp_cntr)(struct ib_comp_cntr *cc, enum ib_comp_cntr_entry entry,
+ enum ib_comp_cntr_modify_op op, u64 value);
+ int (*read_comp_cntr)(struct ib_comp_cntr *cc, enum ib_comp_cntr_entry entry, u64 *value);
+ int (*query_comp_cntr_caps)(struct ib_device *dev,
+ struct ib_comp_cntr_caps *caps,
+ struct uverbs_attr_bundle *attrs);
struct ib_mr *(*get_dma_mr)(struct ib_pd *pd, int mr_access_flags);
struct ib_mr *(*reg_user_mr)(struct ib_pd *pd, u64 start, u64 length,
u64 virt_addr, int mr_access_flags,
@@ -2883,6 +2932,7 @@ struct ib_device_ops {
DECLARE_RDMA_OBJ_SIZE(ib_ah);
DECLARE_RDMA_OBJ_SIZE(ib_counters);
DECLARE_RDMA_OBJ_SIZE(ib_cq);
+ DECLARE_RDMA_OBJ_SIZE(ib_comp_cntr);
DECLARE_RDMA_OBJ_SIZE(ib_dmah);
DECLARE_RDMA_OBJ_SIZE(ib_mw);
DECLARE_RDMA_OBJ_SIZE(ib_pd);
diff --git a/include/rdma/restrack.h b/include/rdma/restrack.h
index 451f99e3717d..47fec3083d28 100644
--- a/include/rdma/restrack.h
+++ b/include/rdma/restrack.h
@@ -61,6 +61,10 @@ enum rdma_restrack_type {
*/
RDMA_RESTRACK_DMAH,
/**
+ * @RDMA_RESTRACK_COMP_CNTR: Completion Counter
+ */
+ RDMA_RESTRACK_COMP_CNTR,
+ /**
* @RDMA_RESTRACK_MAX: Last entry, used for array dclarations
*/
RDMA_RESTRACK_MAX
@@ -123,7 +127,7 @@ struct rdma_restrack_entry {
u32 id;
};
-int rdma_restrack_count(struct ib_device *dev, enum rdma_restrack_type type,
+u32 rdma_restrack_count(struct ib_device *dev, enum rdma_restrack_type type,
bool show_details);
/**
* rdma_is_kernel_res() - check the owner of resource
diff --git a/include/rdma/uverbs_ioctl.h b/include/rdma/uverbs_ioctl.h
index 24fd36213023..80f3ba6663d0 100644
--- a/include/rdma/uverbs_ioctl.h
+++ b/include/rdma/uverbs_ioctl.h
@@ -1151,4 +1151,24 @@ static inline int ib_respond_empty_udata(struct ib_udata *udata)
return 0;
}
+/**
+ * ib_no_udata_io - Ensure no input data and zero fill the response buffer
+ * @udata: The system call's ib_udata struct
+ *
+ * Driver ops which do not accept any input data and do not provide any response
+ * data may call this at the beginning of their handler to fully adhere to the
+ * uAPI forward/backward compatibility rules.
+ *
+ * Return: Negative failure code if the op should be denied, 0 otherwise.
+ */
+static inline int ib_no_udata_io(struct ib_udata *udata)
+{
+ int ret = ib_is_udata_in_empty(udata);
+
+ if (ret)
+ return ret;
+
+ return ib_respond_empty_udata(udata);
+}
+
#endif
diff --git a/include/uapi/rdma/efa-abi.h b/include/uapi/rdma/efa-abi.h
index d5c18f8de182..c79b54aade23 100644
--- a/include/uapi/rdma/efa-abi.h
+++ b/include/uapi/rdma/efa-abi.h
@@ -133,6 +133,7 @@ enum {
EFA_QUERY_DEVICE_CAPS_RDMA_WRITE = 1 << 5,
EFA_QUERY_DEVICE_CAPS_UNSOLICITED_WRITE_RECV = 1 << 6,
EFA_QUERY_DEVICE_CAPS_CQ_WITH_EXT_MEM = 1 << 7,
+ EFA_QUERY_DEVICE_CAPS_COMP_CNTR = 1 << 8,
};
struct efa_ibv_ex_query_device_resp {
@@ -163,4 +164,9 @@ enum efa_mr_methods {
EFA_IB_METHOD_MR_QUERY = (1U << UVERBS_ID_NS_SHIFT),
};
+enum efa_comp_cntr_create_attrs {
+ EFA_IB_ATTR_CREATE_COMP_CNTR_COMP_BUFFER = (1U << UVERBS_ID_NS_SHIFT),
+ EFA_IB_ATTR_CREATE_COMP_CNTR_ERR_BUFFER,
+};
+
#endif /* EFA_ABI_USER_H */
diff --git a/include/uapi/rdma/ib_user_ioctl_cmds.h b/include/uapi/rdma/ib_user_ioctl_cmds.h
index 839835bd4b23..6a3d59d03f54 100644
--- a/include/uapi/rdma/ib_user_ioctl_cmds.h
+++ b/include/uapi/rdma/ib_user_ioctl_cmds.h
@@ -57,6 +57,7 @@ enum uverbs_default_objects {
UVERBS_OBJECT_ASYNC_EVENT,
UVERBS_OBJECT_DMAH,
UVERBS_OBJECT_DMABUF,
+ UVERBS_OBJECT_COMP_CNTR,
};
enum {
@@ -75,6 +76,7 @@ enum uverbs_methods_device {
UVERBS_METHOD_QUERY_GID_TABLE,
UVERBS_METHOD_QUERY_GID_ENTRY,
UVERBS_METHOD_QUERY_PORT_SPEED,
+ UVERBS_METHOD_QUERY_COMP_CNTR_CAPS,
};
enum uverbs_attrs_invoke_write_cmd_attr_ids {
@@ -93,6 +95,12 @@ enum uverbs_attrs_query_port_speed_cmd_attr_ids {
UVERBS_ATTR_QUERY_PORT_SPEED_RESP,
};
+enum uverbs_attrs_query_comp_cntr_caps_attr_ids {
+ UVERBS_ATTR_QUERY_COMP_CNTR_CAPS_MAX_COUNTERS,
+ UVERBS_ATTR_QUERY_COMP_CNTR_CAPS_MAX_VALUE,
+ UVERBS_ATTR_QUERY_COMP_CNTR_CAPS_SUPPORTED_QP_ATTACH_OPS,
+};
+
enum uverbs_attrs_get_context_attr_ids {
UVERBS_ATTR_GET_CONTEXT_NUM_COMP_VECTORS,
UVERBS_ATTR_GET_CONTEXT_CORE_SUPPORT,
@@ -169,9 +177,16 @@ enum uverbs_attrs_destroy_qp_cmd_attr_ids {
UVERBS_ATTR_DESTROY_QP_RESP,
};
+enum uverbs_attrs_qp_attach_comp_cntr_cmd_attr_ids {
+ UVERBS_ATTR_QP_ATTACH_COMP_CNTR_HANDLE,
+ UVERBS_ATTR_QP_ATTACH_COMP_CNTR_CNTR_HANDLE,
+ UVERBS_ATTR_QP_ATTACH_COMP_CNTR_OP_MASK,
+};
+
enum uverbs_methods_qp {
UVERBS_METHOD_QP_CREATE,
UVERBS_METHOD_QP_DESTROY,
+ UVERBS_METHOD_QP_ATTACH_COMP_CNTR,
};
enum uverbs_attrs_create_srq_cmd_attr_ids {
@@ -438,4 +453,32 @@ enum uverbs_attrs_query_gid_entry_cmd_attr_ids {
UVERBS_ATTR_QUERY_GID_ENTRY_RESP_ENTRY,
};
+enum uverbs_methods_comp_cntr {
+ UVERBS_METHOD_COMP_CNTR_CREATE,
+ UVERBS_METHOD_COMP_CNTR_DESTROY,
+ UVERBS_METHOD_COMP_CNTR_MODIFY,
+ UVERBS_METHOD_COMP_CNTR_READ,
+};
+
+enum uverbs_attrs_create_comp_cntr_cmd_attr_ids {
+ UVERBS_ATTR_CREATE_COMP_CNTR_HANDLE,
+};
+
+enum uverbs_attrs_destroy_comp_cntr_cmd_attr_ids {
+ UVERBS_ATTR_DESTROY_COMP_CNTR_HANDLE,
+};
+
+enum uverbs_attrs_modify_comp_cntr_cmd_attr_ids {
+ UVERBS_ATTR_MODIFY_COMP_CNTR_HANDLE,
+ UVERBS_ATTR_MODIFY_COMP_CNTR_ENTRY,
+ UVERBS_ATTR_MODIFY_COMP_CNTR_OP,
+ UVERBS_ATTR_MODIFY_COMP_CNTR_VALUE,
+};
+
+enum uverbs_attrs_read_comp_cntr_cmd_attr_ids {
+ UVERBS_ATTR_READ_COMP_CNTR_HANDLE,
+ UVERBS_ATTR_READ_COMP_CNTR_ENTRY,
+ UVERBS_ATTR_READ_COMP_CNTR_RESP_VALUE,
+};
+
#endif
diff --git a/include/uapi/rdma/ib_user_ioctl_verbs.h b/include/uapi/rdma/ib_user_ioctl_verbs.h
index 51030c27d479..21f86cc7bb1f 100644
--- a/include/uapi/rdma/ib_user_ioctl_verbs.h
+++ b/include/uapi/rdma/ib_user_ioctl_verbs.h
@@ -300,4 +300,23 @@ struct ib_uverbs_buffer_desc {
__aligned_u64 length;
};
+enum ib_uverbs_comp_cntr_entry {
+ IB_UVERBS_COMP_CNTR_ENTRY_COMP,
+ IB_UVERBS_COMP_CNTR_ENTRY_ERR,
+};
+
+enum ib_uverbs_comp_cntr_modify_op {
+ IB_UVERBS_COMP_CNTR_MODIFY_OP_SET,
+ IB_UVERBS_COMP_CNTR_MODIFY_OP_INC,
+};
+
+enum ib_uverbs_qp_attach_comp_cntr_op {
+ IB_UVERBS_QP_ATTACH_COMP_CNTR_OP_SEND = 1 << 0,
+ IB_UVERBS_QP_ATTACH_COMP_CNTR_OP_RECV = 1 << 1,
+ IB_UVERBS_QP_ATTACH_COMP_CNTR_OP_RDMA_READ = 1 << 2,
+ IB_UVERBS_QP_ATTACH_COMP_CNTR_OP_REMOTE_RDMA_READ = 1 << 3,
+ IB_UVERBS_QP_ATTACH_COMP_CNTR_OP_RDMA_WRITE = 1 << 4,
+ IB_UVERBS_QP_ATTACH_COMP_CNTR_OP_REMOTE_RDMA_WRITE = 1 << 5,
+};
+
#endif
diff --git a/include/uapi/rdma/ib_user_verbs.h b/include/uapi/rdma/ib_user_verbs.h
index d2aeadb6d2f9..565301594634 100644
--- a/include/uapi/rdma/ib_user_verbs.h
+++ b/include/uapi/rdma/ib_user_verbs.h
@@ -1379,4 +1379,37 @@ enum ib_uverbs_raw_packet_caps {
IB_UVERBS_RAW_PACKET_CAP_DELAY_DROP = 1 << 3,
};
+/*
+ * struct ib_uverbs_clock_info - timecounter state shared with userspace
+ *
+ * Drivers that use a software timecounter over a free-running hardware
+ * cycle counter can map this page read-only into userspace, allowing
+ * conversion of hardware timestamps to system time without a syscall.
+ *
+ * Synchronization uses a sequence counter (@sign): the kernel sets bit 0
+ * before updating, then advances by 2 after. Userspace must retry the read
+ * if @sign is odd or changed during the read.
+ *
+ * @sign: Sequence counter (bit 0 = update in progress)
+ * @resv: Reserved
+ * @nsec: Nanoseconds at last update
+ * @cycles: Cycle counter value at last update
+ * @frac: Fractional nanoseconds at last update
+ * @mult: Cycle-to-nanosecond multiplier
+ * @shift: Cycle-to-nanosecond shift
+ * @mask: Cycle counter bitmask
+ * @overflow_period: Max interval (nsec) between reads before counter wraps
+ */
+struct ib_uverbs_clock_info {
+ __u32 sign;
+ __u32 resv;
+ __aligned_u64 nsec;
+ __aligned_u64 cycles;
+ __aligned_u64 frac;
+ __u32 mult;
+ __u32 shift;
+ __aligned_u64 mask;
+ __aligned_u64 overflow_period;
+};
+
#endif /* IB_USER_VERBS_H */
diff --git a/include/uapi/rdma/ionic-abi.h b/include/uapi/rdma/ionic-abi.h
index 7b589d3e9728..2c70ac149c4f 100644
--- a/include/uapi/rdma/ionic-abi.h
+++ b/include/uapi/rdma/ionic-abi.h
@@ -48,6 +48,7 @@ struct ionic_ctx_resp {
__u8 expdb_qtypes;
__u8 rsvd2[3];
+ __aligned_u64 phc_offset;
};
struct ionic_qdesc {
diff --git a/include/uapi/rdma/irdma-abi.h b/include/uapi/rdma/irdma-abi.h
index 36f20802bcc8..38155affc8b4 100644
--- a/include/uapi/rdma/irdma-abi.h
+++ b/include/uapi/rdma/irdma-abi.h
@@ -88,6 +88,7 @@ struct irdma_create_srq_resp {
struct irdma_create_qp_req {
__aligned_u64 user_wqe_bufs;
__aligned_u64 user_compl_ctx;
+ __aligned_u64 legacy_dontuse[2];
};
struct irdma_mem_reg_req {
diff --git a/include/uapi/rdma/mana-abi.h b/include/uapi/rdma/mana-abi.h
index a75bf32b8cfb..8336bf51b7c5 100644
--- a/include/uapi/rdma/mana-abi.h
+++ b/include/uapi/rdma/mana-abi.h
@@ -25,7 +25,7 @@ enum mana_ib_create_cq_flags {
struct mana_ib_create_cq {
__aligned_u64 buf_addr;
- __u16 flags;
+ __u16 comp_mask;
__u16 reserved0;
__u32 reserved1;
};
diff --git a/include/uapi/rdma/mlx5-abi.h b/include/uapi/rdma/mlx5-abi.h
index 8a6ad6c6841c..a39226cd62dc 100644
--- a/include/uapi/rdma/mlx5-abi.h
+++ b/include/uapi/rdma/mlx5-abi.h
@@ -472,17 +472,10 @@ struct mlx5_ib_modify_wq {
__u32 reserved;
};
-struct mlx5_ib_clock_info {
- __u32 sign;
- __u32 resv;
- __aligned_u64 nsec;
- __aligned_u64 cycles;
- __aligned_u64 frac;
- __u32 mult;
- __u32 shift;
- __aligned_u64 mask;
- __aligned_u64 overflow_period;
-};
+/*
+ * deprecated, see struct ib_uverbs_clock_info from ib_user_verbs.h
+ */
+#define mlx5_ib_clock_info ib_uverbs_clock_info
enum mlx5_ib_mmap_cmd {
MLX5_IB_MMAP_REGULAR_PAGE = 0,
diff --git a/include/uapi/rdma/rdma_netlink.h b/include/uapi/rdma/rdma_netlink.h
index aac9782ddc09..3af946ecbac3 100644
--- a/include/uapi/rdma/rdma_netlink.h
+++ b/include/uapi/rdma/rdma_netlink.h
@@ -605,6 +605,11 @@ enum rdma_nldev_attr {
RDMA_NLDEV_ATTR_FRMR_POOL_KEY_KERNEL_VENDOR_KEY, /* u64 */
/*
+ * Resource summary entry maximum value.
+ */
+ RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_MAX, /* u64 */
+
+ /*
* Always the end
*/
RDMA_NLDEV_ATTR_MAX
diff --git a/net/rds/ib.c b/net/rds/ib.c
index 8f9cf491984f..786f39169bc1 100644
--- a/net/rds/ib.c
+++ b/net/rds/ib.c
@@ -162,12 +162,12 @@ static int rds_ib_add_one(struct ib_device *device)
IB_ODP_SUPPORT_READ);
rds_ibdev->max_1m_mrs = device->attrs.max_mr ?
- min_t(unsigned int, (device->attrs.max_mr / 2),
- rds_ib_mr_1m_pool_size) : rds_ib_mr_1m_pool_size;
+ min(device->attrs.max_mr / 2,
+ rds_ib_mr_1m_pool_size) : rds_ib_mr_1m_pool_size;
rds_ibdev->max_8k_mrs = device->attrs.max_mr ?
- min_t(unsigned int, ((device->attrs.max_mr / 2) * RDS_MR_8K_SCALE),
- rds_ib_mr_8k_pool_size) : rds_ib_mr_8k_pool_size;
+ min((device->attrs.max_mr / 2) * RDS_MR_8K_SCALE,
+ rds_ib_mr_8k_pool_size) : rds_ib_mr_8k_pool_size;
rds_ibdev->max_initiator_depth = device->attrs.max_qp_init_rd_atom;
rds_ibdev->max_responder_resources = device->attrs.max_qp_rd_atom;
@@ -204,7 +204,7 @@ static int rds_ib_add_one(struct ib_device *device)
goto put_dev;
}
- rdsdebug("RDS/IB: max_mr = %d, max_wrs = %d, max_sge = %d, max_1m_mrs = %d, max_8k_mrs = %d\n",
+ rdsdebug("RDS/IB: max_mr = %u, max_wrs = %d, max_sge = %d, max_1m_mrs = %d, max_8k_mrs = %d\n",
device->attrs.max_mr, rds_ibdev->max_wrs, rds_ibdev->max_sge,
rds_ibdev->max_1m_mrs, rds_ibdev->max_8k_mrs);
diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c
index d46146887ba4..4feb0edc360c 100644
--- a/net/rds/ib_cm.c
+++ b/net/rds/ib_cm.c
@@ -173,11 +173,11 @@ static void rds_ib_cm_fill_conn_param(struct rds_connection *conn,
memset(conn_param, 0, sizeof(struct rdma_conn_param));
- conn_param->responder_resources =
- min_t(u32, rds_ibdev->max_responder_resources, max_responder_resources);
- conn_param->initiator_depth =
- min_t(u32, rds_ibdev->max_initiator_depth, max_initiator_depth);
- conn_param->retry_count = min_t(unsigned int, rds_ib_retry_count, 7);
+ conn_param->responder_resources = min3(rds_ibdev->max_responder_resources,
+ max_responder_resources, U8_MAX);
+ conn_param->initiator_depth = min3(rds_ibdev->max_initiator_depth,
+ max_initiator_depth, U8_MAX);
+ conn_param->retry_count = min(rds_ib_retry_count, 7U);
conn_param->rnr_retry_count = 7;
if (dp) {
diff --git a/net/sunrpc/xprtrdma/frwr_ops.c b/net/sunrpc/xprtrdma/frwr_ops.c
index e5c71cf705a3..e83cef19e656 100644
--- a/net/sunrpc/xprtrdma/frwr_ops.c
+++ b/net/sunrpc/xprtrdma/frwr_ops.c
@@ -172,8 +172,9 @@ out_mr_err:
int frwr_query_device(struct rpcrdma_ep *ep, const struct ib_device *device)
{
const struct ib_device_attr *attrs = &device->attrs;
- int max_qp_wr, depth, delta;
unsigned int max_sge;
+ u32 max_qp_wr;
+ int depth, delta;
if (!(attrs->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS) ||
attrs->max_fast_reg_page_list_len == 0) {
@@ -229,10 +230,10 @@ int frwr_query_device(struct rpcrdma_ep *ep, const struct ib_device *device)
}
max_qp_wr = attrs->max_qp_wr;
+ if (max_qp_wr < RPCRDMA_BACKWARD_WRS + 1 + RPCRDMA_MIN_SLOT_TABLE)
+ return -ENOMEM;
max_qp_wr -= RPCRDMA_BACKWARD_WRS;
max_qp_wr -= 1;
- if (max_qp_wr < RPCRDMA_MIN_SLOT_TABLE)
- return -ENOMEM;
if (ep->re_max_requests > max_qp_wr)
ep->re_max_requests = max_qp_wr;
ep->re_attr.cap.max_send_wr = ep->re_max_requests * depth;
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
index 093371f9d245..927269598ac2 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
@@ -574,8 +574,7 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
set_bit(RDMAXPRT_CONN_PENDING, &newxprt->sc_flags);
memset(&conn_param, 0, sizeof conn_param);
conn_param.responder_resources = 0;
- conn_param.initiator_depth = min_t(int, newxprt->sc_ord,
- dev->attrs.max_qp_init_rd_atom);
+ conn_param.initiator_depth = min(newxprt->sc_ord, dev->attrs.max_qp_init_rd_atom);
if (!conn_param.initiator_depth) {
ret = -EINVAL;
trace_svcrdma_initdepth_err(newxprt, ret);
@@ -600,7 +599,7 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
dprintk(" local address : %pIS:%u\n", sap, rpc_get_port(sap));
sap = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.dst_addr;
dprintk(" remote address : %pIS:%u\n", sap, rpc_get_port(sap));
- dprintk(" max_sge : %d\n", newxprt->sc_max_send_sges);
+ dprintk(" max_sge : %u\n", newxprt->sc_max_send_sges);
dprintk(" sq_depth : %d\n", newxprt->sc_sq_depth);
dprintk(" rdma_rw_ctxs : %d\n", ctxts);
dprintk(" max_requests : %d\n", newxprt->sc_max_requests);
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c
index 04b286223b24..be335eed329d 100644
--- a/net/sunrpc/xprtrdma/verbs.c
+++ b/net/sunrpc/xprtrdma/verbs.c
@@ -465,7 +465,7 @@ static int rpcrdma_ep_create(struct rpcrdma_xprt *r_xprt)
/* Client offers RDMA Read but does not initiate */
ep->re_remote_cma.initiator_depth = 0;
ep->re_remote_cma.responder_resources =
- min_t(int, U8_MAX, device->attrs.max_qp_rd_atom);
+ min(device->attrs.max_qp_rd_atom, U8_MAX);
/* Limit transport retries so client can detect server
* GID changes quickly. RPC layer handles re-establishing