1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 /* 3 * Copyright (c) 2018, Mellanox Technologies inc. All rights reserved. 4 * 5 * This software is available to you under a choice of one of two 6 * licenses. You may choose to be licensed under the terms of the GNU 7 * General Public License (GPL) Version 2, available from the file 8 * COPYING in the main directory of this source tree, or the 9 * OpenIB.org BSD license below: 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 15 * - Redistributions of source code must retain the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer. 18 * 19 * - Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials 22 * provided with the distribution. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 * SOFTWARE. 32 */ 33 34 #include "rdma_core.h" 35 #include "uverbs.h" 36 #include <rdma/uverbs_std_types.h> 37 38 static int uverbs_free_counters(struct ib_uobject *uobject, 39 enum rdma_remove_reason why, 40 struct uverbs_attr_bundle *attrs) 41 { 42 struct ib_counters *counters = uobject->object; 43 int ret; 44 45 if (atomic_read(&counters->usecnt)) 46 return -EBUSY; 47 48 ret = counters->device->ops.destroy_counters(counters); 49 if (ret) 50 return ret; 51 kfree(counters); 52 return 0; 53 } 54 55 static int UVERBS_HANDLER(UVERBS_METHOD_COUNTERS_CREATE)( 56 struct uverbs_attr_bundle *attrs) 57 { 58 struct ib_uobject *uobj = uverbs_attr_get_uobject( 59 attrs, UVERBS_ATTR_CREATE_COUNTERS_HANDLE); 60 struct ib_device *ib_dev = attrs->context->device; 61 struct ib_counters *counters; 62 int ret; 63 64 /* 65 * This check should be removed once the infrastructure 66 * have the ability to remove methods from parse tree once 67 * such condition is met. 68 */ 69 if (!ib_dev->ops.create_counters) 70 return -EOPNOTSUPP; 71 72 counters = rdma_zalloc_drv_obj(ib_dev, ib_counters); 73 if (!counters) 74 return -ENOMEM; 75 76 counters->device = ib_dev; 77 counters->uobject = uobj; 78 uobj->object = counters; 79 atomic_set(&counters->usecnt, 0); 80 81 ret = ib_dev->ops.create_counters(counters, attrs); 82 if (ret) 83 kfree(counters); 84 85 return ret; 86 } 87 88 static int UVERBS_HANDLER(UVERBS_METHOD_COUNTERS_READ)( 89 struct uverbs_attr_bundle *attrs) 90 { 91 struct ib_counters_read_attr read_attr = {}; 92 const struct uverbs_attr *uattr; 93 struct ib_counters *counters = 94 uverbs_attr_get_obj(attrs, UVERBS_ATTR_READ_COUNTERS_HANDLE); 95 int ret; 96 97 if (!counters->device->ops.read_counters) 98 return -EOPNOTSUPP; 99 100 if (!atomic_read(&counters->usecnt)) 101 return -EINVAL; 102 103 ret = uverbs_get_flags32(&read_attr.flags, attrs, 104 UVERBS_ATTR_READ_COUNTERS_FLAGS, 105 IB_UVERBS_READ_COUNTERS_PREFER_CACHED); 106 if (ret) 107 return ret; 108 109 uattr = uverbs_attr_get(attrs, UVERBS_ATTR_READ_COUNTERS_BUFF); 110 read_attr.ncounters = uattr->ptr_attr.len / sizeof(u64); 111 read_attr.counters_buff = uverbs_zalloc( 112 attrs, array_size(read_attr.ncounters, sizeof(u64))); 113 if (IS_ERR(read_attr.counters_buff)) 114 return PTR_ERR(read_attr.counters_buff); 115 116 ret = counters->device->ops.read_counters(counters, &read_attr, attrs); 117 if (ret) 118 return ret; 119 120 return uverbs_copy_to(attrs, UVERBS_ATTR_READ_COUNTERS_BUFF, 121 read_attr.counters_buff, 122 read_attr.ncounters * sizeof(u64)); 123 } 124 125 DECLARE_UVERBS_NAMED_METHOD( 126 UVERBS_METHOD_COUNTERS_CREATE, 127 UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_COUNTERS_HANDLE, 128 UVERBS_OBJECT_COUNTERS, 129 UVERBS_ACCESS_NEW, 130 UA_MANDATORY)); 131 132 DECLARE_UVERBS_NAMED_METHOD_DESTROY( 133 UVERBS_METHOD_COUNTERS_DESTROY, 134 UVERBS_ATTR_IDR(UVERBS_ATTR_DESTROY_COUNTERS_HANDLE, 135 UVERBS_OBJECT_COUNTERS, 136 UVERBS_ACCESS_DESTROY, 137 UA_MANDATORY)); 138 139 DECLARE_UVERBS_NAMED_METHOD( 140 UVERBS_METHOD_COUNTERS_READ, 141 UVERBS_ATTR_IDR(UVERBS_ATTR_READ_COUNTERS_HANDLE, 142 UVERBS_OBJECT_COUNTERS, 143 UVERBS_ACCESS_READ, 144 UA_MANDATORY), 145 UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_READ_COUNTERS_BUFF, 146 UVERBS_ATTR_MIN_SIZE(0), 147 UA_MANDATORY), 148 UVERBS_ATTR_FLAGS_IN(UVERBS_ATTR_READ_COUNTERS_FLAGS, 149 enum ib_uverbs_read_counters_flags)); 150 151 DECLARE_UVERBS_NAMED_OBJECT(UVERBS_OBJECT_COUNTERS, 152 UVERBS_TYPE_ALLOC_IDR(uverbs_free_counters), 153 &UVERBS_METHOD(UVERBS_METHOD_COUNTERS_CREATE), 154 &UVERBS_METHOD(UVERBS_METHOD_COUNTERS_DESTROY), 155 &UVERBS_METHOD(UVERBS_METHOD_COUNTERS_READ)); 156 157 const struct uapi_definition uverbs_def_obj_counters[] = { 158 UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_COUNTERS, 159 UAPI_DEF_OBJ_NEEDS_FN(destroy_counters)), 160 {} 161 }; 162