IB/uverbs: Extend modify_qp and support packet pacing

An new uverbs command ib_uverbs_ex_modify_qp is added to support more QP
attributes. User driver should choose to call the legacy/extended API
based on input mask.

IB_USER_LAST_QP_ATTR_MASK is added to indicated the maximum bit position
which supports legacy ib_uverbs_modify_qp.
IB_USER_LEGACY_LAST_QP_ATTR_MASK indicates the maximum bit position
which supports ib_uverbs_ex_modify_qp, the value of this mask should be
updated if new mask is added later.

Along with this change, rate_limit is supported by the extended command,
user driver could use it to control packet packing.

Signed-off-by: Bodong Wang <bodong@mellanox.com>
Reviewed-by: Matan Barak <matanb@mellanox.com>
Signed-off-by: Leon Romanovsky <leon@kernel.org>
Signed-off-by: Doug Ledford <dledford@redhat.com>
This commit is contained in:
Bodong Wang 2016-12-01 13:43:15 +02:00 committed by Doug Ledford
parent 528e5a1bd3
commit 189aba99e7
4 changed files with 144 additions and 67 deletions

View File

@ -289,5 +289,6 @@ IB_UVERBS_DECLARE_EX_CMD(modify_wq);
IB_UVERBS_DECLARE_EX_CMD(destroy_wq); IB_UVERBS_DECLARE_EX_CMD(destroy_wq);
IB_UVERBS_DECLARE_EX_CMD(create_rwq_ind_table); IB_UVERBS_DECLARE_EX_CMD(create_rwq_ind_table);
IB_UVERBS_DECLARE_EX_CMD(destroy_rwq_ind_table); IB_UVERBS_DECLARE_EX_CMD(destroy_rwq_ind_table);
IB_UVERBS_DECLARE_EX_CMD(modify_qp);
#endif /* UVERBS_H */ #endif /* UVERBS_H */

View File

