mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	RDMA/verbs: Store the write/write_ex uapi entry points in the uverbs_api
Bringing all uapi entry points into one place lets us deal with them consistently. For instance the write, write_ex and ioctl paths can be disabled when an API is not supported by the driver. This will replace the uverbs_cmd_table static arrays. Signed-off-by: Jason Gunthorpe <jgg@mellanox.com> Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
This commit is contained in:
		
							parent
							
								
									0bd01f3d09
								
							
						
					
					
						commit
						6884c6c4bd
					
				
					 3 changed files with 238 additions and 8 deletions
				
			
		| 
						 | 
				
			
			@ -136,6 +136,15 @@ struct uverbs_api_ioctl_method {
 | 
			
		|||
	u8 destroy_bkey;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct uverbs_api_write_method {
 | 
			
		||||
	ssize_t (*handler)(struct ib_uverbs_file *file, const char __user *buf,
 | 
			
		||||
			   int in_len, int out_len);
 | 
			
		||||
	int (*handler_ex)(struct ib_uverbs_file *file, struct ib_udata *ucore,
 | 
			
		||||
			  struct ib_udata *uhw);
 | 
			
		||||
	u8 disabled:1;
 | 
			
		||||
	u8 is_ex:1;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct uverbs_api_attr {
 | 
			
		||||
	struct uverbs_attr_spec spec;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -144,6 +153,12 @@ struct uverbs_api {
 | 
			
		|||
	/* radix tree contains struct uverbs_api_* pointers */
 | 
			
		||||
	struct radix_tree_root radix;
 | 
			
		||||
	enum rdma_driver_id driver_id;
 | 
			
		||||
 | 
			
		||||
	unsigned int num_write;
 | 
			
		||||
	unsigned int num_write_ex;
 | 
			
		||||
	struct uverbs_api_write_method notsupp_method;
 | 
			
		||||
	const struct uverbs_api_write_method **write_methods;
 | 
			
		||||
	const struct uverbs_api_write_method **write_ex_methods;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline const struct uverbs_api_object *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,19 @@
 | 
			
		|||
#include "rdma_core.h"
 | 
			
		||||
#include "uverbs.h"
 | 
			
		||||
 | 
			
		||||
static ssize_t ib_uverbs_notsupp(struct ib_uverbs_file *file,
 | 
			
		||||
				 const char __user *buf, int in_len,
 | 
			
		||||
				 int out_len)
 | 
			
		||||
{
 | 
			
		||||
	return -EOPNOTSUPP;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ib_uverbs_ex_notsupp(struct ib_uverbs_file *file,
 | 
			
		||||
				struct ib_udata *ucore, struct ib_udata *uhw)
 | 
			
		||||
{
 | 
			
		||||
	return -EOPNOTSUPP;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void *uapi_add_elm(struct uverbs_api *uapi, u32 key, size_t alloc_size)
 | 
			
		||||
{
 | 
			
		||||
	void *elm;
 | 
			
		||||
| 
						 | 
				
			
			@ -47,6 +60,42 @@ static void *uapi_add_get_elm(struct uverbs_api *uapi, u32 key,
 | 
			
		|||
	return elm;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int uapi_create_write(struct uverbs_api *uapi, struct ib_device *ibdev,
 | 
			
		||||
			     const struct uapi_definition *def, u32 obj_key)
 | 
			
		||||
{
 | 
			
		||||
	struct uverbs_api_write_method *method_elm;
 | 
			
		||||
	u32 method_key = obj_key;
 | 
			
		||||
	bool exists;
 | 
			
		||||
 | 
			
		||||
	if (def->write.is_ex)
 | 
			
		||||
		method_key |= uapi_key_write_ex_method(def->write.command_num);
 | 
			
		||||
	else
 | 
			
		||||
		method_key |= uapi_key_write_method(def->write.command_num);
 | 
			
		||||
 | 
			
		||||
	method_elm = uapi_add_get_elm(uapi, method_key, sizeof(*method_elm),
 | 
			
		||||
				      &exists);
 | 
			
		||||
	if (IS_ERR(method_elm))
 | 
			
		||||
		return PTR_ERR(method_elm);
 | 
			
		||||
 | 
			
		||||
	if (WARN_ON(exists && (def->write.is_ex != method_elm->is_ex ||
 | 
			
		||||
			       method_elm->handler_ex || method_elm->handler)))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	method_elm->is_ex = def->write.is_ex;
 | 
			
		||||
	if (def->write.is_ex) {
 | 
			
		||||
		method_elm->handler_ex = def->func_write_ex;
 | 
			
		||||
 | 
			
		||||
		method_elm->disabled = !(ibdev->uverbs_ex_cmd_mask &
 | 
			
		||||
					 BIT_ULL(def->write.command_num));
 | 
			
		||||
	} else {
 | 
			
		||||
		method_elm->handler = def->func_write;
 | 
			
		||||
 | 
			
		||||
		method_elm->disabled = !(ibdev->uverbs_cmd_mask &
 | 
			
		||||
					 BIT_ULL(def->write.command_num));
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int uapi_merge_method(struct uverbs_api *uapi,
 | 
			
		||||
			     struct uverbs_api_object *obj_elm, u32 obj_key,
 | 
			
		||||
			     const struct uverbs_method_def *method,
 | 
			
		||||
| 
						 | 
				
			
			@ -194,6 +243,7 @@ static int uapi_merge_def(struct uverbs_api *uapi, struct ib_device *ibdev,
 | 
			
		|||
{
 | 
			
		||||
	const struct uapi_definition *def = def_list;
 | 
			
		||||
	u32 cur_obj_key = UVERBS_API_KEY_ERR;
 | 
			
		||||
	bool exists;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	if (!def_list)
 | 
			
		||||
| 
						 | 
				
			
			@ -240,6 +290,23 @@ static int uapi_merge_def(struct uverbs_api *uapi, struct ib_device *ibdev,
 | 
			
		|||
			if (rc)
 | 
			
		||||
				return rc;
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		case UAPI_DEF_OBJECT_START: {
 | 
			
		||||
			struct uverbs_api_object *obj_elm;
 | 
			
		||||
 | 
			
		||||
			cur_obj_key = uapi_key_obj(def->object_start.object_id);
 | 
			
		||||
			obj_elm = uapi_add_get_elm(uapi, cur_obj_key,
 | 
			
		||||
						   sizeof(*obj_elm), &exists);
 | 
			
		||||
			if (IS_ERR(obj_elm))
 | 
			
		||||
				return PTR_ERR(obj_elm);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		case UAPI_DEF_WRITE:
 | 
			
		||||
			rc = uapi_create_write(uapi, ibdev, def, cur_obj_key);
 | 
			
		||||
			if (rc)
 | 
			
		||||
				return rc;
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		WARN_ON(true);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
| 
						 | 
				
			
			@ -266,8 +333,8 @@ uapi_finalize_ioctl_method(struct uverbs_api *uapi,
 | 
			
		|||
		u32 attr_bkey = uapi_bkey_attr(attr_key);
 | 
			
		||||
		u8 type = elm->spec.type;
 | 
			
		||||
 | 
			
		||||
		if (uapi_key_attr_to_method(iter.index) !=
 | 
			
		||||
		    uapi_key_attr_to_method(method_key))
 | 
			
		||||
		if (uapi_key_attr_to_ioctl_method(iter.index) !=
 | 
			
		||||
		    uapi_key_attr_to_ioctl_method(method_key))
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		if (elm->spec.mandatory)
 | 
			
		||||
| 
						 | 
				
			
			@ -309,9 +376,13 @@ uapi_finalize_ioctl_method(struct uverbs_api *uapi,
 | 
			
		|||
 | 
			
		||||
static int uapi_finalize(struct uverbs_api *uapi)
 | 
			
		||||
{
 | 
			
		||||
	const struct uverbs_api_write_method **data;
 | 
			
		||||
	unsigned long max_write_ex = 0;
 | 
			
		||||
	unsigned long max_write = 0;
 | 
			
		||||
	struct radix_tree_iter iter;
 | 
			
		||||
	void __rcu **slot;
 | 
			
		||||
	int rc;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	radix_tree_for_each_slot (slot, &uapi->radix, &iter, 0) {
 | 
			
		||||
		struct uverbs_api_ioctl_method *method_elm =
 | 
			
		||||
| 
						 | 
				
			
			@ -323,6 +394,36 @@ static int uapi_finalize(struct uverbs_api *uapi)
 | 
			
		|||
			if (rc)
 | 
			
		||||
				return rc;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (uapi_key_is_write_method(iter.index))
 | 
			
		||||
			max_write = max(max_write,
 | 
			
		||||
					iter.index & UVERBS_API_ATTR_KEY_MASK);
 | 
			
		||||
		if (uapi_key_is_write_ex_method(iter.index))
 | 
			
		||||
			max_write_ex =
 | 
			
		||||
				max(max_write_ex,
 | 
			
		||||
				    iter.index & UVERBS_API_ATTR_KEY_MASK);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uapi->notsupp_method.handler = ib_uverbs_notsupp;
 | 
			
		||||
	uapi->notsupp_method.handler_ex = ib_uverbs_ex_notsupp;
 | 
			
		||||
	uapi->num_write = max_write + 1;
 | 
			
		||||
	uapi->num_write_ex = max_write_ex + 1;
 | 
			
		||||
	data = kmalloc_array(uapi->num_write + uapi->num_write_ex,
 | 
			
		||||
			     sizeof(*uapi->write_methods), GFP_KERNEL);
 | 
			
		||||
	for (i = 0; i != uapi->num_write + uapi->num_write_ex; i++)
 | 
			
		||||
		data[i] = &uapi->notsupp_method;
 | 
			
		||||
	uapi->write_methods = data;
 | 
			
		||||
	uapi->write_ex_methods = data + uapi->num_write;
 | 
			
		||||
 | 
			
		||||
	radix_tree_for_each_slot (slot, &uapi->radix, &iter, 0) {
 | 
			
		||||
		if (uapi_key_is_write_method(iter.index))
 | 
			
		||||
			uapi->write_methods[iter.index &
 | 
			
		||||
					    UVERBS_API_ATTR_KEY_MASK] =
 | 
			
		||||
				rcu_dereference_protected(*slot, true);
 | 
			
		||||
		if (uapi_key_is_write_ex_method(iter.index))
 | 
			
		||||
			uapi->write_ex_methods[iter.index &
 | 
			
		||||
					       UVERBS_API_ATTR_KEY_MASK] =
 | 
			
		||||
				rcu_dereference_protected(*slot, true);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -365,6 +466,23 @@ static u32 uapi_get_obj_id(struct uverbs_attr_spec *spec)
 | 
			
		|||
	return UVERBS_API_KEY_ERR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void uapi_key_okay(u32 key)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int count = 0;
 | 
			
		||||
 | 
			
		||||
	if (uapi_key_is_object(key))
 | 
			
		||||
		count++;
 | 
			
		||||
	if (uapi_key_is_ioctl_method(key))
 | 
			
		||||
		count++;
 | 
			
		||||
	if (uapi_key_is_write_method(key))
 | 
			
		||||
		count++;
 | 
			
		||||
	if (uapi_key_is_write_ex_method(key))
 | 
			
		||||
		count++;
 | 
			
		||||
	if (uapi_key_is_attr(key))
 | 
			
		||||
		count++;
 | 
			
		||||
	WARN(count != 1, "Bad count %d key=%x", count, key);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void uapi_finalize_disable(struct uverbs_api *uapi)
 | 
			
		||||
{
 | 
			
		||||
	struct radix_tree_iter iter;
 | 
			
		||||
| 
						 | 
				
			
			@ -374,6 +492,8 @@ static void uapi_finalize_disable(struct uverbs_api *uapi)
 | 
			
		|||
 | 
			
		||||
again:
 | 
			
		||||
	radix_tree_for_each_slot (slot, &uapi->radix, &iter, starting_key) {
 | 
			
		||||
		uapi_key_okay(iter.index);
 | 
			
		||||
 | 
			
		||||
		if (uapi_key_is_object(iter.index)) {
 | 
			
		||||
			struct uverbs_api_object *obj_elm =
 | 
			
		||||
				rcu_dereference_protected(*slot, true);
 | 
			
		||||
| 
						 | 
				
			
			@ -400,6 +520,18 @@ static void uapi_finalize_disable(struct uverbs_api *uapi)
 | 
			
		|||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (uapi_key_is_write_method(iter.index) ||
 | 
			
		||||
		    uapi_key_is_write_ex_method(iter.index)) {
 | 
			
		||||
			struct uverbs_api_write_method *method_elm =
 | 
			
		||||
				rcu_dereference_protected(*slot, true);
 | 
			
		||||
 | 
			
		||||
			if (method_elm->disabled) {
 | 
			
		||||
				kfree(method_elm);
 | 
			
		||||
				radix_tree_iter_delete(&uapi->radix, &iter, slot);
 | 
			
		||||
			}
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (uapi_key_is_attr(iter.index)) {
 | 
			
		||||
			struct uverbs_api_attr *attr_elm =
 | 
			
		||||
				rcu_dereference_protected(*slot, true);
 | 
			
		||||
| 
						 | 
				
			
			@ -444,6 +576,7 @@ void uverbs_destroy_api(struct uverbs_api *uapi)
 | 
			
		|||
		return;
 | 
			
		||||
 | 
			
		||||
	uapi_remove_range(uapi, 0, U32_MAX);
 | 
			
		||||
	kfree(uapi->write_methods);
 | 
			
		||||
	kfree(uapi);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -140,6 +140,13 @@ struct uverbs_attr_spec {
 | 
			
		|||
 *
 | 
			
		||||
 * The tree encodes multiple types, and uses a scheme where OBJ_ID,0,0 returns
 | 
			
		||||
 * the object slot, and OBJ_ID,METH_ID,0 and returns the method slot.
 | 
			
		||||
 *
 | 
			
		||||
 * This also encodes the tables for the write() and write() extended commands
 | 
			
		||||
 * using the coding
 | 
			
		||||
 *   OBJ_ID,UVERBS_API_METHOD_IS_WRITE,command #
 | 
			
		||||
 *   OBJ_ID,UVERBS_API_METHOD_IS_WRITE_EX,command_ex #
 | 
			
		||||
 * ie the WRITE path is treated as a special method type in the ioctl
 | 
			
		||||
 * framework.
 | 
			
		||||
 */
 | 
			
		||||
enum uapi_radix_data {
 | 
			
		||||
	UVERBS_API_NS_FLAG = 1U << UVERBS_ID_NS_SHIFT,
 | 
			
		||||
| 
						 | 
				
			
			@ -147,12 +154,16 @@ enum uapi_radix_data {
 | 
			
		|||
	UVERBS_API_ATTR_KEY_BITS = 6,
 | 
			
		||||
	UVERBS_API_ATTR_KEY_MASK = GENMASK(UVERBS_API_ATTR_KEY_BITS - 1, 0),
 | 
			
		||||
	UVERBS_API_ATTR_BKEY_LEN = (1 << UVERBS_API_ATTR_KEY_BITS) - 1,
 | 
			
		||||
	UVERBS_API_WRITE_KEY_NUM = 1 << UVERBS_API_ATTR_KEY_BITS,
 | 
			
		||||
 | 
			
		||||
	UVERBS_API_METHOD_KEY_BITS = 5,
 | 
			
		||||
	UVERBS_API_METHOD_KEY_SHIFT = UVERBS_API_ATTR_KEY_BITS,
 | 
			
		||||
	UVERBS_API_METHOD_KEY_NUM_CORE = 24,
 | 
			
		||||
	UVERBS_API_METHOD_KEY_NUM_DRIVER = (1 << UVERBS_API_METHOD_KEY_BITS) -
 | 
			
		||||
					   UVERBS_API_METHOD_KEY_NUM_CORE,
 | 
			
		||||
	UVERBS_API_METHOD_KEY_NUM_CORE = 22,
 | 
			
		||||
	UVERBS_API_METHOD_IS_WRITE = 30 << UVERBS_API_METHOD_KEY_SHIFT,
 | 
			
		||||
	UVERBS_API_METHOD_IS_WRITE_EX = 31 << UVERBS_API_METHOD_KEY_SHIFT,
 | 
			
		||||
	UVERBS_API_METHOD_KEY_NUM_DRIVER =
 | 
			
		||||
		(UVERBS_API_METHOD_IS_WRITE >> UVERBS_API_METHOD_KEY_SHIFT) -
 | 
			
		||||
		UVERBS_API_METHOD_KEY_NUM_CORE,
 | 
			
		||||
	UVERBS_API_METHOD_KEY_MASK = GENMASK(
 | 
			
		||||
		UVERBS_API_METHOD_KEY_BITS + UVERBS_API_METHOD_KEY_SHIFT - 1,
 | 
			
		||||
		UVERBS_API_METHOD_KEY_SHIFT),
 | 
			
		||||
| 
						 | 
				
			
			@ -205,7 +216,22 @@ static inline __attribute_const__ u32 uapi_key_ioctl_method(u32 id)
 | 
			
		|||
	return id << UVERBS_API_METHOD_KEY_SHIFT;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline __attribute_const__ u32 uapi_key_attr_to_method(u32 attr_key)
 | 
			
		||||
static inline __attribute_const__ u32 uapi_key_write_method(u32 id)
 | 
			
		||||
{
 | 
			
		||||
	if (id >= UVERBS_API_WRITE_KEY_NUM)
 | 
			
		||||
		return UVERBS_API_KEY_ERR;
 | 
			
		||||
	return UVERBS_API_METHOD_IS_WRITE | id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline __attribute_const__ u32 uapi_key_write_ex_method(u32 id)
 | 
			
		||||
{
 | 
			
		||||
	if (id >= UVERBS_API_WRITE_KEY_NUM)
 | 
			
		||||
		return UVERBS_API_KEY_ERR;
 | 
			
		||||
	return UVERBS_API_METHOD_IS_WRITE_EX | id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline __attribute_const__ u32
 | 
			
		||||
uapi_key_attr_to_ioctl_method(u32 attr_key)
 | 
			
		||||
{
 | 
			
		||||
	return attr_key &
 | 
			
		||||
	       (UVERBS_API_OBJ_KEY_MASK | UVERBS_API_METHOD_KEY_MASK);
 | 
			
		||||
| 
						 | 
				
			
			@ -213,10 +239,23 @@ static inline __attribute_const__ u32 uapi_key_attr_to_method(u32 attr_key)
 | 
			
		|||
 | 
			
		||||
static inline __attribute_const__ bool uapi_key_is_ioctl_method(u32 key)
 | 
			
		||||
{
 | 
			
		||||
	return (key & UVERBS_API_METHOD_KEY_MASK) != 0 &&
 | 
			
		||||
	unsigned int method = key & UVERBS_API_METHOD_KEY_MASK;
 | 
			
		||||
 | 
			
		||||
	return method != 0 && method < UVERBS_API_METHOD_IS_WRITE &&
 | 
			
		||||
	       (key & UVERBS_API_ATTR_KEY_MASK) == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline __attribute_const__ bool uapi_key_is_write_method(u32 key)
 | 
			
		||||
{
 | 
			
		||||
	return (key & UVERBS_API_METHOD_KEY_MASK) == UVERBS_API_METHOD_IS_WRITE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline __attribute_const__ bool uapi_key_is_write_ex_method(u32 key)
 | 
			
		||||
{
 | 
			
		||||
	return (key & UVERBS_API_METHOD_KEY_MASK) ==
 | 
			
		||||
	       UVERBS_API_METHOD_IS_WRITE_EX;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline __attribute_const__ u32 uapi_key_attrs_start(u32 ioctl_method_key)
 | 
			
		||||
{
 | 
			
		||||
	/* 0 is the method slot itself */
 | 
			
		||||
| 
						 | 
				
			
			@ -246,9 +285,12 @@ static inline __attribute_const__ u32 uapi_key_attr(u32 id)
 | 
			
		|||
	return id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Only true for ioctl methods */
 | 
			
		||||
static inline __attribute_const__ bool uapi_key_is_attr(u32 key)
 | 
			
		||||
{
 | 
			
		||||
	return (key & UVERBS_API_METHOD_KEY_MASK) != 0 &&
 | 
			
		||||
	unsigned int method = key & UVERBS_API_METHOD_KEY_MASK;
 | 
			
		||||
 | 
			
		||||
	return method != 0 && method < UVERBS_API_METHOD_IS_WRITE &&
 | 
			
		||||
	       (key & UVERBS_API_ATTR_KEY_MASK) != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -298,6 +340,8 @@ struct uverbs_object_def {
 | 
			
		|||
 | 
			
		||||
enum uapi_definition_kind {
 | 
			
		||||
	UAPI_DEF_END = 0,
 | 
			
		||||
	UAPI_DEF_OBJECT_START,
 | 
			
		||||
	UAPI_DEF_WRITE,
 | 
			
		||||
	UAPI_DEF_CHAIN_OBJ_TREE,
 | 
			
		||||
	UAPI_DEF_CHAIN,
 | 
			
		||||
	UAPI_DEF_IS_SUPPORTED_FUNC,
 | 
			
		||||
| 
						 | 
				
			
			@ -315,16 +359,54 @@ struct uapi_definition {
 | 
			
		|||
		struct {
 | 
			
		||||
			u16 object_id;
 | 
			
		||||
		} object_start;
 | 
			
		||||
		struct {
 | 
			
		||||
			u8 is_ex;
 | 
			
		||||
			u16 command_num;
 | 
			
		||||
		} write;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	union {
 | 
			
		||||
		bool (*func_is_supported)(struct ib_device *device);
 | 
			
		||||
		ssize_t (*func_write)(struct ib_uverbs_file *file,
 | 
			
		||||
				      const char __user *buf, int in_len,
 | 
			
		||||
				      int out_len);
 | 
			
		||||
		int (*func_write_ex)(struct ib_uverbs_file *file,
 | 
			
		||||
				     struct ib_udata *ucore,
 | 
			
		||||
				     struct ib_udata *uhw);
 | 
			
		||||
		const struct uapi_definition *chain;
 | 
			
		||||
		const struct uverbs_object_def *chain_obj_tree;
 | 
			
		||||
		size_t needs_fn_offset;
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Define things connected to object_id */
 | 
			
		||||
#define DECLARE_UVERBS_OBJECT(_object_id, ...)                                 \
 | 
			
		||||
	{                                                                      \
 | 
			
		||||
		.kind = UAPI_DEF_OBJECT_START,                                 \
 | 
			
		||||
		.object_start = { .object_id = _object_id },                   \
 | 
			
		||||
	},                                                                     \
 | 
			
		||||
		##__VA_ARGS__
 | 
			
		||||
 | 
			
		||||
/* Use in a var_args of DECLARE_UVERBS_OBJECT */
 | 
			
		||||
#define DECLARE_UVERBS_WRITE(_command_num, _func, ...)                         \
 | 
			
		||||
	{                                                                      \
 | 
			
		||||
		.kind = UAPI_DEF_WRITE,                                        \
 | 
			
		||||
		.scope = UAPI_SCOPE_OBJECT,                                    \
 | 
			
		||||
		.write = { .is_ex = 0, .command_num = _command_num },          \
 | 
			
		||||
		.func_write = _func,                                           \
 | 
			
		||||
	},                                                                     \
 | 
			
		||||
		##__VA_ARGS__
 | 
			
		||||
 | 
			
		||||
/* Use in a var_args of DECLARE_UVERBS_OBJECT */
 | 
			
		||||
#define DECLARE_UVERBS_WRITE_EX(_command_num, _func, ...)                      \
 | 
			
		||||
	{                                                                      \
 | 
			
		||||
		.kind = UAPI_DEF_WRITE,                                        \
 | 
			
		||||
		.scope = UAPI_SCOPE_OBJECT,                                    \
 | 
			
		||||
		.write = { .is_ex = 1, .command_num = _command_num },          \
 | 
			
		||||
		.func_write_ex = _func,                                        \
 | 
			
		||||
	},                                                                     \
 | 
			
		||||
		##__VA_ARGS__
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Object is only supported if the function pointer named ibdev_fn in struct
 | 
			
		||||
 * ib_device is not NULL.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue