1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 /* 3 * Copyright (c) 2018, Mellanox Technologies inc. All rights reserved. 4 */ 5 6 #include <rdma/uverbs_std_types.h> 7 #include "rdma_core.h" 8 #include "uverbs.h" 9 #include <rdma/uverbs_ioctl.h> 10 #include <rdma/opa_addr.h> 11 12 /* 13 * This ioctl method allows calling any defined write or write_ex 14 * handler. This essentially replaces the hdr/ex_hdr system with the ioctl 15 * marshalling, and brings the non-ex path into the same marshalling as the ex 16 * path. 17 */ 18 static int UVERBS_HANDLER(UVERBS_METHOD_INVOKE_WRITE)( 19 struct uverbs_attr_bundle *attrs) 20 { 21 struct uverbs_api *uapi = attrs->ufile->device->uapi; 22 const struct uverbs_api_write_method *method_elm; 23 u32 cmd; 24 int rc; 25 26 rc = uverbs_get_const(&cmd, attrs, UVERBS_ATTR_WRITE_CMD); 27 if (rc) 28 return rc; 29 30 method_elm = uapi_get_method(uapi, cmd); 31 if (IS_ERR(method_elm)) 32 return PTR_ERR(method_elm); 33 34 uverbs_fill_udata(attrs, &attrs->ucore, UVERBS_ATTR_CORE_IN, 35 UVERBS_ATTR_CORE_OUT); 36 37 if (attrs->ucore.inlen < method_elm->req_size || 38 attrs->ucore.outlen < method_elm->resp_size) 39 return -ENOSPC; 40 41 attrs->uobject = NULL; 42 rc = method_elm->handler(attrs); 43 if (attrs->uobject) 44 uverbs_finalize_object(attrs->uobject, UVERBS_ACCESS_NEW, true, 45 !rc, attrs); 46 return rc; 47 } 48 49 DECLARE_UVERBS_NAMED_METHOD(UVERBS_METHOD_INVOKE_WRITE, 50 UVERBS_ATTR_CONST_IN(UVERBS_ATTR_WRITE_CMD, 51 enum ib_uverbs_write_cmds, 52 UA_MANDATORY), 53 UVERBS_ATTR_PTR_IN(UVERBS_ATTR_CORE_IN, 54 UVERBS_ATTR_MIN_SIZE(sizeof(u32)), 55 UA_OPTIONAL), 56 UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_CORE_OUT, 57 UVERBS_ATTR_MIN_SIZE(0), 58 UA_OPTIONAL), 59 UVERBS_ATTR_UHW()); 60 61 static uint32_t * 62 gather_objects_handle(struct ib_uverbs_file *ufile, 63 const struct uverbs_api_object *uapi_object, 64 struct uverbs_attr_bundle *attrs, 65 ssize_t out_len, 66 u64 *total) 67 { 68 u64 max_count = out_len / sizeof(u32); 69 struct ib_uobject *obj; 70 u64 count = 0; 71 u32 *handles; 72 73 /* Allocated memory that cannot page out where we gather 74 * all object ids under a spin_lock. 75 */ 76 handles = uverbs_zalloc(attrs, out_len); 77 if (IS_ERR(handles)) 78 return handles; 79 80 spin_lock_irq(&ufile->uobjects_lock); 81 list_for_each_entry(obj, &ufile->uobjects, list) { 82 u32 obj_id = obj->id; 83 84 if (obj->uapi_object != uapi_object) 85 continue; 86 87 if (count >= max_count) 88 break; 89 90 handles[count] = obj_id; 91 count++; 92 } 93 spin_unlock_irq(&ufile->uobjects_lock); 94 95 *total = count; 96 return handles; 97 } 98 99 static int UVERBS_HANDLER(UVERBS_METHOD_INFO_HANDLES)( 100 struct uverbs_attr_bundle *attrs) 101 { 102 const struct uverbs_api_object *uapi_object; 103 ssize_t out_len; 104 u64 total = 0; 105 u16 object_id; 106 u32 *handles; 107 int ret; 108 109 out_len = uverbs_attr_get_len(attrs, UVERBS_ATTR_INFO_HANDLES_LIST); 110 if (out_len <= 0 || (out_len % sizeof(u32) != 0)) 111 return -EINVAL; 112 113 ret = uverbs_get_const(&object_id, attrs, UVERBS_ATTR_INFO_OBJECT_ID); 114 if (ret) 115 return ret; 116 117 uapi_object = uapi_get_object(attrs->ufile->device->uapi, object_id); 118 if (!uapi_object) 119 return -EINVAL; 120 121 handles = gather_objects_handle(attrs->ufile, uapi_object, attrs, 122 out_len, &total); 123 if (IS_ERR(handles)) 124 return PTR_ERR(handles); 125 126 ret = uverbs_copy_to(attrs, UVERBS_ATTR_INFO_HANDLES_LIST, handles, 127 sizeof(u32) * total); 128 if (ret) 129 goto err; 130 131 ret = uverbs_copy_to(attrs, UVERBS_ATTR_INFO_TOTAL_HANDLES, &total, 132 sizeof(total)); 133 err: 134 return ret; 135 } 136 137 void copy_port_attr_to_resp(struct ib_port_attr *attr, 138 struct ib_uverbs_query_port_resp *resp, 139 struct ib_device *ib_dev, u8 port_num) 140 { 141 resp->state = attr->state; 142 resp->max_mtu = attr->max_mtu; 143 resp->active_mtu = attr->active_mtu; 144 resp->gid_tbl_len = attr->gid_tbl_len; 145 resp->port_cap_flags = make_port_cap_flags(attr); 146 resp->max_msg_sz = attr->max_msg_sz; 147 resp->bad_pkey_cntr = attr->bad_pkey_cntr; 148 resp->qkey_viol_cntr = attr->qkey_viol_cntr; 149 resp->pkey_tbl_len = attr->pkey_tbl_len; 150 151 if (rdma_is_grh_required(ib_dev, port_num)) 152 resp->flags |= IB_UVERBS_QPF_GRH_REQUIRED; 153 154 if (rdma_cap_opa_ah(ib_dev, port_num)) { 155 resp->lid = OPA_TO_IB_UCAST_LID(attr->lid); 156 resp->sm_lid = OPA_TO_IB_UCAST_LID(attr->sm_lid); 157 } else { 158 resp->lid = ib_lid_cpu16(attr->lid); 159 resp->sm_lid = ib_lid_cpu16(attr->sm_lid); 160 } 161 162 resp->lmc = attr->lmc; 163 resp->max_vl_num = attr->max_vl_num; 164 resp->sm_sl = attr->sm_sl; 165 resp->subnet_timeout = attr->subnet_timeout; 166 resp->init_type_reply = attr->init_type_reply; 167 resp->active_width = attr->active_width; 168 resp->active_speed = attr->active_speed; 169 resp->phys_state = attr->phys_state; 170 resp->link_layer = rdma_port_get_link_layer(ib_dev, port_num); 171 } 172 173 static int UVERBS_HANDLER(UVERBS_METHOD_QUERY_PORT)( 174 struct uverbs_attr_bundle *attrs) 175 { 176 struct ib_device *ib_dev; 177 struct ib_port_attr attr = {}; 178 struct ib_uverbs_query_port_resp_ex resp = {}; 179 struct ib_ucontext *ucontext; 180 int ret; 181 u8 port_num; 182 183 ucontext = ib_uverbs_get_ucontext(attrs); 184 if (IS_ERR(ucontext)) 185 return PTR_ERR(ucontext); 186 ib_dev = ucontext->device; 187 188 /* FIXME: Extend the UAPI_DEF_OBJ_NEEDS_FN stuff.. */ 189 if (!ib_dev->ops.query_port) 190 return -EOPNOTSUPP; 191 192 ret = uverbs_get_const(&port_num, attrs, 193 UVERBS_ATTR_QUERY_PORT_PORT_NUM); 194 if (ret) 195 return ret; 196 197 ret = ib_query_port(ib_dev, port_num, &attr); 198 if (ret) 199 return ret; 200 201 copy_port_attr_to_resp(&attr, &resp.legacy_resp, ib_dev, port_num); 202 resp.port_cap_flags2 = attr.port_cap_flags2; 203 204 return uverbs_copy_to_struct_or_zero(attrs, UVERBS_ATTR_QUERY_PORT_RESP, 205 &resp, sizeof(resp)); 206 } 207 208 static int UVERBS_HANDLER(UVERBS_METHOD_GET_CONTEXT)( 209 struct uverbs_attr_bundle *attrs) 210 { 211 u32 num_comp = attrs->ufile->device->num_comp_vectors; 212 u64 core_support = IB_UVERBS_CORE_SUPPORT_OPTIONAL_MR_ACCESS; 213 int ret; 214 215 ret = uverbs_copy_to(attrs, UVERBS_ATTR_GET_CONTEXT_NUM_COMP_VECTORS, 216 &num_comp, sizeof(num_comp)); 217 if (IS_UVERBS_COPY_ERR(ret)) 218 return ret; 219 220 ret = uverbs_copy_to(attrs, UVERBS_ATTR_GET_CONTEXT_CORE_SUPPORT, 221 &core_support, sizeof(core_support)); 222 if (IS_UVERBS_COPY_ERR(ret)) 223 return ret; 224 225 ret = ib_alloc_ucontext(attrs); 226 if (ret) 227 return ret; 228 ret = ib_init_ucontext(attrs); 229 if (ret) { 230 kfree(attrs->context); 231 attrs->context = NULL; 232 return ret; 233 } 234 return 0; 235 } 236 237 static int UVERBS_HANDLER(UVERBS_METHOD_QUERY_CONTEXT)( 238 struct uverbs_attr_bundle *attrs) 239 { 240 u64 core_support = IB_UVERBS_CORE_SUPPORT_OPTIONAL_MR_ACCESS; 241 struct ib_ucontext *ucontext; 242 struct ib_device *ib_dev; 243 u32 num_comp; 244 int ret; 245 246 ucontext = ib_uverbs_get_ucontext(attrs); 247 if (IS_ERR(ucontext)) 248 return PTR_ERR(ucontext); 249 ib_dev = ucontext->device; 250 251 if (!ib_dev->ops.query_ucontext) 252 return -EOPNOTSUPP; 253 254 num_comp = attrs->ufile->device->num_comp_vectors; 255 ret = uverbs_copy_to(attrs, UVERBS_ATTR_QUERY_CONTEXT_NUM_COMP_VECTORS, 256 &num_comp, sizeof(num_comp)); 257 if (IS_UVERBS_COPY_ERR(ret)) 258 return ret; 259 260 ret = uverbs_copy_to(attrs, UVERBS_ATTR_QUERY_CONTEXT_CORE_SUPPORT, 261 &core_support, sizeof(core_support)); 262 if (IS_UVERBS_COPY_ERR(ret)) 263 return ret; 264 265 return ucontext->device->ops.query_ucontext(ucontext, attrs); 266 } 267 268 DECLARE_UVERBS_NAMED_METHOD( 269 UVERBS_METHOD_GET_CONTEXT, 270 UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_GET_CONTEXT_NUM_COMP_VECTORS, 271 UVERBS_ATTR_TYPE(u32), UA_OPTIONAL), 272 UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_GET_CONTEXT_CORE_SUPPORT, 273 UVERBS_ATTR_TYPE(u64), UA_OPTIONAL), 274 UVERBS_ATTR_UHW()); 275 276 DECLARE_UVERBS_NAMED_METHOD( 277 UVERBS_METHOD_QUERY_CONTEXT, 278 UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_QUERY_CONTEXT_NUM_COMP_VECTORS, 279 UVERBS_ATTR_TYPE(u32), UA_OPTIONAL), 280 UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_QUERY_CONTEXT_CORE_SUPPORT, 281 UVERBS_ATTR_TYPE(u64), UA_OPTIONAL)); 282 283 DECLARE_UVERBS_NAMED_METHOD( 284 UVERBS_METHOD_INFO_HANDLES, 285 /* Also includes any device specific object ids */ 286 UVERBS_ATTR_CONST_IN(UVERBS_ATTR_INFO_OBJECT_ID, 287 enum uverbs_default_objects, UA_MANDATORY), 288 UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_INFO_TOTAL_HANDLES, 289 UVERBS_ATTR_TYPE(u32), UA_OPTIONAL), 290 UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_INFO_HANDLES_LIST, 291 UVERBS_ATTR_MIN_SIZE(sizeof(u32)), UA_OPTIONAL)); 292 293 DECLARE_UVERBS_NAMED_METHOD( 294 UVERBS_METHOD_QUERY_PORT, 295 UVERBS_ATTR_CONST_IN(UVERBS_ATTR_QUERY_PORT_PORT_NUM, u8, UA_MANDATORY), 296 UVERBS_ATTR_PTR_OUT( 297 UVERBS_ATTR_QUERY_PORT_RESP, 298 UVERBS_ATTR_STRUCT(struct ib_uverbs_query_port_resp_ex, 299 reserved), 300 UA_MANDATORY)); 301 302 DECLARE_UVERBS_GLOBAL_METHODS(UVERBS_OBJECT_DEVICE, 303 &UVERBS_METHOD(UVERBS_METHOD_GET_CONTEXT), 304 &UVERBS_METHOD(UVERBS_METHOD_INVOKE_WRITE), 305 &UVERBS_METHOD(UVERBS_METHOD_INFO_HANDLES), 306 &UVERBS_METHOD(UVERBS_METHOD_QUERY_PORT), 307 &UVERBS_METHOD(UVERBS_METHOD_QUERY_CONTEXT)); 308 309 const struct uapi_definition uverbs_def_obj_device[] = { 310 UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_DEVICE), 311 {}, 312 }; 313