@ -2328,96 +2328,88 @@ static int modify_qp_mask(enum ib_qp_type qp_type, int mask)
} }
} }
ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file, static int modify_qp(struct ib_uverbs_file *file,
struct ib_device *ib_dev, struct ib_uverbs_ex_modify_qp *cmd, struct ib_udata *udata)
const char __user *buf, int in_len,
int out_len)
{ {
struct ib_uverbs_modify_qp cmd; struct ib_qp_attr *attr;
struct ib_udata udata; struct ib_qp *qp;
struct ib_qp *qp; int ret;
struct ib_qp_attr *attr;
int ret;
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
INIT_UDATA(&udata, buf + sizeof cmd, NULL, in_len - sizeof cmd,
out_len);
attr = kmalloc(sizeof *attr, GFP_KERNEL); attr = kmalloc(sizeof *attr, GFP_KERNEL);
if (!attr) if (!attr)
return -ENOMEM; return -ENOMEM;
qp = idr_read_qp(cmd.qp_handle, file->ucontext); qp = idr_read_qp(cmd->base.qp_handle, file->ucontext);
if (!qp) { if (!qp) {
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
attr->qp_state = cmd.qp_state; attr->qp_state = cmd->base.qp_state;
attr->cur_qp_state = cmd.cur_qp_state; attr->cur_qp_state = cmd->base.cur_qp_state;
attr->path_mtu = cmd.path_mtu; attr->path_mtu = cmd->base.path_mtu;
attr->path_mig_state = cmd.path_mig_state; attr->path_mig_state = cmd->base.path_mig_state;
attr->qkey = cmd.qkey; attr->qkey = cmd->base.qkey;
attr->rq_psn = cmd.rq_psn; attr->rq_psn = cmd->base.rq_psn;
attr->sq_psn = cmd.sq_psn; attr->sq_psn = cmd->base.sq_psn;
attr->dest_qp_num = cmd.dest_qp_num; attr->dest_qp_num = cmd->base.dest_qp_num;
attr->qp_access_flags = cmd.qp_access_flags; attr->qp_access_flags = cmd->base.qp_access_flags;
attr->pkey_index = cmd.pkey_index; attr->pkey_index = cmd->base.pkey_index;
attr->alt_pkey_index = cmd.alt_pkey_index; attr->alt_pkey_index = cmd->base.alt_pkey_index;
attr->en_sqd_async_notify = cmd.en_sqd_async_notify; attr->en_sqd_async_notify = cmd->base.en_sqd_async_notify;
attr->max_rd_atomic = cmd.max_rd_atomic; attr->max_rd_atomic = cmd->base.max_rd_atomic;
attr->max_dest_rd_atomic = cmd.max_dest_rd_atomic; attr->max_dest_rd_atomic = cmd->base.max_dest_rd_atomic;
attr->min_rnr_timer = cmd.min_rnr_timer; attr->min_rnr_timer = cmd->base.min_rnr_timer;
attr->port_num = cmd.port_num; attr->port_num = cmd->base.port_num;
attr->timeout = cmd.timeout; attr->timeout = cmd->base.timeout;
attr->retry_cnt = cmd.retry_cnt; attr->retry_cnt = cmd->base.retry_cnt;
attr->rnr_retry = cmd.rnr_retry; attr->rnr_retry = cmd->base.rnr_retry;
attr->alt_port_num = cmd.alt_port_num; attr->alt_port_num = cmd->base.alt_port_num;
attr->alt_timeout = cmd.alt_timeout; attr->alt_timeout = cmd->base.alt_timeout;
attr->rate_limit = cmd->rate_limit;
memcpy(attr->ah_attr.grh.dgid.raw, cmd.dest.dgid, 16); memcpy(attr->ah_attr.grh.dgid.raw, cmd->base.dest.dgid, 16);
attr->ah_attr.grh.flow_label = cmd.dest.flow_label; attr->ah_attr.grh.flow_label = cmd->base.dest.flow_label;
attr->ah_attr.grh.sgid_index = cmd.dest.sgid_index; attr->ah_attr.grh.sgid_index = cmd->base.dest.sgid_index;
attr->ah_attr.grh.hop_limit = cmd.dest.hop_limit; attr->ah_attr.grh.hop_limit = cmd->base.dest.hop_limit;
attr->ah_attr.grh.traffic_class = cmd.dest.traffic_class; attr->ah_attr.grh.traffic_class = cmd->base.dest.traffic_class;
attr->ah_attr.dlid = cmd.dest.dlid; attr->ah_attr.dlid = cmd->base.dest.dlid;
attr->ah_attr.sl = cmd.dest.sl; attr->ah_attr.sl = cmd->base.dest.sl;
attr->ah_attr.src_path_bits = cmd.dest.src_path_bits; attr->ah_attr.src_path_bits = cmd->base.dest.src_path_bits;
attr->ah_attr.static_rate = cmd.dest.static_rate; attr->ah_attr.static_rate = cmd->base.dest.static_rate;
attr->ah_attr.ah_flags = cmd.dest.is_global ? IB_AH_GRH : 0; attr->ah_attr.ah_flags = cmd->base.dest.is_global ?
attr->ah_attr.port_num = cmd.dest.port_num; IB_AH_GRH : 0;
attr->ah_attr.port_num = cmd->base.dest.port_num;
memcpy(attr->alt_ah_attr.grh.dgid.raw, cmd.alt_dest.dgid, 16); memcpy(attr->alt_ah_attr.grh.dgid.raw, cmd->base.alt_dest.dgid, 16);
attr->alt_ah_attr.grh.flow_label = cmd.alt_dest.flow_label; attr->alt_ah_attr.grh.flow_label = cmd->base.alt_dest.flow_label;
attr->alt_ah_attr.grh.sgid_index = cmd.alt_dest.sgid_index; attr->alt_ah_attr.grh.sgid_index = cmd->base.alt_dest.sgid_index;
attr->alt_ah_attr.grh.hop_limit = cmd.alt_dest.hop_limit; attr->alt_ah_attr.grh.hop_limit = cmd->base.alt_dest.hop_limit;
attr->alt_ah_attr.grh.traffic_class = cmd.alt_dest.traffic_class; attr->alt_ah_attr.grh.traffic_class = cmd->base.alt_dest.traffic_class;
attr->alt_ah_attr.dlid = cmd.alt_dest.dlid; attr->alt_ah_attr.dlid = cmd->base.alt_dest.dlid;
attr->alt_ah_attr.sl = cmd.alt_dest.sl; attr->alt_ah_attr.sl = cmd->base.alt_dest.sl;
attr->alt_ah_attr.src_path_bits = cmd.alt_dest.src_path_bits; attr->alt_ah_attr.src_path_bits = cmd->base.alt_dest.src_path_bits;
attr->alt_ah_attr.static_rate = cmd.alt_dest.static_rate; attr->alt_ah_attr.static_rate = cmd->base.alt_dest.static_rate;
attr->alt_ah_attr.ah_flags = cmd.alt_dest.is_global ? IB_AH_GRH : 0; attr->alt_ah_attr.ah_flags = cmd->base.alt_dest.is_global ?
attr->alt_ah_attr.port_num = cmd.alt_dest.port_num; IB_AH_GRH : 0;
attr->alt_ah_attr.port_num = cmd->base.alt_dest.port_num;
if (qp->real_qp == qp) { if (qp->real_qp == qp) {
if (cmd.attr_mask & IB_QP_AV) { if (cmd->base.attr_mask & IB_QP_AV) {
ret = ib_resolve_eth_dmac(qp->device, &attr->ah_attr); ret = ib_resolve_eth_dmac(qp->device, &attr->ah_attr);
if (ret) if (ret)
goto release_qp; goto release_qp;
} }
ret = qp->device->modify_qp(qp, attr, ret = qp->device->modify_qp(qp, attr,
modify_qp_mask(qp->qp_type, cmd.attr_mask), &udata); modify_qp_mask(qp->qp_type,
cmd->base.attr_mask),
udata);
} else { } else {
ret = ib_modify_qp(qp, attr, modify_qp_mask(qp->qp_type, cmd.attr_mask)); ret = ib_modify_qp(qp, attr,
modify_qp_mask(qp->qp_type,
cmd->base.attr_mask));
} }
if (ret)
goto release_qp;
ret = in_len;
release_qp: release_qp:
put_qp_read(qp); put_qp_read(qp);
@ -2427,6 +2419,68 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
return ret; return ret;
} }
ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
struct ib_device *ib_dev,
const char __user *buf, int in_len,
int out_len)
{
struct ib_uverbs_ex_modify_qp cmd = {};
struct ib_udata udata;
int ret;
if (copy_from_user(&cmd.base, buf, sizeof(cmd.base)))
return -EFAULT;
if (cmd.base.attr_mask &
~((IB_USER_LEGACY_LAST_QP_ATTR_MASK << 1) - 1))
return -EOPNOTSUPP;
INIT_UDATA(&udata, buf + sizeof(cmd.base), NULL,
in_len - sizeof(cmd.base), out_len);
ret = modify_qp(file, &cmd, &udata);
if (ret)
return ret;
return in_len;
}
int ib_uverbs_ex_modify_qp(struct ib_uverbs_file *file,
struct ib_device *ib_dev,
struct ib_udata *ucore,
struct ib_udata *uhw)
{
struct ib_uverbs_ex_modify_qp cmd = {};
int ret;
/*
* Last bit is reserved for extending the attr_mask by
* using another field.
*/
BUILD_BUG_ON(IB_USER_LAST_QP_ATTR_MASK == (1 << 31));
if (ucore->inlen < sizeof(cmd.base))
return -EINVAL;
ret = ib_copy_from_udata(&cmd, ucore, min(sizeof(cmd), ucore->inlen));
if (ret)
return ret;
if (cmd.base.attr_mask &
~((IB_USER_LAST_QP_ATTR_MASK << 1) - 1))
return -EOPNOTSUPP;
if (ucore->inlen > sizeof(cmd)) {
if (ib_is_udata_cleared(ucore, sizeof(cmd),
ucore->inlen - sizeof(cmd)))
return -EOPNOTSUPP;
}
ret = modify_qp(file, &cmd, uhw);
return ret;
}
ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
struct ib_device *ib_dev, struct ib_device *ib_dev,
const char __user *buf, int in_len, const char __user *buf, int in_len,

View File

@ -137,6 +137,7 @@ static int (*uverbs_ex_cmd_table[])(struct ib_uverbs_file *file,
[IB_USER_VERBS_EX_CMD_DESTROY_WQ] = ib_uverbs_ex_destroy_wq, [IB_USER_VERBS_EX_CMD_DESTROY_WQ] = ib_uverbs_ex_destroy_wq,
[IB_USER_VERBS_EX_CMD_CREATE_RWQ_IND_TBL] = ib_uverbs_ex_create_rwq_ind_table, [IB_USER_VERBS_EX_CMD_CREATE_RWQ_IND_TBL] = ib_uverbs_ex_create_rwq_ind_table,
[IB_USER_VERBS_EX_CMD_DESTROY_RWQ_IND_TBL] = ib_uverbs_ex_destroy_rwq_ind_table, [IB_USER_VERBS_EX_CMD_DESTROY_RWQ_IND_TBL] = ib_uverbs_ex_destroy_rwq_ind_table,
[IB_USER_VERBS_EX_CMD_MODIFY_QP] = ib_uverbs_ex_modify_qp,
}; };
static void ib_uverbs_add_one(struct ib_device *device); static void ib_uverbs_add_one(struct ib_device *device);

