Introduce mlx5 DEVX interface
Subsystems (7)
v2 cover Introduce mlx5 DEVX interface
From: Leon Romanovsky <[email protected]>
Changelog:v1->v2:
* Rebase on top of v4.18-rc1
v0 -> v1:
* Dropped few validation/debug patches from the KABI part as of Jason's comments.
* Use kvmalloc/kvfree instead of kmalloc/kfree to prevent higher order allocation under user control.
* Cleaned up a dependency of CONFIG_INFINIBAND_USER_ACCESS from the uverbs layer.
* Moved to white list command mode.
* Serialize access to DEVX object - odify/read new methods were added
with the appropriate IDR lock.
* Block DEVX on IB port as of SELinux.
* Improve uverbs_cleanup_ucontext algorithm to support two objects from the same type.
* Fix mlx5_ifc.h to use reserved_at_xxx.
* Enforce devx_uid existence upon DEVX methods.
Quoted 1 line
From Yishai:
----------------------------------------------------------------------
This DEVX series enables direct access from the user space area to the mlx5 device driver by using the KABI mechanism.
The main purpose here is to make the user space driver as independent as possible from the kernel so that future device functionality and commands can be activated with minimal to none kernel changes.
The series keeps the same level of user process security/isolation as provided today by the kernel IB verbs by using a user id returned from the firmware upon context creation.
This user id is put by the kernel code in all firmware command from the DEVX interface so that the isolation/security will be enforced by the firmware based on that id.
Below kernel services are exposed to let the above work:
1) Expose a DEVX object that represent some underlay firmware object, the input command to create it is some raw data given by the user application which should match the device specification.
2) Expose a UMEM DEVX object for user memory registration for DMA:
The driver provides an API to register user memory, getting as input the user address, length and access flags, and provides to the user as output an ID (UMEM ID) returned by the firmware to this registered memory.
The user will use that UMEM ID in device direct commands that use this memory instead of the physical addresses list.
3) Expose device general command API:
The driver provides an API to issue some general command except than create and destroy.
4) UAR mapping:
Returns a device UAR ID for a given user index by using the kernel context information.
This is safe from security point of view as described in details in the relevant patch in the series.
5) EQ mapping:
Returns the matching device EQN for a given user vector number via the DEVX interface.
6) Process resources cleanup:
This is achieved by the existing kernel KABI logic, upon DEVX object creation the kernel builds the FW destroy command inbox in the KABI object and uses it upon cleanup.
7) Future device commands:
This will be supported by some general command type (create, destroy) that the DEVX code embeds as part of its code and is going to be used from now on by the firmware.
At the beginning of this series there are some KABI infra-structures improvements and fixes to enable the above DEVX functionality in a cleaner way.
More details appear as part of the commit logs of the series and as part of the comments in the code itself.
Thanks
Leon Romanovsky (2):
drm/i915: Move u64-to-ptr helpers to general header kernel.h: Reuse u64_to_ptr macro to cast __user pointers
Matan Barak (5):
IB/uverbs: Export uverbs idr and fd types
IB/uverbs: Refactor uverbs_finalize_objects
IB/uverbs: Add PTR_IN attributes that are allocated/copied
automatically
IB/uverbs: Add a macro to define a type with no kernel known size IB/uverbs: Allow an empty namespace in ioctl() framework
Yishai Hadas (13):
net/mlx5_core: Prevent warns in dmesg upon firmware commands IB/core: Improve uverbs_cleanup_ucontext algorithm net/mlx5: Expose DEVX ifc structures
IB/mlx5: Introduce DEVX
IB/core: Introduce DECLARE_UVERBS_GLOBAL_METHODS
IB: Expose ib_ucontext from a given ib_uverbs_file IB/mlx5: Add support for DEVX general command IB/mlx5: Add obj create and destroy functionality IB/mlx5: Add DEVX support for modify and query commands IB/mlx5: Add support for DEVX query UAR
IB/mlx5: Add DEVX support for memory registration IB/mlx5: Add DEVX query EQN support
IB/mlx5: Expose DEVX tree
drivers/gpu/drm/i915/i915_utils.h | 12 +- drivers/infiniband/core/rdma_core.c | 138 +-- drivers/infiniband/core/rdma_core.h | 10 +- drivers/infiniband/core/uverbs_ioctl.c | 104 +- drivers/infiniband/core/uverbs_main.c | 6 + drivers/infiniband/core/uverbs_std_types.c | 26 +- .../infiniband/core/uverbs_std_types_counters.c | 2 +- drivers/infiniband/core/uverbs_std_types_cq.c | 2 +- drivers/infiniband/core/uverbs_std_types_dm.c | 3 +- .../infiniband/core/uverbs_std_types_flow_action.c | 2 +- drivers/infiniband/core/uverbs_std_types_mr.c | 3 +- drivers/infiniband/hw/mlx5/Makefile | 1 + drivers/infiniband/hw/mlx5/devx.c | 1106 ++++++++++++++++++++ drivers/infiniband/hw/mlx5/main.c | 31 +- drivers/infiniband/hw/mlx5/mlx5_ib.h | 19 + drivers/infiniband/hw/mlx5/qp.c | 9 +- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 24 +- include/linux/kernel.h | 11 +- include/linux/mlx5/device.h | 3 + include/linux/mlx5/mlx5_ifc.h | 71 +- include/rdma/ib_verbs.h | 4 +- include/rdma/uverbs_ioctl.h | 27 + include/rdma/uverbs_named_ioctl.h | 4 + include/rdma/uverbs_std_types.h | 2 - include/rdma/uverbs_types.h | 11 +- include/uapi/rdma/mlx5-abi.h | 3 + include/uapi/rdma/mlx5_user_ioctl_cmds.h | 73 ++ 27 files changed, 1548 insertions(+), 159 deletions(-) create mode 100644 drivers/infiniband/hw/mlx5/devx.c
PATCH v2 1/20 net/mlx5_core: Prevent warns in dmesg upon firmware commands
From: Yishai Hadas <[email protected]>
When DEVX is used application builds by itself the command mail box, this patch prevents warns upon firmware commands as of invalid user space usage.
In addition,
A failure in destroy_mkey command was changed to be printed only under debug mode.
This prevents a redundant warn when a memory window was used with rereg_mr and finally was some kernel cleanup as of reset flow/process termination.
In that case this command might temporarily fails as part of the cleanup but finally it expects to succeed.
--- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/cmd.c +13 -2
@@ -677,7 +677,7 @@ struct mlx5_ifc_mbox_out_bits {struct mlx5_ifc_mbox_in_bits {u8 opcode[0x10 ]; -u8 reserved_at_10[0x10 ]; +u8 uid[0x10 ];u8 reserved_at_20[0x10 ];u8 op_mod[0x10 ];
@@ -697,6 +697,7 @@ static int mlx5_cmd_check(struct mlx5_core_dev *dev, void *in, void *out)u8 status;u16 opcode;u16 op_mod; +u16 uid;mlx5_cmd_mbox_status (out, &status, &syndrome);if (!status)
@@ -704,8 +705,18 @@ static int mlx5_cmd_check(struct mlx5_core_dev *dev, void *in, void *out) opcode =MLX5_GET (mbox_in, in, opcode); op_mod =MLX5_GET (mbox_in, in, op_mod); + uid =MLX5_GET (mbox_in, in, uid); - mlx5_core_err(dev, +if (!uid && opcode !=MLX5_CMD_OP_DESTROY_MKEY ) +mlx5_core_err (dev, +"%s(0x%x) op_mod(0x%x) failed, status %s(0x%x), syndrome (0x%x)\n" , +mlx5_command_str (opcode), + opcode, op_mod, +cmd_status_str (status), + status, + syndrome); +else + mlx5_core_dbg(dev, "%s(0x%x) op_mod(0x%x) failed, status %s(0x%x), syndrome (0x%x)\n", mlx5_command_str(opcode), opcode, op_mod,
Signature · 1 line
2.14.4
PATCH v2 2/20 drm/i915: Move u64-to-ptr helpers to general header
In reply to Leon RomanovskyFrom: Leon Romanovsky <[email protected]>
The macro u64_to_ptr() and function ptr_to_u64() are useful enough to be part of general header, so move them there and allow RDMA subsystem reuse them.
--- drivers/gpu/drm/i915/i915_utils.h | 12 ++---------- include/linux/kernel.h | 12 ++++++++++++ 2 files changed, 14 insertions(+), 10 deletions(-)
drivers/gpu/drm/i915/i915_utils.h +2 -10
@@ -25,6 +25,8 @@#ifndef __I915_UTILS_H#define __I915_UTILS_H +#include <linux/kernel.h> +#undef WARN_ON/* Many gcc seem to no see through this and fall over :( */ #if 0
@@ -102,16 +104,6 @@ __T; \ }) -static inline u64 ptr_to_u64 (const void *ptr) -{ -return (uintptr_t )ptr; -} - -#define u64_to_ptr (T , x) ({ \ - typecheck(u64, x); \ - (T *)(uintptr_t)(x); \ -}) -#define __mask_next_bit (mask) ({ \ int __idx = ffs(mask) - 1; \ mask &= ~BIT(__idx); \
include/linux/kernel.h +12 -0
@@ -71,6 +71,18 @@*/ #define ARRAY_SIZE (arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) +static inline u64 ptr_to_u64 (const void *ptr) +{ +return (uintptr_t )ptr; +} + +#define u64_to_ptr (T , x) ( \ +{ \ + typecheck(u64, x); \ + (T *)(uintptr_t)(x); \ +} \ +) +#define u64_to_user_ptr (x) ( \ { \ typecheck(u64, x); \
Signature · 1 line
2.14.4
PATCH v2 3/20 kernel.h: Reuse u64_to_ptr macro to cast __user pointers
In reply to Leon RomanovskyFrom: Leon Romanovsky <[email protected]>
Redefine u64_to_user_ptr() macro to be implemented with u64_to_ptr().
--- include/linux/kernel.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-)
include/linux/kernel.h +1 -6
@@ -83,12 +83,7 @@ static inline u64 ptr_to_u64(const void *ptr) } \ ) -#define u64_to_user_ptr (x) ( \ -{ \ - typecheck(u64, x); \ - (void __user *)(uintptr_t)x; \ -} \ -) +#define u64_to_user_ptr (x) u64_to_ptr(void __user, x)/* * This looks more complex than it should be. But we need to
Signature · 1 line
2.14.4
PATCH v2 4/20 IB/uverbs: Export uverbs idr and fd types
In reply to Leon RomanovskyFrom: Matan Barak <[email protected]>
As provider drivers could use UVERBS_ATTR_FD and UVERBS_ATTR_IDR macros need to export them.
--- drivers/infiniband/core/rdma_core.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/infiniband/core/rdma_core.c +2 -0
@@ -611,6 +611,7 @@ const struct uverbs_obj_type_class uverbs_idr_class = {*/ .needs_kfree_rcu = true, }; +EXPORT_SYMBOL (uverbs_idr_class);static void _uverbs_close_fd (struct ib_uobject_file *uobj_file) {
@@ -719,6 +720,7 @@ const struct uverbs_obj_type_class uverbs_fd_class = { .remove_commit = remove_commit_fd_uobject, .needs_kfree_rcu = false, }; +EXPORT_SYMBOL (uverbs_fd_class); struct ib_uobject *uverbs_get_uobject_from_context(const struct uverbs_obj_type *type_attrs, struct ib_ucontext *ucontext,
Signature · 1 line
2.14.4
PATCH v2 5/20 IB/uverbs: Refactor uverbs_finalize_objects
In reply to Leon RomanovskyFrom: Matan Barak <[email protected]>
uverbs_finalize_objects is currently used only to commit or abort objects. Since we want to add automatic allocation/free of PTR_IN attributes, moving it to uverbs_ioctl.c and renamit it to uverbs_finalize_attrs.
--- drivers/infiniband/core/rdma_core.c | 40 --------------------- drivers/infiniband/core/rdma_core.h | 10 ++---- drivers/infiniband/core/uverbs_ioctl.c | 64 +++++++++++++++++++++++++++------- 3 files changed, 55 insertions(+), 59 deletions(-)
drivers/infiniband/core/rdma_core.c +0 -40
@@ -779,43 +779,3 @@ int uverbs_finalize_object(struct ib_uobject *uobj,return ret; } - -int uverbs_finalize_objects (struct uverbs_attr_bundle *attrs_bundle, -struct uverbs_attr_spec_hash *const *spec_hash, -size_t num, -bool commit) -{ -unsigned int i; -int ret =0 ; - -for (i =0 ; i < num; i++) { -struct uverbs_attr_bundle_hash *curr_bundle = - &attrs_bundle->hash[i]; -const struct uverbs_attr_spec_hash *curr_spec_bucket = - spec_hash[i]; -unsigned int j; - -for (j =0 ; j < curr_bundle->num_attrs; j++) { -struct uverbs_attr *attr; -const struct uverbs_attr_spec *spec; - -if (!uverbs_attr_is_valid_in_hash (curr_bundle, j)) -continue ; - - attr = &curr_bundle->attrs[j]; - spec = &curr_spec_bucket->attrs[j]; - -if (spec->type ==UVERBS_ATTR_TYPE_IDR || - spec->type ==UVERBS_ATTR_TYPE_FD ) { -int current_ret; - - current_ret =uverbs_finalize_object (attr->obj_attr.uobject, - spec->obj.access, - commit); -if (!ret) - ret = current_ret; - } - } - } -return ret; -}
drivers/infiniband/core/rdma_core.h +3 -7
@@ -94,9 +94,6 @@ struct ib_uobject *uverbs_get_uobject_from_context(const struct uverbs_obj_typestruct ib_ucontext *ucontext, enum uverbs_obj_access access, int id); -int uverbs_finalize_object (struct ib_uobject *uobj, -enum uverbs_obj_access access, -bool commit);/* * Note that certain finalize stages could return a status: * (a) alloc_commit could return a failure if the object is committed at the
@@ -112,9 +109,8 @@ int uverbs_finalize_object(struct ib_uobject *uobj,* function. For example, this could happen when we couldn't destroy an * object. */ -int uverbs_finalize_objects (struct uverbs_attr_bundle *attrs_bundle, -struct uverbs_attr_spec_hash *const *spec_hash, -size_t num, -bool commit); +int uverbs_finalize_object (struct ib_uobject *uobj, +enum uverbs_obj_access access, +bool commit);#endif /* RDMA_CORE_H */
drivers/infiniband/core/uverbs_ioctl.c +52 -12
88 lines not on this page · raw message
Signature · 1 line
2.14.4
PATCH v2 6/20 IB/uverbs: Add PTR_IN attributes that are allocated/copied automatically
In reply to Leon RomanovskyFrom: Matan Barak <[email protected]>
Adding UVERBS_ATTR_SPEC_F_ALLOC_AND_COPY flag to PTR_IN attributes. By using this flag, the parse automatically allocates and copies the user-space data. This data is accessible by using uverbs_attr_get_len and uverbs_attr_get_alloced_ptr inline accessor functions from the handler.
--- drivers/infiniband/core/uverbs_ioctl.c | 25 ++++++++++++++++++++++++- include/rdma/uverbs_ioctl.h | 25 +++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-)
drivers/infiniband/core/uverbs_ioctl.c +24 -1
@@ -114,7 +114,26 @@ static int uverbs_process_attr(struct ib_device *ibdev, uattr->attr_data.reserved)return -EINVAL ; - e->ptr_attr.data = uattr->data; +if (val_spec->flags &UVERBS_ATTR_SPEC_F_ALLOC_AND_COPY && + uattr->len >sizeof (((struct ib_uverbs_attr *)0 )->data)) { +int ret; +void *p; + + p =kvmalloc (uattr->len,GFP_KERNEL ); +if (!p) +return -ENOMEM ; + + e->ptr_attr.data =ptr_to_u64 (p); + + ret =copy_from_user (p,u64_to_user_ptr (uattr->data), + uattr->len); +if (ret) { +kvfree (p); +return -EFAULT ; + } + }else { + e->ptr_attr.data = uattr->data; + } e->ptr_attr.len = uattr->len; e->ptr_attr.flags = uattr->flags;break ;
@@ -201,6 +220,10 @@ static int uverbs_finalize_attrs(struct uverbs_attr_bundle *attrs_bundle, commit);if (!ret) ret = current_ret; + }else if (spec->type ==UVERBS_ATTR_TYPE_PTR_IN && + spec->flags &UVERBS_ATTR_SPEC_F_ALLOC_AND_COPY && + !uverbs_attr_ptr_is_inline (attr)) { +kvfree (u64_to_ptr (void, attr->ptr_attr.data)); } } }
include/rdma/uverbs_ioctl.h +25 -0
@@ -65,6 +65,8 @@ enum {UVERBS_ATTR_SPEC_F_MANDATORY =1U <<0 ,/* Support extending attributes by length, validate all unknown size == zero */ UVERBS_ATTR_SPEC_F_MIN_SZ_OR_ZERO =1U <<1 , +/* Valid only for PTR_IN. Allocate and copy the data inside the parser */ + UVERBS_ATTR_SPEC_F_ALLOC_AND_COPY = 1U << 2, };/* Specification of a single attribute inside the ioctl message */
@@ -431,6 +433,17 @@ static inline struct ib_uobject *uverbs_attr_get_uobject(const struct uverbs_attreturn attr->obj_attr.uobject; } +static inline int uverbs_attr_get_len (const struct uverbs_attr_bundle *attrs_bundle, +u16 idx) +{ +const struct uverbs_attr *attr =uverbs_attr_get (attrs_bundle, idx); + +if (IS_ERR (attr)) +return PTR_ERR (attr); + +return attr->ptr_attr.len; +} +static inline int uverbs_copy_to (const struct uverbs_attr_bundle *attrs_bundle,size_t idx,const void *from,size_t size) {
@@ -457,6 +470,18 @@ static inline bool uverbs_attr_ptr_is_inline(const struct uverbs_attr *attr)return attr->ptr_attr.len <=sizeof (attr->ptr_attr.data); } +static inline void *uverbs_attr_get_alloced_ptr (const struct uverbs_attr_bundle *attrs_bundle, +u16 idx) +{ +const struct uverbs_attr *attr =uverbs_attr_get (attrs_bundle, idx); + +if (IS_ERR (attr)) +return (void *)attr; + + return uverbs_attr_ptr_is_inline(attr) ? u64_to_ptr(void *, attr->ptr_attr.data) : +u64_to_ptr (void, attr->ptr_attr.data); +} + static inline int _uverbs_copy_from(void *to, const struct uverbs_attr_bundle *attrs_bundle, size_t idx,
Signature · 1 line
2.14.4
Re: [PATCH rdma-next v2 06/20] IB/uverbs: Add PTR_IN attributes that are allocated/copied automatically
Quoted 19 lines · Leon Romanovsky
From: Matan Barak <[email protected]>
Adding
UVERBS_ATTR_SPEC_F_ALLOC_AND_COPYflag toPTR_INattributes. By using this flag, the parse automatically allocates and copies the user-space data. This data is accessible by usinguverbs_attr_get_lenanduverbs_attr_get_alloced_ptrinline accessor functions from the handler.Signed-off-by Matan Barak <[email protected]>Signed-off-by Yishai Hadas <[email protected]>Signed-off-by Leon Romanovsky <[email protected]>drivers/infiniband/core/uverbs_ioctl.c | 25 ++++++++++++++++++++++++- include/rdma/uverbs_ioctl.h | 25 +++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-)drivers/infiniband/core/uverbs_ioctl.c +1
-0+++ b/drivers/infiniband/core/uverbs_ioctl.c
drivers/infiniband/core/uverbs_ioctl.c static int uverbs_process_attr(struct ib_device *ibdev, · line 118
Quoted 6 lines
drivers/infiniband/core/uverbs_ioctl.c +2
-1@@ -114,7 +114,26 @@ static int uverbs_process_attr(struct ib_device *ibdev, uattr->attr_data.reserved)return -EINVAL ; - e->ptr_attr.data = uattr->data; +if (val_spec->flags &UVERBS_ATTR_SPEC_F_ALLOC_AND_COPY && + uattr->len >sizeof (((struct ib_uverbs_attr *)0 )->data)) {
Why open-code uverbs_attr_ptr_is_inline() ?
Quoted 34 lines
include/rdma/uverbs_ioctl.h +14
-0+++ b/include/rdma/uverbs_ioctl.h@@ -65,6 +65,8 @@ enum {UVERBS_ATTR_SPEC_F_MANDATORY =1U <<0 ,/* Support extending attributes by length, validate all unknown size == zero */ UVERBS_ATTR_SPEC_F_MIN_SZ_OR_ZERO =1U <<1 , +/* Valid only for PTR_IN. Allocate and copy the data inside the parser */ + UVERBS_ATTR_SPEC_F_ALLOC_AND_COPY = 1U << 2, };/* Specification of a single attribute inside the ioctl message */ @@ -431,6 +433,17 @@ static inline struct ib_uobject *uverbs_attr_get_uobject(const struct uverbs_attreturn attr->obj_attr.uobject; } +static inline int uverbs_attr_get_len (const struct uverbs_attr_bundle *attrs_bundle, +u16 idx) +{ +const struct uverbs_attr *attr =uverbs_attr_get (attrs_bundle, idx); + +if (IS_ERR (attr)) +return PTR_ERR (attr); + +return attr->ptr_attr.len; +} +static inline int uverbs_copy_to (const struct uverbs_attr_bundle *attrs_bundle,size_t idx,const void *from,size_t size) {@@ -457,6 +470,18 @@ static inline bool uverbs_attr_ptr_is_inline(const struct uverbs_attr *attr)return attr->ptr_attr.len <=sizeof (attr->ptr_attr.data); }
include/rdma/uverbs_ioctl.h static inline bool uverbs_attr_ptr_is_inline(const struct uverbs_attr *attr) · line 482
Quoted 10 lines
include/rdma/uverbs_ioctl.h +10
-0+static inline void *uverbs_attr_get_alloced_ptr (const struct uverbs_attr_bundle *attrs_bundle, +u16 idx) +{ +const struct uverbs_attr *attr =uverbs_attr_get (attrs_bundle, idx); + +if (IS_ERR (attr)) +return (void *)attr; + + return uverbs_attr_ptr_is_inline(attr) ? u64_to_ptr(void *, attr->ptr_attr.data) : +u64_to_ptr (void, attr->ptr_attr.data);
WTF is this:
u64_to_ptr(void *, attr->ptr_attr.data)
That returns attr->ptr_attr.data casted to a void **, then casts it to a void * - which is identical to u64_to_ptr(void, attr->ptr_attr.data)
It should be &attr->ptr_attr.data. And the return should be const, the caller shouldn't be mutating the copy.
All this use of u64_to_ptr is ugly needless obfuscation here, and look, it causes bugs. Use a union.
Like this:
drivers/infiniband/core/uverbs_ioctl.c +23 -1
@@ -114,9 +114,27 @@ static int uverbs_process_attr(struct ib_device *ibdev, uattr->attr_data.reserved)return -EINVAL ; - e->ptr_attr.data = uattr->data; e->ptr_attr.len = uattr->len; e->ptr_attr.flags = uattr->flags; + +if (val_spec->flags &UVERBS_ATTR_SPEC_F_ALLOC_AND_COPY && + !uverbs_attr_ptr_is_inline (e)) { +void *p; + + p =kvmalloc (uattr->len,GFP_KERNEL ); +if (!p) +return -ENOMEM ; + + e->ptr_attr.ptr = p; + +if (copy_from_user (p,u64_to_user_ptr (uattr->data), + uattr->len)) { +kvfree (p); +return -EFAULT ; + } + }else { + e->ptr_attr.data = uattr->data; + }break ;case UVERBS_ATTR_TYPE_IDR :
@@ -201,6 +219,10 @@ static int uverbs_finalize_attrs(struct uverbs_attr_bundle *attrs_bundle, commit);if (!ret) ret = current_ret; + }else if (spec->type ==UVERBS_ATTR_TYPE_PTR_IN && + spec->flags &UVERBS_ATTR_SPEC_F_ALLOC_AND_COPY && + !uverbs_attr_ptr_is_inline (attr)) { +kvfree (attr->ptr_attr.ptr); } } }
include/rdma/uverbs_ioctl.h +34 -1
@@ -65,6 +65,8 @@ enum {UVERBS_ATTR_SPEC_F_MANDATORY =1U <<0 ,/* Support extending attributes by length, validate all unknown size == zero */ UVERBS_ATTR_SPEC_F_MIN_SZ_OR_ZERO =1U <<1 , +/* Valid only for PTR_IN. Allocate and copy the data inside the parser */ + UVERBS_ATTR_SPEC_F_ALLOC_AND_COPY = 1U << 2, };/* Specification of a single attribute inside the ioctl message */
@@ -323,7 +325,15 @@ struct uverbs_object_tree_def {*/ struct uverbs_ptr_attr { -u64 data; +/* +* If UVERBS_ATTR_SPEC_F_ALLOC_AND_COPY is set then the 'ptr' is +* used. +*/ +union + { +void *ptr; +u64 data; + };u16 len;/* Combination of bits from enum UVERBS_ATTR_F_XXXX */ u16 flags;
@@ -431,6 +441,17 @@ static inline struct ib_uobject *uverbs_attr_get_uobject(const struct uverbs_attreturn attr->obj_attr.uobject; } +static inline int uverbs_attr_get_len (const struct uverbs_attr_bundle *attrs_bundle, +u16 idx) +{ +const struct uverbs_attr *attr =uverbs_attr_get (attrs_bundle, idx); + +if (IS_ERR (attr)) +return PTR_ERR (attr); + +return attr->ptr_attr.len; +} +static inline int uverbs_copy_to (const struct uverbs_attr_bundle *attrs_bundle,size_t idx,const void *from,size_t size) {
@@ -457,6 +478,18 @@ static inline bool uverbs_attr_ptr_is_inline(const struct uverbs_attr *attr)return attr->ptr_attr.len <=sizeof (attr->ptr_attr.data); } +static inline const void *uverbs_attr_get_alloced_ptr ( +const struct uverbs_attr_bundle *attrs_bundle,u16 idx) +{ +const struct uverbs_attr *attr =uverbs_attr_get (attrs_bundle, idx); + +if (IS_ERR (attr)) +return (void *)attr; + +return uverbs_attr_ptr_is_inline (attr) ? &attr->ptr_attr.data : + attr->ptr_attr.ptr; +} + static inline int _uverbs_copy_from(void *to, const struct uverbs_attr_bundle *attrs_bundle, size_t idx,
PATCH v2 7/20 IB/uverbs: Add a macro to define a type with no kernel known size
In reply to Leon RomanovskyFrom: Matan Barak <[email protected]>
Sometimes the uverbs uAPI doesn't really care about the structure it gets from user-space. All it wants to do is to allocate enough space and send it to the hardware/provider driver. Adding a UVERBS_ATTR_MIN_SIZE that could be used for this scenarios. We use USHRT_MAX as the kernel known size to bypass any zero validations.
--- drivers/infiniband/core/uverbs_std_types.c | 4 ++-- include/rdma/uverbs_ioctl.h | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-)
drivers/infiniband/core/uverbs_std_types.c +2 -2
@@ -207,10 +207,10 @@ int uverbs_destroy_def_handler(struct ib_device *ib_dev,* spec. */ const struct uverbs_attr_def uverbs_uhw_compat_in = -UVERBS_ATTR_PTR_IN_SZ (UVERBS_ATTR_UHW_IN ,UVERBS_ATTR_SIZE (0 ,USHRT_MAX ), +UVERBS_ATTR_PTR_IN_SZ (UVERBS_ATTR_UHW_IN ,UVERBS_ATTR_MIN_SIZE (0 ),UA_FLAGS (UVERBS_ATTR_SPEC_F_MIN_SZ_OR_ZERO ));const struct uverbs_attr_def uverbs_uhw_compat_out = -UVERBS_ATTR_PTR_OUT_SZ (UVERBS_ATTR_UHW_OUT ,UVERBS_ATTR_SIZE (0 ,USHRT_MAX ), +UVERBS_ATTR_PTR_OUT_SZ (UVERBS_ATTR_UHW_OUT ,UVERBS_ATTR_MIN_SIZE (0 ),UA_FLAGS (UVERBS_ATTR_SPEC_F_MIN_SZ_OR_ZERO ));void create_udata (struct uverbs_attr_bundle *ctx,struct ib_udata *udata)
include/rdma/uverbs_ioctl.h +2 -0
@@ -213,6 +213,8 @@ struct uverbs_object_tree_def { .min_len = ((uintptr_t)(&((_type *)0)->_last + 1)), .len = sizeof(_type)#define UVERBS_ATTR_SIZE (_min_len, _len) \ .min_len = _min_len, .len = _len +#define UVERBS_ATTR_MIN_SIZE (_min_len) \ + UVERBS_ATTR_SIZE(_min_len, USHRT_MAX)/* * In new compiler, UVERBS_ATTR could be simplified by declaring it as
Signature · 1 line
2.14.4
PATCH v2 8/20 IB/uverbs: Allow an empty namespace in ioctl() framework
In reply to Leon RomanovskyFrom: Matan Barak <[email protected]>
The ioctl parser framework wrongly assumed that each namespace is populated. This could lead to NULL dereferences. Fix the parser to always check that a given namespace indeed exists.
--- drivers/infiniband/core/uverbs_ioctl.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-)
drivers/infiniband/core/uverbs_ioctl.c +13 -2
@@ -201,6 +201,9 @@ static int uverbs_finalize_attrs(struct uverbs_attr_bundle *attrs_bundle, spec_hash[i];unsigned int j; +if (!curr_spec_bucket) +continue ; +for (j =0 ; j < curr_bundle->num_attrs; j++) {struct uverbs_attr *attr;const struct uverbs_attr_spec *spec;
@@ -248,7 +251,7 @@ static int uverbs_uattrs_process(struct ib_device *ibdev,struct uverbs_attr_spec_hash *attr_spec_bucket; ret =uverbs_ns_idx (&attr_id, method->num_buckets); -if (ret <0 ) { +if (ret <0 || !method->attr_buckets[ret]) {if (uattr->flags &UVERBS_ATTR_F_MANDATORY ) { uverbs_finalize_attrs(attr_bundle, method->attr_buckets,
@@ -291,6 +294,9 @@ static int uverbs_validate_kernel_mandatory(const struct uverbs_method_spec *metstruct uverbs_attr_spec_hash *attr_spec_bucket = method_spec->attr_buckets[i]; +if (!attr_spec_bucket) +continue ; +if (!bitmap_subset (attr_spec_bucket->mandatory_attrs_bitmask, attr_bundle->hash[i].valid_bitmap, attr_spec_bucket->num_attrs))
@@ -404,7 +410,12 @@ static long ib_uverbs_cmd_verbs(struct ib_device *ib_dev,* filled at a later stage (uverbs_process_attr) */ for (i =0 ; i < method_spec->num_buckets; i++) { -unsigned int curr_num_attrs = method_spec->attr_buckets[i]->num_attrs; +unsigned int curr_num_attrs; + +if (!method_spec->attr_buckets[i]) +continue ; + + curr_num_attrs = method_spec->attr_buckets[i]->num_attrs; ctx->uverbs_attr_bundle->hash[i].attrs = curr_attr; curr_attr += curr_num_attrs;
Signature · 1 line
2.14.4
PATCH v2 9/20 IB/core: Improve uverbs_cleanup_ucontext algorithm
In reply to Leon RomanovskyFrom: Yishai Hadas <[email protected]>
Improve uverbs_cleanup_ucontext algorithm to work properly even when there are two objects from the same type and one points to the other. For that case to work the 'destroy_order' is not used any more as it's static per type and can't support this use case.
Instead, the new algorithm iterates over the objects in a LIFO mode as was before, at the end of each loop if were left objects that couldn't be destroyed it re-iterates over them give another chance to destroy them successfully.
If was one iteration that didn't cleanup any object the last iteration will force the cleanup as was done before this change, this is coming to prevent memory leaks even in that fatal case.
--- drivers/infiniband/core/rdma_core.c | 96 ++++++++++++---------- drivers/infiniband/core/uverbs_std_types.c | 22 +++-- .../infiniband/core/uverbs_std_types_counters.c | 2 +- drivers/infiniband/core/uverbs_std_types_cq.c | 2 +- drivers/infiniband/core/uverbs_std_types_dm.c | 3 +- .../infiniband/core/uverbs_std_types_flow_action.c | 2 +- drivers/infiniband/core/uverbs_std_types_mr.c | 3 +- include/rdma/ib_verbs.h | 2 +- include/rdma/uverbs_types.h | 11 +-- 9 files changed, 72 insertions(+), 71 deletions(-)
drivers/infiniband/core/rdma_core.c +52 -44
@@ -645,61 +645,69 @@ void uverbs_close_fd(struct file *f)kref_put (uverbs_file_ref, ib_uverbs_release_file); } -void uverbs_cleanup_ucontext (struct ib_ucontext *ucontext,bool device_removed) +static int __uverbs_cleanup_ucontext (struct ib_ucontext *ucontext, +enum rdma_remove_reason reason) { -enum rdma_remove_reason reason = device_removed ? -RDMA_REMOVE_DRIVER_REMOVE :RDMA_REMOVE_CLOSE ; -unsigned int cur_order =0 ; +struct ib_uobject *obj, *next_obj; +int ret = -EINVAL ; +int err =0 ; +/* +* This shouldn't run while executing other commands on this +* context. Thus, the only thing we should take care of is +* releasing a FD while traversing this list. The FD could be +* closed and released from the _release fop of this FD. +* In order to mitigate this, we add a lock. +* We take and release the lock per traversal in order to let +* other threads (which might still use the FDs) chance to run. +*/ +mutex_lock (&ucontext->uobjects_lock); ucontext->cleanup_reason = reason; +list_for_each_entry_safe (obj, next_obj, &ucontext->uobjects, list) { +/* +* if we hit this WARN_ON, that means we are +* racing with a lookup_get. +*/ +WARN_ON (uverbs_try_lock_object (obj, true)); + err = obj->type->type_class->remove_commit (obj, reason); +if (err) { +if (reason ==RDMA_REMOVE_DESTROY ) { +pr_debug ("ib_uverbs: failed to remove uobject id %d err %d\n" , + obj->id, err); +atomic_set (&obj->usecnt,0 ); +continue ; + } + +pr_warn ("ib_uverbs: unable to remove uobject id %d err %d\n" , + obj->id, err); + } + +list_del (&obj->list); +/* put the ref we took when we created the object */ +uverbs_uobject_put (obj); + ret =0 ; + } +mutex_unlock (&ucontext->uobjects_lock); +return ret; +} + +void uverbs_cleanup_ucontext (struct ib_ucontext *ucontext,bool device_removed) +{/* * Waits for all remove_commit and alloc_commit to finish. Logically, We * want to hold this forever as the context is going to be destroyed, * but we'll release it since it causes a "held lock freed" BUG message. */ down_write (&ucontext->cleanup_rwsem); +while (!list_empty (&ucontext->uobjects)) +if (__uverbs_cleanup_ucontext (ucontext,RDMA_REMOVE_DESTROY )) +/* No entry was cleaned-up successfully during this iteration */ +break ; -while (!list_empty (&ucontext->uobjects)) { -struct ib_uobject *obj, *next_obj; -unsigned int next_order =UINT_MAX ; +if (!list_empty (&ucontext->uobjects)) +__uverbs_cleanup_ucontext (ucontext, device_removed ? +RDMA_REMOVE_DRIVER_REMOVE :RDMA_REMOVE_CLOSE ); -/* -* This shouldn't run while executing other commands on this -* context. Thus, the only thing we should take care of is -* releasing a FD while traversing this list. The FD could be -* closed and released from the _release fop of this FD. -* In order to mitigate this, we add a lock. -* We take and release the lock per order traversal in order -* to let other threads (which might still use the FDs) chance -* to run. -*/ -mutex_lock (&ucontext->uobjects_lock); -list_for_each_entry_safe (obj, next_obj, &ucontext->uobjects, - list) { -if (obj->type->destroy_order == cur_order) { -int ret; - -/* -* if we hit this WARN_ON, that means we are -* racing with a lookup_get. -*/ -WARN_ON (uverbs_try_lock_object (obj, true)); - ret = obj->type->type_class->remove_commit (obj, - reason); -list_del (&obj->list); -if (ret) -pr_warn ("ib_uverbs: failed to remove uobject id %d order %u\n" , - obj->id, cur_order); -/* put the ref we took when we created the object */ -uverbs_uobject_put (obj); - }else { - next_order =min (next_order, - obj->type->destroy_order); - } - } -mutex_unlock (&ucontext->uobjects_lock); - cur_order = next_order; - }up_write (&ucontext->cleanup_rwsem); }
drivers/infiniband/core/uverbs_std_types.c +10 -12
@@ -246,44 +246,42 @@ void create_udata(struct uverbs_attr_bundle *ctx, struct ib_udata *udata) }DECLARE_UVERBS_NAMED_OBJECT (UVERBS_OBJECT_COMP_CHANNEL , - &UVERBS_TYPE_ALLOC_FD (0 , -sizeof (struct ib_uverbs_completion_event_file ), + &UVERBS_TYPE_ALLOC_FD (sizeof (struct ib_uverbs_completion_event_file ), uverbs_hot_unplug_completion_event_file, &uverbs_event_fops,"[infinibandevent]" ,O_RDONLY ));DECLARE_UVERBS_NAMED_OBJECT (UVERBS_OBJECT_QP , - &UVERBS_TYPE_ALLOC_IDR_SZ (sizeof (struct ib_uqp_object ),0 , + &UVERBS_TYPE_ALLOC_IDR_SZ (sizeof (struct ib_uqp_object ), uverbs_free_qp));DECLARE_UVERBS_NAMED_OBJECT (UVERBS_OBJECT_MW , - &UVERBS_TYPE_ALLOC_IDR (0 , uverbs_free_mw)); + &UVERBS_TYPE_ALLOC_IDR (uverbs_free_mw));DECLARE_UVERBS_NAMED_OBJECT (UVERBS_OBJECT_SRQ , - &UVERBS_TYPE_ALLOC_IDR_SZ (sizeof (struct ib_usrq_object ),0 , + &UVERBS_TYPE_ALLOC_IDR_SZ (sizeof (struct ib_usrq_object ), uverbs_free_srq));DECLARE_UVERBS_NAMED_OBJECT (UVERBS_OBJECT_AH , - &UVERBS_TYPE_ALLOC_IDR (0 , uverbs_free_ah)); + &UVERBS_TYPE_ALLOC_IDR (uverbs_free_ah));DECLARE_UVERBS_NAMED_OBJECT (UVERBS_OBJECT_FLOW , &UVERBS_TYPE_ALLOC_IDR_SZ (sizeof (struct ib_uflow_object ), -0 , uverbs_free_flow)); + uverbs_free_flow));DECLARE_UVERBS_NAMED_OBJECT (UVERBS_OBJECT_WQ , - &UVERBS_TYPE_ALLOC_IDR_SZ (sizeof (struct ib_uwq_object ),0 , + &UVERBS_TYPE_ALLOC_IDR_SZ (sizeof (struct ib_uwq_object ), uverbs_free_wq));DECLARE_UVERBS_NAMED_OBJECT (UVERBS_OBJECT_RWQ_IND_TBL , - &UVERBS_TYPE_ALLOC_IDR (0 , uverbs_free_rwq_ind_tbl)); + &UVERBS_TYPE_ALLOC_IDR (uverbs_free_rwq_ind_tbl));DECLARE_UVERBS_NAMED_OBJECT (UVERBS_OBJECT_XRCD , - &UVERBS_TYPE_ALLOC_IDR_SZ (sizeof (struct ib_uxrcd_object ),0 , + &UVERBS_TYPE_ALLOC_IDR_SZ (sizeof (struct ib_uxrcd_object ), uverbs_free_xrcd));DECLARE_UVERBS_NAMED_OBJECT (UVERBS_OBJECT_PD , -/* 2 is used in order to free the PD after MRs */ - &UVERBS_TYPE_ALLOC_IDR (2 , uverbs_free_pd)); + &UVERBS_TYPE_ALLOC_IDR (uverbs_free_pd));DECLARE_UVERBS_NAMED_OBJECT (UVERBS_OBJECT_DEVICE ,NULL );
drivers/infiniband/core/uverbs_std_types_counters.c +1 -1
@@ -150,7 +150,7 @@ static DECLARE_UVERBS_NAMED_METHOD(UVERBS_METHOD_COUNTERS_READ, UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY)));DECLARE_UVERBS_NAMED_OBJECT (UVERBS_OBJECT_COUNTERS , - &UVERBS_TYPE_ALLOC_IDR (0 , uverbs_free_counters), + &UVERBS_TYPE_ALLOC_IDR (uverbs_free_counters), &UVERBS_METHOD (UVERBS_METHOD_COUNTERS_CREATE ), &UVERBS_METHOD (UVERBS_METHOD_COUNTERS_DESTROY ), &UVERBS_METHOD (UVERBS_METHOD_COUNTERS_READ ));
drivers/infiniband/core/uverbs_std_types_cq.c +1 -1
@@ -201,7 +201,7 @@ static DECLARE_UVERBS_NAMED_METHOD(UVERBS_METHOD_CQ_DESTROY, UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY))); DECLARE_UVERBS_NAMED_OBJECT(UVERBS_OBJECT_CQ, - &UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_ucq_object), 0, + &UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_ucq_object), uverbs_free_cq), #if IS_ENABLED(CONFIG_INFINIBAND_EXP_LEGACY_VERBS_NEW_UAPI) &UVERBS_METHOD(UVERBS_METHOD_CQ_CREATE),
drivers/infiniband/core/uverbs_std_types_dm.c +1 -2
@@ -102,7 +102,6 @@ static DECLARE_UVERBS_NAMED_METHOD_WITH_HANDLER(UVERBS_METHOD_DM_FREE, UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY)));DECLARE_UVERBS_NAMED_OBJECT (UVERBS_OBJECT_DM , -/* 1 is used in order to free the DM after MRs */ - &UVERBS_TYPE_ALLOC_IDR (1 , uverbs_free_dm), + &UVERBS_TYPE_ALLOC_IDR (uverbs_free_dm), &UVERBS_METHOD (UVERBS_METHOD_DM_ALLOC ), &UVERBS_METHOD (UVERBS_METHOD_DM_FREE ));
drivers/infiniband/core/uverbs_std_types_flow_action.c +1 -1
@@ -428,7 +428,7 @@ static DECLARE_UVERBS_NAMED_METHOD_WITH_HANDLER(UVERBS_METHOD_FLOW_ACTION_DESTRO UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY)));DECLARE_UVERBS_NAMED_OBJECT (UVERBS_OBJECT_FLOW_ACTION , - &UVERBS_TYPE_ALLOC_IDR (0 , uverbs_free_flow_action), + &UVERBS_TYPE_ALLOC_IDR (uverbs_free_flow_action), &UVERBS_METHOD (UVERBS_METHOD_FLOW_ACTION_ESP_CREATE ), &UVERBS_METHOD (UVERBS_METHOD_FLOW_ACTION_DESTROY ), &UVERBS_METHOD (UVERBS_METHOD_FLOW_ACTION_ESP_MODIFY ));
drivers/infiniband/core/uverbs_std_types_mr.c +1 -2
@@ -142,6 +142,5 @@ static DECLARE_UVERBS_NAMED_METHOD(UVERBS_METHOD_DM_MR_REG, UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY)));DECLARE_UVERBS_NAMED_OBJECT (UVERBS_OBJECT_MR , -/* 1 is used in order to free the MR after all the MWs */ - &UVERBS_TYPE_ALLOC_IDR (1 , uverbs_free_mr), + &UVERBS_TYPE_ALLOC_IDR (uverbs_free_mr), &UVERBS_METHOD (UVERBS_METHOD_DM_MR_REG ));
include/rdma/ib_verbs.h +1 -1
@@ -1473,7 +1473,7 @@ struct ib_fmr_attr {struct ib_umem ;enum rdma_remove_reason { -/* Userspace requested uobject deletion. Call could fail */ +/* Userspace requested uobject deletion or initial try to remove uobject via cleanup. Call could fail */ RDMA_REMOVE_DESTROY ,/* Context deletion. This call should delete the actual object itself */ RDMA_REMOVE_CLOSE ,
include/rdma/uverbs_types.h +4 -7
@@ -93,7 +93,6 @@ struct uverbs_obj_type_class {struct uverbs_obj_type {const struct uverbs_obj_type_class *const type_class;size_t obj_size; -unsigned int destroy_order; };/*
@@ -152,10 +151,9 @@ extern const struct uverbs_obj_type_class uverbs_fd_class;#define UVERBS_BUILD_BUG_ON (cond) (sizeof(char[1 - 2 * !!(cond)]) - \ sizeof(char)) -#define UVERBS_TYPE_ALLOC_FD (_order, _obj_size, _context_closed, _fops, _name, _flags)\ +#define UVERBS_TYPE_ALLOC_FD (_obj_size, _context_closed, _fops, _name, _flags)\ ((&((const struct uverbs_obj_fd_type) \ {.type = { \ - .destroy_order = _order, \ .type_class = &uverbs_fd_class, \ .obj_size = (_obj_size) + \ UVERBS_BUILD_BUG_ON((_obj_size) < sizeof(struct ib_uobject_file)), \
@@ -164,18 +162,17 @@ extern const struct uverbs_obj_type_class uverbs_fd_class; .fops = _fops, \ .name = _name, \ .flags = _flags}))->type) -#define UVERBS_TYPE_ALLOC_IDR_SZ (_size, _order, _destroy_object) \ +#define UVERBS_TYPE_ALLOC_IDR_SZ (_size, _destroy_object) \ ((&((const struct uverbs_obj_idr_type) \ {.type = { \ - .destroy_order = _order, \ .type_class = &uverbs_idr_class, \ .obj_size = (_size) + \ UVERBS_BUILD_BUG_ON((_size) < \ sizeof(struct ib_uobject)) \ }, \ .destroy_object = _destroy_object,}))->type) -#define UVERBS_TYPE_ALLOC_IDR (_order, _destroy_object) \ - UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_uobject), _order, \ +#define UVERBS_TYPE_ALLOC_IDR (_destroy_object) \ + UVERBS_TYPE_ALLOC_IDR_SZ(sizeof(struct ib_uobject), \ _destroy_object)#endif
Signature · 1 line
2.14.4
Re: [PATCH rdma-next v2 09/20] IB/core: Improve uverbs_cleanup_ucontext algorithm
drivers/infiniband/core/rdma_core.c void uverbs_close_fd(struct file *f) · line 705
Quoted 12 lines · Leon Romanovsky
drivers/infiniband/core/rdma_core.c +6
-0+void uverbs_cleanup_ucontext (struct ib_ucontext *ucontext,bool device_removed) +{/* * Waits for all remove_commit and alloc_commit to finish. Logically, We * want to hold this forever as the context is going to be destroyed, * but we'll release it since it causes a "held lock freed" BUG message. */ down_write (&ucontext->cleanup_rwsem); +while (!list_empty (&ucontext->uobjects)) +if (__uverbs_cleanup_ucontext (ucontext,RDMA_REMOVE_DESTROY )) +/* No entry was cleaned-up successfully during this iteration */ +break ;
No, this isn't right, it must remain REMOVE or CLOSE here. The enum is a signal to the driver what is going on. DESTROY is only for user triggered destroy called in a user context.
There needs to be some kind of guarenteed return from the driver that destroy is failing due to elevated refcounts, and not some other reason.. This is just checking for any ret?
drivers/infiniband/core/rdma_core.c void uverbs_close_fd(struct file *f) · line 709
Quoted 6 lines
drivers/infiniband/core/rdma_core.c +3
-3-while (!list_empty (&ucontext->uobjects)) { -struct ib_uobject *obj, *next_obj; -unsigned int next_order =UINT_MAX ; +if (!list_empty (&ucontext->uobjects)) +__uverbs_cleanup_ucontext (ucontext, device_removed ? +RDMA_REMOVE_DRIVER_REMOVE :RDMA_REMOVE_CLOSE );
Failure to cleanup is a driver bug, and should be reported with WARN_ON. This is also mis using the remove enum, CLOSE is not a 'bigger hammer'
Jason
Re: [PATCH rdma-next v2 09/20] IB/core: Improve uverbs_cleanup_ucontext algorithm
Quoted 19 lines · Jason Gunthorpe
Review
Quoted 12 lines · Leon Romanovsky
(quoted diff) +6
-0+void uverbs_cleanup_ucontext(struct ib_ucontext *ucontext, bool device_removed) +{ /* * Waits for all remove_commit and alloc_commit to finish. Logically, We * want to hold this forever as the context is going to be destroyed, * but we'll release it since it causes a "held lock freed" BUG message. */ down_write(&ucontext->cleanup_rwsem); + while (!list_empty(&ucontext->uobjects)) + if (__uverbs_cleanup_ucontext(ucontext, RDMA_REMOVE_DESTROY)) + /* No entry was cleaned-up successfully during this iteration */ + break;No, this isn't right, it must remain REMOVE or CLOSE here. The enum is a signal to the driver what is going on. DESTROY is only for user triggered destroy called in a user context.
The algorithm must enable the drivers an option to fully cleanup their resources as was done before this change.
Using REMOVE or CLOSE without some following change won't do the work as the infrastructure (e.g. remove_commit_idr_uobject) and other IB cleanup functions during the road (e.g. uverbs_free_qp, uverbs_free_cq) will force cleanup of some memory/idr/ref resources and prevent a second successful iteration in case of a failure.
For that reason the initial iteration should be with some relaxed mode and just later in case were left uncleaned-up resources the code should use the REMOVE/CLOSE option.
However, I do agree that we need to preserve the original signal to let downstream layers to know what happened, at the moment it looks like there is one place that it's even a must as part of uverbs_hot_unplug_completion_event_file() where 'RDMA_REMOVE_DRIVER_REMOVE' is used explicitly as part of the cleanup flow.
For that I suggest below [1] patch which replaces RDMA_REMOVE_DESTROY in the first iteration with RDMA_REMOVE_DRIVER_REMOVE_RELAX/ RDMA_REMOVE_CLOSE_RELAX new enum values to do the job.
Quoted 3 lines
There needs to be some kind of guarenteed return from the driver that destroy is failing due to elevated refcounts, and not some other reason.. This is just checking for any ret?
We can't rely on all drivers' return codes from legacy/current firmware code for all objects to return a specific ret code for that case. Even if we had such, the second iteration where we should force cleanup might still fail with that ret code and a kernel memory leak would occur.
Quoted 12 lines
Review
Quoted 7 lines
(quoted diff) +3
-3- while (!list_empty(&ucontext->uobjects)) { - struct ib_uobject *obj, *next_obj; - unsigned int next_order = UINT_MAX; + if (!list_empty(&ucontext->uobjects)) + __uverbs_cleanup_ucontext(ucontext, device_removed ? + RDMA_REMOVE_DRIVER_REMOVE : RDMA_REMOVE_CLOSE);Failure to cleanup is a driver bug, and should be reported with
WARN_ON. This is also mis using the remove enum, CLOSE is not a 'bigger hammer'
The patch saves the previous behavior that set a warn message [2] and not a WARN_ON, if you think that WARN_ON is better we can change to.
[2]
pr_warn("ib_uverbs: unable to remove uobject id %d err %d\n",
obj->id, err);
The suggested patch on top of current can look like below.
include/rdma/ib_verbs.h +13 -0
@@ -1468,8 +1468,21 @@ enum rdma_remove_reason {RDMA_REMOVE_DRIVER_REMOVE ,/* Context is being cleaned-up, but commit was just completed */ RDMA_REMOVE_DURING_CLEANUP , +/* Driver is being hot-unplugged, retry may be called upon an error */ +RDMA_REMOVE_DRIVER_REMOVE_RELAX , +/* Context deletion, retry may be called upon an error */ + RDMA_REMOVE_CLOSE_RELAX, }; +static inline bool ib_is_remove_retry (enum rdma_remove_reason why) +{ +if (why ==RDMA_REMOVE_DESTROY || why ==RDMA_REMOVE_DRIVER_REMOVE_RELAX || + why ==RDMA_REMOVE_CLOSE_RELAX ) +return true; + +return false; +} +
// In the new algorithm below enums will be used instead of //RDMA_REMOVE_DESTROY
@@ -700,7 +701,9 @@ void uverbs_cleanup_ucontext(struct ib_ucontext *ucontext, bool device_removed)
*/
down_write(&ucontext->cleanup_rwsem);
while (!list_empty(&ucontext->uobjects))- if (__uverbs_cleanup_ucontext(ucontext, RDMA_REMOVE_DESTROY))
+ if (__uverbs_cleanup_ucontext(ucontext, device_removed ?
+ RDMA_REMOVE_DRIVER_REMOVE_RELAX :
+ RDMA_REMOVE_CLOSE_RELAX))
/* No entry was cleaned-up successfully during
this iteration */
break;// Below logic will be replaced in all applicable places, I just put few // of to demonstrate the solution.
drivers/infiniband/core/uverbs_std_types_cq.c +1 -1
@@ -44,7 +44,7 @@ static int uverbs_free_cq(struct ib_uobject *uobject,int ret; ret =ib_destroy_cq (cq); -if (!ret || why !=RDMA_REMOVE_DESTROY ) +if (!ret || !ib_is_remove_retry (why)) ib_uverbs_release_ucq(uobject->context->ufile, ev_queue
? container_of(ev_queue, struct ib_uverbs_completion_event_file,
++ b/drivers/infiniband/core/rdma_core.c
@@ -360,9 +360,10 @@ static int __must_check remove_commit_idr_uobject(struct ib_uobject *uobj,
/*
* We can only fail gracefully if the user requested to destroy the
- * object. In the rest of the cases, just remove whatever you can.
+ * object or when a retry may be called upon an error.
+ * In the rest of the cases, just remove whatever you can.
*/
- if (why == RDMA_REMOVE_DESTROY && ret)
+ if (ret && ib_is_remove_retry(why))
return ret;
ib_rdmacg_uncharge(&uobj->cg_obj, uobj->context->device,
@@ -393,7 +394,7 @@ static int __must_check remove_commit_fd_uobject(struct ib_uobject *uobj,
container_of(uobj, struct ib_uobject_file, uobj);
int ret = fd_type->context_closed(uobj_file, why);- if (why == RDMA_REMOVE_DESTROY && ret)
+ if (ret && ib_is_remove_retry(why))
return ret;
//Here is the specific place that checks for RDMA_REMOVE_DRIVER_REMOVE. // it should do the work also when RDMA_REMOVE_DRIVER_REMOVE was called.
@@ -187,7 +187,7 @@ static int uverbs_hot_unplug_completion_event_file(struct ib_uobject_file *uobj_
event_queue->is_closed = 1;
spin_unlock_irq(&event_queue->lock);- if (why == RDMA_REMOVE_DRIVER_REMOVE) {
+ if (why == RDMA_REMOVE_DRIVER_REMOVE || why == RDMA_REMOVE_DRIVER_REMOVE_RELAX) {
wake_up_interruptible(&event_queue->poll_wait);
kill_fasync(&event_queue->async_queue, SIGIO, POLL_IN);
}What do you think ?
Yishai
PATCH v2 10/20 net/mlx5: Expose DEVX ifc structures
In reply to Leon RomanovskyFrom: Yishai Hadas <[email protected]>
This patch updates the mlx5_ifc structures with the following:
- Expose general command header in/out format.
- Expose user context format.
- Expose umem format.
Downstream patches from this series will use this stuff.
--- include/linux/mlx5/mlx5_ifc.h | 52 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+)
include/linux/mlx5/mlx5_ifc.h +52 -0
@@ -9115,4 +9115,56 @@ struct mlx5_ifc_dealloc_memic_out_bits {u8 reserved_at_40[0x40 ]; }; +struct mlx5_ifc_general_obj_in_cmd_hdr_bits { +u8 opcode[0x10 ]; +u8 uid[0x10 ]; + +u8 reserved_at_20[0x10 ]; +u8 obj_type[0x10 ]; + +u8 obj_id[0x20 ]; + +u8 reserved_at_60[0x20 ]; +}; + +struct mlx5_ifc_general_obj_out_cmd_hdr_bits { +u8 status[0x8 ]; +u8 reserved_at_8[0x18 ]; + +u8 syndrome[0x20 ]; + +u8 obj_id[0x20 ]; + +u8 reserved_at_60[0x20 ]; +}; + +struct mlx5_ifc_umem_bits { +u8 modify_field_select[0x40 ]; + +u8 reserved_at_40[0x5b ]; +u8 log_page_size[0x5 ]; + +u8 page_offset[0x20 ]; + +u8 num_of_mtt[0x40 ]; + +struct mlx5_ifc_mtt_bits mtt[0 ]; +}; + +struct mlx5_ifc_uctx_bits { +u8 modify_field_select[0x40 ]; + +u8 reserved_at_40[0x1c0 ]; +}; + +struct mlx5_ifc_create_umem_in_bits { +struct mlx5_ifc_general_obj_in_cmd_hdr_bits hdr; +struct mlx5_ifc_umem_bits umem; +}; + +struct mlx5_ifc_create_uctx_in_bits { +struct mlx5_ifc_general_obj_in_cmd_hdr_bits hdr; +struct mlx5_ifc_uctx_bits uctx; +}; +#endif /* MLX5_IFC_H */
Signature · 1 line
2.14.4
PATCH v2 11/20 IB/mlx5: Introduce DEVX
In reply to Leon RomanovskyFrom: Yishai Hadas <[email protected]>
Introduce DEVX to enable direct device commands in downstream patches from this series.
In that mode of work the firmware manages the isolation between processes' resources and as such a DEVX user id is created and assigned to the given user context upon allocation request.
A capability check is done to make sure that this feature is really supported by the firmware prior to creating the DEVX user id.
--- drivers/infiniband/hw/mlx5/Makefile | 1 + drivers/infiniband/hw/mlx5/devx.c | 58 +++++++++++++++++++++++++++ drivers/infiniband/hw/mlx5/main.c | 24 +++++++++-- drivers/infiniband/hw/mlx5/mlx5_ib.h | 13 ++++++ drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 4 ++ include/linux/mlx5/device.h | 3 ++ include/linux/mlx5/mlx5_ifc.h | 15 ++++++- include/uapi/rdma/mlx5-abi.h | 3 ++ 8 files changed, 117 insertions(+), 4 deletions(-) create mode 100644 drivers/infiniband/hw/mlx5/devx.c
drivers/infiniband/hw/mlx5/Makefile +1 -0
@@ -3,3 +3,4 @@ obj-$(CONFIG_MLX5_INFINIBAND) += mlx5_ib.o mlx5_ib-y := main.o cq.o doorbell.o qp.o mem.o srq.o mr.o ah.o mad.o gsi.o ib_virt.o cmd.o cong.o mlx5_ib-$(CONFIG_INFINIBAND_ON_DEMAND_PAGING) += odp.o mlx5_ib-$(CONFIG_MLX5_ESWITCH) += ib_rep.o +mlx5_ib-$(CONFIG_INFINIBAND_USER_ACCESS) += devx.o
drivers/infiniband/hw/mlx5/devx.c new file +58 -0
58 lines not on this page · raw message
drivers/infiniband/hw/mlx5/main.c +21 -3
@@ -1676,8 +1676,8 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,if (err)return ERR_PTR (err); -if (req.flags) -return ERR_PTR (-EINVAL ); +if (req.flags & ~MLX5_IB_ALLOC_UCTX_DEVX ) +return ERR_PTR (-EOPNOTSUPP );if (req.comp_mask || req.reserved0 || req.reserved1 || req.reserved2)return ERR_PTR (-EOPNOTSUPP );
@@ -1761,6 +1761,18 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, goto out_uars; } +if (req.flags &MLX5_IB_ALLOC_UCTX_DEVX ) { +/* Block DEVX on Infiniband as of SELinux */ +if (mlx5_ib_port_link_layer (ibdev,1 ) !=IB_LINK_LAYER_ETHERNET ) { + err = -EPERM ; + goto out_td; + } + + err =mlx5_ib_devx_create (dev, context); +if (err) + goto out_td; + } +INIT_LIST_HEAD (&context->vma_private_list);mutex_init (&context->vma_private_list_mutex);INIT_LIST_HEAD (&context->db_page_list);
@@ -1821,7 +1833,7 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, err =ib_copy_to_udata (udata, &resp, resp.response_length);if (err) - goto out_td; + goto out_mdev; bfregi->ver = ver; bfregi->num_low_latency_bfregs = req.num_low_latency_bfregs;
@@ -1831,6 +1843,9 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,return &context->ibucontext; +out_mdev: +if (req.flags &MLX5_IB_ALLOC_UCTX_DEVX ) +mlx5_ib_devx_destroy (dev, context); out_td:if (MLX5_CAP_GEN (dev->mdev, log_max_transport_domain))mlx5_ib_dealloc_transport_domain (dev, context->tdn);
@@ -1856,6 +1871,9 @@ static int mlx5_ib_dealloc_ucontext(struct ib_ucontext *ibcontext)struct mlx5_ib_dev *dev =to_mdev (ibcontext->device);struct mlx5_bfreg_info *bfregi; +if (context->devx_uid) +mlx5_ib_devx_destroy (dev, context); + bfregi = &context->bfregi;if (MLX5_CAP_GEN (dev->mdev, log_max_transport_domain))mlx5_ib_dealloc_transport_domain (dev, context->tdn);
drivers/infiniband/hw/mlx5/mlx5_ib.h +13 -0
@@ -143,6 +143,7 @@ struct mlx5_ib_ucontext {u64 lib_caps;DECLARE_BITMAP (dm_pages,MLX5_MAX_MEMIC_PAGES ); +u16 devx_uid; };static inline struct mlx5_ib_ucontext *to_mucontext (struct ib_ucontext *ibucontext)
@@ -1217,6 +1218,18 @@ struct mlx5_core_dev *mlx5_ib_get_native_port_mdev(struct mlx5_ib_dev *dev,void mlx5_ib_put_native_port_mdev (struct mlx5_ib_dev *dev,u8 port_num); +#if IS_ENABLED (CONFIG_INFINIBAND_USER_ACCESS ) +int mlx5_ib_devx_create (struct mlx5_ib_dev *dev, +struct mlx5_ib_ucontext *context); +void mlx5_ib_devx_destroy (struct mlx5_ib_dev *dev, +struct mlx5_ib_ucontext *context); +#else +static inline int +mlx5_ib_devx_create (struct mlx5_ib_dev *dev, +struct mlx5_ib_ucontext *context) {return -EOPNOTSUPP ; }; +static inline void mlx5_ib_devx_destroy (struct mlx5_ib_dev *dev, +struct mlx5_ib_ucontext *context) {} +#endif static inline void init_query_mad (struct ib_smp *mad) { mad->base_version =1 ;
drivers/net/ethernet/mellanox/mlx5/core/cmd.c +4 -0
@@ -310,6 +310,7 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op,case MLX5_CMD_OP_DEALLOC_ENCAP_HEADER :case MLX5_CMD_OP_DEALLOC_MODIFY_HEADER_CONTEXT :case MLX5_CMD_OP_FPGA_DESTROY_QP : +case MLX5_CMD_OP_DESTROY_GENERAL_OBJECT :return MLX5_CMD_STAT_OK ;case MLX5_CMD_OP_QUERY_HCA_CAP :
@@ -427,6 +428,7 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op,case MLX5_CMD_OP_FPGA_MODIFY_QP :case MLX5_CMD_OP_FPGA_QUERY_QP :case MLX5_CMD_OP_FPGA_QUERY_QP_COUNTERS : +case MLX5_CMD_OP_CREATE_GENERAL_OBJECT : *status =MLX5_DRIVER_STATUS_ABORTED ; *synd =MLX5_DRIVER_SYND ;return -EIO ;
@@ -599,6 +601,8 @@ const char *mlx5_command_str(int command)MLX5_COMMAND_STR_CASE (FPGA_QUERY_QP );MLX5_COMMAND_STR_CASE (FPGA_QUERY_QP_COUNTERS );MLX5_COMMAND_STR_CASE (FPGA_DESTROY_QP ); +MLX5_COMMAND_STR_CASE (CREATE_GENERAL_OBJECT ); +MLX5_COMMAND_STR_CASE (DESTROY_GENERAL_OBJECT );default :return "unknown command opcode" ; } }
include/linux/mlx5/device.h +3 -0
@@ -1071,6 +1071,9 @@ enum mlx5_qcam_feature_groups {#define MLX5_CAP_GEN (mdev, cap) \ MLX5_GET(cmd_hca_cap, mdev->caps.hca_cur[MLX5_CAP_GENERAL], cap) +#define MLX5_CAP_GEN_64 (mdev, cap) \ + MLX5_GET64(cmd_hca_cap, mdev->caps.hca_cur[MLX5_CAP_GENERAL], cap) +#define MLX5_CAP_GEN_MAX (mdev, cap) \ MLX5_GET(cmd_hca_cap, mdev->caps.hca_max[MLX5_CAP_GENERAL], cap)
include/linux/mlx5/mlx5_ifc.h +14 -1
@@ -75,6 +75,15 @@ enum { MLX5_SET_HCA_CAP_OP_MOD_ATOMIC = 0x3, }; +enum { +MLX5_GENERAL_OBJ_TYPES_CAP_UCTX = (1ULL <<4 ), +MLX5_GENERAL_OBJ_TYPES_CAP_UMEM = (1ULL <<5 ), +}; + +enum { +MLX5_OBJ_TYPE_UCTX =0x0004 , +}; +enum {MLX5_CMD_OP_QUERY_HCA_CAP =0x100 ,MLX5_CMD_OP_QUERY_ADAPTER =0x101 ,
@@ -242,6 +251,8 @@ enum {MLX5_CMD_OP_FPGA_QUERY_QP =0x962 ,MLX5_CMD_OP_FPGA_DESTROY_QP =0x963 ,MLX5_CMD_OP_FPGA_QUERY_QP_COUNTERS =0x964 , +MLX5_CMD_OP_CREATE_GENERAL_OBJECT =0xa00 , +MLX5_CMD_OP_DESTROY_GENERAL_OBJECT =0xa03 , MLX5_CMD_OP_MAX };
@@ -1113,7 +1124,9 @@ struct mlx5_ifc_cmd_hca_cap_bits {u8 reserved_at_3f8[0x3 ];u8 log_max_current_uc_list[0x5 ]; -u8 reserved_at_400[0x80 ]; +u8 general_obj_types[0x40 ]; + +u8 reserved_at_440[0x40 ];u8 reserved_at_480[0x3 ];u8 log_max_l2_table[0x5 ];
include/uapi/rdma/mlx5-abi.h +3 -0
@@ -76,6 +76,9 @@ enum mlx5_lib_caps { MLX5_LIB_CAP_4K_UAR = (__u64)1 << 0, }; +enum mlx5_ib_alloc_uctx_v2_flags { +MLX5_IB_ALLOC_UCTX_DEVX =1 <<0 , +};struct mlx5_ib_alloc_ucontext_req_v2 {__u32 total_num_bfregs;__u32 num_low_latency_bfregs;
Signature · 1 line
2.14.4
PATCH v2 12/20 IB/core: Introduce DECLARE_UVERBS_GLOBAL_METHODS
In reply to Leon RomanovskyFrom: Yishai Hadas <[email protected]>
Introduce a new macro to be used for global methods on a singleton object.
This macros sets internally the type_attrs to be NULL as such an object can't be created.
Downstream patches from this series will use this macro.
--- include/rdma/uverbs_named_ioctl.h | 4 ++++ include/rdma/uverbs_std_types.h | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-)
include/rdma/uverbs_named_ioctl.h +4 -0
@@ -43,6 +43,7 @@#define _UVERBS_NAME (x, y) _UVERBS_PASTE(x, y)#define UVERBS_METHOD (id) _UVERBS_NAME(UVERBS_MODULE_NAME, _method_##id)#define UVERBS_HANDLER (id) _UVERBS_NAME(UVERBS_MODULE_NAME, _handler_##id) +#define UVERBS_OBJECT (id) _UVERBS_NAME(UVERBS_MOUDLE_NAME, _object_##id)#define DECLARE_UVERBS_NAMED_METHOD (id, ...) \ DECLARE_UVERBS_METHOD(UVERBS_METHOD(id), id, UVERBS_HANDLER(id), ##__VA_ARGS__)
@@ -56,6 +57,9 @@#define DECLARE_UVERBS_NAMED_OBJECT (id, ...) \ DECLARE_UVERBS_OBJECT(UVERBS_OBJECT(id), id, ##__VA_ARGS__) +#define DECLARE_UVERBS_GLOBAL_METHODS (_name, ...) \ + DECLARE_UVERBS_NAMED_OBJECT(_name, NULL, ##__VA_ARGS__) +#define _UVERBS_COMP_NAME (x, y, z) _UVERBS_NAME(_UVERBS_NAME(x, y), z)#define UVERBS_NO_OVERRIDE NULL
include/rdma/uverbs_std_types.h +0 -2
@@ -37,8 +37,6 @@#include <rdma/uverbs_ioctl.h> #include <rdma/ib_user_ioctl_verbs.h> -#define UVERBS_OBJECT (id) uverbs_object_##id -#if IS_ENABLED (CONFIG_INFINIBAND_USER_ACCESS )const struct uverbs_object_tree_def *uverbs_default_get_objects (void );#else
Signature · 1 line
2.14.4
PATCH v2 13/20 IB: Expose ib_ucontext from a given ib_uverbs_file
In reply to Leon RomanovskyFrom: Yishai Hadas <[email protected]>
Drivers that use the IOCTL API may have the ib_uverbs_file and need a way to get the related ib_ucontext from it, this is enabled by this patch.
Downstream patches from this series will use it.
--- drivers/infiniband/core/uverbs_main.c | 6 ++++++ include/rdma/ib_verbs.h | 2 ++ 2 files changed, 8 insertions(+)
drivers/infiniband/core/uverbs_main.c +6 -0
@@ -138,6 +138,12 @@ static int (*uverbs_ex_cmd_table[])(struct ib_uverbs_file *file,static void ib_uverbs_add_one (struct ib_device *device);static void ib_uverbs_remove_one (struct ib_device *device,void *client_data); +struct ib_ucontext *ib_uverbs_get_ucontext (struct ib_uverbs_file *ufile) +{ +return ufile->ucontext; +} +EXPORT_SYMBOL (ib_uverbs_get_ucontext); +int uverbs_dealloc_mw (struct ib_mw *mw) {struct ib_pd *pd = mw->pd;
include/rdma/ib_verbs.h +2 -0
@@ -4107,4 +4107,6 @@ ib_get_vector_affinity(struct ib_device *device, int comp_vector)*/ void rdma_roce_rescan_device (struct ib_device *ibdev); +struct ib_ucontext *ib_uverbs_get_ucontext (struct ib_uverbs_file *ufile); +#endif /* IB_VERBS_H */
Signature · 1 line
2.14.4
PATCH v2 14/20 IB/mlx5: Add support for DEVX general command
In reply to Leon RomanovskyFrom: Yishai Hadas <[email protected]>
Add support to run general firmware command via the DEVX interface.
A command that works on some object (e.g. CQ, WQ, etc.) will be added in next patches while maintaining the required object lock.
--- drivers/infiniband/hw/mlx5/devx.c | 87 ++++++++++++++++++++++++++++++++ include/uapi/rdma/mlx5_user_ioctl_cmds.h | 13 +++++ 2 files changed, 100 insertions(+)
drivers/infiniband/hw/mlx5/devx.c +87 -0
@@ -13,6 +13,14 @@#include <linux/mlx5/fs.h> #include "mlx5_ib.h" +#define UVERBS_MODULE_NAME mlx5_ib +#include <rdma/uverbs_named_ioctl.h> + +static struct mlx5_ib_ucontext *devx_ufile2uctx (struct ib_uverbs_file *file) +{ +return to_mucontext (ib_uverbs_get_ucontext (file)); +} +int mlx5_ib_devx_create (struct mlx5_ib_dev *dev,struct mlx5_ib_ucontext *context) {u32 in[MLX5_ST_SZ_DW (create_uctx_in)] = {0 };
@@ -56,3 +64,82 @@ void mlx5_ib_devx_destroy(struct mlx5_ib_dev *dev,mlx5_cmd_exec (dev->mdev, in,sizeof (in), out,sizeof (out)); } + +static bool devx_is_general_cmd (void *in) +{ +u16 opcode =MLX5_GET (general_obj_in_cmd_hdr, in, opcode); + +switch (opcode) { +case MLX5_CMD_OP_QUERY_HCA_CAP : +case MLX5_CMD_OP_QUERY_VPORT_STATE : +case MLX5_CMD_OP_QUERY_ADAPTER : +case MLX5_CMD_OP_QUERY_ISSI : +case MLX5_CMD_OP_QUERY_NIC_VPORT_CONTEXT : +case MLX5_CMD_OP_QUERY_ROCE_ADDRESS : +case MLX5_CMD_OP_QUERY_VNIC_ENV : +case MLX5_CMD_OP_QUERY_VPORT_COUNTER : +case MLX5_CMD_OP_GET_DROPPED_PACKET_LOG : +case MLX5_CMD_OP_NOP : +case MLX5_CMD_OP_QUERY_CONG_STATUS : +case MLX5_CMD_OP_QUERY_CONG_PARAMS : +case MLX5_CMD_OP_QUERY_CONG_STATISTICS : +return true; +default : +return false; + } +} + +static int UVERBS_HANDLER (MLX5_IB_METHOD_DEVX_OTHER )(struct ib_device *ib_dev, +struct ib_uverbs_file *file, +struct uverbs_attr_bundle *attrs) +{ +struct mlx5_ib_ucontext *c =devx_ufile2uctx (file); +struct mlx5_ib_dev *dev =to_mdev (ib_dev); +void *cmd_in =uverbs_attr_get_alloced_ptr (attrs,MLX5_IB_ATTR_DEVX_OTHER_CMD_IN ); +int cmd_out_len =uverbs_attr_get_len (attrs, +MLX5_IB_ATTR_DEVX_OTHER_CMD_OUT ); +void *cmd_out; +int err; + +if (!c->devx_uid) +return -EPERM ; + +/* Only white list of some general HCA commands are allowed for this method. */ +if (!devx_is_general_cmd (cmd_in)) +return -EINVAL ; + + cmd_out =kvzalloc (cmd_out_len,GFP_KERNEL ); +if (!cmd_out) +return -ENOMEM ; + +MLX5_SET (general_obj_in_cmd_hdr, cmd_in, uid, c->devx_uid); + err =mlx5_cmd_exec (dev->mdev, cmd_in, +uverbs_attr_get_len (attrs,MLX5_IB_ATTR_DEVX_OTHER_CMD_IN ), + cmd_out, cmd_out_len); +if (err) + goto other_cmd_free; + + err =uverbs_copy_to (attrs,MLX5_IB_ATTR_DEVX_OTHER_CMD_OUT , cmd_out, cmd_out_len); + +other_cmd_free: +kvfree (cmd_out); +return err; +} + +static DECLARE_UVERBS_NAMED_METHOD(MLX5_IB_METHOD_DEVX_OTHER, + &UVERBS_ATTR_PTR_IN_SZ(MLX5_IB_ATTR_DEVX_OTHER_CMD_IN, + UVERBS_ATTR_MIN_SIZE(MLX5_ST_SZ_BYTES(general_obj_in_cmd_hdr)), + UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY | + UVERBS_ATTR_SPEC_F_MIN_SZ_OR_ZERO | + UVERBS_ATTR_SPEC_F_ALLOC_AND_COPY)), + &UVERBS_ATTR_PTR_OUT_SZ(MLX5_IB_ATTR_DEVX_OTHER_CMD_OUT, +UVERBS_ATTR_MIN_SIZE (MLX5_ST_SZ_BYTES (general_obj_out_cmd_hdr )), + UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY | + UVERBS_ATTR_SPEC_F_MIN_SZ_OR_ZERO)) +); + +static DECLARE_UVERBS_GLOBAL_METHODS(MLX5_IB_OBJECT_DEVX, + &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_OTHER)); + +static DECLARE_UVERBS_OBJECT_TREE(devx_objects, + &UVERBS_OBJECT(MLX5_IB_OBJECT_DEVX));
include/uapi/rdma/mlx5_user_ioctl_cmds.h +13 -0
@@ -45,4 +45,17 @@ enum mlx5_ib_alloc_dm_attrs { MLX5_IB_ATTR_ALLOC_DM_RESP_PAGE_INDEX, }; +enum mlx5_ib_devx_methods { +MLX5_IB_METHOD_DEVX_OTHER = (1U <<UVERBS_ID_NS_SHIFT ), +}; + +enum mlx5_ib_devx_other_attrs { +MLX5_IB_ATTR_DEVX_OTHER_CMD_IN = (1U <<UVERBS_ID_NS_SHIFT ), +MLX5_IB_ATTR_DEVX_OTHER_CMD_OUT , +}; + +enum mlx5_ib_devx_objects { +MLX5_IB_OBJECT_DEVX = (1U <<UVERBS_ID_NS_SHIFT ), +}; +#endif
Signature · 1 line
2.14.4
PATCH v2 15/20 IB/mlx5: Add obj create and destroy functionality
In reply to Leon RomanovskyFrom: Yishai Hadas <[email protected]>
Add support to create and destroy firmware objects via the DEVX interface.
--- drivers/infiniband/hw/mlx5/devx.c | 332 ++++++++++++++++++++++++++++++- include/uapi/rdma/mlx5_user_ioctl_cmds.h | 16 ++ 2 files changed, 347 insertions(+), 1 deletion(-)
drivers/infiniband/hw/mlx5/devx.c +331 -1
@@ -16,6 +16,14 @@#define UVERBS_MODULE_NAME mlx5_ib#include <rdma/uverbs_named_ioctl.h> +#define MLX5_MAX_DESTROY_INBOX_SIZE_DW MLX5_ST_SZ_DW(delete_fte_in) +struct devx_obj { +struct mlx5_core_dev *mdev; +u32 obj_id; +u32 dinlen;/* destroy inbox length */ +u32 dinbox[MLX5_MAX_DESTROY_INBOX_SIZE_DW ]; +}; +static struct mlx5_ib_ucontext *devx_ufile2uctx (struct ib_uverbs_file *file) {return to_mucontext (ib_uverbs_get_ucontext (file));
@@ -65,6 +73,51 @@ void mlx5_ib_devx_destroy(struct mlx5_ib_dev *dev,mlx5_cmd_exec (dev->mdev, in,sizeof (in), out,sizeof (out)); } +static bool devx_is_obj_create_cmd (const void *in) +{ +u16 opcode =MLX5_GET (general_obj_in_cmd_hdr, in, opcode); + +switch (opcode) { +case MLX5_CMD_OP_CREATE_GENERAL_OBJECT : +case MLX5_CMD_OP_CREATE_MKEY : +case MLX5_CMD_OP_CREATE_CQ : +case MLX5_CMD_OP_ALLOC_PD : +case MLX5_CMD_OP_ALLOC_TRANSPORT_DOMAIN : +case MLX5_CMD_OP_CREATE_RMP : +case MLX5_CMD_OP_CREATE_SQ : +case MLX5_CMD_OP_CREATE_RQ : +case MLX5_CMD_OP_CREATE_RQT : +case MLX5_CMD_OP_CREATE_TIR : +case MLX5_CMD_OP_CREATE_TIS : +case MLX5_CMD_OP_ALLOC_Q_COUNTER : +case MLX5_CMD_OP_CREATE_FLOW_TABLE : +case MLX5_CMD_OP_CREATE_FLOW_GROUP : +case MLX5_CMD_OP_ALLOC_FLOW_COUNTER : +case MLX5_CMD_OP_ALLOC_ENCAP_HEADER : +case MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT : +case MLX5_CMD_OP_CREATE_SCHEDULING_ELEMENT : +case MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT : +case MLX5_CMD_OP_SET_L2_TABLE_ENTRY : +case MLX5_CMD_OP_CREATE_QP : +case MLX5_CMD_OP_CREATE_SRQ : +case MLX5_CMD_OP_CREATE_XRC_SRQ : +case MLX5_CMD_OP_CREATE_DCT : +case MLX5_CMD_OP_CREATE_XRQ : +case MLX5_CMD_OP_ATTACH_TO_MCG : +case MLX5_CMD_OP_ALLOC_XRCD : +return true; +case MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY : + { +u16 op_mod =MLX5_GET (set_fte_in, in, op_mod); +if (op_mod ==0 ) +return true; +return false; + } +default : +return false; + } +} +static bool devx_is_general_cmd (void *in) {u16 opcode =MLX5_GET (general_obj_in_cmd_hdr, in, opcode);
@@ -126,6 +179,256 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OTHER)(struct ib_device *ib_dev,return err; } +static void devx_obj_build_destroy_cmd (void *in,void *out,void *din, +u32 *dinlen, +u32 *obj_id) +{ +u16 obj_type =MLX5_GET (general_obj_in_cmd_hdr, in, obj_type); +u16 uid =MLX5_GET (general_obj_in_cmd_hdr, in, uid); + + *obj_id =MLX5_GET (general_obj_out_cmd_hdr, out, obj_id); + *dinlen =MLX5_ST_SZ_BYTES (general_obj_in_cmd_hdr); + +MLX5_SET (general_obj_in_cmd_hdr, din, obj_id, *obj_id); +MLX5_SET (general_obj_in_cmd_hdr, din, uid, uid); + +switch (MLX5_GET (general_obj_in_cmd_hdr, in, opcode)) { +case MLX5_CMD_OP_CREATE_GENERAL_OBJECT : +MLX5_SET (general_obj_in_cmd_hdr, din, opcode,MLX5_CMD_OP_DESTROY_GENERAL_OBJECT ); +MLX5_SET (general_obj_in_cmd_hdr, din, obj_type, obj_type); +break ; + +case MLX5_CMD_OP_CREATE_MKEY : +MLX5_SET (general_obj_in_cmd_hdr, din, opcode,MLX5_CMD_OP_DESTROY_MKEY ); +break ; +case MLX5_CMD_OP_CREATE_CQ : +MLX5_SET (general_obj_in_cmd_hdr, din, opcode,MLX5_CMD_OP_DESTROY_CQ ); +break ; +case MLX5_CMD_OP_ALLOC_PD : +MLX5_SET (general_obj_in_cmd_hdr, din, opcode,MLX5_CMD_OP_DEALLOC_PD ); +break ; +case MLX5_CMD_OP_ALLOC_TRANSPORT_DOMAIN : +MLX5_SET (general_obj_in_cmd_hdr, din, opcode, +MLX5_CMD_OP_DEALLOC_TRANSPORT_DOMAIN ); +break ; +case MLX5_CMD_OP_CREATE_RMP : +MLX5_SET (general_obj_in_cmd_hdr, din, opcode,MLX5_CMD_OP_DESTROY_RMP ); +break ; +case MLX5_CMD_OP_CREATE_SQ : +MLX5_SET (general_obj_in_cmd_hdr, din, opcode,MLX5_CMD_OP_DESTROY_SQ ); +break ; +case MLX5_CMD_OP_CREATE_RQ : +MLX5_SET (general_obj_in_cmd_hdr, din, opcode,MLX5_CMD_OP_DESTROY_RQ ); +break ; +case MLX5_CMD_OP_CREATE_RQT : +MLX5_SET (general_obj_in_cmd_hdr, din, opcode,MLX5_CMD_OP_DESTROY_RQT ); +break ; +case MLX5_CMD_OP_CREATE_TIR : +MLX5_SET (general_obj_in_cmd_hdr, din, opcode,MLX5_CMD_OP_DESTROY_TIR ); +break ; +case MLX5_CMD_OP_CREATE_TIS : +MLX5_SET (general_obj_in_cmd_hdr, din, opcode,MLX5_CMD_OP_DESTROY_TIS ); +break ; +case MLX5_CMD_OP_ALLOC_Q_COUNTER : +MLX5_SET (general_obj_in_cmd_hdr, din, opcode, +MLX5_CMD_OP_DEALLOC_Q_COUNTER ); +break ; +case MLX5_CMD_OP_CREATE_FLOW_TABLE : + *dinlen =MLX5_ST_SZ_BYTES (destroy_flow_table_in); + *obj_id =MLX5_GET (create_flow_table_out, out, table_id); +MLX5_SET (destroy_flow_table_in, din, other_vport, +MLX5_GET (create_flow_table_in, in, other_vport)); +MLX5_SET (destroy_flow_table_in, din, vport_number, +MLX5_GET (create_flow_table_in, in, vport_number)); +MLX5_SET (destroy_flow_table_in, din, table_type, +MLX5_GET (create_flow_table_in, in, table_type)); +MLX5_SET (destroy_flow_table_in, din, table_id, *obj_id); +MLX5_SET (general_obj_in_cmd_hdr, din, opcode, +MLX5_CMD_OP_DESTROY_FLOW_TABLE ); +break ; +case MLX5_CMD_OP_CREATE_FLOW_GROUP : + *dinlen =MLX5_ST_SZ_BYTES (destroy_flow_group_in); + *obj_id =MLX5_GET (create_flow_group_out, out, group_id); +MLX5_SET (destroy_flow_group_in, din, other_vport, +MLX5_GET (create_flow_group_in, in, other_vport)); +MLX5_SET (destroy_flow_group_in, din, vport_number, +MLX5_GET (create_flow_group_in, in, vport_number)); +MLX5_SET (destroy_flow_group_in, din, table_type, +MLX5_GET (create_flow_group_in, in, table_type)); +MLX5_SET (destroy_flow_group_in, din, table_id, +MLX5_GET (create_flow_group_in, in, table_id)); +MLX5_SET (destroy_flow_group_in, din, group_id, *obj_id); +MLX5_SET (general_obj_in_cmd_hdr, din, opcode, +MLX5_CMD_OP_DESTROY_FLOW_GROUP ); +break ; +case MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY : + *dinlen =MLX5_ST_SZ_BYTES (delete_fte_in); + *obj_id =MLX5_GET (set_fte_in, in, flow_index); +MLX5_SET (delete_fte_in, din, other_vport, +MLX5_GET (set_fte_in, in, other_vport)); +MLX5_SET (delete_fte_in, din, vport_number, +MLX5_GET (set_fte_in, in, vport_number)); +MLX5_SET (delete_fte_in, din, table_type, +MLX5_GET (set_fte_in, in, table_type)); +MLX5_SET (delete_fte_in, din, table_id, +MLX5_GET (set_fte_in, in, table_id)); +MLX5_SET (delete_fte_in, din, flow_index, *obj_id); +MLX5_SET (general_obj_in_cmd_hdr, din, opcode, +MLX5_CMD_OP_DELETE_FLOW_TABLE_ENTRY ); +break ; +case MLX5_CMD_OP_ALLOC_FLOW_COUNTER : +MLX5_SET (general_obj_in_cmd_hdr, din, opcode, +MLX5_CMD_OP_DEALLOC_FLOW_COUNTER ); +break ; +case MLX5_CMD_OP_ALLOC_ENCAP_HEADER : +MLX5_SET (general_obj_in_cmd_hdr, din, opcode, +MLX5_CMD_OP_DEALLOC_ENCAP_HEADER ); +break ; +case MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT : +MLX5_SET (general_obj_in_cmd_hdr, din, opcode, +MLX5_CMD_OP_DEALLOC_MODIFY_HEADER_CONTEXT ); +break ; +case MLX5_CMD_OP_CREATE_SCHEDULING_ELEMENT : + *dinlen =MLX5_ST_SZ_BYTES (destroy_scheduling_element_in); + *obj_id =MLX5_GET (create_scheduling_element_out, out, + scheduling_element_id); +MLX5_SET (destroy_scheduling_element_in, din, + scheduling_hierarchy, +MLX5_GET (create_scheduling_element_in, in, + scheduling_hierarchy)); +MLX5_SET (destroy_scheduling_element_in, din, + scheduling_element_id, *obj_id); +MLX5_SET (general_obj_in_cmd_hdr, din, opcode, +MLX5_CMD_OP_DESTROY_SCHEDULING_ELEMENT ); +break ; +case MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT : + *dinlen =MLX5_ST_SZ_BYTES (delete_vxlan_udp_dport_in); + *obj_id =MLX5_GET (add_vxlan_udp_dport_in, in, vxlan_udp_port); +MLX5_SET (delete_vxlan_udp_dport_in, din, vxlan_udp_port, *obj_id); +MLX5_SET (general_obj_in_cmd_hdr, din, opcode, +MLX5_CMD_OP_DELETE_VXLAN_UDP_DPORT ); +break ; +case MLX5_CMD_OP_SET_L2_TABLE_ENTRY : + *dinlen =MLX5_ST_SZ_BYTES (delete_l2_table_entry_in); + *obj_id =MLX5_GET (set_l2_table_entry_in, in, table_index); +MLX5_SET (delete_l2_table_entry_in, din, table_index, *obj_id); +MLX5_SET (general_obj_in_cmd_hdr, din, opcode, +MLX5_CMD_OP_DELETE_L2_TABLE_ENTRY ); +break ; +case MLX5_CMD_OP_CREATE_QP : +MLX5_SET (general_obj_in_cmd_hdr, din, opcode,MLX5_CMD_OP_DESTROY_QP ); +break ; +case MLX5_CMD_OP_CREATE_SRQ : +MLX5_SET (general_obj_in_cmd_hdr, din, opcode,MLX5_CMD_OP_DESTROY_SRQ ); +break ; +case MLX5_CMD_OP_CREATE_XRC_SRQ : +MLX5_SET (general_obj_in_cmd_hdr, din, opcode, +MLX5_CMD_OP_DESTROY_XRC_SRQ ); +break ; +case MLX5_CMD_OP_CREATE_DCT : +MLX5_SET (general_obj_in_cmd_hdr, din, opcode,MLX5_CMD_OP_DESTROY_DCT ); +break ; +case MLX5_CMD_OP_CREATE_XRQ : +MLX5_SET (general_obj_in_cmd_hdr, din, opcode,MLX5_CMD_OP_DESTROY_XRQ ); +break ; +case MLX5_CMD_OP_ATTACH_TO_MCG : + *dinlen =MLX5_ST_SZ_BYTES (detach_from_mcg_in); +MLX5_SET (detach_from_mcg_in, din, qpn, +MLX5_GET (attach_to_mcg_in, in, qpn)); +memcpy (MLX5_ADDR_OF (detach_from_mcg_in, din, multicast_gid), +MLX5_ADDR_OF (attach_to_mcg_in, in, multicast_gid), +MLX5_FLD_SZ_BYTES (attach_to_mcg_in, multicast_gid)); +MLX5_SET (general_obj_in_cmd_hdr, din, opcode,MLX5_CMD_OP_DETACH_FROM_MCG ); +break ; +case MLX5_CMD_OP_ALLOC_XRCD : +MLX5_SET (general_obj_in_cmd_hdr, din, opcode,MLX5_CMD_OP_DEALLOC_XRCD ); +break ; +default : +/* The entry must match to one of the devx_is_obj_create_cmd */ +WARN_ON (true); +break ; + } +} + +static int devx_obj_cleanup (struct ib_uobject *uobject, +enum rdma_remove_reason why) +{ +u32 out[MLX5_ST_SZ_DW (general_obj_out_cmd_hdr)]; +struct devx_obj *obj = uobject->object; +int ret; + + ret =mlx5_cmd_exec (obj->mdev, obj->dinbox, obj->dinlen, out,sizeof (out)); +if (ret && why ==RDMA_REMOVE_DESTROY ) +return ret; + +kfree (obj); +return ret; +} + +static int UVERBS_HANDLER (MLX5_IB_METHOD_DEVX_OBJ_DESTROY )(struct ib_device *ib_dev, +struct ib_uverbs_file *file, +struct uverbs_attr_bundle *attrs) +{ +return 0 ; +} + +static int UVERBS_HANDLER (MLX5_IB_METHOD_DEVX_OBJ_CREATE )(struct ib_device *ib_dev, +struct ib_uverbs_file *file, +struct uverbs_attr_bundle *attrs) +{ +struct mlx5_ib_ucontext *c =devx_ufile2uctx (file); +struct mlx5_ib_dev *dev =to_mdev (ib_dev); +void *cmd_in =uverbs_attr_get_alloced_ptr (attrs,MLX5_IB_ATTR_DEVX_OBJ_CREATE_CMD_IN ); +int cmd_out_len =uverbs_attr_get_len (attrs, +MLX5_IB_ATTR_DEVX_OBJ_CREATE_CMD_OUT ); +void *cmd_out; +struct ib_uobject *uobj; +struct devx_obj *obj; +int err; + +if (!c->devx_uid) +return -EPERM ; + +if (!devx_is_obj_create_cmd (cmd_in)) +return -EINVAL ; + + obj =kzalloc (sizeof (struct devx_obj ),GFP_KERNEL ); +if (!obj) +return -ENOMEM ; + + cmd_out =kvzalloc (cmd_out_len,GFP_KERNEL ); +if (!cmd_out) { + err = -ENOMEM ; + goto obj_free; + } + +MLX5_SET (general_obj_in_cmd_hdr, cmd_in, uid, c->devx_uid); + err =mlx5_cmd_exec (dev->mdev, cmd_in, +uverbs_attr_get_len (attrs,MLX5_IB_ATTR_DEVX_OBJ_CREATE_CMD_IN ), + cmd_out, cmd_out_len); +if (err) + goto cmd_free; + + uobj =uverbs_attr_get_uobject (attrs,MLX5_IB_ATTR_DEVX_OBJ_CREATE_HANDLE ); + uobj->object = obj; + obj->mdev = dev->mdev; +devx_obj_build_destroy_cmd (cmd_in, cmd_out, obj->dinbox, &obj->dinlen, &obj->obj_id); +WARN_ON (obj->dinlen >MLX5_MAX_DESTROY_INBOX_SIZE_DW *sizeof (u32)); + + err =uverbs_copy_to (attrs,MLX5_IB_ATTR_DEVX_OBJ_CREATE_CMD_OUT , cmd_out, cmd_out_len); +if (err) + goto cmd_free; + +kvfree (cmd_out); +return 0 ; + +cmd_free: +kvfree (cmd_out); +obj_free: +kfree (obj); +return err; +} + static DECLARE_UVERBS_NAMED_METHOD(MLX5_IB_METHOD_DEVX_OTHER, &UVERBS_ATTR_PTR_IN_SZ(MLX5_IB_ATTR_DEVX_OTHER_CMD_IN, UVERBS_ATTR_MIN_SIZE(MLX5_ST_SZ_BYTES(general_obj_in_cmd_hdr)),
@@ -138,8 +441,35 @@ static DECLARE_UVERBS_NAMED_METHOD(MLX5_IB_METHOD_DEVX_OTHER, UVERBS_ATTR_SPEC_F_MIN_SZ_OR_ZERO)) ); +static DECLARE_UVERBS_NAMED_METHOD(MLX5_IB_METHOD_DEVX_OBJ_CREATE, + &UVERBS_ATTR_IDR(MLX5_IB_ATTR_DEVX_OBJ_CREATE_HANDLE, + MLX5_IB_OBJECT_DEVX_OBJ, + UVERBS_ACCESS_NEW, + UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY)), + &UVERBS_ATTR_PTR_IN_SZ(MLX5_IB_ATTR_DEVX_OBJ_CREATE_CMD_IN, + UVERBS_ATTR_MIN_SIZE(MLX5_ST_SZ_BYTES(general_obj_in_cmd_hdr)), + UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY | + UVERBS_ATTR_SPEC_F_MIN_SZ_OR_ZERO | + UVERBS_ATTR_SPEC_F_ALLOC_AND_COPY)), + &UVERBS_ATTR_PTR_OUT_SZ(MLX5_IB_ATTR_DEVX_OBJ_CREATE_CMD_OUT, +UVERBS_ATTR_MIN_SIZE (MLX5_ST_SZ_BYTES (general_obj_out_cmd_hdr )), + UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY | + UVERBS_ATTR_SPEC_F_MIN_SZ_OR_ZERO))); + +static DECLARE_UVERBS_NAMED_METHOD(MLX5_IB_METHOD_DEVX_OBJ_DESTROY, + &UVERBS_ATTR_IDR(MLX5_IB_ATTR_DEVX_OBJ_DESTROY_HANDLE, +MLX5_IB_OBJECT_DEVX_OBJ , +UVERBS_ACCESS_DESTROY , + UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY))); + static DECLARE_UVERBS_GLOBAL_METHODS(MLX5_IB_OBJECT_DEVX, &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_OTHER)); +static DECLARE_UVERBS_NAMED_OBJECT(MLX5_IB_OBJECT_DEVX_OBJ, + &UVERBS_TYPE_ALLOC_IDR(devx_obj_cleanup), + &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_OBJ_CREATE), + &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_OBJ_DESTROY)); + static DECLARE_UVERBS_OBJECT_TREE(devx_objects, - &UVERBS_OBJECT(MLX5_IB_OBJECT_DEVX)); + &UVERBS_OBJECT(MLX5_IB_OBJECT_DEVX), + &UVERBS_OBJECT(MLX5_IB_OBJECT_DEVX_OBJ));
include/uapi/rdma/mlx5_user_ioctl_cmds.h +16 -0
@@ -54,8 +54,24 @@ enum mlx5_ib_devx_other_attrs { MLX5_IB_ATTR_DEVX_OTHER_CMD_OUT, }; +enum mlx5_ib_devx_obj_create_attrs { +MLX5_IB_ATTR_DEVX_OBJ_CREATE_HANDLE = (1U <<UVERBS_ID_NS_SHIFT ), +MLX5_IB_ATTR_DEVX_OBJ_CREATE_CMD_IN , +MLX5_IB_ATTR_DEVX_OBJ_CREATE_CMD_OUT , +}; + +enum mlx5_ib_devx_obj_destroy_attrs { +MLX5_IB_ATTR_DEVX_OBJ_DESTROY_HANDLE = (1U <<UVERBS_ID_NS_SHIFT ), +}; + +enum mlx5_ib_devx_obj_methods { +MLX5_IB_METHOD_DEVX_OBJ_CREATE = (1U <<UVERBS_ID_NS_SHIFT ), +MLX5_IB_METHOD_DEVX_OBJ_DESTROY , +}; +enum mlx5_ib_devx_objects {MLX5_IB_OBJECT_DEVX = (1U <<UVERBS_ID_NS_SHIFT ), +MLX5_IB_OBJECT_DEVX_OBJ , };#endif
Signature · 1 line
2.14.4
PATCH v2 16/20 IB/mlx5: Add DEVX support for modify and query commands
In reply to Leon RomanovskyFrom: Yishai Hadas <[email protected]>
Add support in DEVX for modify and query commands, the required lock is taken (i.e. READ/WRITE) by the KABI infrastructure accordingly.
--- drivers/infiniband/hw/mlx5/devx.c | 348 +++++++++++++++++++++++++- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 5 + include/linux/mlx5/mlx5_ifc.h | 3 + include/uapi/rdma/mlx5_user_ioctl_cmds.h | 14 ++ 4 files changed, 369 insertions(+), 1 deletion(-)
drivers/infiniband/hw/mlx5/devx.c +347 -1
@@ -73,6 +73,161 @@ void mlx5_ib_devx_destroy(struct mlx5_ib_dev *dev,mlx5_cmd_exec (dev->mdev, in,sizeof (in), out,sizeof (out)); } +static int devx_is_valid_obj_id (struct devx_obj *obj,const void *in) +{ +u16 opcode =MLX5_GET (general_obj_in_cmd_hdr, in, opcode); +u32 obj_id; + +switch (opcode) { +case MLX5_CMD_OP_MODIFY_GENERAL_OBJECT : +case MLX5_CMD_OP_QUERY_GENERAL_OBJECT : + obj_id =MLX5_GET (general_obj_in_cmd_hdr, in, obj_id); +break ; +case MLX5_CMD_OP_QUERY_MKEY : + obj_id =MLX5_GET (query_mkey_in, in, mkey_index); +break ; +case MLX5_CMD_OP_QUERY_CQ : + obj_id =MLX5_GET (query_cq_in, in, cqn); +break ; +case MLX5_CMD_OP_MODIFY_CQ : + obj_id =MLX5_GET (modify_cq_in, in, cqn); +break ; +case MLX5_CMD_OP_QUERY_SQ : + obj_id =MLX5_GET (query_sq_in, in, sqn); +break ; +case MLX5_CMD_OP_MODIFY_SQ : + obj_id =MLX5_GET (modify_sq_in, in, sqn); +break ; +case MLX5_CMD_OP_QUERY_RQ : + obj_id =MLX5_GET (query_rq_in, in, rqn); +break ; +case MLX5_CMD_OP_MODIFY_RQ : + obj_id =MLX5_GET (modify_rq_in, in, rqn); +break ; +case MLX5_CMD_OP_QUERY_RMP : + obj_id =MLX5_GET (query_rmp_in, in, rmpn); +break ; +case MLX5_CMD_OP_MODIFY_RMP : + obj_id =MLX5_GET (modify_rmp_in, in, rmpn); +break ; +case MLX5_CMD_OP_QUERY_RQT : + obj_id =MLX5_GET (query_rqt_in, in, rqtn); +break ; +case MLX5_CMD_OP_MODIFY_RQT : + obj_id =MLX5_GET (modify_rqt_in, in, rqtn); +break ; +case MLX5_CMD_OP_QUERY_TIR : + obj_id =MLX5_GET (query_tir_in, in, tirn); +break ; +case MLX5_CMD_OP_MODIFY_TIR : + obj_id =MLX5_GET (modify_tir_in, in, tirn); +break ; +case MLX5_CMD_OP_QUERY_TIS : + obj_id =MLX5_GET (query_tis_in, in, tisn); +break ; +case MLX5_CMD_OP_MODIFY_TIS : + obj_id =MLX5_GET (modify_tis_in, in, tisn); +break ; +case MLX5_CMD_OP_QUERY_FLOW_TABLE : + obj_id =MLX5_GET (query_flow_table_in, in, table_id); +break ; +case MLX5_CMD_OP_MODIFY_FLOW_TABLE : + obj_id =MLX5_GET (modify_flow_table_in, in, table_id); +break ; +case MLX5_CMD_OP_QUERY_FLOW_GROUP : + obj_id =MLX5_GET (query_flow_group_in, in, group_id); +break ; +case MLX5_CMD_OP_QUERY_FLOW_TABLE_ENTRY : + obj_id =MLX5_GET (query_fte_in, in, flow_index); +break ; +case MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY : + obj_id =MLX5_GET (set_fte_in, in, flow_index); +break ; +case MLX5_CMD_OP_QUERY_Q_COUNTER : + obj_id =MLX5_GET (query_q_counter_in, in, counter_set_id); +break ; +case MLX5_CMD_OP_QUERY_FLOW_COUNTER : + obj_id =MLX5_GET (query_flow_counter_in, in, flow_counter_id); +break ; +case MLX5_CMD_OP_QUERY_MODIFY_HEADER_CONTEXT : + obj_id =MLX5_GET (general_obj_in_cmd_hdr, in, obj_id); +break ; +case MLX5_CMD_OP_QUERY_SCHEDULING_ELEMENT : + obj_id =MLX5_GET (query_scheduling_element_in, in, + scheduling_element_id); +break ; +case MLX5_CMD_OP_MODIFY_SCHEDULING_ELEMENT : + obj_id =MLX5_GET (modify_scheduling_element_in, in, + scheduling_element_id); +break ; +case MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT : + obj_id =MLX5_GET (add_vxlan_udp_dport_in, in, vxlan_udp_port); +break ; +case MLX5_CMD_OP_QUERY_L2_TABLE_ENTRY : + obj_id =MLX5_GET (query_l2_table_entry_in, in, table_index); +break ; +case MLX5_CMD_OP_SET_L2_TABLE_ENTRY : + obj_id =MLX5_GET (set_l2_table_entry_in, in, table_index); +break ; +case MLX5_CMD_OP_QUERY_QP : + obj_id =MLX5_GET (query_qp_in, in, qpn); +break ; +case MLX5_CMD_OP_RST2INIT_QP : + obj_id =MLX5_GET (rst2init_qp_in, in, qpn); +break ; +case MLX5_CMD_OP_INIT2RTR_QP : + obj_id =MLX5_GET (init2rtr_qp_in, in, qpn); +break ; +case MLX5_CMD_OP_RTR2RTS_QP : + obj_id =MLX5_GET (rtr2rts_qp_in, in, qpn); +break ; +case MLX5_CMD_OP_RTS2RTS_QP : + obj_id =MLX5_GET (rts2rts_qp_in, in, qpn); +break ; +case MLX5_CMD_OP_SQERR2RTS_QP : + obj_id =MLX5_GET (sqerr2rts_qp_in, in, qpn); +break ; +case MLX5_CMD_OP_2ERR_QP : + obj_id =MLX5_GET (qp_2err_in, in, qpn); +break ; +case MLX5_CMD_OP_2RST_QP : + obj_id =MLX5_GET (qp_2rst_in, in, qpn); +break ; +case MLX5_CMD_OP_QUERY_DCT : + obj_id =MLX5_GET (query_dct_in, in, dctn); +break ; +case MLX5_CMD_OP_QUERY_XRQ : + obj_id =MLX5_GET (query_xrq_in, in, xrqn); +break ; +case MLX5_CMD_OP_QUERY_XRC_SRQ : + obj_id =MLX5_GET (query_xrc_srq_in, in, xrc_srqn); +break ; +case MLX5_CMD_OP_ARM_XRC_SRQ : + obj_id =MLX5_GET (arm_xrc_srq_in, in, xrc_srqn); +break ; +case MLX5_CMD_OP_QUERY_SRQ : + obj_id =MLX5_GET (query_srq_in, in, srqn); +break ; +case MLX5_CMD_OP_ARM_RQ : + obj_id =MLX5_GET (arm_rq_in, in, srq_number); +break ; +case MLX5_CMD_OP_DRAIN_DCT : +case MLX5_CMD_OP_ARM_DCT_FOR_KEY_VIOLATION : + obj_id =MLX5_GET (drain_dct_in, in, dctn); +break ; +case MLX5_CMD_OP_ARM_XRQ : + obj_id =MLX5_GET (arm_xrq_in, in, xrqn); +break ; +default : +return false; + } + +if (obj_id == obj->obj_id) +return true; + +return false; +} +static bool devx_is_obj_create_cmd (const void *in) {u16 opcode =MLX5_GET (general_obj_in_cmd_hdr, in, opcode);
@@ -118,6 +273,82 @@ static bool devx_is_obj_create_cmd(const void *in) } } +static bool devx_is_obj_modify_cmd (const void *in) +{ +u16 opcode =MLX5_GET (general_obj_in_cmd_hdr, in, opcode); + +switch (opcode) { +case MLX5_CMD_OP_MODIFY_GENERAL_OBJECT : +case MLX5_CMD_OP_MODIFY_CQ : +case MLX5_CMD_OP_MODIFY_RMP : +case MLX5_CMD_OP_MODIFY_SQ : +case MLX5_CMD_OP_MODIFY_RQ : +case MLX5_CMD_OP_MODIFY_RQT : +case MLX5_CMD_OP_MODIFY_TIR : +case MLX5_CMD_OP_MODIFY_TIS : +case MLX5_CMD_OP_MODIFY_FLOW_TABLE : +case MLX5_CMD_OP_MODIFY_SCHEDULING_ELEMENT : +case MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT : +case MLX5_CMD_OP_SET_L2_TABLE_ENTRY : +case MLX5_CMD_OP_RST2INIT_QP : +case MLX5_CMD_OP_INIT2RTR_QP : +case MLX5_CMD_OP_RTR2RTS_QP : +case MLX5_CMD_OP_RTS2RTS_QP : +case MLX5_CMD_OP_SQERR2RTS_QP : +case MLX5_CMD_OP_2ERR_QP : +case MLX5_CMD_OP_2RST_QP : +case MLX5_CMD_OP_ARM_XRC_SRQ : +case MLX5_CMD_OP_ARM_RQ : +case MLX5_CMD_OP_DRAIN_DCT : +case MLX5_CMD_OP_ARM_DCT_FOR_KEY_VIOLATION : +case MLX5_CMD_OP_ARM_XRQ : +return true; +case MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY : + { +u16 op_mod =MLX5_GET (set_fte_in, in, op_mod); + +if (op_mod ==1 ) +return true; +return false; + } +default : +return false; + } +} + +static bool devx_is_obj_query_cmd (const void *in) +{ +u16 opcode =MLX5_GET (general_obj_in_cmd_hdr, in, opcode); + +switch (opcode) { +case MLX5_CMD_OP_QUERY_GENERAL_OBJECT : +case MLX5_CMD_OP_QUERY_MKEY : +case MLX5_CMD_OP_QUERY_CQ : +case MLX5_CMD_OP_QUERY_RMP : +case MLX5_CMD_OP_QUERY_SQ : +case MLX5_CMD_OP_QUERY_RQ : +case MLX5_CMD_OP_QUERY_RQT : +case MLX5_CMD_OP_QUERY_TIR : +case MLX5_CMD_OP_QUERY_TIS : +case MLX5_CMD_OP_QUERY_Q_COUNTER : +case MLX5_CMD_OP_QUERY_FLOW_TABLE : +case MLX5_CMD_OP_QUERY_FLOW_GROUP : +case MLX5_CMD_OP_QUERY_FLOW_TABLE_ENTRY : +case MLX5_CMD_OP_QUERY_FLOW_COUNTER : +case MLX5_CMD_OP_QUERY_MODIFY_HEADER_CONTEXT : +case MLX5_CMD_OP_QUERY_SCHEDULING_ELEMENT : +case MLX5_CMD_OP_QUERY_L2_TABLE_ENTRY : +case MLX5_CMD_OP_QUERY_QP : +case MLX5_CMD_OP_QUERY_SRQ : +case MLX5_CMD_OP_QUERY_XRC_SRQ : +case MLX5_CMD_OP_QUERY_DCT : +case MLX5_CMD_OP_QUERY_XRQ : +return true; +default : +return false; + } +} +static bool devx_is_general_cmd (void *in) {u16 opcode =MLX5_GET (general_obj_in_cmd_hdr, in, opcode);
@@ -429,6 +660,89 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_CREATE)(struct ib_device *ib_dreturn err; } +static int UVERBS_HANDLER (MLX5_IB_METHOD_DEVX_OBJ_MODIFY )(struct ib_device *ib_dev, +struct ib_uverbs_file *file, +struct uverbs_attr_bundle *attrs) +{ +struct mlx5_ib_ucontext *c =devx_ufile2uctx (file); +struct mlx5_ib_dev *dev =to_mdev (ib_dev); +void *cmd_in =uverbs_attr_get_alloced_ptr (attrs,MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_IN ); +int cmd_out_len =uverbs_attr_get_len (attrs, +MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_OUT ); +struct ib_uobject *uobj =uverbs_attr_get_uobject (attrs, +MLX5_IB_ATTR_DEVX_OBJ_MODIFY_HANDLE ); +void *cmd_out; +int err; + +if (!c->devx_uid) +return -EPERM ; + +if (!devx_is_obj_modify_cmd (cmd_in)) +return -EINVAL ; + +if (!devx_is_valid_obj_id (uobj->object, cmd_in)) +return -EINVAL ; + + cmd_out =kvzalloc (cmd_out_len,GFP_KERNEL ); +if (!cmd_out) +return -ENOMEM ; + +MLX5_SET (general_obj_in_cmd_hdr, cmd_in, uid, c->devx_uid); + err =mlx5_cmd_exec (dev->mdev, cmd_in, +uverbs_attr_get_len (attrs,MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_IN ), + cmd_out, cmd_out_len); +if (err) + goto other_cmd_free; + + err =uverbs_copy_to (attrs,MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_OUT , + cmd_out, cmd_out_len); + +other_cmd_free: +kvfree (cmd_out); +return err; +} + +static int UVERBS_HANDLER (MLX5_IB_METHOD_DEVX_OBJ_QUERY )(struct ib_device *ib_dev, +struct ib_uverbs_file *file, +struct uverbs_attr_bundle *attrs) +{ +struct mlx5_ib_ucontext *c =devx_ufile2uctx (file); +struct mlx5_ib_dev *dev =to_mdev (ib_dev); +void *cmd_in =uverbs_attr_get_alloced_ptr (attrs,MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_IN ); +int cmd_out_len =uverbs_attr_get_len (attrs, +MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_OUT ); +struct ib_uobject *uobj =uverbs_attr_get_uobject (attrs, +MLX5_IB_ATTR_DEVX_OBJ_QUERY_HANDLE ); +void *cmd_out; +int err; + +if (!c->devx_uid) +return -EPERM ; + +if (!devx_is_obj_query_cmd (cmd_in)) +return -EINVAL ; + +if (!devx_is_valid_obj_id (uobj->object, cmd_in)) +return -EINVAL ; + + cmd_out =kvzalloc (cmd_out_len,GFP_KERNEL ); +if (!cmd_out) +return -ENOMEM ; + +MLX5_SET (general_obj_in_cmd_hdr, cmd_in, uid, c->devx_uid); + err =mlx5_cmd_exec (dev->mdev, cmd_in, +uverbs_attr_get_len (attrs,MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_IN ), + cmd_out, cmd_out_len); +if (err) + goto other_cmd_free; + + err =uverbs_copy_to (attrs,MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_OUT , cmd_out, cmd_out_len); + +other_cmd_free: +kvfree (cmd_out); +return err; +} + static DECLARE_UVERBS_NAMED_METHOD(MLX5_IB_METHOD_DEVX_OTHER, &UVERBS_ATTR_PTR_IN_SZ(MLX5_IB_ATTR_DEVX_OTHER_CMD_IN, UVERBS_ATTR_MIN_SIZE(MLX5_ST_SZ_BYTES(general_obj_in_cmd_hdr)),
@@ -462,13 +776,45 @@ static DECLARE_UVERBS_NAMED_METHOD(MLX5_IB_METHOD_DEVX_OBJ_DESTROY,UVERBS_ACCESS_DESTROY , UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY))); +static DECLARE_UVERBS_NAMED_METHOD(MLX5_IB_METHOD_DEVX_OBJ_MODIFY, + &UVERBS_ATTR_IDR(MLX5_IB_ATTR_DEVX_OBJ_MODIFY_HANDLE, + MLX5_IB_OBJECT_DEVX_OBJ, + UVERBS_ACCESS_WRITE, + UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY)), + &UVERBS_ATTR_PTR_IN_SZ(MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_IN, + UVERBS_ATTR_MIN_SIZE(MLX5_ST_SZ_BYTES(general_obj_in_cmd_hdr)), + UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY | + UVERBS_ATTR_SPEC_F_MIN_SZ_OR_ZERO | + UVERBS_ATTR_SPEC_F_ALLOC_AND_COPY)), + &UVERBS_ATTR_PTR_OUT_SZ(MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_OUT, +UVERBS_ATTR_MIN_SIZE (MLX5_ST_SZ_BYTES (general_obj_out_cmd_hdr )), + UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY | + UVERBS_ATTR_SPEC_F_MIN_SZ_OR_ZERO))); + +static DECLARE_UVERBS_NAMED_METHOD(MLX5_IB_METHOD_DEVX_OBJ_QUERY, + &UVERBS_ATTR_IDR(MLX5_IB_ATTR_DEVX_OBJ_QUERY_HANDLE, + MLX5_IB_OBJECT_DEVX_OBJ, + UVERBS_ACCESS_READ, + UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY)), + &UVERBS_ATTR_PTR_IN_SZ(MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_IN, + UVERBS_ATTR_MIN_SIZE(MLX5_ST_SZ_BYTES(general_obj_in_cmd_hdr)), + UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY | + UVERBS_ATTR_SPEC_F_MIN_SZ_OR_ZERO | + UVERBS_ATTR_SPEC_F_ALLOC_AND_COPY)), + &UVERBS_ATTR_PTR_OUT_SZ(MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_OUT, +UVERBS_ATTR_MIN_SIZE (MLX5_ST_SZ_BYTES (general_obj_out_cmd_hdr )), + UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY | + UVERBS_ATTR_SPEC_F_MIN_SZ_OR_ZERO))); + static DECLARE_UVERBS_GLOBAL_METHODS(MLX5_IB_OBJECT_DEVX, &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_OTHER)); static DECLARE_UVERBS_NAMED_OBJECT(MLX5_IB_OBJECT_DEVX_OBJ, &UVERBS_TYPE_ALLOC_IDR(devx_obj_cleanup), &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_OBJ_CREATE), - &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_OBJ_DESTROY)); + &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_OBJ_DESTROY), + &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_OBJ_MODIFY), + &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_OBJ_QUERY)); static DECLARE_UVERBS_OBJECT_TREE(devx_objects, &UVERBS_OBJECT(MLX5_IB_OBJECT_DEVX),
drivers/net/ethernet/mellanox/mlx5/core/cmd.c +5 -0
@@ -429,6 +429,8 @@ static int mlx5_internal_err_ret_value(struct mlx5_core_dev *dev, u16 op,case MLX5_CMD_OP_FPGA_QUERY_QP :case MLX5_CMD_OP_FPGA_QUERY_QP_COUNTERS :case MLX5_CMD_OP_CREATE_GENERAL_OBJECT : +case MLX5_CMD_OP_MODIFY_GENERAL_OBJECT : +case MLX5_CMD_OP_QUERY_GENERAL_OBJECT : *status =MLX5_DRIVER_STATUS_ABORTED ; *synd =MLX5_DRIVER_SYND ;return -EIO ;
@@ -603,6 +605,9 @@ const char *mlx5_command_str(int command)MLX5_COMMAND_STR_CASE (FPGA_DESTROY_QP );MLX5_COMMAND_STR_CASE (CREATE_GENERAL_OBJECT );MLX5_COMMAND_STR_CASE (DESTROY_GENERAL_OBJECT ); +MLX5_COMMAND_STR_CASE (MODIFY_GENERAL_OBJECT ); +MLX5_COMMAND_STR_CASE (QUERY_GENERAL_OBJECT ); +MLX5_COMMAND_STR_CASE (QUERY_MODIFY_HEADER_CONTEXT );default :return "unknown command opcode" ; } }
include/linux/mlx5/mlx5_ifc.h +3 -0
@@ -246,12 +246,15 @@ enum {MLX5_CMD_OP_DEALLOC_ENCAP_HEADER =0x93e ,MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT =0x940 ,MLX5_CMD_OP_DEALLOC_MODIFY_HEADER_CONTEXT =0x941 , +MLX5_CMD_OP_QUERY_MODIFY_HEADER_CONTEXT =0x942 ,MLX5_CMD_OP_FPGA_CREATE_QP =0x960 ,MLX5_CMD_OP_FPGA_MODIFY_QP =0x961 ,MLX5_CMD_OP_FPGA_QUERY_QP =0x962 ,MLX5_CMD_OP_FPGA_DESTROY_QP =0x963 ,MLX5_CMD_OP_FPGA_QUERY_QP_COUNTERS =0x964 ,MLX5_CMD_OP_CREATE_GENERAL_OBJECT =0xa00 , +MLX5_CMD_OP_MODIFY_GENERAL_OBJECT =0xa01 , +MLX5_CMD_OP_QUERY_GENERAL_OBJECT =0xa02 ,MLX5_CMD_OP_DESTROY_GENERAL_OBJECT =0xa03 ,MLX5_CMD_OP_MAX };
include/uapi/rdma/mlx5_user_ioctl_cmds.h +14 -0
@@ -64,9 +64,23 @@ enum mlx5_ib_devx_obj_destroy_attrs { MLX5_IB_ATTR_DEVX_OBJ_DESTROY_HANDLE = (1U << UVERBS_ID_NS_SHIFT), }; +enum mlx5_ib_devx_obj_modify_attrs { +MLX5_IB_ATTR_DEVX_OBJ_MODIFY_HANDLE = (1U <<UVERBS_ID_NS_SHIFT ), +MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_IN , +MLX5_IB_ATTR_DEVX_OBJ_MODIFY_CMD_OUT , +}; + +enum mlx5_ib_devx_obj_query_attrs { +MLX5_IB_ATTR_DEVX_OBJ_QUERY_HANDLE = (1U <<UVERBS_ID_NS_SHIFT ), +MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_IN , +MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_OUT , +}; +enum mlx5_ib_devx_obj_methods {MLX5_IB_METHOD_DEVX_OBJ_CREATE = (1U <<UVERBS_ID_NS_SHIFT ),MLX5_IB_METHOD_DEVX_OBJ_DESTROY , +MLX5_IB_METHOD_DEVX_OBJ_MODIFY , +MLX5_IB_METHOD_DEVX_OBJ_QUERY , };enum mlx5_ib_devx_objects {
Signature · 1 line
2.14.4
PATCH v2 17/20 IB/mlx5: Add support for DEVX query UAR
In reply to Leon RomanovskyFrom: Yishai Hadas <[email protected]>
Return a device UAR index for a given user index via the DEVX interface.
Security note:
The hardware protection mechanism works like this: Each device object that is subject to UAR doorbells (QP/SQ/CQ) gets a UAR ID (called uar_page in the device specification manual) upon its creation. Then upon doorbell, hardware fetches the object context for which the doorbell was rang, and validates that the UAR through which the DB was rang matches the UAR ID of the object.
If no match the doorbell is silently ignored by the hardware. Of course, the user cannot ring a doorbell on a UAR that was not mapped to it.
Now in devx, as the devx kernel does not manipulate the QP/SQ/CQ command mailboxes (except tagging them with UID), we expose to the user its UAR ID, so it can embed it in these objects in the expected specification format. So the only thing the user can do is hurt itself by creating a QP/SQ/CQ with a UAR ID other than his, and then in this case other users may ring a doorbell on its objects.
The consequence of that will be that another user can schedule a QP/SQ of the buggy user for execution (just insert it to the hardware schedule queue or arm its CQ for event generation), no further harm is expected.
--- drivers/infiniband/hw/mlx5/devx.c | 53 +++++++++++++++++++++++++++++++- drivers/infiniband/hw/mlx5/mlx5_ib.h | 3 ++ drivers/infiniband/hw/mlx5/qp.c | 9 ++++-- include/uapi/rdma/mlx5_user_ioctl_cmds.h | 6 ++++ 4 files changed, 67 insertions(+), 4 deletions(-)
drivers/infiniband/hw/mlx5/devx.c +52 -1
@@ -373,6 +373,50 @@ static bool devx_is_general_cmd(void *in) } } +/* +*Security note: +* The hardware protection mechanism works like this: Each device object that +* is subject to UAR doorbells (QP/SQ/CQ) gets a UAR ID (called uar_page in +* the device specification manual) upon its creation. Then upon doorbell, +* hardware fetches the object context for which the doorbell was rang, and +* validates that the UAR through which the DB was rang matches the UAR ID +* of the object. +* If no match the doorbell is silently ignored by the hardware. Of course, +* the user cannot ring a doorbell on a UAR that was not mapped to it. +* Now in devx, as the devx kernel does not manipulate the QP/SQ/CQ command +* mailboxes (except tagging them with UID), we expose to the user its UAR +* ID, so it can embed it in these objects in the expected specification +* format. So the only thing the user can do is hurt itself by creating a +* QP/SQ/CQ with a UAR ID other than his, and then in this case other users +* may ring a doorbell on its objects. +* The consequence of that will be that another user can schedule a QP/SQ +* of the buggy user for execution (just insert it to the hardware schedule +* queue or arm its CQ for event generation), no further harm is expected. +*/ +static int UVERBS_HANDLER (MLX5_IB_METHOD_DEVX_QUERY_UAR )(struct ib_device *ib_dev, +struct ib_uverbs_file *file, +struct uverbs_attr_bundle *attrs) +{ +struct mlx5_ib_ucontext *c =devx_ufile2uctx (file); +u32 user_idx; +s32 dev_idx; + +if (uverbs_copy_from (&user_idx, attrs, +MLX5_IB_ATTR_DEVX_QUERY_UAR_USER_IDX )) +return -EFAULT ; + + dev_idx =bfregn_to_uar_index (to_mdev (ib_dev), + &c->bfregi, user_idx, true); +if (dev_idx <0 ) +return dev_idx; + +if (uverbs_copy_to (attrs,MLX5_IB_ATTR_DEVX_QUERY_UAR_DEV_IDX , + &dev_idx,sizeof (dev_idx))) +return -EFAULT ; + +return 0 ; +} +static int UVERBS_HANDLER (MLX5_IB_METHOD_DEVX_OTHER )(struct ib_device *ib_dev,struct ib_uverbs_file *file,struct uverbs_attr_bundle *attrs)
@@ -743,6 +787,12 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_QUERY)(struct ib_device *ib_dereturn err; } +static DECLARE_UVERBS_NAMED_METHOD(MLX5_IB_METHOD_DEVX_QUERY_UAR, + &UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_DEVX_QUERY_UAR_USER_IDX, UVERBS_ATTR_TYPE(u32), + UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY)), + &UVERBS_ATTR_PTR_OUT(MLX5_IB_ATTR_DEVX_QUERY_UAR_DEV_IDX, UVERBS_ATTR_TYPE(u32), + UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY))); + static DECLARE_UVERBS_NAMED_METHOD(MLX5_IB_METHOD_DEVX_OTHER, &UVERBS_ATTR_PTR_IN_SZ(MLX5_IB_ATTR_DEVX_OTHER_CMD_IN, UVERBS_ATTR_MIN_SIZE(MLX5_ST_SZ_BYTES(general_obj_in_cmd_hdr)),
@@ -807,7 +857,8 @@ static DECLARE_UVERBS_NAMED_METHOD(MLX5_IB_METHOD_DEVX_OBJ_QUERY, UVERBS_ATTR_SPEC_F_MIN_SZ_OR_ZERO))); static DECLARE_UVERBS_GLOBAL_METHODS(MLX5_IB_OBJECT_DEVX, - &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_OTHER)); + &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_OTHER), + &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_QUERY_UAR)); static DECLARE_UVERBS_NAMED_OBJECT(MLX5_IB_OBJECT_DEVX_OBJ, &UVERBS_TYPE_ALLOC_IDR(devx_obj_cleanup),
drivers/infiniband/hw/mlx5/mlx5_ib.h +3 -0
@@ -1331,4 +1331,7 @@ static inline int get_num_static_uars(struct mlx5_ib_dev *dev,unsigned long mlx5_ib_get_xlt_emergency_page (void );void mlx5_ib_put_xlt_emergency_page (void ); +int bfregn_to_uar_index (struct mlx5_ib_dev *dev, +struct mlx5_bfreg_info *bfregi,int bfregn, +bool dyn_bfreg);#endif /* MLX5_IB_H */
drivers/infiniband/hw/mlx5/qp.c +6 -3
@@ -641,9 +641,9 @@ static void mlx5_ib_lock_cqs(struct mlx5_ib_cq *send_cq,static void mlx5_ib_unlock_cqs (struct mlx5_ib_cq *send_cq,struct mlx5_ib_cq *recv_cq); -static int bfregn_to_uar_index (struct mlx5_ib_dev *dev, -struct mlx5_bfreg_info *bfregi,int bfregn, -bool dyn_bfreg) +int bfregn_to_uar_index (struct mlx5_ib_dev *dev, +struct mlx5_bfreg_info *bfregi,int bfregn, +bool dyn_bfreg) {int bfregs_per_sys_page;int index_of_sys_page;
@@ -653,6 +653,9 @@ static int bfregn_to_uar_index(struct mlx5_ib_dev *dev,MLX5_NON_FP_BFREGS_PER_UAR ; index_of_sys_page = bfregn / bfregs_per_sys_page; +if (index_of_sys_page >= bfregi->num_sys_pages) +return -EINVAL ; +if (dyn_bfreg) { index_of_sys_page += bfregi->num_static_sys_pages; if (bfregn > bfregi->num_dyn_bfregs ||
include/uapi/rdma/mlx5_user_ioctl_cmds.h +6 -0
@@ -47,6 +47,7 @@ enum mlx5_ib_alloc_dm_attrs {enum mlx5_ib_devx_methods {MLX5_IB_METHOD_DEVX_OTHER = (1U <<UVERBS_ID_NS_SHIFT ), +MLX5_IB_METHOD_DEVX_QUERY_UAR , };enum mlx5_ib_devx_other_attrs {
@@ -60,6 +61,11 @@ enum mlx5_ib_devx_obj_create_attrs { MLX5_IB_ATTR_DEVX_OBJ_CREATE_CMD_OUT, }; +enum mlx5_ib_devx_query_uar_attrs { +MLX5_IB_ATTR_DEVX_QUERY_UAR_USER_IDX = (1U <<UVERBS_ID_NS_SHIFT ), +MLX5_IB_ATTR_DEVX_QUERY_UAR_DEV_IDX , +}; +enum mlx5_ib_devx_obj_destroy_attrs {MLX5_IB_ATTR_DEVX_OBJ_DESTROY_HANDLE = (1U <<UVERBS_ID_NS_SHIFT ), };
Signature · 1 line
2.14.4
PATCH v2 18/20 IB/mlx5: Add DEVX support for memory registration
In reply to Leon RomanovskyFrom: Yishai Hadas <[email protected]>
Add support to register a memory with the firmware via the DEVX interface.
The driver translates a given user address to ib_umem then it will register the physical addresses with the firmware and get a unique id for this registration to be used for this virtual address.
--- drivers/infiniband/hw/mlx5/devx.c | 199 ++++++++++++++++++++++++++++++- include/linux/mlx5/mlx5_ifc.h | 1 + include/uapi/rdma/mlx5_user_ioctl_cmds.h | 18 +++ 3 files changed, 217 insertions(+), 1 deletion(-)
drivers/infiniband/hw/mlx5/devx.c +198 -1
@@ -24,6 +24,22 @@ struct devx_obj {u32 dinbox[MLX5_MAX_DESTROY_INBOX_SIZE_DW ]; }; +struct devx_umem { +struct mlx5_core_dev *mdev; +struct ib_umem *umem; +u32 page_offset; +int page_shift; +int ncont; +u32 dinlen; +u32 dinbox[MLX5_ST_SZ_DW (general_obj_in_cmd_hdr)]; +}; + +struct devx_umem_reg_cmd { +void *in; +u32 inlen; +u32 out[MLX5_ST_SZ_DW (general_obj_out_cmd_hdr)]; +}; +static struct mlx5_ib_ucontext *devx_ufile2uctx (struct ib_uverbs_file *file) {return to_mucontext (ib_uverbs_get_ucontext (file));
@@ -787,6 +803,181 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_DEVX_OBJ_QUERY)(struct ib_device *ib_dereturn err; } +static int devx_umem_get (struct mlx5_ib_dev *dev,struct ib_ucontext *ucontext, +struct uverbs_attr_bundle *attrs, +struct devx_umem *obj) +{ +u64 addr; +size_t size; +int access; +int npages; +int err; +u32 page_mask; + +if (uverbs_copy_from (&addr, attrs,MLX5_IB_ATTR_DEVX_UMEM_REG_ADDR ) || +uverbs_copy_from (&size, attrs,MLX5_IB_ATTR_DEVX_UMEM_REG_LEN ) || +uverbs_copy_from (&access, attrs,MLX5_IB_ATTR_DEVX_UMEM_REG_ACCESS )) +return -EFAULT ; + + err =ib_check_mr_access (access); +if (err) +return err; + + obj->umem =ib_umem_get (ucontext, addr, size, access,0 ); +if (IS_ERR (obj->umem)) +return PTR_ERR (obj->umem); + +mlx5_ib_cont_pages (obj->umem, obj->umem->address, +MLX5_MKEY_PAGE_SHIFT_MASK , &npages, + &obj->page_shift, &obj->ncont,NULL ); + +if (!npages) { +ib_umem_release (obj->umem); +return -EINVAL ; + } + + page_mask = (1 << obj->page_shift) -1 ; + obj->page_offset = obj->umem->address & page_mask; + +return 0 ; +} + +static int devx_umem_reg_cmd_alloc (struct devx_umem *obj, +struct devx_umem_reg_cmd *cmd) +{ + cmd->inlen =MLX5_ST_SZ_BYTES (create_umem_in) + + (MLX5_ST_SZ_BYTES (mtt) * obj->ncont); + cmd->in =kvzalloc (cmd->inlen,GFP_KERNEL ); +return cmd->in ?0 : -ENOMEM ; +} + +static void devx_umem_reg_cmd_free (struct devx_umem_reg_cmd *cmd) +{ +kvfree (cmd->in); +} + +static void devx_umem_reg_cmd_build (struct mlx5_ib_dev *dev, +struct devx_umem *obj, +struct devx_umem_reg_cmd *cmd) +{ +void *umem; +__be64 *mtt; + + umem =MLX5_ADDR_OF (create_umem_in, cmd->in, umem); + mtt = (__be64 *)MLX5_ADDR_OF (umem, umem, mtt); + +MLX5_SET (general_obj_in_cmd_hdr, cmd->in, opcode,MLX5_CMD_OP_CREATE_GENERAL_OBJECT ); +MLX5_SET (general_obj_in_cmd_hdr, cmd->in, obj_type,MLX5_OBJ_TYPE_UMEM ); +MLX5_SET64 (umem, umem, num_of_mtt, obj->ncont); +MLX5_SET (umem, umem, log_page_size, obj->page_shift - +MLX5_ADAPTER_PAGE_SHIFT ); +MLX5_SET (umem, umem, page_offset, obj->page_offset); +mlx5_ib_populate_pas (dev, obj->umem, obj->page_shift, mtt, + (obj->umem->writable ?MLX5_IB_MTT_WRITE :0 ) | +MLX5_IB_MTT_READ ); +} + +static int UVERBS_HANDLER (MLX5_IB_METHOD_DEVX_UMEM_REG )(struct ib_device *ib_dev, +struct ib_uverbs_file *file, +struct uverbs_attr_bundle *attrs) +{ +struct mlx5_ib_ucontext *c =devx_ufile2uctx (file); +struct mlx5_ib_dev *dev =to_mdev (ib_dev); +struct devx_umem_reg_cmd cmd; +struct devx_umem *obj; +struct ib_uobject *uobj; +u32 obj_id; +int err; + +if (!c->devx_uid) +return -EPERM ; + + uobj =uverbs_attr_get_uobject (attrs,MLX5_IB_ATTR_DEVX_UMEM_REG_HANDLE ); + obj =kzalloc (sizeof (struct devx_umem ),GFP_KERNEL ); +if (!obj) +return -ENOMEM ; + + err =devx_umem_get (dev, &c->ibucontext, attrs, obj); +if (err) + goto err_obj_free; + + err =devx_umem_reg_cmd_alloc (obj, &cmd); +if (err) + goto err_umem_release; + +devx_umem_reg_cmd_build (dev, obj, &cmd); + +MLX5_SET (general_obj_in_cmd_hdr, cmd.in, uid, c->devx_uid); + err =mlx5_cmd_exec (dev->mdev, cmd.in, cmd.inlen, cmd.out, +sizeof (cmd.out)); +if (err) + goto err_umem_reg_cmd_free; + + obj->mdev = dev->mdev; + uobj->object = obj; +devx_obj_build_destroy_cmd (cmd.in, cmd.out, obj->dinbox, &obj->dinlen, &obj_id); + err =uverbs_copy_to (attrs,MLX5_IB_ATTR_DEVX_UMEM_REG_OUT_ID , &obj_id,sizeof (obj_id)); +if (err) + goto err_umem_destroy; + +devx_umem_reg_cmd_free (&cmd); + +return 0 ; + +err_umem_destroy: +mlx5_cmd_exec (obj->mdev, obj->dinbox, obj->dinlen, cmd.out,sizeof (cmd.out)); +err_umem_reg_cmd_free: +devx_umem_reg_cmd_free (&cmd); +err_umem_release: +ib_umem_release (obj->umem); +err_obj_free: +kfree (obj); +return err; +} + +static int UVERBS_HANDLER (MLX5_IB_METHOD_DEVX_UMEM_DEREG )(struct ib_device *ib_dev, +struct ib_uverbs_file *file, +struct uverbs_attr_bundle *attrs) +{ +return 0 ; +} + +static int devx_umem_cleanup (struct ib_uobject *uobject, +enum rdma_remove_reason why) +{ +struct devx_umem *obj = uobject->object; +u32 out[MLX5_ST_SZ_DW (general_obj_out_cmd_hdr)]; +int err; + + err =mlx5_cmd_exec (obj->mdev, obj->dinbox, obj->dinlen, out,sizeof (out)); +if (err && why ==RDMA_REMOVE_DESTROY ) +return err; + +ib_umem_release (obj->umem); +kfree (obj); +return 0 ; +} + +static DECLARE_UVERBS_NAMED_METHOD(MLX5_IB_METHOD_DEVX_UMEM_REG, + &UVERBS_ATTR_IDR(MLX5_IB_ATTR_DEVX_UMEM_REG_HANDLE, + MLX5_IB_OBJECT_DEVX_UMEM, + UVERBS_ACCESS_NEW, + UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY)), + &UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_DEVX_UMEM_REG_ADDR, UVERBS_ATTR_TYPE(u64), + UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY)), + &UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_DEVX_UMEM_REG_LEN, UVERBS_ATTR_TYPE(u64), + UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY)), + &UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_DEVX_UMEM_REG_ACCESS, UVERBS_ATTR_TYPE(u32), + UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY)), + &UVERBS_ATTR_PTR_OUT(MLX5_IB_ATTR_DEVX_UMEM_REG_OUT_ID, UVERBS_ATTR_TYPE(u32), + UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY))); + +static DECLARE_UVERBS_NAMED_METHOD(MLX5_IB_METHOD_DEVX_UMEM_DEREG, + &UVERBS_ATTR_IDR(MLX5_IB_ATTR_DEVX_UMEM_DEREG_HANDLE, +MLX5_IB_OBJECT_DEVX_UMEM , +UVERBS_ACCESS_DESTROY , + UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY))); + static DECLARE_UVERBS_NAMED_METHOD(MLX5_IB_METHOD_DEVX_QUERY_UAR, &UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_DEVX_QUERY_UAR_USER_IDX, UVERBS_ATTR_TYPE(u32), UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY)),
@@ -867,6 +1058,12 @@ static DECLARE_UVERBS_NAMED_OBJECT(MLX5_IB_OBJECT_DEVX_OBJ, &UVERBS_METHOD (MLX5_IB_METHOD_DEVX_OBJ_MODIFY ), &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_OBJ_QUERY)); +static DECLARE_UVERBS_NAMED_OBJECT(MLX5_IB_OBJECT_DEVX_UMEM, + &UVERBS_TYPE_ALLOC_IDR(devx_umem_cleanup), + &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_UMEM_REG), + &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_UMEM_DEREG)); + static DECLARE_UVERBS_OBJECT_TREE(devx_objects, &UVERBS_OBJECT(MLX5_IB_OBJECT_DEVX), - &UVERBS_OBJECT(MLX5_IB_OBJECT_DEVX_OBJ)); + &UVERBS_OBJECT(MLX5_IB_OBJECT_DEVX_OBJ), + &UVERBS_OBJECT(MLX5_IB_OBJECT_DEVX_UMEM));
include/linux/mlx5/mlx5_ifc.h +1 -0
@@ -82,6 +82,7 @@ enum {enum {MLX5_OBJ_TYPE_UCTX =0x0004 , +MLX5_OBJ_TYPE_UMEM =0x0005 , };enum {
include/uapi/rdma/mlx5_user_ioctl_cmds.h +18 -0
@@ -89,9 +89,27 @@ enum mlx5_ib_devx_obj_methods { MLX5_IB_METHOD_DEVX_OBJ_QUERY, }; +enum mlx5_ib_devx_umem_reg_attrs { +MLX5_IB_ATTR_DEVX_UMEM_REG_HANDLE = (1U <<UVERBS_ID_NS_SHIFT ), +MLX5_IB_ATTR_DEVX_UMEM_REG_ADDR , +MLX5_IB_ATTR_DEVX_UMEM_REG_LEN , +MLX5_IB_ATTR_DEVX_UMEM_REG_ACCESS , +MLX5_IB_ATTR_DEVX_UMEM_REG_OUT_ID , +}; + +enum mlx5_ib_devx_umem_dereg_attrs { +MLX5_IB_ATTR_DEVX_UMEM_DEREG_HANDLE = (1U <<UVERBS_ID_NS_SHIFT ), +}; + +enum mlx5_ib_devx_umem_methods { +MLX5_IB_METHOD_DEVX_UMEM_REG = (1U <<UVERBS_ID_NS_SHIFT ), +MLX5_IB_METHOD_DEVX_UMEM_DEREG , +}; +enum mlx5_ib_devx_objects {MLX5_IB_OBJECT_DEVX = (1U <<UVERBS_ID_NS_SHIFT ),MLX5_IB_OBJECT_DEVX_OBJ , +MLX5_IB_OBJECT_DEVX_UMEM , };#endif
Signature · 1 line
2.14.4
PATCH v2 19/20 IB/mlx5: Add DEVX query EQN support
In reply to Leon RomanovskyFrom: Yishai Hadas <[email protected]>
Return the matching device EQN for a given user vector number via the DEVX interface.
Note:
EQs are owned by the kernel and shared by all user processes. Basically, a user CQ can point to any EQ.
The kernel doesn't enforce any such limitation today either.
--- drivers/infiniband/hw/mlx5/devx.c | 34 +++++++++++++++++++++++++++++++- include/uapi/rdma/mlx5_user_ioctl_cmds.h | 6 ++++++ 2 files changed, 39 insertions(+), 1 deletion(-)
drivers/infiniband/hw/mlx5/devx.c +33 -1
@@ -389,6 +389,31 @@ static bool devx_is_general_cmd(void *in) } } +static int UVERBS_HANDLER (MLX5_IB_METHOD_DEVX_QUERY_EQN )(struct ib_device *ib_dev, +struct ib_uverbs_file *file, +struct uverbs_attr_bundle *attrs) +{ +struct mlx5_ib_dev *dev =to_mdev (ib_dev); +int user_vector; +int dev_eqn; +unsigned int irqn; +int err; + +if (uverbs_copy_from (&user_vector, attrs, +MLX5_IB_ATTR_DEVX_QUERY_EQN_USER_VEC )) +return -EFAULT ; + + err =mlx5_vector2eqn (dev->mdev, user_vector, &dev_eqn, &irqn); +if (err <0 ) +return err; + +if (uverbs_copy_to (attrs,MLX5_IB_ATTR_DEVX_QUERY_EQN_DEV_EQN , + &dev_eqn,sizeof (dev_eqn))) +return -EFAULT ; + +return 0 ; +} +/* *Security note: * The hardware protection mechanism works like this: Each device object that
@@ -978,6 +1003,12 @@ static DECLARE_UVERBS_NAMED_METHOD(MLX5_IB_METHOD_DEVX_UMEM_DEREG,UVERBS_ACCESS_DESTROY , UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY))); +static DECLARE_UVERBS_NAMED_METHOD(MLX5_IB_METHOD_DEVX_QUERY_EQN, + &UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_DEVX_QUERY_EQN_USER_VEC, UVERBS_ATTR_TYPE(u32), + UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY)), + &UVERBS_ATTR_PTR_OUT(MLX5_IB_ATTR_DEVX_QUERY_EQN_DEV_EQN, UVERBS_ATTR_TYPE(u32), + UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY))); + static DECLARE_UVERBS_NAMED_METHOD(MLX5_IB_METHOD_DEVX_QUERY_UAR, &UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_DEVX_QUERY_UAR_USER_IDX, UVERBS_ATTR_TYPE(u32), UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY)),
@@ -1049,7 +1080,8 @@ static DECLARE_UVERBS_NAMED_METHOD(MLX5_IB_METHOD_DEVX_OBJ_QUERY, static DECLARE_UVERBS_GLOBAL_METHODS(MLX5_IB_OBJECT_DEVX, &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_OTHER), - &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_QUERY_UAR)); + &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_QUERY_UAR), + &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_QUERY_EQN)); static DECLARE_UVERBS_NAMED_OBJECT(MLX5_IB_OBJECT_DEVX_OBJ, &UVERBS_TYPE_ALLOC_IDR(devx_obj_cleanup),
include/uapi/rdma/mlx5_user_ioctl_cmds.h +6 -0
@@ -48,6 +48,7 @@ enum mlx5_ib_alloc_dm_attrs {enum mlx5_ib_devx_methods {MLX5_IB_METHOD_DEVX_OTHER = (1U <<UVERBS_ID_NS_SHIFT ),MLX5_IB_METHOD_DEVX_QUERY_UAR , +MLX5_IB_METHOD_DEVX_QUERY_EQN , };enum mlx5_ib_devx_other_attrs {
@@ -82,6 +83,11 @@ enum mlx5_ib_devx_obj_query_attrs { MLX5_IB_ATTR_DEVX_OBJ_QUERY_CMD_OUT, }; +enum mlx5_ib_devx_query_eqn_attrs { +MLX5_IB_ATTR_DEVX_QUERY_EQN_USER_VEC = (1U <<UVERBS_ID_NS_SHIFT ), +MLX5_IB_ATTR_DEVX_QUERY_EQN_DEV_EQN , +}; +enum mlx5_ib_devx_obj_methods {MLX5_IB_METHOD_DEVX_OBJ_CREATE = (1U <<UVERBS_ID_NS_SHIFT ),MLX5_IB_METHOD_DEVX_OBJ_DESTROY ,
Signature · 1 line
2.14.4
PATCH v2 20/20 IB/mlx5: Expose DEVX tree
In reply to Leon RomanovskyFrom: Yishai Hadas <[email protected]>
Expose DEVX tree to be used by upper layers.
--- drivers/infiniband/hw/mlx5/devx.c | 5 +++++ drivers/infiniband/hw/mlx5/main.c | 7 ++++++- drivers/infiniband/hw/mlx5/mlx5_ib.h | 3 +++ 3 files changed, 14 insertions(+), 1 deletion(-)
drivers/infiniband/hw/mlx5/devx.c +5 -0
@@ -1099,3 +1099,8 @@ static DECLARE_UVERBS_OBJECT_TREE(devx_objects, &UVERBS_OBJECT (MLX5_IB_OBJECT_DEVX ), &UVERBS_OBJECT (MLX5_IB_OBJECT_DEVX_OBJ ), &UVERBS_OBJECT(MLX5_IB_OBJECT_DEVX_UMEM)); + +const struct uverbs_object_tree_def *mlx5_ib_get_devx_tree (void ) +{ +return &devx_objects; +}
drivers/infiniband/hw/mlx5/main.c +6 -1
@@ -5290,7 +5290,7 @@ ADD_UVERBS_ATTRIBUTES_SIMPLE(mlx5_ib_flow_action, UVERBS_OBJECT_FLOW_ACTION,UVERBS_ATTR_TYPE (u64), UA_FLAGS(UVERBS_ATTR_SPEC_F_MANDATORY))); -#define NUM_TREES 2 +#define NUM_TREES 3static int populate_specs_root (struct mlx5_ib_dev *dev) {const struct uverbs_object_tree_def *default_root[NUM_TREES +1 ] = {
@@ -5305,6 +5305,11 @@ static int populate_specs_root(struct mlx5_ib_dev *dev) !WARN_ON(num_trees >= ARRAY_SIZE(default_root))) default_root[num_trees++] = &mlx5_ib_dm; +if (MLX5_CAP_GEN_64 (dev->mdev, general_obj_types) & +MLX5_GENERAL_OBJ_TYPES_CAP_UCTX && + !WARN_ON (num_trees >=ARRAY_SIZE (default_root))) + default_root[num_trees++] =mlx5_ib_get_devx_tree (); + dev->ib_dev.specs_root =uverbs_alloc_spec_tree (num_trees, default_root);
drivers/infiniband/hw/mlx5/mlx5_ib.h +3 -0
@@ -1223,12 +1223,15 @@ int mlx5_ib_devx_create(struct mlx5_ib_dev *dev, struct mlx5_ib_ucontext *context);void mlx5_ib_devx_destroy (struct mlx5_ib_dev *dev,struct mlx5_ib_ucontext *context); +const struct uverbs_object_tree_def *mlx5_ib_get_devx_tree (void );#else static inline int mlx5_ib_devx_create (struct mlx5_ib_dev *dev,struct mlx5_ib_ucontext *context) {return -EOPNOTSUPP ; };static inline void mlx5_ib_devx_destroy (struct mlx5_ib_dev *dev,struct mlx5_ib_ucontext *context) {} +static inline const struct uverbs_object_tree_def * +mlx5_ib_get_devx_tree (void ) {return NULL ; }#endif static inline void init_query_mad (struct ib_smp *mad) {
Signature · 1 line
2.14.4
Quoted 3 lines · Leon Romanovsky
Leon Romanovsky (2):
drm/i915: Move u64-to-ptr helpers to general headerkernel.h: Reuseu64_to_ptrmacro to cast__userpointers
I dropped these since they are not needed by this series when using a union.
Quoted 4 lines
Matan Barak (5):
IB/uverbs: Export uverbs idr and fd types IB/uverbs: AddPTR_INattributes that are allocated/copied
automatically
Revised this one, as noted
Quoted 3 lines
IB/uverbs: Add a macro to define a type with no kernel known size IB/uverbs: Allow an empty namespace in
ioctl()framework IB/uverbs: Refactoruverbs_finalize_objects
I put the above in a branch and can apply them if you ack my revisions..
Quoted 2 lines
net/mlx5_core: Prevent warns in dmesg upon firmware commands IB/core: Improveuverbs_cleanup_ucontextalgorithm
I dropped these two (they are linked), need comments addressed and resent.
Quoted 4 lines
Yishai Hadas (13):
net/mlx5: Expose DEVX ifc structures IB/mlx5: Introduce DEVX
IB/core: IntroduceDECLARE_UVERBS_GLOBAL_METHODS
Quoted 8 lines
IB: Expose
ib_ucontextfrom a givenib_uverbs_fileIB/mlx5: Add support for DEVX general command IB/mlx5: Add obj create and destroy functionality IB/mlx5: Add DEVX support for modify and query commands IB/mlx5: Add support for DEVX query UAR IB/mlx5: Add DEVX support for memory registration IB/mlx5: Add DEVX query EQN support
IB/mlx5: Expose DEVX tree
I put these in a branch also and can apply them, but I need the first two patches in the mlx5 core branch first please, thanks.
Since this requires so many core patches I think I prefer to merge the mlx core branch then apply rather merge a branch.
Jason
Quoted 8 lines · Jason Gunthorpe
Quoted 3 lines · Leon Romanovsky
Leon Romanovsky (2):
drm/i915: Move u64-to-ptr helpers to general headerkernel.h: Reuseu64_to_ptrmacro to cast__userpointersI dropped these since they are not needed by this series when using a union.
No problem, it was my idea to reuse existing macro, before it was hard-coded implementation, but union makes it cleaner.
Quoted 7 lines
Quoted 5 lines
Matan Barak (5):
IB/uverbs: Export uverbs idr and fd types IB/uverbs: AddPTR_INattributes that are allocated/copied
automaticallyRevised this one, as noted
Thanks
Quoted 7 lines
Quoted 4 lines
IB/uverbs: Add a macro to define a type with no kernel known size IB/uverbs: Allow an empty namespace in
ioctl()framework IB/uverbs: Refactoruverbs_finalize_objectsI put the above in a branch and can apply them if you ack my revisions..
Except the line "return (void *)attr;", which should be "return ERR_CAST(attr);" everything looks reasonable. I didn't test it, but I'm not worried, we will have enough time to fix if needed.
Quoted 5 lines
Quoted 2 lines
net/mlx5_core: Prevent warns in dmesg upon firmware commands IB/core: Improveuverbs_cleanup_ucontextalgorithmI dropped these two (they are linked), need comments addressed and resent.
They are linked only logically, the second patch will trigger warning which is suppressed by first patch. So actually mlx5-net branch will have only first patch "net/mlx5_core: Prevent warns in dmesg upon firmware commands" and you will apply "IB/core: Improve uverbs_cleanup_ucontext algorithm" in your rdma-next.
Quoted 14 lines
Quoted 13 lines
Yishai Hadas (13):
net/mlx5: Expose DEVX ifc structures
IB/mlx5: Introduce DEVX
IB/core: IntroduceDECLARE_UVERBS_GLOBAL_METHODS
IB: Exposeib_ucontextfrom a givenib_uverbs_fileIB/mlx5: Add support for DEVX general command IB/mlx5: Add obj create and destroy functionality IB/mlx5: Add DEVX support for modify and query commands IB/mlx5: Add support for DEVX query UAR IB/mlx5: Add DEVX support for memory registration IB/mlx5: Add DEVX query EQN support
IB/mlx5: Expose DEVX tree
Quoted 5 lines
I put these in a branch also and can apply them, but I need the first two patches in the mlx5 core branch first please, thanks.
Since this requires so many core patches I think I prefer to merge the mlx core branch then apply rather merge a branch.
So to summarize, I'm applying those three patches to mlx5-next:
* net/mlx5_core: Prevent warns in dmesg upon firmware commands
* net/mlx5: Expose DEVX ifc structures
* IB/mlx5: Introduce DEVX
And resend:
* IB/core: Improve uverbs_cleanup_ucontext algorithm
Thanks
Quoted 2 lines
Jason
Quoted 64 lines · Leon Romanovsky
Quoted 8 lines · Jason Gunthorpe
Quoted 3 lines · Leon Romanovsky
Leon Romanovsky (2):
drm/i915: Move u64-to-ptr helpers to general headerkernel.h: Reuseu64_to_ptrmacro to cast__userpointersI dropped these since they are not needed by this series when using a union.
No problem, it was my idea to reuse existing macro, before it was hard-coded implementation, but union makes it cleaner.
Quoted 7 lines
Quoted 5 lines
Matan Barak (5):
IB/uverbs: Export uverbs idr and fd types IB/uverbs: AddPTR_INattributes that are allocated/copied
automaticallyRevised this one, as noted
Thanks
Quoted 7 lines
Quoted 4 lines
IB/uverbs: Add a macro to define a type with no kernel known size IB/uverbs: Allow an empty namespace in
ioctl()framework IB/uverbs: Refactoruverbs_finalize_objectsI put the above in a branch and can apply them if you ack my revisions..
Except the line "return (void *)attr;", which should be "return
ERR_CAST(attr);" everything looks reasonable. I didn't test it, but I'm not worried, we will have enough time to fix if needed.Quoted 5 lines
Quoted 2 lines
net/mlx5_core: Prevent warns in dmesg upon firmware commands IB/core: Improveuverbs_cleanup_ucontextalgorithmI dropped these two (they are linked), need comments addressed and resent.
They are linked only logically, the second patch will trigger warning which is suppressed by first patch. So actually mlx5-net branch will have only first patch "
net/mlx5_core: Prevent warns in dmesg upon firmware commands" and you will apply "IB/core: Improveuverbs_cleanup_ucontextalgorithm" in your rdma-next.Quoted 17 lines
Quoted 13 lines
Yishai Hadas (13):
net/mlx5: Expose DEVX ifc structures
IB/mlx5: Introduce DEVX
IB/core: IntroduceDECLARE_UVERBS_GLOBAL_METHODS
IB: Exposeib_ucontextfrom a givenib_uverbs_fileIB/mlx5: Add support for DEVX general command IB/mlx5: Add obj create and destroy functionality IB/mlx5: Add DEVX support for modify and query commands IB/mlx5: Add support for DEVX query UAR IB/mlx5: Add DEVX support for memory registration IB/mlx5: Add DEVX query EQN support
IB/mlx5: Expose DEVX treeI put these in a branch also and can apply them, but I need the first two patches in the mlx5 core branch first please, thanks.
Quoted 7 lines
Quoted 2 lines
Since this requires so many core patches I think I prefer to merge the mlx core branch then apply rather merge a branch.
So to summarize, I'm applying those three patches to mlx5-next:
*net/mlx5_core: Prevent warns in dmesg upon firmware commands
* net/mlx5: Expose DEVX ifc structures
* IB/mlx5: Introduce DEVX
Updated mlx5-next with two patches and squashed ifc and commands bits from third commit into second one.
Quoted 4 lines
And resend:
* IB/core: Improveuverbs_cleanup_ucontextalgorithm
Resent.
Quoted 4 lines
Thanks
Quoted 2 lines
Jason