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 ret = ib_destroy_usecnt(&counters->usecnt, why, uobject); 46 if (ret) 47 return ret; 48 49 counters->device->ops.destroy_counters(counters); 50 kfree(counters); 51 return 0; 52 } 53 54 static int UVERBS_HANDLER(UVERBS_METHOD_COUNTERS_CREATE)( 55 struct uverbs_attr_bundle *attrs) 56 { 57 struct ib_uobject *uobj = uverbs_attr_get_uobject( 58 attrs, UVERBS_ATTR_CREATE_COUNTERS_HANDLE); 59 struct ib_device *ib_dev = attrs->context->device; 60 struct ib_counters *counters; 61 int ret; 62 63 /* 64 * This check should be removed once the infrastructure 65 * have the ability to remove methods from parse tree once 66 * such condition is met. 67 */ 68 if (!ib_dev->ops.create_counters) 69 return -EOPNOTSUPP; 70 71 counters = rdma_zalloc_drv_obj(ib_dev, ib_counters); 72 if (!counters) 73 return -ENOMEM; 74 75 counters->device = ib_dev; 76 counters->uobject = uobj; 77 uobj->object = counters; 78 atomic_set(&counters->usecnt, 0); 79 80 ret = ib_dev->ops.create_counters(counters, attrs); 81 if (ret) 82 kfree(counters); 83 84 return ret; 85 } 86 87 static int UVERBS_HANDLER(UVERBS_METHOD_COUNTERS_READ)( 88 struct uverbs_attr_bundle *attrs) 89 { 90 struct ib_counters_read_attr read_attr = {}; 91 const struct uverbs_attr *uattr; 92 struct ib_counters *counters = 93 uverbs_attr_get_obj(attrs, UVERBS_ATTR_READ_COUNTERS_HANDLE); 94 int ret; 95 96 if (!counters->device->ops.read_counters) 97 return -EOPNOTSUPP; 98 99 if (!atomic_read(&counters->usecnt)) 100 return -EINVAL; 101 102 ret = uverbs_get_flags32(&read_attr.flags, attrs, 103 UVERBS_ATTR_READ_COUNTERS_FLAGS, 104 IB_UVERBS_READ_COUNTERS_PREFER_CACHED); 105 if (ret) 106 return ret; 107 108 uattr = uverbs_attr_get(attrs, UVERBS_ATTR_READ_COUNTERS_BUFF); 109 read_attr.ncounters = uattr->ptr_attr.len / sizeof(u64); 110 read_attr.counters_buff = uverbs_zalloc( 111 attrs, array_size(read_attr.ncounters, sizeof(u64))); 112 if (IS_ERR(read_attr.counters_buff)) 113 return PTR_ERR(read_attr.counters_buff); 114 115 ret = counters->device->ops.read_counters(counters, &read_attr, attrs); 116 if (ret) 117 return ret; 118 119 return uverbs_copy_to(attrs, UVERBS_ATTR_READ_COUNTERS_BUFF, 120 read_attr.counters_buff, 121 read_attr.ncounters * sizeof(u64)); 122 } 123 124 DECLARE_UVERBS_NAMED_METHOD( 125 UVERBS_METHOD_COUNTERS_CREATE, 126 UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_COUNTERS_HANDLE, 127 UVERBS_OBJECT_COUNTERS, 128 UVERBS_ACCESS_NEW, 129 UA_MANDATORY)); 130 131 DECLARE_UVERBS_NAMED_METHOD_DESTROY( 132 UVERBS_METHOD_COUNTERS_DESTROY, 133 UVERBS_ATTR_IDR(UVERBS_ATTR_DESTROY_COUNTERS_HANDLE, 134 UVERBS_OBJECT_COUNTERS, 135 UVERBS_ACCESS_DESTROY, 136 UA_MANDATORY)); 137 138 DECLARE_UVERBS_NAMED_METHOD( 139 UVERBS_METHOD_COUNTERS_READ, 140 UVERBS_ATTR_IDR(UVERBS_ATTR_READ_COUNTERS_HANDLE, 141 UVERBS_OBJECT_COUNTERS, 142 UVERBS_ACCESS_READ, 143 UA_MANDATORY), 144 UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_READ_COUNTERS_BUFF, 145 UVERBS_ATTR_MIN_SIZE(0), 146 UA_MANDATORY), 147 UVERBS_ATTR_FLAGS_IN(UVERBS_ATTR_READ_COUNTERS_FLAGS, 148 enum ib_uverbs_read_counters_flags)); 149 150 DECLARE_UVERBS_NAMED_OBJECT(UVERBS_OBJECT_COUNTERS, 151 UVERBS_TYPE_ALLOC_IDR(uverbs_free_counters), 152 &UVERBS_METHOD(UVERBS_METHOD_COUNTERS_CREATE), 153 &UVERBS_METHOD(UVERBS_METHOD_COUNTERS_DESTROY), 154 &UVERBS_METHOD(UVERBS_METHOD_COUNTERS_READ)); 155 156 const struct uapi_definition uverbs_def_obj_counters[] = { 157 UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_COUNTERS, 158 UAPI_DEF_OBJ_NEEDS_FN(destroy_counters)), 159 {} 160 }; 161