View File

@ -37,6 +37,7 @@
#define IB_USER_VERBS_H #define IB_USER_VERBS_H
#include <linux/types.h> #include <linux/types.h>
#include <rdma/ib_verbs.h>
/* /*
* Increment this value if any changes that break userspace ABI * Increment this value if any changes that break userspace ABI
@ -93,6 +94,7 @@ enum {
IB_USER_VERBS_EX_CMD_QUERY_DEVICE = IB_USER_VERBS_CMD_QUERY_DEVICE, IB_USER_VERBS_EX_CMD_QUERY_DEVICE = IB_USER_VERBS_CMD_QUERY_DEVICE,
IB_USER_VERBS_EX_CMD_CREATE_CQ = IB_USER_VERBS_CMD_CREATE_CQ, IB_USER_VERBS_EX_CMD_CREATE_CQ = IB_USER_VERBS_CMD_CREATE_CQ,
IB_USER_VERBS_EX_CMD_CREATE_QP = IB_USER_VERBS_CMD_CREATE_QP, IB_USER_VERBS_EX_CMD_CREATE_QP = IB_USER_VERBS_CMD_CREATE_QP,
IB_USER_VERBS_EX_CMD_MODIFY_QP = IB_USER_VERBS_CMD_MODIFY_QP,
IB_USER_VERBS_EX_CMD_CREATE_FLOW = IB_USER_VERBS_CMD_THRESHOLD, IB_USER_VERBS_EX_CMD_CREATE_FLOW = IB_USER_VERBS_CMD_THRESHOLD,
IB_USER_VERBS_EX_CMD_DESTROY_FLOW, IB_USER_VERBS_EX_CMD_DESTROY_FLOW,
IB_USER_VERBS_EX_CMD_CREATE_WQ, IB_USER_VERBS_EX_CMD_CREATE_WQ,
@ -545,6 +547,14 @@ enum {
IB_UVERBS_CREATE_QP_SUP_COMP_MASK = IB_UVERBS_CREATE_QP_MASK_IND_TABLE, IB_UVERBS_CREATE_QP_SUP_COMP_MASK = IB_UVERBS_CREATE_QP_MASK_IND_TABLE,
}; };
enum {
IB_USER_LEGACY_LAST_QP_ATTR_MASK = IB_QP_DEST_QPN
};
enum {
IB_USER_LAST_QP_ATTR_MASK = IB_QP_RATE_LIMIT
};
struct ib_uverbs_ex_create_qp { struct ib_uverbs_ex_create_qp {
__u64 user_handle; __u64 user_handle;
__u32 pd_handle; __u32 pd_handle;
@ -684,9 +694,20 @@ struct ib_uverbs_modify_qp {
__u64 driver_data[0]; __u64 driver_data[0];
}; };
struct ib_uverbs_ex_modify_qp {
struct ib_uverbs_modify_qp base;
__u32 rate_limit;
__u32 reserved;
};
struct ib_uverbs_modify_qp_resp { struct ib_uverbs_modify_qp_resp {
}; };
struct ib_uverbs_ex_modify_qp_resp {
__u32 comp_mask;
__u32 response_length;
};
struct ib_uverbs_destroy_qp { struct ib_uverbs_destroy_qp {
__u64 response; __u64 response;
__u32 qp_handle; __u32 qp_handle;