162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2017 Mellanox Technologies. All rights reserved. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 562306a36Sopenharmony_ci * modification, are permitted provided that the following conditions are met: 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 862306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 962306a36Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 1062306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 1162306a36Sopenharmony_ci * documentation and/or other materials provided with the distribution. 1262306a36Sopenharmony_ci * 3. Neither the names of the copyright holders nor the names of its 1362306a36Sopenharmony_ci * contributors may be used to endorse or promote products derived from 1462306a36Sopenharmony_ci * this software without specific prior written permission. 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the 1762306a36Sopenharmony_ci * GNU General Public License ("GPL") version 2 as published by the Free 1862306a36Sopenharmony_ci * Software Foundation. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2162306a36Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2262306a36Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2362306a36Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 2462306a36Sopenharmony_ci * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2562306a36Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2662306a36Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2762306a36Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2862306a36Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2962306a36Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3062306a36Sopenharmony_ci * POSSIBILITY OF SUCH DAMAGE. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include <linux/module.h> 3462306a36Sopenharmony_ci#include <linux/pid.h> 3562306a36Sopenharmony_ci#include <linux/pid_namespace.h> 3662306a36Sopenharmony_ci#include <linux/mutex.h> 3762306a36Sopenharmony_ci#include <net/netlink.h> 3862306a36Sopenharmony_ci#include <rdma/rdma_cm.h> 3962306a36Sopenharmony_ci#include <rdma/rdma_netlink.h> 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#include "core_priv.h" 4262306a36Sopenharmony_ci#include "cma_priv.h" 4362306a36Sopenharmony_ci#include "restrack.h" 4462306a36Sopenharmony_ci#include "uverbs.h" 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_citypedef int (*res_fill_func_t)(struct sk_buff*, bool, 4762306a36Sopenharmony_ci struct rdma_restrack_entry*, uint32_t); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* 5062306a36Sopenharmony_ci * Sort array elements by the netlink attribute name 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_cistatic const struct nla_policy nldev_policy[RDMA_NLDEV_ATTR_MAX] = { 5362306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_CHARDEV] = { .type = NLA_U64 }, 5462306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_CHARDEV_ABI] = { .type = NLA_U64 }, 5562306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_CHARDEV_NAME] = { .type = NLA_NUL_STRING, 5662306a36Sopenharmony_ci .len = RDMA_NLDEV_ATTR_EMPTY_STRING }, 5762306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_CHARDEV_TYPE] = { .type = NLA_NUL_STRING, 5862306a36Sopenharmony_ci .len = RDMA_NLDEV_ATTR_CHARDEV_TYPE_SIZE }, 5962306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_DEV_DIM] = { .type = NLA_U8 }, 6062306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_DEV_INDEX] = { .type = NLA_U32 }, 6162306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, 6262306a36Sopenharmony_ci .len = IB_DEVICE_NAME_MAX }, 6362306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_DEV_NODE_TYPE] = { .type = NLA_U8 }, 6462306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_DEV_PROTOCOL] = { .type = NLA_NUL_STRING, 6562306a36Sopenharmony_ci .len = RDMA_NLDEV_ATTR_EMPTY_STRING }, 6662306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_DRIVER] = { .type = NLA_NESTED }, 6762306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_DRIVER_ENTRY] = { .type = NLA_NESTED }, 6862306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_DRIVER_PRINT_TYPE] = { .type = NLA_U8 }, 6962306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_DRIVER_STRING] = { .type = NLA_NUL_STRING, 7062306a36Sopenharmony_ci .len = RDMA_NLDEV_ATTR_EMPTY_STRING }, 7162306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_DRIVER_S32] = { .type = NLA_S32 }, 7262306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_DRIVER_S64] = { .type = NLA_S64 }, 7362306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_DRIVER_U32] = { .type = NLA_U32 }, 7462306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_DRIVER_U64] = { .type = NLA_U64 }, 7562306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_FW_VERSION] = { .type = NLA_NUL_STRING, 7662306a36Sopenharmony_ci .len = RDMA_NLDEV_ATTR_EMPTY_STRING }, 7762306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_LID] = { .type = NLA_U32 }, 7862306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_LINK_TYPE] = { .type = NLA_NUL_STRING, 7962306a36Sopenharmony_ci .len = IFNAMSIZ }, 8062306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_LMC] = { .type = NLA_U8 }, 8162306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_NDEV_INDEX] = { .type = NLA_U32 }, 8262306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_NDEV_NAME] = { .type = NLA_NUL_STRING, 8362306a36Sopenharmony_ci .len = IFNAMSIZ }, 8462306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_NODE_GUID] = { .type = NLA_U64 }, 8562306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_PORT_INDEX] = { .type = NLA_U32 }, 8662306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_PORT_PHYS_STATE] = { .type = NLA_U8 }, 8762306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_PORT_STATE] = { .type = NLA_U8 }, 8862306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_CM_ID] = { .type = NLA_NESTED }, 8962306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_CM_IDN] = { .type = NLA_U32 }, 9062306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_CM_ID_ENTRY] = { .type = NLA_NESTED }, 9162306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_CQ] = { .type = NLA_NESTED }, 9262306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_CQE] = { .type = NLA_U32 }, 9362306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_CQN] = { .type = NLA_U32 }, 9462306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_CQ_ENTRY] = { .type = NLA_NESTED }, 9562306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_CTX] = { .type = NLA_NESTED }, 9662306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_CTXN] = { .type = NLA_U32 }, 9762306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_CTX_ENTRY] = { .type = NLA_NESTED }, 9862306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_DST_ADDR] = { 9962306a36Sopenharmony_ci .len = sizeof(struct __kernel_sockaddr_storage) }, 10062306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_IOVA] = { .type = NLA_U64 }, 10162306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_KERN_NAME] = { .type = NLA_NUL_STRING, 10262306a36Sopenharmony_ci .len = RDMA_NLDEV_ATTR_EMPTY_STRING }, 10362306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_LKEY] = { .type = NLA_U32 }, 10462306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY] = { .type = NLA_U32 }, 10562306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_LQPN] = { .type = NLA_U32 }, 10662306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_MR] = { .type = NLA_NESTED }, 10762306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_MRLEN] = { .type = NLA_U64 }, 10862306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_MRN] = { .type = NLA_U32 }, 10962306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_MR_ENTRY] = { .type = NLA_NESTED }, 11062306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE] = { .type = NLA_U8 }, 11162306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_PD] = { .type = NLA_NESTED }, 11262306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_PDN] = { .type = NLA_U32 }, 11362306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_PD_ENTRY] = { .type = NLA_NESTED }, 11462306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_PID] = { .type = NLA_U32 }, 11562306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_POLL_CTX] = { .type = NLA_U8 }, 11662306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_PS] = { .type = NLA_U32 }, 11762306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_QP] = { .type = NLA_NESTED }, 11862306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_QP_ENTRY] = { .type = NLA_NESTED }, 11962306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_RAW] = { .type = NLA_BINARY }, 12062306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_RKEY] = { .type = NLA_U32 }, 12162306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_RQPN] = { .type = NLA_U32 }, 12262306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_RQ_PSN] = { .type = NLA_U32 }, 12362306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_SQ_PSN] = { .type = NLA_U32 }, 12462306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_SRC_ADDR] = { 12562306a36Sopenharmony_ci .len = sizeof(struct __kernel_sockaddr_storage) }, 12662306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_STATE] = { .type = NLA_U8 }, 12762306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_SUMMARY] = { .type = NLA_NESTED }, 12862306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY] = { .type = NLA_NESTED }, 12962306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR]= { .type = NLA_U64 }, 13062306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME]= { .type = NLA_NUL_STRING, 13162306a36Sopenharmony_ci .len = RDMA_NLDEV_ATTR_EMPTY_STRING }, 13262306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_TYPE] = { .type = NLA_U8 }, 13362306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY]= { .type = NLA_U32 }, 13462306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_USECNT] = { .type = NLA_U64 }, 13562306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_SRQ] = { .type = NLA_NESTED }, 13662306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_SRQN] = { .type = NLA_U32 }, 13762306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_RES_SRQ_ENTRY] = { .type = NLA_NESTED }, 13862306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_MIN_RANGE] = { .type = NLA_U32 }, 13962306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_MAX_RANGE] = { .type = NLA_U32 }, 14062306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_SM_LID] = { .type = NLA_U32 }, 14162306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_SUBNET_PREFIX] = { .type = NLA_U64 }, 14262306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK] = { .type = NLA_U32 }, 14362306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_STAT_MODE] = { .type = NLA_U32 }, 14462306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_STAT_RES] = { .type = NLA_U32 }, 14562306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_STAT_COUNTER] = { .type = NLA_NESTED }, 14662306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_STAT_COUNTER_ENTRY] = { .type = NLA_NESTED }, 14762306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_STAT_COUNTER_ID] = { .type = NLA_U32 }, 14862306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_STAT_HWCOUNTERS] = { .type = NLA_NESTED }, 14962306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY] = { .type = NLA_NESTED }, 15062306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME] = { .type = NLA_NUL_STRING }, 15162306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_VALUE] = { .type = NLA_U64 }, 15262306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_SYS_IMAGE_GUID] = { .type = NLA_U64 }, 15362306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_UVERBS_DRIVER_ID] = { .type = NLA_U32 }, 15462306a36Sopenharmony_ci [RDMA_NLDEV_NET_NS_FD] = { .type = NLA_U32 }, 15562306a36Sopenharmony_ci [RDMA_NLDEV_SYS_ATTR_NETNS_MODE] = { .type = NLA_U8 }, 15662306a36Sopenharmony_ci [RDMA_NLDEV_SYS_ATTR_COPY_ON_FORK] = { .type = NLA_U8 }, 15762306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_STAT_HWCOUNTER_INDEX] = { .type = NLA_U32 }, 15862306a36Sopenharmony_ci [RDMA_NLDEV_ATTR_STAT_HWCOUNTER_DYNAMIC] = { .type = NLA_U8 }, 15962306a36Sopenharmony_ci}; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic int put_driver_name_print_type(struct sk_buff *msg, const char *name, 16262306a36Sopenharmony_ci enum rdma_nldev_print_type print_type) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci if (nla_put_string(msg, RDMA_NLDEV_ATTR_DRIVER_STRING, name)) 16562306a36Sopenharmony_ci return -EMSGSIZE; 16662306a36Sopenharmony_ci if (print_type != RDMA_NLDEV_PRINT_TYPE_UNSPEC && 16762306a36Sopenharmony_ci nla_put_u8(msg, RDMA_NLDEV_ATTR_DRIVER_PRINT_TYPE, print_type)) 16862306a36Sopenharmony_ci return -EMSGSIZE; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci return 0; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic int _rdma_nl_put_driver_u32(struct sk_buff *msg, const char *name, 17462306a36Sopenharmony_ci enum rdma_nldev_print_type print_type, 17562306a36Sopenharmony_ci u32 value) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci if (put_driver_name_print_type(msg, name, print_type)) 17862306a36Sopenharmony_ci return -EMSGSIZE; 17962306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_DRIVER_U32, value)) 18062306a36Sopenharmony_ci return -EMSGSIZE; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci return 0; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic int _rdma_nl_put_driver_u64(struct sk_buff *msg, const char *name, 18662306a36Sopenharmony_ci enum rdma_nldev_print_type print_type, 18762306a36Sopenharmony_ci u64 value) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci if (put_driver_name_print_type(msg, name, print_type)) 19062306a36Sopenharmony_ci return -EMSGSIZE; 19162306a36Sopenharmony_ci if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_DRIVER_U64, value, 19262306a36Sopenharmony_ci RDMA_NLDEV_ATTR_PAD)) 19362306a36Sopenharmony_ci return -EMSGSIZE; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci return 0; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ciint rdma_nl_put_driver_string(struct sk_buff *msg, const char *name, 19962306a36Sopenharmony_ci const char *str) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci if (put_driver_name_print_type(msg, name, 20262306a36Sopenharmony_ci RDMA_NLDEV_PRINT_TYPE_UNSPEC)) 20362306a36Sopenharmony_ci return -EMSGSIZE; 20462306a36Sopenharmony_ci if (nla_put_string(msg, RDMA_NLDEV_ATTR_DRIVER_STRING, str)) 20562306a36Sopenharmony_ci return -EMSGSIZE; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci return 0; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_nl_put_driver_string); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ciint rdma_nl_put_driver_u32(struct sk_buff *msg, const char *name, u32 value) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci return _rdma_nl_put_driver_u32(msg, name, RDMA_NLDEV_PRINT_TYPE_UNSPEC, 21462306a36Sopenharmony_ci value); 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_nl_put_driver_u32); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ciint rdma_nl_put_driver_u32_hex(struct sk_buff *msg, const char *name, 21962306a36Sopenharmony_ci u32 value) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci return _rdma_nl_put_driver_u32(msg, name, RDMA_NLDEV_PRINT_TYPE_HEX, 22262306a36Sopenharmony_ci value); 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_nl_put_driver_u32_hex); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ciint rdma_nl_put_driver_u64(struct sk_buff *msg, const char *name, u64 value) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci return _rdma_nl_put_driver_u64(msg, name, RDMA_NLDEV_PRINT_TYPE_UNSPEC, 22962306a36Sopenharmony_ci value); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_nl_put_driver_u64); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ciint rdma_nl_put_driver_u64_hex(struct sk_buff *msg, const char *name, u64 value) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci return _rdma_nl_put_driver_u64(msg, name, RDMA_NLDEV_PRINT_TYPE_HEX, 23662306a36Sopenharmony_ci value); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_nl_put_driver_u64_hex); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic int fill_nldev_handle(struct sk_buff *msg, struct ib_device *device) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_DEV_INDEX, device->index)) 24362306a36Sopenharmony_ci return -EMSGSIZE; 24462306a36Sopenharmony_ci if (nla_put_string(msg, RDMA_NLDEV_ATTR_DEV_NAME, 24562306a36Sopenharmony_ci dev_name(&device->dev))) 24662306a36Sopenharmony_ci return -EMSGSIZE; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci return 0; 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic int fill_dev_info(struct sk_buff *msg, struct ib_device *device) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci char fw[IB_FW_VERSION_NAME_MAX]; 25462306a36Sopenharmony_ci int ret = 0; 25562306a36Sopenharmony_ci u32 port; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (fill_nldev_handle(msg, device)) 25862306a36Sopenharmony_ci return -EMSGSIZE; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, rdma_end_port(device))) 26162306a36Sopenharmony_ci return -EMSGSIZE; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(device->attrs.device_cap_flags) != sizeof(u64)); 26462306a36Sopenharmony_ci if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_CAP_FLAGS, 26562306a36Sopenharmony_ci device->attrs.device_cap_flags, 26662306a36Sopenharmony_ci RDMA_NLDEV_ATTR_PAD)) 26762306a36Sopenharmony_ci return -EMSGSIZE; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci ib_get_device_fw_str(device, fw); 27062306a36Sopenharmony_ci /* Device without FW has strlen(fw) = 0 */ 27162306a36Sopenharmony_ci if (strlen(fw) && nla_put_string(msg, RDMA_NLDEV_ATTR_FW_VERSION, fw)) 27262306a36Sopenharmony_ci return -EMSGSIZE; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_NODE_GUID, 27562306a36Sopenharmony_ci be64_to_cpu(device->node_guid), 27662306a36Sopenharmony_ci RDMA_NLDEV_ATTR_PAD)) 27762306a36Sopenharmony_ci return -EMSGSIZE; 27862306a36Sopenharmony_ci if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_SYS_IMAGE_GUID, 27962306a36Sopenharmony_ci be64_to_cpu(device->attrs.sys_image_guid), 28062306a36Sopenharmony_ci RDMA_NLDEV_ATTR_PAD)) 28162306a36Sopenharmony_ci return -EMSGSIZE; 28262306a36Sopenharmony_ci if (nla_put_u8(msg, RDMA_NLDEV_ATTR_DEV_NODE_TYPE, device->node_type)) 28362306a36Sopenharmony_ci return -EMSGSIZE; 28462306a36Sopenharmony_ci if (nla_put_u8(msg, RDMA_NLDEV_ATTR_DEV_DIM, device->use_cq_dim)) 28562306a36Sopenharmony_ci return -EMSGSIZE; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci /* 28862306a36Sopenharmony_ci * Link type is determined on first port and mlx4 device 28962306a36Sopenharmony_ci * which can potentially have two different link type for the same 29062306a36Sopenharmony_ci * IB device is considered as better to be avoided in the future, 29162306a36Sopenharmony_ci */ 29262306a36Sopenharmony_ci port = rdma_start_port(device); 29362306a36Sopenharmony_ci if (rdma_cap_opa_mad(device, port)) 29462306a36Sopenharmony_ci ret = nla_put_string(msg, RDMA_NLDEV_ATTR_DEV_PROTOCOL, "opa"); 29562306a36Sopenharmony_ci else if (rdma_protocol_ib(device, port)) 29662306a36Sopenharmony_ci ret = nla_put_string(msg, RDMA_NLDEV_ATTR_DEV_PROTOCOL, "ib"); 29762306a36Sopenharmony_ci else if (rdma_protocol_iwarp(device, port)) 29862306a36Sopenharmony_ci ret = nla_put_string(msg, RDMA_NLDEV_ATTR_DEV_PROTOCOL, "iw"); 29962306a36Sopenharmony_ci else if (rdma_protocol_roce(device, port)) 30062306a36Sopenharmony_ci ret = nla_put_string(msg, RDMA_NLDEV_ATTR_DEV_PROTOCOL, "roce"); 30162306a36Sopenharmony_ci else if (rdma_protocol_usnic(device, port)) 30262306a36Sopenharmony_ci ret = nla_put_string(msg, RDMA_NLDEV_ATTR_DEV_PROTOCOL, 30362306a36Sopenharmony_ci "usnic"); 30462306a36Sopenharmony_ci return ret; 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic int fill_port_info(struct sk_buff *msg, 30862306a36Sopenharmony_ci struct ib_device *device, u32 port, 30962306a36Sopenharmony_ci const struct net *net) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci struct net_device *netdev = NULL; 31262306a36Sopenharmony_ci struct ib_port_attr attr; 31362306a36Sopenharmony_ci int ret; 31462306a36Sopenharmony_ci u64 cap_flags = 0; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (fill_nldev_handle(msg, device)) 31762306a36Sopenharmony_ci return -EMSGSIZE; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, port)) 32062306a36Sopenharmony_ci return -EMSGSIZE; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci ret = ib_query_port(device, port, &attr); 32362306a36Sopenharmony_ci if (ret) 32462306a36Sopenharmony_ci return ret; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (rdma_protocol_ib(device, port)) { 32762306a36Sopenharmony_ci BUILD_BUG_ON((sizeof(attr.port_cap_flags) + 32862306a36Sopenharmony_ci sizeof(attr.port_cap_flags2)) > sizeof(u64)); 32962306a36Sopenharmony_ci cap_flags = attr.port_cap_flags | 33062306a36Sopenharmony_ci ((u64)attr.port_cap_flags2 << 32); 33162306a36Sopenharmony_ci if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_CAP_FLAGS, 33262306a36Sopenharmony_ci cap_flags, RDMA_NLDEV_ATTR_PAD)) 33362306a36Sopenharmony_ci return -EMSGSIZE; 33462306a36Sopenharmony_ci if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_SUBNET_PREFIX, 33562306a36Sopenharmony_ci attr.subnet_prefix, RDMA_NLDEV_ATTR_PAD)) 33662306a36Sopenharmony_ci return -EMSGSIZE; 33762306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_LID, attr.lid)) 33862306a36Sopenharmony_ci return -EMSGSIZE; 33962306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_SM_LID, attr.sm_lid)) 34062306a36Sopenharmony_ci return -EMSGSIZE; 34162306a36Sopenharmony_ci if (nla_put_u8(msg, RDMA_NLDEV_ATTR_LMC, attr.lmc)) 34262306a36Sopenharmony_ci return -EMSGSIZE; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci if (nla_put_u8(msg, RDMA_NLDEV_ATTR_PORT_STATE, attr.state)) 34562306a36Sopenharmony_ci return -EMSGSIZE; 34662306a36Sopenharmony_ci if (nla_put_u8(msg, RDMA_NLDEV_ATTR_PORT_PHYS_STATE, attr.phys_state)) 34762306a36Sopenharmony_ci return -EMSGSIZE; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci netdev = ib_device_get_netdev(device, port); 35062306a36Sopenharmony_ci if (netdev && net_eq(dev_net(netdev), net)) { 35162306a36Sopenharmony_ci ret = nla_put_u32(msg, 35262306a36Sopenharmony_ci RDMA_NLDEV_ATTR_NDEV_INDEX, netdev->ifindex); 35362306a36Sopenharmony_ci if (ret) 35462306a36Sopenharmony_ci goto out; 35562306a36Sopenharmony_ci ret = nla_put_string(msg, 35662306a36Sopenharmony_ci RDMA_NLDEV_ATTR_NDEV_NAME, netdev->name); 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ciout: 36062306a36Sopenharmony_ci if (netdev) 36162306a36Sopenharmony_ci dev_put(netdev); 36262306a36Sopenharmony_ci return ret; 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic int fill_res_info_entry(struct sk_buff *msg, 36662306a36Sopenharmony_ci const char *name, u64 curr) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci struct nlattr *entry_attr; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci entry_attr = nla_nest_start_noflag(msg, 37162306a36Sopenharmony_ci RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY); 37262306a36Sopenharmony_ci if (!entry_attr) 37362306a36Sopenharmony_ci return -EMSGSIZE; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (nla_put_string(msg, RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME, name)) 37662306a36Sopenharmony_ci goto err; 37762306a36Sopenharmony_ci if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR, curr, 37862306a36Sopenharmony_ci RDMA_NLDEV_ATTR_PAD)) 37962306a36Sopenharmony_ci goto err; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci nla_nest_end(msg, entry_attr); 38262306a36Sopenharmony_ci return 0; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cierr: 38562306a36Sopenharmony_ci nla_nest_cancel(msg, entry_attr); 38662306a36Sopenharmony_ci return -EMSGSIZE; 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_cistatic int fill_res_info(struct sk_buff *msg, struct ib_device *device) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci static const char * const names[RDMA_RESTRACK_MAX] = { 39262306a36Sopenharmony_ci [RDMA_RESTRACK_PD] = "pd", 39362306a36Sopenharmony_ci [RDMA_RESTRACK_CQ] = "cq", 39462306a36Sopenharmony_ci [RDMA_RESTRACK_QP] = "qp", 39562306a36Sopenharmony_ci [RDMA_RESTRACK_CM_ID] = "cm_id", 39662306a36Sopenharmony_ci [RDMA_RESTRACK_MR] = "mr", 39762306a36Sopenharmony_ci [RDMA_RESTRACK_CTX] = "ctx", 39862306a36Sopenharmony_ci [RDMA_RESTRACK_SRQ] = "srq", 39962306a36Sopenharmony_ci }; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci struct nlattr *table_attr; 40262306a36Sopenharmony_ci int ret, i, curr; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (fill_nldev_handle(msg, device)) 40562306a36Sopenharmony_ci return -EMSGSIZE; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci table_attr = nla_nest_start_noflag(msg, RDMA_NLDEV_ATTR_RES_SUMMARY); 40862306a36Sopenharmony_ci if (!table_attr) 40962306a36Sopenharmony_ci return -EMSGSIZE; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci for (i = 0; i < RDMA_RESTRACK_MAX; i++) { 41262306a36Sopenharmony_ci if (!names[i]) 41362306a36Sopenharmony_ci continue; 41462306a36Sopenharmony_ci curr = rdma_restrack_count(device, i); 41562306a36Sopenharmony_ci ret = fill_res_info_entry(msg, names[i], curr); 41662306a36Sopenharmony_ci if (ret) 41762306a36Sopenharmony_ci goto err; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci nla_nest_end(msg, table_attr); 42162306a36Sopenharmony_ci return 0; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cierr: 42462306a36Sopenharmony_ci nla_nest_cancel(msg, table_attr); 42562306a36Sopenharmony_ci return ret; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic int fill_res_name_pid(struct sk_buff *msg, 42962306a36Sopenharmony_ci struct rdma_restrack_entry *res) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci int err = 0; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci /* 43462306a36Sopenharmony_ci * For user resources, user is should read /proc/PID/comm to get the 43562306a36Sopenharmony_ci * name of the task file. 43662306a36Sopenharmony_ci */ 43762306a36Sopenharmony_ci if (rdma_is_kernel_res(res)) { 43862306a36Sopenharmony_ci err = nla_put_string(msg, RDMA_NLDEV_ATTR_RES_KERN_NAME, 43962306a36Sopenharmony_ci res->kern_name); 44062306a36Sopenharmony_ci } else { 44162306a36Sopenharmony_ci pid_t pid; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci pid = task_pid_vnr(res->task); 44462306a36Sopenharmony_ci /* 44562306a36Sopenharmony_ci * Task is dead and in zombie state. 44662306a36Sopenharmony_ci * There is no need to print PID anymore. 44762306a36Sopenharmony_ci */ 44862306a36Sopenharmony_ci if (pid) 44962306a36Sopenharmony_ci /* 45062306a36Sopenharmony_ci * This part is racy, task can be killed and PID will 45162306a36Sopenharmony_ci * be zero right here but it is ok, next query won't 45262306a36Sopenharmony_ci * return PID. We don't promise real-time reflection 45362306a36Sopenharmony_ci * of SW objects. 45462306a36Sopenharmony_ci */ 45562306a36Sopenharmony_ci err = nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_PID, pid); 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci return err ? -EMSGSIZE : 0; 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic int fill_res_qp_entry_query(struct sk_buff *msg, 46262306a36Sopenharmony_ci struct rdma_restrack_entry *res, 46362306a36Sopenharmony_ci struct ib_device *dev, 46462306a36Sopenharmony_ci struct ib_qp *qp) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci struct ib_qp_init_attr qp_init_attr; 46762306a36Sopenharmony_ci struct ib_qp_attr qp_attr; 46862306a36Sopenharmony_ci int ret; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci ret = ib_query_qp(qp, &qp_attr, 0, &qp_init_attr); 47162306a36Sopenharmony_ci if (ret) 47262306a36Sopenharmony_ci return ret; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (qp->qp_type == IB_QPT_RC || qp->qp_type == IB_QPT_UC) { 47562306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_RQPN, 47662306a36Sopenharmony_ci qp_attr.dest_qp_num)) 47762306a36Sopenharmony_ci goto err; 47862306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_RQ_PSN, 47962306a36Sopenharmony_ci qp_attr.rq_psn)) 48062306a36Sopenharmony_ci goto err; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_SQ_PSN, qp_attr.sq_psn)) 48462306a36Sopenharmony_ci goto err; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (qp->qp_type == IB_QPT_RC || qp->qp_type == IB_QPT_UC || 48762306a36Sopenharmony_ci qp->qp_type == IB_QPT_XRC_INI || qp->qp_type == IB_QPT_XRC_TGT) { 48862306a36Sopenharmony_ci if (nla_put_u8(msg, RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE, 48962306a36Sopenharmony_ci qp_attr.path_mig_state)) 49062306a36Sopenharmony_ci goto err; 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci if (nla_put_u8(msg, RDMA_NLDEV_ATTR_RES_TYPE, qp->qp_type)) 49362306a36Sopenharmony_ci goto err; 49462306a36Sopenharmony_ci if (nla_put_u8(msg, RDMA_NLDEV_ATTR_RES_STATE, qp_attr.qp_state)) 49562306a36Sopenharmony_ci goto err; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (dev->ops.fill_res_qp_entry) 49862306a36Sopenharmony_ci return dev->ops.fill_res_qp_entry(msg, qp); 49962306a36Sopenharmony_ci return 0; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cierr: return -EMSGSIZE; 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic int fill_res_qp_entry(struct sk_buff *msg, bool has_cap_net_admin, 50562306a36Sopenharmony_ci struct rdma_restrack_entry *res, uint32_t port) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci struct ib_qp *qp = container_of(res, struct ib_qp, res); 50862306a36Sopenharmony_ci struct ib_device *dev = qp->device; 50962306a36Sopenharmony_ci int ret; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (port && port != qp->port) 51262306a36Sopenharmony_ci return -EAGAIN; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci /* In create_qp() port is not set yet */ 51562306a36Sopenharmony_ci if (qp->port && nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, qp->port)) 51662306a36Sopenharmony_ci return -EMSGSIZE; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci ret = nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_LQPN, qp->qp_num); 51962306a36Sopenharmony_ci if (ret) 52062306a36Sopenharmony_ci return -EMSGSIZE; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci if (!rdma_is_kernel_res(res) && 52362306a36Sopenharmony_ci nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_PDN, qp->pd->res.id)) 52462306a36Sopenharmony_ci return -EMSGSIZE; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci ret = fill_res_name_pid(msg, res); 52762306a36Sopenharmony_ci if (ret) 52862306a36Sopenharmony_ci return -EMSGSIZE; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci return fill_res_qp_entry_query(msg, res, dev, qp); 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cistatic int fill_res_qp_raw_entry(struct sk_buff *msg, bool has_cap_net_admin, 53462306a36Sopenharmony_ci struct rdma_restrack_entry *res, uint32_t port) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci struct ib_qp *qp = container_of(res, struct ib_qp, res); 53762306a36Sopenharmony_ci struct ib_device *dev = qp->device; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci if (port && port != qp->port) 54062306a36Sopenharmony_ci return -EAGAIN; 54162306a36Sopenharmony_ci if (!dev->ops.fill_res_qp_entry_raw) 54262306a36Sopenharmony_ci return -EINVAL; 54362306a36Sopenharmony_ci return dev->ops.fill_res_qp_entry_raw(msg, qp); 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_cistatic int fill_res_cm_id_entry(struct sk_buff *msg, bool has_cap_net_admin, 54762306a36Sopenharmony_ci struct rdma_restrack_entry *res, uint32_t port) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci struct rdma_id_private *id_priv = 55062306a36Sopenharmony_ci container_of(res, struct rdma_id_private, res); 55162306a36Sopenharmony_ci struct ib_device *dev = id_priv->id.device; 55262306a36Sopenharmony_ci struct rdma_cm_id *cm_id = &id_priv->id; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci if (port && port != cm_id->port_num) 55562306a36Sopenharmony_ci return -EAGAIN; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (cm_id->port_num && 55862306a36Sopenharmony_ci nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, cm_id->port_num)) 55962306a36Sopenharmony_ci goto err; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (id_priv->qp_num) { 56262306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_LQPN, id_priv->qp_num)) 56362306a36Sopenharmony_ci goto err; 56462306a36Sopenharmony_ci if (nla_put_u8(msg, RDMA_NLDEV_ATTR_RES_TYPE, cm_id->qp_type)) 56562306a36Sopenharmony_ci goto err; 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_PS, cm_id->ps)) 56962306a36Sopenharmony_ci goto err; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci if (nla_put_u8(msg, RDMA_NLDEV_ATTR_RES_STATE, id_priv->state)) 57262306a36Sopenharmony_ci goto err; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci if (cm_id->route.addr.src_addr.ss_family && 57562306a36Sopenharmony_ci nla_put(msg, RDMA_NLDEV_ATTR_RES_SRC_ADDR, 57662306a36Sopenharmony_ci sizeof(cm_id->route.addr.src_addr), 57762306a36Sopenharmony_ci &cm_id->route.addr.src_addr)) 57862306a36Sopenharmony_ci goto err; 57962306a36Sopenharmony_ci if (cm_id->route.addr.dst_addr.ss_family && 58062306a36Sopenharmony_ci nla_put(msg, RDMA_NLDEV_ATTR_RES_DST_ADDR, 58162306a36Sopenharmony_ci sizeof(cm_id->route.addr.dst_addr), 58262306a36Sopenharmony_ci &cm_id->route.addr.dst_addr)) 58362306a36Sopenharmony_ci goto err; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_CM_IDN, res->id)) 58662306a36Sopenharmony_ci goto err; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (fill_res_name_pid(msg, res)) 58962306a36Sopenharmony_ci goto err; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (dev->ops.fill_res_cm_id_entry) 59262306a36Sopenharmony_ci return dev->ops.fill_res_cm_id_entry(msg, cm_id); 59362306a36Sopenharmony_ci return 0; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_cierr: return -EMSGSIZE; 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cistatic int fill_res_cq_entry(struct sk_buff *msg, bool has_cap_net_admin, 59962306a36Sopenharmony_ci struct rdma_restrack_entry *res, uint32_t port) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci struct ib_cq *cq = container_of(res, struct ib_cq, res); 60262306a36Sopenharmony_ci struct ib_device *dev = cq->device; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_CQE, cq->cqe)) 60562306a36Sopenharmony_ci return -EMSGSIZE; 60662306a36Sopenharmony_ci if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_RES_USECNT, 60762306a36Sopenharmony_ci atomic_read(&cq->usecnt), RDMA_NLDEV_ATTR_PAD)) 60862306a36Sopenharmony_ci return -EMSGSIZE; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci /* Poll context is only valid for kernel CQs */ 61162306a36Sopenharmony_ci if (rdma_is_kernel_res(res) && 61262306a36Sopenharmony_ci nla_put_u8(msg, RDMA_NLDEV_ATTR_RES_POLL_CTX, cq->poll_ctx)) 61362306a36Sopenharmony_ci return -EMSGSIZE; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci if (nla_put_u8(msg, RDMA_NLDEV_ATTR_DEV_DIM, (cq->dim != NULL))) 61662306a36Sopenharmony_ci return -EMSGSIZE; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_CQN, res->id)) 61962306a36Sopenharmony_ci return -EMSGSIZE; 62062306a36Sopenharmony_ci if (!rdma_is_kernel_res(res) && 62162306a36Sopenharmony_ci nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_CTXN, 62262306a36Sopenharmony_ci cq->uobject->uevent.uobject.context->res.id)) 62362306a36Sopenharmony_ci return -EMSGSIZE; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (fill_res_name_pid(msg, res)) 62662306a36Sopenharmony_ci return -EMSGSIZE; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci return (dev->ops.fill_res_cq_entry) ? 62962306a36Sopenharmony_ci dev->ops.fill_res_cq_entry(msg, cq) : 0; 63062306a36Sopenharmony_ci} 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_cistatic int fill_res_cq_raw_entry(struct sk_buff *msg, bool has_cap_net_admin, 63362306a36Sopenharmony_ci struct rdma_restrack_entry *res, uint32_t port) 63462306a36Sopenharmony_ci{ 63562306a36Sopenharmony_ci struct ib_cq *cq = container_of(res, struct ib_cq, res); 63662306a36Sopenharmony_ci struct ib_device *dev = cq->device; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci if (!dev->ops.fill_res_cq_entry_raw) 63962306a36Sopenharmony_ci return -EINVAL; 64062306a36Sopenharmony_ci return dev->ops.fill_res_cq_entry_raw(msg, cq); 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_cistatic int fill_res_mr_entry(struct sk_buff *msg, bool has_cap_net_admin, 64462306a36Sopenharmony_ci struct rdma_restrack_entry *res, uint32_t port) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci struct ib_mr *mr = container_of(res, struct ib_mr, res); 64762306a36Sopenharmony_ci struct ib_device *dev = mr->pd->device; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci if (has_cap_net_admin) { 65062306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_RKEY, mr->rkey)) 65162306a36Sopenharmony_ci return -EMSGSIZE; 65262306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_LKEY, mr->lkey)) 65362306a36Sopenharmony_ci return -EMSGSIZE; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_RES_MRLEN, mr->length, 65762306a36Sopenharmony_ci RDMA_NLDEV_ATTR_PAD)) 65862306a36Sopenharmony_ci return -EMSGSIZE; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_MRN, res->id)) 66162306a36Sopenharmony_ci return -EMSGSIZE; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (!rdma_is_kernel_res(res) && 66462306a36Sopenharmony_ci nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_PDN, mr->pd->res.id)) 66562306a36Sopenharmony_ci return -EMSGSIZE; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci if (fill_res_name_pid(msg, res)) 66862306a36Sopenharmony_ci return -EMSGSIZE; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci return (dev->ops.fill_res_mr_entry) ? 67162306a36Sopenharmony_ci dev->ops.fill_res_mr_entry(msg, mr) : 67262306a36Sopenharmony_ci 0; 67362306a36Sopenharmony_ci} 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_cistatic int fill_res_mr_raw_entry(struct sk_buff *msg, bool has_cap_net_admin, 67662306a36Sopenharmony_ci struct rdma_restrack_entry *res, uint32_t port) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci struct ib_mr *mr = container_of(res, struct ib_mr, res); 67962306a36Sopenharmony_ci struct ib_device *dev = mr->pd->device; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if (!dev->ops.fill_res_mr_entry_raw) 68262306a36Sopenharmony_ci return -EINVAL; 68362306a36Sopenharmony_ci return dev->ops.fill_res_mr_entry_raw(msg, mr); 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_cistatic int fill_res_pd_entry(struct sk_buff *msg, bool has_cap_net_admin, 68762306a36Sopenharmony_ci struct rdma_restrack_entry *res, uint32_t port) 68862306a36Sopenharmony_ci{ 68962306a36Sopenharmony_ci struct ib_pd *pd = container_of(res, struct ib_pd, res); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci if (has_cap_net_admin) { 69262306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY, 69362306a36Sopenharmony_ci pd->local_dma_lkey)) 69462306a36Sopenharmony_ci goto err; 69562306a36Sopenharmony_ci if ((pd->flags & IB_PD_UNSAFE_GLOBAL_RKEY) && 69662306a36Sopenharmony_ci nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY, 69762306a36Sopenharmony_ci pd->unsafe_global_rkey)) 69862306a36Sopenharmony_ci goto err; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_RES_USECNT, 70162306a36Sopenharmony_ci atomic_read(&pd->usecnt), RDMA_NLDEV_ATTR_PAD)) 70262306a36Sopenharmony_ci goto err; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_PDN, res->id)) 70562306a36Sopenharmony_ci goto err; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci if (!rdma_is_kernel_res(res) && 70862306a36Sopenharmony_ci nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_CTXN, 70962306a36Sopenharmony_ci pd->uobject->context->res.id)) 71062306a36Sopenharmony_ci goto err; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci return fill_res_name_pid(msg, res); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_cierr: return -EMSGSIZE; 71562306a36Sopenharmony_ci} 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_cistatic int fill_res_ctx_entry(struct sk_buff *msg, bool has_cap_net_admin, 71862306a36Sopenharmony_ci struct rdma_restrack_entry *res, uint32_t port) 71962306a36Sopenharmony_ci{ 72062306a36Sopenharmony_ci struct ib_ucontext *ctx = container_of(res, struct ib_ucontext, res); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci if (rdma_is_kernel_res(res)) 72362306a36Sopenharmony_ci return 0; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_CTXN, ctx->res.id)) 72662306a36Sopenharmony_ci return -EMSGSIZE; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci return fill_res_name_pid(msg, res); 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic int fill_res_range_qp_entry(struct sk_buff *msg, uint32_t min_range, 73262306a36Sopenharmony_ci uint32_t max_range) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci struct nlattr *entry_attr; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci if (!min_range) 73762306a36Sopenharmony_ci return 0; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci entry_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_RES_QP_ENTRY); 74062306a36Sopenharmony_ci if (!entry_attr) 74162306a36Sopenharmony_ci return -EMSGSIZE; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci if (min_range == max_range) { 74462306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_LQPN, min_range)) 74562306a36Sopenharmony_ci goto err; 74662306a36Sopenharmony_ci } else { 74762306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_MIN_RANGE, min_range)) 74862306a36Sopenharmony_ci goto err; 74962306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_MAX_RANGE, max_range)) 75062306a36Sopenharmony_ci goto err; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci nla_nest_end(msg, entry_attr); 75362306a36Sopenharmony_ci return 0; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_cierr: 75662306a36Sopenharmony_ci nla_nest_cancel(msg, entry_attr); 75762306a36Sopenharmony_ci return -EMSGSIZE; 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cistatic int fill_res_srq_qps(struct sk_buff *msg, struct ib_srq *srq) 76162306a36Sopenharmony_ci{ 76262306a36Sopenharmony_ci uint32_t min_range = 0, prev = 0; 76362306a36Sopenharmony_ci struct rdma_restrack_entry *res; 76462306a36Sopenharmony_ci struct rdma_restrack_root *rt; 76562306a36Sopenharmony_ci struct nlattr *table_attr; 76662306a36Sopenharmony_ci struct ib_qp *qp = NULL; 76762306a36Sopenharmony_ci unsigned long id = 0; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci table_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_RES_QP); 77062306a36Sopenharmony_ci if (!table_attr) 77162306a36Sopenharmony_ci return -EMSGSIZE; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci rt = &srq->device->res[RDMA_RESTRACK_QP]; 77462306a36Sopenharmony_ci xa_lock(&rt->xa); 77562306a36Sopenharmony_ci xa_for_each(&rt->xa, id, res) { 77662306a36Sopenharmony_ci if (!rdma_restrack_get(res)) 77762306a36Sopenharmony_ci continue; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci qp = container_of(res, struct ib_qp, res); 78062306a36Sopenharmony_ci if (!qp->srq || (qp->srq->res.id != srq->res.id)) { 78162306a36Sopenharmony_ci rdma_restrack_put(res); 78262306a36Sopenharmony_ci continue; 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci if (qp->qp_num < prev) 78662306a36Sopenharmony_ci /* qp_num should be ascending */ 78762306a36Sopenharmony_ci goto err_loop; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci if (min_range == 0) { 79062306a36Sopenharmony_ci min_range = qp->qp_num; 79162306a36Sopenharmony_ci } else if (qp->qp_num > (prev + 1)) { 79262306a36Sopenharmony_ci if (fill_res_range_qp_entry(msg, min_range, prev)) 79362306a36Sopenharmony_ci goto err_loop; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci min_range = qp->qp_num; 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci prev = qp->qp_num; 79862306a36Sopenharmony_ci rdma_restrack_put(res); 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci xa_unlock(&rt->xa); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci if (fill_res_range_qp_entry(msg, min_range, prev)) 80462306a36Sopenharmony_ci goto err; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci nla_nest_end(msg, table_attr); 80762306a36Sopenharmony_ci return 0; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_cierr_loop: 81062306a36Sopenharmony_ci rdma_restrack_put(res); 81162306a36Sopenharmony_ci xa_unlock(&rt->xa); 81262306a36Sopenharmony_cierr: 81362306a36Sopenharmony_ci nla_nest_cancel(msg, table_attr); 81462306a36Sopenharmony_ci return -EMSGSIZE; 81562306a36Sopenharmony_ci} 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_cistatic int fill_res_srq_entry(struct sk_buff *msg, bool has_cap_net_admin, 81862306a36Sopenharmony_ci struct rdma_restrack_entry *res, uint32_t port) 81962306a36Sopenharmony_ci{ 82062306a36Sopenharmony_ci struct ib_srq *srq = container_of(res, struct ib_srq, res); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_SRQN, srq->res.id)) 82362306a36Sopenharmony_ci goto err; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci if (nla_put_u8(msg, RDMA_NLDEV_ATTR_RES_TYPE, srq->srq_type)) 82662306a36Sopenharmony_ci goto err; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_PDN, srq->pd->res.id)) 82962306a36Sopenharmony_ci goto err; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci if (ib_srq_has_cq(srq->srq_type)) { 83262306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_CQN, 83362306a36Sopenharmony_ci srq->ext.cq->res.id)) 83462306a36Sopenharmony_ci goto err; 83562306a36Sopenharmony_ci } 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci if (fill_res_srq_qps(msg, srq)) 83862306a36Sopenharmony_ci goto err; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci return fill_res_name_pid(msg, res); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_cierr: 84362306a36Sopenharmony_ci return -EMSGSIZE; 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_cistatic int fill_stat_counter_mode(struct sk_buff *msg, 84762306a36Sopenharmony_ci struct rdma_counter *counter) 84862306a36Sopenharmony_ci{ 84962306a36Sopenharmony_ci struct rdma_counter_mode *m = &counter->mode; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_STAT_MODE, m->mode)) 85262306a36Sopenharmony_ci return -EMSGSIZE; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci if (m->mode == RDMA_COUNTER_MODE_AUTO) { 85562306a36Sopenharmony_ci if ((m->mask & RDMA_COUNTER_MASK_QP_TYPE) && 85662306a36Sopenharmony_ci nla_put_u8(msg, RDMA_NLDEV_ATTR_RES_TYPE, m->param.qp_type)) 85762306a36Sopenharmony_ci return -EMSGSIZE; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci if ((m->mask & RDMA_COUNTER_MASK_PID) && 86062306a36Sopenharmony_ci fill_res_name_pid(msg, &counter->res)) 86162306a36Sopenharmony_ci return -EMSGSIZE; 86262306a36Sopenharmony_ci } 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci return 0; 86562306a36Sopenharmony_ci} 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_cistatic int fill_stat_counter_qp_entry(struct sk_buff *msg, u32 qpn) 86862306a36Sopenharmony_ci{ 86962306a36Sopenharmony_ci struct nlattr *entry_attr; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci entry_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_RES_QP_ENTRY); 87262306a36Sopenharmony_ci if (!entry_attr) 87362306a36Sopenharmony_ci return -EMSGSIZE; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_LQPN, qpn)) 87662306a36Sopenharmony_ci goto err; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci nla_nest_end(msg, entry_attr); 87962306a36Sopenharmony_ci return 0; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_cierr: 88262306a36Sopenharmony_ci nla_nest_cancel(msg, entry_attr); 88362306a36Sopenharmony_ci return -EMSGSIZE; 88462306a36Sopenharmony_ci} 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_cistatic int fill_stat_counter_qps(struct sk_buff *msg, 88762306a36Sopenharmony_ci struct rdma_counter *counter) 88862306a36Sopenharmony_ci{ 88962306a36Sopenharmony_ci struct rdma_restrack_entry *res; 89062306a36Sopenharmony_ci struct rdma_restrack_root *rt; 89162306a36Sopenharmony_ci struct nlattr *table_attr; 89262306a36Sopenharmony_ci struct ib_qp *qp = NULL; 89362306a36Sopenharmony_ci unsigned long id = 0; 89462306a36Sopenharmony_ci int ret = 0; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci table_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_RES_QP); 89762306a36Sopenharmony_ci if (!table_attr) 89862306a36Sopenharmony_ci return -EMSGSIZE; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci rt = &counter->device->res[RDMA_RESTRACK_QP]; 90162306a36Sopenharmony_ci xa_lock(&rt->xa); 90262306a36Sopenharmony_ci xa_for_each(&rt->xa, id, res) { 90362306a36Sopenharmony_ci qp = container_of(res, struct ib_qp, res); 90462306a36Sopenharmony_ci if (!qp->counter || (qp->counter->id != counter->id)) 90562306a36Sopenharmony_ci continue; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci ret = fill_stat_counter_qp_entry(msg, qp->qp_num); 90862306a36Sopenharmony_ci if (ret) 90962306a36Sopenharmony_ci goto err; 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci xa_unlock(&rt->xa); 91362306a36Sopenharmony_ci nla_nest_end(msg, table_attr); 91462306a36Sopenharmony_ci return 0; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_cierr: 91762306a36Sopenharmony_ci xa_unlock(&rt->xa); 91862306a36Sopenharmony_ci nla_nest_cancel(msg, table_attr); 91962306a36Sopenharmony_ci return ret; 92062306a36Sopenharmony_ci} 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ciint rdma_nl_stat_hwcounter_entry(struct sk_buff *msg, const char *name, 92362306a36Sopenharmony_ci u64 value) 92462306a36Sopenharmony_ci{ 92562306a36Sopenharmony_ci struct nlattr *entry_attr; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci entry_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY); 92862306a36Sopenharmony_ci if (!entry_attr) 92962306a36Sopenharmony_ci return -EMSGSIZE; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci if (nla_put_string(msg, RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME, 93262306a36Sopenharmony_ci name)) 93362306a36Sopenharmony_ci goto err; 93462306a36Sopenharmony_ci if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_VALUE, 93562306a36Sopenharmony_ci value, RDMA_NLDEV_ATTR_PAD)) 93662306a36Sopenharmony_ci goto err; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci nla_nest_end(msg, entry_attr); 93962306a36Sopenharmony_ci return 0; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_cierr: 94262306a36Sopenharmony_ci nla_nest_cancel(msg, entry_attr); 94362306a36Sopenharmony_ci return -EMSGSIZE; 94462306a36Sopenharmony_ci} 94562306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_nl_stat_hwcounter_entry); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_cistatic int fill_stat_mr_entry(struct sk_buff *msg, bool has_cap_net_admin, 94862306a36Sopenharmony_ci struct rdma_restrack_entry *res, uint32_t port) 94962306a36Sopenharmony_ci{ 95062306a36Sopenharmony_ci struct ib_mr *mr = container_of(res, struct ib_mr, res); 95162306a36Sopenharmony_ci struct ib_device *dev = mr->pd->device; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_MRN, res->id)) 95462306a36Sopenharmony_ci goto err; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci if (dev->ops.fill_stat_mr_entry) 95762306a36Sopenharmony_ci return dev->ops.fill_stat_mr_entry(msg, mr); 95862306a36Sopenharmony_ci return 0; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_cierr: 96162306a36Sopenharmony_ci return -EMSGSIZE; 96262306a36Sopenharmony_ci} 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_cistatic int fill_stat_counter_hwcounters(struct sk_buff *msg, 96562306a36Sopenharmony_ci struct rdma_counter *counter) 96662306a36Sopenharmony_ci{ 96762306a36Sopenharmony_ci struct rdma_hw_stats *st = counter->stats; 96862306a36Sopenharmony_ci struct nlattr *table_attr; 96962306a36Sopenharmony_ci int i; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci table_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_STAT_HWCOUNTERS); 97262306a36Sopenharmony_ci if (!table_attr) 97362306a36Sopenharmony_ci return -EMSGSIZE; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci mutex_lock(&st->lock); 97662306a36Sopenharmony_ci for (i = 0; i < st->num_counters; i++) { 97762306a36Sopenharmony_ci if (test_bit(i, st->is_disabled)) 97862306a36Sopenharmony_ci continue; 97962306a36Sopenharmony_ci if (rdma_nl_stat_hwcounter_entry(msg, st->descs[i].name, 98062306a36Sopenharmony_ci st->value[i])) 98162306a36Sopenharmony_ci goto err; 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci mutex_unlock(&st->lock); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci nla_nest_end(msg, table_attr); 98662306a36Sopenharmony_ci return 0; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_cierr: 98962306a36Sopenharmony_ci mutex_unlock(&st->lock); 99062306a36Sopenharmony_ci nla_nest_cancel(msg, table_attr); 99162306a36Sopenharmony_ci return -EMSGSIZE; 99262306a36Sopenharmony_ci} 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_cistatic int fill_res_counter_entry(struct sk_buff *msg, bool has_cap_net_admin, 99562306a36Sopenharmony_ci struct rdma_restrack_entry *res, 99662306a36Sopenharmony_ci uint32_t port) 99762306a36Sopenharmony_ci{ 99862306a36Sopenharmony_ci struct rdma_counter *counter = 99962306a36Sopenharmony_ci container_of(res, struct rdma_counter, res); 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci if (port && port != counter->port) 100262306a36Sopenharmony_ci return -EAGAIN; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci /* Dump it even query failed */ 100562306a36Sopenharmony_ci rdma_counter_query_stats(counter); 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, counter->port) || 100862306a36Sopenharmony_ci nla_put_u32(msg, RDMA_NLDEV_ATTR_STAT_COUNTER_ID, counter->id) || 100962306a36Sopenharmony_ci fill_stat_counter_mode(msg, counter) || 101062306a36Sopenharmony_ci fill_stat_counter_qps(msg, counter) || 101162306a36Sopenharmony_ci fill_stat_counter_hwcounters(msg, counter)) 101262306a36Sopenharmony_ci return -EMSGSIZE; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci return 0; 101562306a36Sopenharmony_ci} 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_cistatic int nldev_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh, 101862306a36Sopenharmony_ci struct netlink_ext_ack *extack) 101962306a36Sopenharmony_ci{ 102062306a36Sopenharmony_ci struct nlattr *tb[RDMA_NLDEV_ATTR_MAX]; 102162306a36Sopenharmony_ci struct ib_device *device; 102262306a36Sopenharmony_ci struct sk_buff *msg; 102362306a36Sopenharmony_ci u32 index; 102462306a36Sopenharmony_ci int err; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci err = nlmsg_parse_deprecated(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, 102762306a36Sopenharmony_ci nldev_policy, extack); 102862306a36Sopenharmony_ci if (err || !tb[RDMA_NLDEV_ATTR_DEV_INDEX]) 102962306a36Sopenharmony_ci return -EINVAL; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci device = ib_device_get_by_index(sock_net(skb->sk), index); 103462306a36Sopenharmony_ci if (!device) 103562306a36Sopenharmony_ci return -EINVAL; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 103862306a36Sopenharmony_ci if (!msg) { 103962306a36Sopenharmony_ci err = -ENOMEM; 104062306a36Sopenharmony_ci goto err; 104162306a36Sopenharmony_ci } 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 104462306a36Sopenharmony_ci RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET), 104562306a36Sopenharmony_ci 0, 0); 104662306a36Sopenharmony_ci if (!nlh) { 104762306a36Sopenharmony_ci err = -EMSGSIZE; 104862306a36Sopenharmony_ci goto err_free; 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci err = fill_dev_info(msg, device); 105262306a36Sopenharmony_ci if (err) 105362306a36Sopenharmony_ci goto err_free; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci nlmsg_end(msg, nlh); 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci ib_device_put(device); 105862306a36Sopenharmony_ci return rdma_nl_unicast(sock_net(skb->sk), msg, NETLINK_CB(skb).portid); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_cierr_free: 106162306a36Sopenharmony_ci nlmsg_free(msg); 106262306a36Sopenharmony_cierr: 106362306a36Sopenharmony_ci ib_device_put(device); 106462306a36Sopenharmony_ci return err; 106562306a36Sopenharmony_ci} 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_cistatic int nldev_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh, 106862306a36Sopenharmony_ci struct netlink_ext_ack *extack) 106962306a36Sopenharmony_ci{ 107062306a36Sopenharmony_ci struct nlattr *tb[RDMA_NLDEV_ATTR_MAX]; 107162306a36Sopenharmony_ci struct ib_device *device; 107262306a36Sopenharmony_ci u32 index; 107362306a36Sopenharmony_ci int err; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci err = nlmsg_parse_deprecated(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, 107662306a36Sopenharmony_ci nldev_policy, extack); 107762306a36Sopenharmony_ci if (err || !tb[RDMA_NLDEV_ATTR_DEV_INDEX]) 107862306a36Sopenharmony_ci return -EINVAL; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); 108162306a36Sopenharmony_ci device = ib_device_get_by_index(sock_net(skb->sk), index); 108262306a36Sopenharmony_ci if (!device) 108362306a36Sopenharmony_ci return -EINVAL; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci if (tb[RDMA_NLDEV_ATTR_DEV_NAME]) { 108662306a36Sopenharmony_ci char name[IB_DEVICE_NAME_MAX] = {}; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci nla_strscpy(name, tb[RDMA_NLDEV_ATTR_DEV_NAME], 108962306a36Sopenharmony_ci IB_DEVICE_NAME_MAX); 109062306a36Sopenharmony_ci if (strlen(name) == 0) { 109162306a36Sopenharmony_ci err = -EINVAL; 109262306a36Sopenharmony_ci goto done; 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci err = ib_device_rename(device, name); 109562306a36Sopenharmony_ci goto done; 109662306a36Sopenharmony_ci } 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci if (tb[RDMA_NLDEV_NET_NS_FD]) { 109962306a36Sopenharmony_ci u32 ns_fd; 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci ns_fd = nla_get_u32(tb[RDMA_NLDEV_NET_NS_FD]); 110262306a36Sopenharmony_ci err = ib_device_set_netns_put(skb, device, ns_fd); 110362306a36Sopenharmony_ci goto put_done; 110462306a36Sopenharmony_ci } 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci if (tb[RDMA_NLDEV_ATTR_DEV_DIM]) { 110762306a36Sopenharmony_ci u8 use_dim; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci use_dim = nla_get_u8(tb[RDMA_NLDEV_ATTR_DEV_DIM]); 111062306a36Sopenharmony_ci err = ib_device_set_dim(device, use_dim); 111162306a36Sopenharmony_ci goto done; 111262306a36Sopenharmony_ci } 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_cidone: 111562306a36Sopenharmony_ci ib_device_put(device); 111662306a36Sopenharmony_ciput_done: 111762306a36Sopenharmony_ci return err; 111862306a36Sopenharmony_ci} 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_cistatic int _nldev_get_dumpit(struct ib_device *device, 112162306a36Sopenharmony_ci struct sk_buff *skb, 112262306a36Sopenharmony_ci struct netlink_callback *cb, 112362306a36Sopenharmony_ci unsigned int idx) 112462306a36Sopenharmony_ci{ 112562306a36Sopenharmony_ci int start = cb->args[0]; 112662306a36Sopenharmony_ci struct nlmsghdr *nlh; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci if (idx < start) 112962306a36Sopenharmony_ci return 0; 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 113262306a36Sopenharmony_ci RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET), 113362306a36Sopenharmony_ci 0, NLM_F_MULTI); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci if (!nlh || fill_dev_info(skb, device)) { 113662306a36Sopenharmony_ci nlmsg_cancel(skb, nlh); 113762306a36Sopenharmony_ci goto out; 113862306a36Sopenharmony_ci } 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci nlmsg_end(skb, nlh); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci idx++; 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ciout: cb->args[0] = idx; 114562306a36Sopenharmony_ci return skb->len; 114662306a36Sopenharmony_ci} 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_cistatic int nldev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) 114962306a36Sopenharmony_ci{ 115062306a36Sopenharmony_ci /* 115162306a36Sopenharmony_ci * There is no need to take lock, because 115262306a36Sopenharmony_ci * we are relying on ib_core's locking. 115362306a36Sopenharmony_ci */ 115462306a36Sopenharmony_ci return ib_enum_all_devs(_nldev_get_dumpit, skb, cb); 115562306a36Sopenharmony_ci} 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_cistatic int nldev_port_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh, 115862306a36Sopenharmony_ci struct netlink_ext_ack *extack) 115962306a36Sopenharmony_ci{ 116062306a36Sopenharmony_ci struct nlattr *tb[RDMA_NLDEV_ATTR_MAX]; 116162306a36Sopenharmony_ci struct ib_device *device; 116262306a36Sopenharmony_ci struct sk_buff *msg; 116362306a36Sopenharmony_ci u32 index; 116462306a36Sopenharmony_ci u32 port; 116562306a36Sopenharmony_ci int err; 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci err = nlmsg_parse_deprecated(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, 116862306a36Sopenharmony_ci nldev_policy, extack); 116962306a36Sopenharmony_ci if (err || 117062306a36Sopenharmony_ci !tb[RDMA_NLDEV_ATTR_DEV_INDEX] || 117162306a36Sopenharmony_ci !tb[RDMA_NLDEV_ATTR_PORT_INDEX]) 117262306a36Sopenharmony_ci return -EINVAL; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); 117562306a36Sopenharmony_ci device = ib_device_get_by_index(sock_net(skb->sk), index); 117662306a36Sopenharmony_ci if (!device) 117762306a36Sopenharmony_ci return -EINVAL; 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci port = nla_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]); 118062306a36Sopenharmony_ci if (!rdma_is_port_valid(device, port)) { 118162306a36Sopenharmony_ci err = -EINVAL; 118262306a36Sopenharmony_ci goto err; 118362306a36Sopenharmony_ci } 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 118662306a36Sopenharmony_ci if (!msg) { 118762306a36Sopenharmony_ci err = -ENOMEM; 118862306a36Sopenharmony_ci goto err; 118962306a36Sopenharmony_ci } 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 119262306a36Sopenharmony_ci RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET), 119362306a36Sopenharmony_ci 0, 0); 119462306a36Sopenharmony_ci if (!nlh) { 119562306a36Sopenharmony_ci err = -EMSGSIZE; 119662306a36Sopenharmony_ci goto err_free; 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci err = fill_port_info(msg, device, port, sock_net(skb->sk)); 120062306a36Sopenharmony_ci if (err) 120162306a36Sopenharmony_ci goto err_free; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci nlmsg_end(msg, nlh); 120462306a36Sopenharmony_ci ib_device_put(device); 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci return rdma_nl_unicast(sock_net(skb->sk), msg, NETLINK_CB(skb).portid); 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_cierr_free: 120962306a36Sopenharmony_ci nlmsg_free(msg); 121062306a36Sopenharmony_cierr: 121162306a36Sopenharmony_ci ib_device_put(device); 121262306a36Sopenharmony_ci return err; 121362306a36Sopenharmony_ci} 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_cistatic int nldev_port_get_dumpit(struct sk_buff *skb, 121662306a36Sopenharmony_ci struct netlink_callback *cb) 121762306a36Sopenharmony_ci{ 121862306a36Sopenharmony_ci struct nlattr *tb[RDMA_NLDEV_ATTR_MAX]; 121962306a36Sopenharmony_ci struct ib_device *device; 122062306a36Sopenharmony_ci int start = cb->args[0]; 122162306a36Sopenharmony_ci struct nlmsghdr *nlh; 122262306a36Sopenharmony_ci u32 idx = 0; 122362306a36Sopenharmony_ci u32 ifindex; 122462306a36Sopenharmony_ci int err; 122562306a36Sopenharmony_ci unsigned int p; 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci err = nlmsg_parse_deprecated(cb->nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, 122862306a36Sopenharmony_ci nldev_policy, NULL); 122962306a36Sopenharmony_ci if (err || !tb[RDMA_NLDEV_ATTR_DEV_INDEX]) 123062306a36Sopenharmony_ci return -EINVAL; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci ifindex = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); 123362306a36Sopenharmony_ci device = ib_device_get_by_index(sock_net(skb->sk), ifindex); 123462306a36Sopenharmony_ci if (!device) 123562306a36Sopenharmony_ci return -EINVAL; 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci rdma_for_each_port (device, p) { 123862306a36Sopenharmony_ci /* 123962306a36Sopenharmony_ci * The dumpit function returns all information from specific 124062306a36Sopenharmony_ci * index. This specific index is taken from the netlink 124162306a36Sopenharmony_ci * messages request sent by user and it is available 124262306a36Sopenharmony_ci * in cb->args[0]. 124362306a36Sopenharmony_ci * 124462306a36Sopenharmony_ci * Usually, the user doesn't fill this field and it causes 124562306a36Sopenharmony_ci * to return everything. 124662306a36Sopenharmony_ci * 124762306a36Sopenharmony_ci */ 124862306a36Sopenharmony_ci if (idx < start) { 124962306a36Sopenharmony_ci idx++; 125062306a36Sopenharmony_ci continue; 125162306a36Sopenharmony_ci } 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, 125462306a36Sopenharmony_ci cb->nlh->nlmsg_seq, 125562306a36Sopenharmony_ci RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, 125662306a36Sopenharmony_ci RDMA_NLDEV_CMD_PORT_GET), 125762306a36Sopenharmony_ci 0, NLM_F_MULTI); 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci if (!nlh || fill_port_info(skb, device, p, sock_net(skb->sk))) { 126062306a36Sopenharmony_ci nlmsg_cancel(skb, nlh); 126162306a36Sopenharmony_ci goto out; 126262306a36Sopenharmony_ci } 126362306a36Sopenharmony_ci idx++; 126462306a36Sopenharmony_ci nlmsg_end(skb, nlh); 126562306a36Sopenharmony_ci } 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ciout: 126862306a36Sopenharmony_ci ib_device_put(device); 126962306a36Sopenharmony_ci cb->args[0] = idx; 127062306a36Sopenharmony_ci return skb->len; 127162306a36Sopenharmony_ci} 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_cistatic int nldev_res_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh, 127462306a36Sopenharmony_ci struct netlink_ext_ack *extack) 127562306a36Sopenharmony_ci{ 127662306a36Sopenharmony_ci struct nlattr *tb[RDMA_NLDEV_ATTR_MAX]; 127762306a36Sopenharmony_ci struct ib_device *device; 127862306a36Sopenharmony_ci struct sk_buff *msg; 127962306a36Sopenharmony_ci u32 index; 128062306a36Sopenharmony_ci int ret; 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci ret = nlmsg_parse_deprecated(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, 128362306a36Sopenharmony_ci nldev_policy, extack); 128462306a36Sopenharmony_ci if (ret || !tb[RDMA_NLDEV_ATTR_DEV_INDEX]) 128562306a36Sopenharmony_ci return -EINVAL; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); 128862306a36Sopenharmony_ci device = ib_device_get_by_index(sock_net(skb->sk), index); 128962306a36Sopenharmony_ci if (!device) 129062306a36Sopenharmony_ci return -EINVAL; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 129362306a36Sopenharmony_ci if (!msg) { 129462306a36Sopenharmony_ci ret = -ENOMEM; 129562306a36Sopenharmony_ci goto err; 129662306a36Sopenharmony_ci } 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 129962306a36Sopenharmony_ci RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_RES_GET), 130062306a36Sopenharmony_ci 0, 0); 130162306a36Sopenharmony_ci if (!nlh) { 130262306a36Sopenharmony_ci ret = -EMSGSIZE; 130362306a36Sopenharmony_ci goto err_free; 130462306a36Sopenharmony_ci } 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci ret = fill_res_info(msg, device); 130762306a36Sopenharmony_ci if (ret) 130862306a36Sopenharmony_ci goto err_free; 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci nlmsg_end(msg, nlh); 131162306a36Sopenharmony_ci ib_device_put(device); 131262306a36Sopenharmony_ci return rdma_nl_unicast(sock_net(skb->sk), msg, NETLINK_CB(skb).portid); 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_cierr_free: 131562306a36Sopenharmony_ci nlmsg_free(msg); 131662306a36Sopenharmony_cierr: 131762306a36Sopenharmony_ci ib_device_put(device); 131862306a36Sopenharmony_ci return ret; 131962306a36Sopenharmony_ci} 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_cistatic int _nldev_res_get_dumpit(struct ib_device *device, 132262306a36Sopenharmony_ci struct sk_buff *skb, 132362306a36Sopenharmony_ci struct netlink_callback *cb, 132462306a36Sopenharmony_ci unsigned int idx) 132562306a36Sopenharmony_ci{ 132662306a36Sopenharmony_ci int start = cb->args[0]; 132762306a36Sopenharmony_ci struct nlmsghdr *nlh; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci if (idx < start) 133062306a36Sopenharmony_ci return 0; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 133362306a36Sopenharmony_ci RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_RES_GET), 133462306a36Sopenharmony_ci 0, NLM_F_MULTI); 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci if (!nlh || fill_res_info(skb, device)) { 133762306a36Sopenharmony_ci nlmsg_cancel(skb, nlh); 133862306a36Sopenharmony_ci goto out; 133962306a36Sopenharmony_ci } 134062306a36Sopenharmony_ci nlmsg_end(skb, nlh); 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci idx++; 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ciout: 134562306a36Sopenharmony_ci cb->args[0] = idx; 134662306a36Sopenharmony_ci return skb->len; 134762306a36Sopenharmony_ci} 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_cistatic int nldev_res_get_dumpit(struct sk_buff *skb, 135062306a36Sopenharmony_ci struct netlink_callback *cb) 135162306a36Sopenharmony_ci{ 135262306a36Sopenharmony_ci return ib_enum_all_devs(_nldev_res_get_dumpit, skb, cb); 135362306a36Sopenharmony_ci} 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_cistruct nldev_fill_res_entry { 135662306a36Sopenharmony_ci enum rdma_nldev_attr nldev_attr; 135762306a36Sopenharmony_ci u8 flags; 135862306a36Sopenharmony_ci u32 entry; 135962306a36Sopenharmony_ci u32 id; 136062306a36Sopenharmony_ci}; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_cienum nldev_res_flags { 136362306a36Sopenharmony_ci NLDEV_PER_DEV = 1 << 0, 136462306a36Sopenharmony_ci}; 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_cistatic const struct nldev_fill_res_entry fill_entries[RDMA_RESTRACK_MAX] = { 136762306a36Sopenharmony_ci [RDMA_RESTRACK_QP] = { 136862306a36Sopenharmony_ci .nldev_attr = RDMA_NLDEV_ATTR_RES_QP, 136962306a36Sopenharmony_ci .entry = RDMA_NLDEV_ATTR_RES_QP_ENTRY, 137062306a36Sopenharmony_ci .id = RDMA_NLDEV_ATTR_RES_LQPN, 137162306a36Sopenharmony_ci }, 137262306a36Sopenharmony_ci [RDMA_RESTRACK_CM_ID] = { 137362306a36Sopenharmony_ci .nldev_attr = RDMA_NLDEV_ATTR_RES_CM_ID, 137462306a36Sopenharmony_ci .entry = RDMA_NLDEV_ATTR_RES_CM_ID_ENTRY, 137562306a36Sopenharmony_ci .id = RDMA_NLDEV_ATTR_RES_CM_IDN, 137662306a36Sopenharmony_ci }, 137762306a36Sopenharmony_ci [RDMA_RESTRACK_CQ] = { 137862306a36Sopenharmony_ci .nldev_attr = RDMA_NLDEV_ATTR_RES_CQ, 137962306a36Sopenharmony_ci .flags = NLDEV_PER_DEV, 138062306a36Sopenharmony_ci .entry = RDMA_NLDEV_ATTR_RES_CQ_ENTRY, 138162306a36Sopenharmony_ci .id = RDMA_NLDEV_ATTR_RES_CQN, 138262306a36Sopenharmony_ci }, 138362306a36Sopenharmony_ci [RDMA_RESTRACK_MR] = { 138462306a36Sopenharmony_ci .nldev_attr = RDMA_NLDEV_ATTR_RES_MR, 138562306a36Sopenharmony_ci .flags = NLDEV_PER_DEV, 138662306a36Sopenharmony_ci .entry = RDMA_NLDEV_ATTR_RES_MR_ENTRY, 138762306a36Sopenharmony_ci .id = RDMA_NLDEV_ATTR_RES_MRN, 138862306a36Sopenharmony_ci }, 138962306a36Sopenharmony_ci [RDMA_RESTRACK_PD] = { 139062306a36Sopenharmony_ci .nldev_attr = RDMA_NLDEV_ATTR_RES_PD, 139162306a36Sopenharmony_ci .flags = NLDEV_PER_DEV, 139262306a36Sopenharmony_ci .entry = RDMA_NLDEV_ATTR_RES_PD_ENTRY, 139362306a36Sopenharmony_ci .id = RDMA_NLDEV_ATTR_RES_PDN, 139462306a36Sopenharmony_ci }, 139562306a36Sopenharmony_ci [RDMA_RESTRACK_COUNTER] = { 139662306a36Sopenharmony_ci .nldev_attr = RDMA_NLDEV_ATTR_STAT_COUNTER, 139762306a36Sopenharmony_ci .entry = RDMA_NLDEV_ATTR_STAT_COUNTER_ENTRY, 139862306a36Sopenharmony_ci .id = RDMA_NLDEV_ATTR_STAT_COUNTER_ID, 139962306a36Sopenharmony_ci }, 140062306a36Sopenharmony_ci [RDMA_RESTRACK_CTX] = { 140162306a36Sopenharmony_ci .nldev_attr = RDMA_NLDEV_ATTR_RES_CTX, 140262306a36Sopenharmony_ci .flags = NLDEV_PER_DEV, 140362306a36Sopenharmony_ci .entry = RDMA_NLDEV_ATTR_RES_CTX_ENTRY, 140462306a36Sopenharmony_ci .id = RDMA_NLDEV_ATTR_RES_CTXN, 140562306a36Sopenharmony_ci }, 140662306a36Sopenharmony_ci [RDMA_RESTRACK_SRQ] = { 140762306a36Sopenharmony_ci .nldev_attr = RDMA_NLDEV_ATTR_RES_SRQ, 140862306a36Sopenharmony_ci .flags = NLDEV_PER_DEV, 140962306a36Sopenharmony_ci .entry = RDMA_NLDEV_ATTR_RES_SRQ_ENTRY, 141062306a36Sopenharmony_ci .id = RDMA_NLDEV_ATTR_RES_SRQN, 141162306a36Sopenharmony_ci }, 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci}; 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_cistatic int res_get_common_doit(struct sk_buff *skb, struct nlmsghdr *nlh, 141662306a36Sopenharmony_ci struct netlink_ext_ack *extack, 141762306a36Sopenharmony_ci enum rdma_restrack_type res_type, 141862306a36Sopenharmony_ci res_fill_func_t fill_func) 141962306a36Sopenharmony_ci{ 142062306a36Sopenharmony_ci const struct nldev_fill_res_entry *fe = &fill_entries[res_type]; 142162306a36Sopenharmony_ci struct nlattr *tb[RDMA_NLDEV_ATTR_MAX]; 142262306a36Sopenharmony_ci struct rdma_restrack_entry *res; 142362306a36Sopenharmony_ci struct ib_device *device; 142462306a36Sopenharmony_ci u32 index, id, port = 0; 142562306a36Sopenharmony_ci bool has_cap_net_admin; 142662306a36Sopenharmony_ci struct sk_buff *msg; 142762306a36Sopenharmony_ci int ret; 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci ret = nlmsg_parse_deprecated(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, 143062306a36Sopenharmony_ci nldev_policy, extack); 143162306a36Sopenharmony_ci if (ret || !tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !fe->id || !tb[fe->id]) 143262306a36Sopenharmony_ci return -EINVAL; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); 143562306a36Sopenharmony_ci device = ib_device_get_by_index(sock_net(skb->sk), index); 143662306a36Sopenharmony_ci if (!device) 143762306a36Sopenharmony_ci return -EINVAL; 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci if (tb[RDMA_NLDEV_ATTR_PORT_INDEX]) { 144062306a36Sopenharmony_ci port = nla_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]); 144162306a36Sopenharmony_ci if (!rdma_is_port_valid(device, port)) { 144262306a36Sopenharmony_ci ret = -EINVAL; 144362306a36Sopenharmony_ci goto err; 144462306a36Sopenharmony_ci } 144562306a36Sopenharmony_ci } 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci if ((port && fe->flags & NLDEV_PER_DEV) || 144862306a36Sopenharmony_ci (!port && ~fe->flags & NLDEV_PER_DEV)) { 144962306a36Sopenharmony_ci ret = -EINVAL; 145062306a36Sopenharmony_ci goto err; 145162306a36Sopenharmony_ci } 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci id = nla_get_u32(tb[fe->id]); 145462306a36Sopenharmony_ci res = rdma_restrack_get_byid(device, res_type, id); 145562306a36Sopenharmony_ci if (IS_ERR(res)) { 145662306a36Sopenharmony_ci ret = PTR_ERR(res); 145762306a36Sopenharmony_ci goto err; 145862306a36Sopenharmony_ci } 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 146162306a36Sopenharmony_ci if (!msg) { 146262306a36Sopenharmony_ci ret = -ENOMEM; 146362306a36Sopenharmony_ci goto err_get; 146462306a36Sopenharmony_ci } 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 146762306a36Sopenharmony_ci RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, 146862306a36Sopenharmony_ci RDMA_NL_GET_OP(nlh->nlmsg_type)), 146962306a36Sopenharmony_ci 0, 0); 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci if (!nlh || fill_nldev_handle(msg, device)) { 147262306a36Sopenharmony_ci ret = -EMSGSIZE; 147362306a36Sopenharmony_ci goto err_free; 147462306a36Sopenharmony_ci } 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci has_cap_net_admin = netlink_capable(skb, CAP_NET_ADMIN); 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci ret = fill_func(msg, has_cap_net_admin, res, port); 147962306a36Sopenharmony_ci if (ret) 148062306a36Sopenharmony_ci goto err_free; 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci rdma_restrack_put(res); 148362306a36Sopenharmony_ci nlmsg_end(msg, nlh); 148462306a36Sopenharmony_ci ib_device_put(device); 148562306a36Sopenharmony_ci return rdma_nl_unicast(sock_net(skb->sk), msg, NETLINK_CB(skb).portid); 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_cierr_free: 148862306a36Sopenharmony_ci nlmsg_free(msg); 148962306a36Sopenharmony_cierr_get: 149062306a36Sopenharmony_ci rdma_restrack_put(res); 149162306a36Sopenharmony_cierr: 149262306a36Sopenharmony_ci ib_device_put(device); 149362306a36Sopenharmony_ci return ret; 149462306a36Sopenharmony_ci} 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_cistatic int res_get_common_dumpit(struct sk_buff *skb, 149762306a36Sopenharmony_ci struct netlink_callback *cb, 149862306a36Sopenharmony_ci enum rdma_restrack_type res_type, 149962306a36Sopenharmony_ci res_fill_func_t fill_func) 150062306a36Sopenharmony_ci{ 150162306a36Sopenharmony_ci const struct nldev_fill_res_entry *fe = &fill_entries[res_type]; 150262306a36Sopenharmony_ci struct nlattr *tb[RDMA_NLDEV_ATTR_MAX]; 150362306a36Sopenharmony_ci struct rdma_restrack_entry *res; 150462306a36Sopenharmony_ci struct rdma_restrack_root *rt; 150562306a36Sopenharmony_ci int err, ret = 0, idx = 0; 150662306a36Sopenharmony_ci struct nlattr *table_attr; 150762306a36Sopenharmony_ci struct nlattr *entry_attr; 150862306a36Sopenharmony_ci struct ib_device *device; 150962306a36Sopenharmony_ci int start = cb->args[0]; 151062306a36Sopenharmony_ci bool has_cap_net_admin; 151162306a36Sopenharmony_ci struct nlmsghdr *nlh; 151262306a36Sopenharmony_ci unsigned long id; 151362306a36Sopenharmony_ci u32 index, port = 0; 151462306a36Sopenharmony_ci bool filled = false; 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci err = nlmsg_parse_deprecated(cb->nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, 151762306a36Sopenharmony_ci nldev_policy, NULL); 151862306a36Sopenharmony_ci /* 151962306a36Sopenharmony_ci * Right now, we are expecting the device index to get res information, 152062306a36Sopenharmony_ci * but it is possible to extend this code to return all devices in 152162306a36Sopenharmony_ci * one shot by checking the existence of RDMA_NLDEV_ATTR_DEV_INDEX. 152262306a36Sopenharmony_ci * if it doesn't exist, we will iterate over all devices. 152362306a36Sopenharmony_ci * 152462306a36Sopenharmony_ci * But it is not needed for now. 152562306a36Sopenharmony_ci */ 152662306a36Sopenharmony_ci if (err || !tb[RDMA_NLDEV_ATTR_DEV_INDEX]) 152762306a36Sopenharmony_ci return -EINVAL; 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); 153062306a36Sopenharmony_ci device = ib_device_get_by_index(sock_net(skb->sk), index); 153162306a36Sopenharmony_ci if (!device) 153262306a36Sopenharmony_ci return -EINVAL; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci /* 153562306a36Sopenharmony_ci * If no PORT_INDEX is supplied, we will return all QPs from that device 153662306a36Sopenharmony_ci */ 153762306a36Sopenharmony_ci if (tb[RDMA_NLDEV_ATTR_PORT_INDEX]) { 153862306a36Sopenharmony_ci port = nla_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]); 153962306a36Sopenharmony_ci if (!rdma_is_port_valid(device, port)) { 154062306a36Sopenharmony_ci ret = -EINVAL; 154162306a36Sopenharmony_ci goto err_index; 154262306a36Sopenharmony_ci } 154362306a36Sopenharmony_ci } 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 154662306a36Sopenharmony_ci RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, 154762306a36Sopenharmony_ci RDMA_NL_GET_OP(cb->nlh->nlmsg_type)), 154862306a36Sopenharmony_ci 0, NLM_F_MULTI); 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci if (!nlh || fill_nldev_handle(skb, device)) { 155162306a36Sopenharmony_ci ret = -EMSGSIZE; 155262306a36Sopenharmony_ci goto err; 155362306a36Sopenharmony_ci } 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci table_attr = nla_nest_start_noflag(skb, fe->nldev_attr); 155662306a36Sopenharmony_ci if (!table_attr) { 155762306a36Sopenharmony_ci ret = -EMSGSIZE; 155862306a36Sopenharmony_ci goto err; 155962306a36Sopenharmony_ci } 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci has_cap_net_admin = netlink_capable(cb->skb, CAP_NET_ADMIN); 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci rt = &device->res[res_type]; 156462306a36Sopenharmony_ci xa_lock(&rt->xa); 156562306a36Sopenharmony_ci /* 156662306a36Sopenharmony_ci * FIXME: if the skip ahead is something common this loop should 156762306a36Sopenharmony_ci * use xas_for_each & xas_pause to optimize, we can have a lot of 156862306a36Sopenharmony_ci * objects. 156962306a36Sopenharmony_ci */ 157062306a36Sopenharmony_ci xa_for_each(&rt->xa, id, res) { 157162306a36Sopenharmony_ci if (idx < start || !rdma_restrack_get(res)) 157262306a36Sopenharmony_ci goto next; 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci xa_unlock(&rt->xa); 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci filled = true; 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci entry_attr = nla_nest_start_noflag(skb, fe->entry); 157962306a36Sopenharmony_ci if (!entry_attr) { 158062306a36Sopenharmony_ci ret = -EMSGSIZE; 158162306a36Sopenharmony_ci rdma_restrack_put(res); 158262306a36Sopenharmony_ci goto msg_full; 158362306a36Sopenharmony_ci } 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci ret = fill_func(skb, has_cap_net_admin, res, port); 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci rdma_restrack_put(res); 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci if (ret) { 159062306a36Sopenharmony_ci nla_nest_cancel(skb, entry_attr); 159162306a36Sopenharmony_ci if (ret == -EMSGSIZE) 159262306a36Sopenharmony_ci goto msg_full; 159362306a36Sopenharmony_ci if (ret == -EAGAIN) 159462306a36Sopenharmony_ci goto again; 159562306a36Sopenharmony_ci goto res_err; 159662306a36Sopenharmony_ci } 159762306a36Sopenharmony_ci nla_nest_end(skb, entry_attr); 159862306a36Sopenharmony_ciagain: xa_lock(&rt->xa); 159962306a36Sopenharmony_cinext: idx++; 160062306a36Sopenharmony_ci } 160162306a36Sopenharmony_ci xa_unlock(&rt->xa); 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_cimsg_full: 160462306a36Sopenharmony_ci nla_nest_end(skb, table_attr); 160562306a36Sopenharmony_ci nlmsg_end(skb, nlh); 160662306a36Sopenharmony_ci cb->args[0] = idx; 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci /* 160962306a36Sopenharmony_ci * No more entries to fill, cancel the message and 161062306a36Sopenharmony_ci * return 0 to mark end of dumpit. 161162306a36Sopenharmony_ci */ 161262306a36Sopenharmony_ci if (!filled) 161362306a36Sopenharmony_ci goto err; 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci ib_device_put(device); 161662306a36Sopenharmony_ci return skb->len; 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_cires_err: 161962306a36Sopenharmony_ci nla_nest_cancel(skb, table_attr); 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_cierr: 162262306a36Sopenharmony_ci nlmsg_cancel(skb, nlh); 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_cierr_index: 162562306a36Sopenharmony_ci ib_device_put(device); 162662306a36Sopenharmony_ci return ret; 162762306a36Sopenharmony_ci} 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci#define RES_GET_FUNCS(name, type) \ 163062306a36Sopenharmony_ci static int nldev_res_get_##name##_dumpit(struct sk_buff *skb, \ 163162306a36Sopenharmony_ci struct netlink_callback *cb) \ 163262306a36Sopenharmony_ci { \ 163362306a36Sopenharmony_ci return res_get_common_dumpit(skb, cb, type, \ 163462306a36Sopenharmony_ci fill_res_##name##_entry); \ 163562306a36Sopenharmony_ci } \ 163662306a36Sopenharmony_ci static int nldev_res_get_##name##_doit(struct sk_buff *skb, \ 163762306a36Sopenharmony_ci struct nlmsghdr *nlh, \ 163862306a36Sopenharmony_ci struct netlink_ext_ack *extack) \ 163962306a36Sopenharmony_ci { \ 164062306a36Sopenharmony_ci return res_get_common_doit(skb, nlh, extack, type, \ 164162306a36Sopenharmony_ci fill_res_##name##_entry); \ 164262306a36Sopenharmony_ci } 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ciRES_GET_FUNCS(qp, RDMA_RESTRACK_QP); 164562306a36Sopenharmony_ciRES_GET_FUNCS(qp_raw, RDMA_RESTRACK_QP); 164662306a36Sopenharmony_ciRES_GET_FUNCS(cm_id, RDMA_RESTRACK_CM_ID); 164762306a36Sopenharmony_ciRES_GET_FUNCS(cq, RDMA_RESTRACK_CQ); 164862306a36Sopenharmony_ciRES_GET_FUNCS(cq_raw, RDMA_RESTRACK_CQ); 164962306a36Sopenharmony_ciRES_GET_FUNCS(pd, RDMA_RESTRACK_PD); 165062306a36Sopenharmony_ciRES_GET_FUNCS(mr, RDMA_RESTRACK_MR); 165162306a36Sopenharmony_ciRES_GET_FUNCS(mr_raw, RDMA_RESTRACK_MR); 165262306a36Sopenharmony_ciRES_GET_FUNCS(counter, RDMA_RESTRACK_COUNTER); 165362306a36Sopenharmony_ciRES_GET_FUNCS(ctx, RDMA_RESTRACK_CTX); 165462306a36Sopenharmony_ciRES_GET_FUNCS(srq, RDMA_RESTRACK_SRQ); 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_cistatic LIST_HEAD(link_ops); 165762306a36Sopenharmony_cistatic DECLARE_RWSEM(link_ops_rwsem); 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_cistatic const struct rdma_link_ops *link_ops_get(const char *type) 166062306a36Sopenharmony_ci{ 166162306a36Sopenharmony_ci const struct rdma_link_ops *ops; 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci list_for_each_entry(ops, &link_ops, list) { 166462306a36Sopenharmony_ci if (!strcmp(ops->type, type)) 166562306a36Sopenharmony_ci goto out; 166662306a36Sopenharmony_ci } 166762306a36Sopenharmony_ci ops = NULL; 166862306a36Sopenharmony_ciout: 166962306a36Sopenharmony_ci return ops; 167062306a36Sopenharmony_ci} 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_civoid rdma_link_register(struct rdma_link_ops *ops) 167362306a36Sopenharmony_ci{ 167462306a36Sopenharmony_ci down_write(&link_ops_rwsem); 167562306a36Sopenharmony_ci if (WARN_ON_ONCE(link_ops_get(ops->type))) 167662306a36Sopenharmony_ci goto out; 167762306a36Sopenharmony_ci list_add(&ops->list, &link_ops); 167862306a36Sopenharmony_ciout: 167962306a36Sopenharmony_ci up_write(&link_ops_rwsem); 168062306a36Sopenharmony_ci} 168162306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_link_register); 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_civoid rdma_link_unregister(struct rdma_link_ops *ops) 168462306a36Sopenharmony_ci{ 168562306a36Sopenharmony_ci down_write(&link_ops_rwsem); 168662306a36Sopenharmony_ci list_del(&ops->list); 168762306a36Sopenharmony_ci up_write(&link_ops_rwsem); 168862306a36Sopenharmony_ci} 168962306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_link_unregister); 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_cistatic int nldev_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, 169262306a36Sopenharmony_ci struct netlink_ext_ack *extack) 169362306a36Sopenharmony_ci{ 169462306a36Sopenharmony_ci struct nlattr *tb[RDMA_NLDEV_ATTR_MAX]; 169562306a36Sopenharmony_ci char ibdev_name[IB_DEVICE_NAME_MAX]; 169662306a36Sopenharmony_ci const struct rdma_link_ops *ops; 169762306a36Sopenharmony_ci char ndev_name[IFNAMSIZ]; 169862306a36Sopenharmony_ci struct net_device *ndev; 169962306a36Sopenharmony_ci char type[IFNAMSIZ]; 170062306a36Sopenharmony_ci int err; 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci err = nlmsg_parse_deprecated(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, 170362306a36Sopenharmony_ci nldev_policy, extack); 170462306a36Sopenharmony_ci if (err || !tb[RDMA_NLDEV_ATTR_DEV_NAME] || 170562306a36Sopenharmony_ci !tb[RDMA_NLDEV_ATTR_LINK_TYPE] || !tb[RDMA_NLDEV_ATTR_NDEV_NAME]) 170662306a36Sopenharmony_ci return -EINVAL; 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci nla_strscpy(ibdev_name, tb[RDMA_NLDEV_ATTR_DEV_NAME], 170962306a36Sopenharmony_ci sizeof(ibdev_name)); 171062306a36Sopenharmony_ci if (strchr(ibdev_name, '%') || strlen(ibdev_name) == 0) 171162306a36Sopenharmony_ci return -EINVAL; 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci nla_strscpy(type, tb[RDMA_NLDEV_ATTR_LINK_TYPE], sizeof(type)); 171462306a36Sopenharmony_ci nla_strscpy(ndev_name, tb[RDMA_NLDEV_ATTR_NDEV_NAME], 171562306a36Sopenharmony_ci sizeof(ndev_name)); 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci ndev = dev_get_by_name(sock_net(skb->sk), ndev_name); 171862306a36Sopenharmony_ci if (!ndev) 171962306a36Sopenharmony_ci return -ENODEV; 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci down_read(&link_ops_rwsem); 172262306a36Sopenharmony_ci ops = link_ops_get(type); 172362306a36Sopenharmony_ci#ifdef CONFIG_MODULES 172462306a36Sopenharmony_ci if (!ops) { 172562306a36Sopenharmony_ci up_read(&link_ops_rwsem); 172662306a36Sopenharmony_ci request_module("rdma-link-%s", type); 172762306a36Sopenharmony_ci down_read(&link_ops_rwsem); 172862306a36Sopenharmony_ci ops = link_ops_get(type); 172962306a36Sopenharmony_ci } 173062306a36Sopenharmony_ci#endif 173162306a36Sopenharmony_ci err = ops ? ops->newlink(ibdev_name, ndev) : -EINVAL; 173262306a36Sopenharmony_ci up_read(&link_ops_rwsem); 173362306a36Sopenharmony_ci dev_put(ndev); 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci return err; 173662306a36Sopenharmony_ci} 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_cistatic int nldev_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, 173962306a36Sopenharmony_ci struct netlink_ext_ack *extack) 174062306a36Sopenharmony_ci{ 174162306a36Sopenharmony_ci struct nlattr *tb[RDMA_NLDEV_ATTR_MAX]; 174262306a36Sopenharmony_ci struct ib_device *device; 174362306a36Sopenharmony_ci u32 index; 174462306a36Sopenharmony_ci int err; 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci err = nlmsg_parse_deprecated(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, 174762306a36Sopenharmony_ci nldev_policy, extack); 174862306a36Sopenharmony_ci if (err || !tb[RDMA_NLDEV_ATTR_DEV_INDEX]) 174962306a36Sopenharmony_ci return -EINVAL; 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); 175262306a36Sopenharmony_ci device = ib_device_get_by_index(sock_net(skb->sk), index); 175362306a36Sopenharmony_ci if (!device) 175462306a36Sopenharmony_ci return -EINVAL; 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_ci if (!(device->attrs.kernel_cap_flags & IBK_ALLOW_USER_UNREG)) { 175762306a36Sopenharmony_ci ib_device_put(device); 175862306a36Sopenharmony_ci return -EINVAL; 175962306a36Sopenharmony_ci } 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci ib_unregister_device_and_put(device); 176262306a36Sopenharmony_ci return 0; 176362306a36Sopenharmony_ci} 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_cistatic int nldev_get_chardev(struct sk_buff *skb, struct nlmsghdr *nlh, 176662306a36Sopenharmony_ci struct netlink_ext_ack *extack) 176762306a36Sopenharmony_ci{ 176862306a36Sopenharmony_ci struct nlattr *tb[RDMA_NLDEV_ATTR_MAX]; 176962306a36Sopenharmony_ci char client_name[RDMA_NLDEV_ATTR_CHARDEV_TYPE_SIZE]; 177062306a36Sopenharmony_ci struct ib_client_nl_info data = {}; 177162306a36Sopenharmony_ci struct ib_device *ibdev = NULL; 177262306a36Sopenharmony_ci struct sk_buff *msg; 177362306a36Sopenharmony_ci u32 index; 177462306a36Sopenharmony_ci int err; 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, nldev_policy, 177762306a36Sopenharmony_ci extack); 177862306a36Sopenharmony_ci if (err || !tb[RDMA_NLDEV_ATTR_CHARDEV_TYPE]) 177962306a36Sopenharmony_ci return -EINVAL; 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_ci nla_strscpy(client_name, tb[RDMA_NLDEV_ATTR_CHARDEV_TYPE], 178262306a36Sopenharmony_ci sizeof(client_name)); 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci if (tb[RDMA_NLDEV_ATTR_DEV_INDEX]) { 178562306a36Sopenharmony_ci index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); 178662306a36Sopenharmony_ci ibdev = ib_device_get_by_index(sock_net(skb->sk), index); 178762306a36Sopenharmony_ci if (!ibdev) 178862306a36Sopenharmony_ci return -EINVAL; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci if (tb[RDMA_NLDEV_ATTR_PORT_INDEX]) { 179162306a36Sopenharmony_ci data.port = nla_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]); 179262306a36Sopenharmony_ci if (!rdma_is_port_valid(ibdev, data.port)) { 179362306a36Sopenharmony_ci err = -EINVAL; 179462306a36Sopenharmony_ci goto out_put; 179562306a36Sopenharmony_ci } 179662306a36Sopenharmony_ci } else { 179762306a36Sopenharmony_ci data.port = -1; 179862306a36Sopenharmony_ci } 179962306a36Sopenharmony_ci } else if (tb[RDMA_NLDEV_ATTR_PORT_INDEX]) { 180062306a36Sopenharmony_ci return -EINVAL; 180162306a36Sopenharmony_ci } 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 180462306a36Sopenharmony_ci if (!msg) { 180562306a36Sopenharmony_ci err = -ENOMEM; 180662306a36Sopenharmony_ci goto out_put; 180762306a36Sopenharmony_ci } 180862306a36Sopenharmony_ci nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 180962306a36Sopenharmony_ci RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, 181062306a36Sopenharmony_ci RDMA_NLDEV_CMD_GET_CHARDEV), 181162306a36Sopenharmony_ci 0, 0); 181262306a36Sopenharmony_ci if (!nlh) { 181362306a36Sopenharmony_ci err = -EMSGSIZE; 181462306a36Sopenharmony_ci goto out_nlmsg; 181562306a36Sopenharmony_ci } 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci data.nl_msg = msg; 181862306a36Sopenharmony_ci err = ib_get_client_nl_info(ibdev, client_name, &data); 181962306a36Sopenharmony_ci if (err) 182062306a36Sopenharmony_ci goto out_nlmsg; 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci err = nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_CHARDEV, 182362306a36Sopenharmony_ci huge_encode_dev(data.cdev->devt), 182462306a36Sopenharmony_ci RDMA_NLDEV_ATTR_PAD); 182562306a36Sopenharmony_ci if (err) 182662306a36Sopenharmony_ci goto out_data; 182762306a36Sopenharmony_ci err = nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_CHARDEV_ABI, data.abi, 182862306a36Sopenharmony_ci RDMA_NLDEV_ATTR_PAD); 182962306a36Sopenharmony_ci if (err) 183062306a36Sopenharmony_ci goto out_data; 183162306a36Sopenharmony_ci if (nla_put_string(msg, RDMA_NLDEV_ATTR_CHARDEV_NAME, 183262306a36Sopenharmony_ci dev_name(data.cdev))) { 183362306a36Sopenharmony_ci err = -EMSGSIZE; 183462306a36Sopenharmony_ci goto out_data; 183562306a36Sopenharmony_ci } 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci nlmsg_end(msg, nlh); 183862306a36Sopenharmony_ci put_device(data.cdev); 183962306a36Sopenharmony_ci if (ibdev) 184062306a36Sopenharmony_ci ib_device_put(ibdev); 184162306a36Sopenharmony_ci return rdma_nl_unicast(sock_net(skb->sk), msg, NETLINK_CB(skb).portid); 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ciout_data: 184462306a36Sopenharmony_ci put_device(data.cdev); 184562306a36Sopenharmony_ciout_nlmsg: 184662306a36Sopenharmony_ci nlmsg_free(msg); 184762306a36Sopenharmony_ciout_put: 184862306a36Sopenharmony_ci if (ibdev) 184962306a36Sopenharmony_ci ib_device_put(ibdev); 185062306a36Sopenharmony_ci return err; 185162306a36Sopenharmony_ci} 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_cistatic int nldev_sys_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh, 185462306a36Sopenharmony_ci struct netlink_ext_ack *extack) 185562306a36Sopenharmony_ci{ 185662306a36Sopenharmony_ci struct nlattr *tb[RDMA_NLDEV_ATTR_MAX]; 185762306a36Sopenharmony_ci struct sk_buff *msg; 185862306a36Sopenharmony_ci int err; 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, 186162306a36Sopenharmony_ci nldev_policy, extack); 186262306a36Sopenharmony_ci if (err) 186362306a36Sopenharmony_ci return err; 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 186662306a36Sopenharmony_ci if (!msg) 186762306a36Sopenharmony_ci return -ENOMEM; 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 187062306a36Sopenharmony_ci RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, 187162306a36Sopenharmony_ci RDMA_NLDEV_CMD_SYS_GET), 187262306a36Sopenharmony_ci 0, 0); 187362306a36Sopenharmony_ci if (!nlh) { 187462306a36Sopenharmony_ci nlmsg_free(msg); 187562306a36Sopenharmony_ci return -EMSGSIZE; 187662306a36Sopenharmony_ci } 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci err = nla_put_u8(msg, RDMA_NLDEV_SYS_ATTR_NETNS_MODE, 187962306a36Sopenharmony_ci (u8)ib_devices_shared_netns); 188062306a36Sopenharmony_ci if (err) { 188162306a36Sopenharmony_ci nlmsg_free(msg); 188262306a36Sopenharmony_ci return err; 188362306a36Sopenharmony_ci } 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci /* 188662306a36Sopenharmony_ci * Copy-on-fork is supported. 188762306a36Sopenharmony_ci * See commits: 188862306a36Sopenharmony_ci * 70e806e4e645 ("mm: Do early cow for pinned pages during fork() for ptes") 188962306a36Sopenharmony_ci * 4eae4efa2c29 ("hugetlb: do early cow when page pinned on src mm") 189062306a36Sopenharmony_ci * for more details. Don't backport this without them. 189162306a36Sopenharmony_ci * 189262306a36Sopenharmony_ci * Return value ignored on purpose, assume copy-on-fork is not 189362306a36Sopenharmony_ci * supported in case of failure. 189462306a36Sopenharmony_ci */ 189562306a36Sopenharmony_ci nla_put_u8(msg, RDMA_NLDEV_SYS_ATTR_COPY_ON_FORK, 1); 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci nlmsg_end(msg, nlh); 189862306a36Sopenharmony_ci return rdma_nl_unicast(sock_net(skb->sk), msg, NETLINK_CB(skb).portid); 189962306a36Sopenharmony_ci} 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_cistatic int nldev_set_sys_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh, 190262306a36Sopenharmony_ci struct netlink_ext_ack *extack) 190362306a36Sopenharmony_ci{ 190462306a36Sopenharmony_ci struct nlattr *tb[RDMA_NLDEV_ATTR_MAX]; 190562306a36Sopenharmony_ci u8 enable; 190662306a36Sopenharmony_ci int err; 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, 190962306a36Sopenharmony_ci nldev_policy, extack); 191062306a36Sopenharmony_ci if (err || !tb[RDMA_NLDEV_SYS_ATTR_NETNS_MODE]) 191162306a36Sopenharmony_ci return -EINVAL; 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci enable = nla_get_u8(tb[RDMA_NLDEV_SYS_ATTR_NETNS_MODE]); 191462306a36Sopenharmony_ci /* Only 0 and 1 are supported */ 191562306a36Sopenharmony_ci if (enable > 1) 191662306a36Sopenharmony_ci return -EINVAL; 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci err = rdma_compatdev_set(enable); 191962306a36Sopenharmony_ci return err; 192062306a36Sopenharmony_ci} 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_cistatic int nldev_stat_set_mode_doit(struct sk_buff *msg, 192362306a36Sopenharmony_ci struct netlink_ext_ack *extack, 192462306a36Sopenharmony_ci struct nlattr *tb[], 192562306a36Sopenharmony_ci struct ib_device *device, u32 port) 192662306a36Sopenharmony_ci{ 192762306a36Sopenharmony_ci u32 mode, mask = 0, qpn, cntn = 0; 192862306a36Sopenharmony_ci int ret; 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci /* Currently only counter for QP is supported */ 193162306a36Sopenharmony_ci if (!tb[RDMA_NLDEV_ATTR_STAT_RES] || 193262306a36Sopenharmony_ci nla_get_u32(tb[RDMA_NLDEV_ATTR_STAT_RES]) != RDMA_NLDEV_ATTR_RES_QP) 193362306a36Sopenharmony_ci return -EINVAL; 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci mode = nla_get_u32(tb[RDMA_NLDEV_ATTR_STAT_MODE]); 193662306a36Sopenharmony_ci if (mode == RDMA_COUNTER_MODE_AUTO) { 193762306a36Sopenharmony_ci if (tb[RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK]) 193862306a36Sopenharmony_ci mask = nla_get_u32( 193962306a36Sopenharmony_ci tb[RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK]); 194062306a36Sopenharmony_ci return rdma_counter_set_auto_mode(device, port, mask, extack); 194162306a36Sopenharmony_ci } 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci if (!tb[RDMA_NLDEV_ATTR_RES_LQPN]) 194462306a36Sopenharmony_ci return -EINVAL; 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci qpn = nla_get_u32(tb[RDMA_NLDEV_ATTR_RES_LQPN]); 194762306a36Sopenharmony_ci if (tb[RDMA_NLDEV_ATTR_STAT_COUNTER_ID]) { 194862306a36Sopenharmony_ci cntn = nla_get_u32(tb[RDMA_NLDEV_ATTR_STAT_COUNTER_ID]); 194962306a36Sopenharmony_ci ret = rdma_counter_bind_qpn(device, port, qpn, cntn); 195062306a36Sopenharmony_ci if (ret) 195162306a36Sopenharmony_ci return ret; 195262306a36Sopenharmony_ci } else { 195362306a36Sopenharmony_ci ret = rdma_counter_bind_qpn_alloc(device, port, qpn, &cntn); 195462306a36Sopenharmony_ci if (ret) 195562306a36Sopenharmony_ci return ret; 195662306a36Sopenharmony_ci } 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci if (nla_put_u32(msg, RDMA_NLDEV_ATTR_STAT_COUNTER_ID, cntn) || 195962306a36Sopenharmony_ci nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_LQPN, qpn)) { 196062306a36Sopenharmony_ci ret = -EMSGSIZE; 196162306a36Sopenharmony_ci goto err_fill; 196262306a36Sopenharmony_ci } 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci return 0; 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_cierr_fill: 196762306a36Sopenharmony_ci rdma_counter_unbind_qpn(device, port, qpn, cntn); 196862306a36Sopenharmony_ci return ret; 196962306a36Sopenharmony_ci} 197062306a36Sopenharmony_ci 197162306a36Sopenharmony_cistatic int nldev_stat_set_counter_dynamic_doit(struct nlattr *tb[], 197262306a36Sopenharmony_ci struct ib_device *device, 197362306a36Sopenharmony_ci u32 port) 197462306a36Sopenharmony_ci{ 197562306a36Sopenharmony_ci struct rdma_hw_stats *stats; 197662306a36Sopenharmony_ci struct nlattr *entry_attr; 197762306a36Sopenharmony_ci unsigned long *target; 197862306a36Sopenharmony_ci int rem, i, ret = 0; 197962306a36Sopenharmony_ci u32 index; 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_ci stats = ib_get_hw_stats_port(device, port); 198262306a36Sopenharmony_ci if (!stats) 198362306a36Sopenharmony_ci return -EINVAL; 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci target = kcalloc(BITS_TO_LONGS(stats->num_counters), 198662306a36Sopenharmony_ci sizeof(*stats->is_disabled), GFP_KERNEL); 198762306a36Sopenharmony_ci if (!target) 198862306a36Sopenharmony_ci return -ENOMEM; 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci nla_for_each_nested(entry_attr, tb[RDMA_NLDEV_ATTR_STAT_HWCOUNTERS], 199162306a36Sopenharmony_ci rem) { 199262306a36Sopenharmony_ci index = nla_get_u32(entry_attr); 199362306a36Sopenharmony_ci if ((index >= stats->num_counters) || 199462306a36Sopenharmony_ci !(stats->descs[index].flags & IB_STAT_FLAG_OPTIONAL)) { 199562306a36Sopenharmony_ci ret = -EINVAL; 199662306a36Sopenharmony_ci goto out; 199762306a36Sopenharmony_ci } 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci set_bit(index, target); 200062306a36Sopenharmony_ci } 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ci for (i = 0; i < stats->num_counters; i++) { 200362306a36Sopenharmony_ci if (!(stats->descs[i].flags & IB_STAT_FLAG_OPTIONAL)) 200462306a36Sopenharmony_ci continue; 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci ret = rdma_counter_modify(device, port, i, test_bit(i, target)); 200762306a36Sopenharmony_ci if (ret) 200862306a36Sopenharmony_ci goto out; 200962306a36Sopenharmony_ci } 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ciout: 201262306a36Sopenharmony_ci kfree(target); 201362306a36Sopenharmony_ci return ret; 201462306a36Sopenharmony_ci} 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_cistatic int nldev_stat_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh, 201762306a36Sopenharmony_ci struct netlink_ext_ack *extack) 201862306a36Sopenharmony_ci{ 201962306a36Sopenharmony_ci struct nlattr *tb[RDMA_NLDEV_ATTR_MAX]; 202062306a36Sopenharmony_ci struct ib_device *device; 202162306a36Sopenharmony_ci struct sk_buff *msg; 202262306a36Sopenharmony_ci u32 index, port; 202362306a36Sopenharmony_ci int ret; 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_ci ret = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, nldev_policy, 202662306a36Sopenharmony_ci extack); 202762306a36Sopenharmony_ci if (ret || !tb[RDMA_NLDEV_ATTR_DEV_INDEX] || 202862306a36Sopenharmony_ci !tb[RDMA_NLDEV_ATTR_PORT_INDEX]) 202962306a36Sopenharmony_ci return -EINVAL; 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); 203262306a36Sopenharmony_ci device = ib_device_get_by_index(sock_net(skb->sk), index); 203362306a36Sopenharmony_ci if (!device) 203462306a36Sopenharmony_ci return -EINVAL; 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci port = nla_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]); 203762306a36Sopenharmony_ci if (!rdma_is_port_valid(device, port)) { 203862306a36Sopenharmony_ci ret = -EINVAL; 203962306a36Sopenharmony_ci goto err_put_device; 204062306a36Sopenharmony_ci } 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_ci if (!tb[RDMA_NLDEV_ATTR_STAT_MODE] && 204362306a36Sopenharmony_ci !tb[RDMA_NLDEV_ATTR_STAT_HWCOUNTERS]) { 204462306a36Sopenharmony_ci ret = -EINVAL; 204562306a36Sopenharmony_ci goto err_put_device; 204662306a36Sopenharmony_ci } 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 204962306a36Sopenharmony_ci if (!msg) { 205062306a36Sopenharmony_ci ret = -ENOMEM; 205162306a36Sopenharmony_ci goto err_put_device; 205262306a36Sopenharmony_ci } 205362306a36Sopenharmony_ci nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 205462306a36Sopenharmony_ci RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, 205562306a36Sopenharmony_ci RDMA_NLDEV_CMD_STAT_SET), 205662306a36Sopenharmony_ci 0, 0); 205762306a36Sopenharmony_ci if (!nlh || fill_nldev_handle(msg, device) || 205862306a36Sopenharmony_ci nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, port)) { 205962306a36Sopenharmony_ci ret = -EMSGSIZE; 206062306a36Sopenharmony_ci goto err_free_msg; 206162306a36Sopenharmony_ci } 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_ci if (tb[RDMA_NLDEV_ATTR_STAT_MODE]) { 206462306a36Sopenharmony_ci ret = nldev_stat_set_mode_doit(msg, extack, tb, device, port); 206562306a36Sopenharmony_ci if (ret) 206662306a36Sopenharmony_ci goto err_free_msg; 206762306a36Sopenharmony_ci } 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci if (tb[RDMA_NLDEV_ATTR_STAT_HWCOUNTERS]) { 207062306a36Sopenharmony_ci ret = nldev_stat_set_counter_dynamic_doit(tb, device, port); 207162306a36Sopenharmony_ci if (ret) 207262306a36Sopenharmony_ci goto err_free_msg; 207362306a36Sopenharmony_ci } 207462306a36Sopenharmony_ci 207562306a36Sopenharmony_ci nlmsg_end(msg, nlh); 207662306a36Sopenharmony_ci ib_device_put(device); 207762306a36Sopenharmony_ci return rdma_nl_unicast(sock_net(skb->sk), msg, NETLINK_CB(skb).portid); 207862306a36Sopenharmony_ci 207962306a36Sopenharmony_cierr_free_msg: 208062306a36Sopenharmony_ci nlmsg_free(msg); 208162306a36Sopenharmony_cierr_put_device: 208262306a36Sopenharmony_ci ib_device_put(device); 208362306a36Sopenharmony_ci return ret; 208462306a36Sopenharmony_ci} 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_cistatic int nldev_stat_del_doit(struct sk_buff *skb, struct nlmsghdr *nlh, 208762306a36Sopenharmony_ci struct netlink_ext_ack *extack) 208862306a36Sopenharmony_ci{ 208962306a36Sopenharmony_ci struct nlattr *tb[RDMA_NLDEV_ATTR_MAX]; 209062306a36Sopenharmony_ci struct ib_device *device; 209162306a36Sopenharmony_ci struct sk_buff *msg; 209262306a36Sopenharmony_ci u32 index, port, qpn, cntn; 209362306a36Sopenharmony_ci int ret; 209462306a36Sopenharmony_ci 209562306a36Sopenharmony_ci ret = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, 209662306a36Sopenharmony_ci nldev_policy, extack); 209762306a36Sopenharmony_ci if (ret || !tb[RDMA_NLDEV_ATTR_STAT_RES] || 209862306a36Sopenharmony_ci !tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_PORT_INDEX] || 209962306a36Sopenharmony_ci !tb[RDMA_NLDEV_ATTR_STAT_COUNTER_ID] || 210062306a36Sopenharmony_ci !tb[RDMA_NLDEV_ATTR_RES_LQPN]) 210162306a36Sopenharmony_ci return -EINVAL; 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_ci if (nla_get_u32(tb[RDMA_NLDEV_ATTR_STAT_RES]) != RDMA_NLDEV_ATTR_RES_QP) 210462306a36Sopenharmony_ci return -EINVAL; 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_ci index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); 210762306a36Sopenharmony_ci device = ib_device_get_by_index(sock_net(skb->sk), index); 210862306a36Sopenharmony_ci if (!device) 210962306a36Sopenharmony_ci return -EINVAL; 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci port = nla_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]); 211262306a36Sopenharmony_ci if (!rdma_is_port_valid(device, port)) { 211362306a36Sopenharmony_ci ret = -EINVAL; 211462306a36Sopenharmony_ci goto err; 211562306a36Sopenharmony_ci } 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 211862306a36Sopenharmony_ci if (!msg) { 211962306a36Sopenharmony_ci ret = -ENOMEM; 212062306a36Sopenharmony_ci goto err; 212162306a36Sopenharmony_ci } 212262306a36Sopenharmony_ci nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 212362306a36Sopenharmony_ci RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, 212462306a36Sopenharmony_ci RDMA_NLDEV_CMD_STAT_SET), 212562306a36Sopenharmony_ci 0, 0); 212662306a36Sopenharmony_ci if (!nlh) { 212762306a36Sopenharmony_ci ret = -EMSGSIZE; 212862306a36Sopenharmony_ci goto err_fill; 212962306a36Sopenharmony_ci } 213062306a36Sopenharmony_ci 213162306a36Sopenharmony_ci cntn = nla_get_u32(tb[RDMA_NLDEV_ATTR_STAT_COUNTER_ID]); 213262306a36Sopenharmony_ci qpn = nla_get_u32(tb[RDMA_NLDEV_ATTR_RES_LQPN]); 213362306a36Sopenharmony_ci if (fill_nldev_handle(msg, device) || 213462306a36Sopenharmony_ci nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, port) || 213562306a36Sopenharmony_ci nla_put_u32(msg, RDMA_NLDEV_ATTR_STAT_COUNTER_ID, cntn) || 213662306a36Sopenharmony_ci nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_LQPN, qpn)) { 213762306a36Sopenharmony_ci ret = -EMSGSIZE; 213862306a36Sopenharmony_ci goto err_fill; 213962306a36Sopenharmony_ci } 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ci ret = rdma_counter_unbind_qpn(device, port, qpn, cntn); 214262306a36Sopenharmony_ci if (ret) 214362306a36Sopenharmony_ci goto err_fill; 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci nlmsg_end(msg, nlh); 214662306a36Sopenharmony_ci ib_device_put(device); 214762306a36Sopenharmony_ci return rdma_nl_unicast(sock_net(skb->sk), msg, NETLINK_CB(skb).portid); 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_cierr_fill: 215062306a36Sopenharmony_ci nlmsg_free(msg); 215162306a36Sopenharmony_cierr: 215262306a36Sopenharmony_ci ib_device_put(device); 215362306a36Sopenharmony_ci return ret; 215462306a36Sopenharmony_ci} 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_cistatic int stat_get_doit_default_counter(struct sk_buff *skb, 215762306a36Sopenharmony_ci struct nlmsghdr *nlh, 215862306a36Sopenharmony_ci struct netlink_ext_ack *extack, 215962306a36Sopenharmony_ci struct nlattr *tb[]) 216062306a36Sopenharmony_ci{ 216162306a36Sopenharmony_ci struct rdma_hw_stats *stats; 216262306a36Sopenharmony_ci struct nlattr *table_attr; 216362306a36Sopenharmony_ci struct ib_device *device; 216462306a36Sopenharmony_ci int ret, num_cnts, i; 216562306a36Sopenharmony_ci struct sk_buff *msg; 216662306a36Sopenharmony_ci u32 index, port; 216762306a36Sopenharmony_ci u64 v; 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_ci if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_PORT_INDEX]) 217062306a36Sopenharmony_ci return -EINVAL; 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); 217362306a36Sopenharmony_ci device = ib_device_get_by_index(sock_net(skb->sk), index); 217462306a36Sopenharmony_ci if (!device) 217562306a36Sopenharmony_ci return -EINVAL; 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_ci if (!device->ops.alloc_hw_port_stats || !device->ops.get_hw_stats) { 217862306a36Sopenharmony_ci ret = -EINVAL; 217962306a36Sopenharmony_ci goto err; 218062306a36Sopenharmony_ci } 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_ci port = nla_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]); 218362306a36Sopenharmony_ci stats = ib_get_hw_stats_port(device, port); 218462306a36Sopenharmony_ci if (!stats) { 218562306a36Sopenharmony_ci ret = -EINVAL; 218662306a36Sopenharmony_ci goto err; 218762306a36Sopenharmony_ci } 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 219062306a36Sopenharmony_ci if (!msg) { 219162306a36Sopenharmony_ci ret = -ENOMEM; 219262306a36Sopenharmony_ci goto err; 219362306a36Sopenharmony_ci } 219462306a36Sopenharmony_ci 219562306a36Sopenharmony_ci nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 219662306a36Sopenharmony_ci RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, 219762306a36Sopenharmony_ci RDMA_NLDEV_CMD_STAT_GET), 219862306a36Sopenharmony_ci 0, 0); 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci if (!nlh || fill_nldev_handle(msg, device) || 220162306a36Sopenharmony_ci nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, port)) { 220262306a36Sopenharmony_ci ret = -EMSGSIZE; 220362306a36Sopenharmony_ci goto err_msg; 220462306a36Sopenharmony_ci } 220562306a36Sopenharmony_ci 220662306a36Sopenharmony_ci mutex_lock(&stats->lock); 220762306a36Sopenharmony_ci 220862306a36Sopenharmony_ci num_cnts = device->ops.get_hw_stats(device, stats, port, 0); 220962306a36Sopenharmony_ci if (num_cnts < 0) { 221062306a36Sopenharmony_ci ret = -EINVAL; 221162306a36Sopenharmony_ci goto err_stats; 221262306a36Sopenharmony_ci } 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_ci table_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_STAT_HWCOUNTERS); 221562306a36Sopenharmony_ci if (!table_attr) { 221662306a36Sopenharmony_ci ret = -EMSGSIZE; 221762306a36Sopenharmony_ci goto err_stats; 221862306a36Sopenharmony_ci } 221962306a36Sopenharmony_ci for (i = 0; i < num_cnts; i++) { 222062306a36Sopenharmony_ci if (test_bit(i, stats->is_disabled)) 222162306a36Sopenharmony_ci continue; 222262306a36Sopenharmony_ci 222362306a36Sopenharmony_ci v = stats->value[i] + 222462306a36Sopenharmony_ci rdma_counter_get_hwstat_value(device, port, i); 222562306a36Sopenharmony_ci if (rdma_nl_stat_hwcounter_entry(msg, 222662306a36Sopenharmony_ci stats->descs[i].name, v)) { 222762306a36Sopenharmony_ci ret = -EMSGSIZE; 222862306a36Sopenharmony_ci goto err_table; 222962306a36Sopenharmony_ci } 223062306a36Sopenharmony_ci } 223162306a36Sopenharmony_ci nla_nest_end(msg, table_attr); 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_ci mutex_unlock(&stats->lock); 223462306a36Sopenharmony_ci nlmsg_end(msg, nlh); 223562306a36Sopenharmony_ci ib_device_put(device); 223662306a36Sopenharmony_ci return rdma_nl_unicast(sock_net(skb->sk), msg, NETLINK_CB(skb).portid); 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_cierr_table: 223962306a36Sopenharmony_ci nla_nest_cancel(msg, table_attr); 224062306a36Sopenharmony_cierr_stats: 224162306a36Sopenharmony_ci mutex_unlock(&stats->lock); 224262306a36Sopenharmony_cierr_msg: 224362306a36Sopenharmony_ci nlmsg_free(msg); 224462306a36Sopenharmony_cierr: 224562306a36Sopenharmony_ci ib_device_put(device); 224662306a36Sopenharmony_ci return ret; 224762306a36Sopenharmony_ci} 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_cistatic int stat_get_doit_qp(struct sk_buff *skb, struct nlmsghdr *nlh, 225062306a36Sopenharmony_ci struct netlink_ext_ack *extack, struct nlattr *tb[]) 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_ci{ 225362306a36Sopenharmony_ci static enum rdma_nl_counter_mode mode; 225462306a36Sopenharmony_ci static enum rdma_nl_counter_mask mask; 225562306a36Sopenharmony_ci struct ib_device *device; 225662306a36Sopenharmony_ci struct sk_buff *msg; 225762306a36Sopenharmony_ci u32 index, port; 225862306a36Sopenharmony_ci int ret; 225962306a36Sopenharmony_ci 226062306a36Sopenharmony_ci if (tb[RDMA_NLDEV_ATTR_STAT_COUNTER_ID]) 226162306a36Sopenharmony_ci return nldev_res_get_counter_doit(skb, nlh, extack); 226262306a36Sopenharmony_ci 226362306a36Sopenharmony_ci if (!tb[RDMA_NLDEV_ATTR_STAT_MODE] || 226462306a36Sopenharmony_ci !tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_PORT_INDEX]) 226562306a36Sopenharmony_ci return -EINVAL; 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_ci index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); 226862306a36Sopenharmony_ci device = ib_device_get_by_index(sock_net(skb->sk), index); 226962306a36Sopenharmony_ci if (!device) 227062306a36Sopenharmony_ci return -EINVAL; 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_ci port = nla_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]); 227362306a36Sopenharmony_ci if (!rdma_is_port_valid(device, port)) { 227462306a36Sopenharmony_ci ret = -EINVAL; 227562306a36Sopenharmony_ci goto err; 227662306a36Sopenharmony_ci } 227762306a36Sopenharmony_ci 227862306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 227962306a36Sopenharmony_ci if (!msg) { 228062306a36Sopenharmony_ci ret = -ENOMEM; 228162306a36Sopenharmony_ci goto err; 228262306a36Sopenharmony_ci } 228362306a36Sopenharmony_ci 228462306a36Sopenharmony_ci nlh = nlmsg_put(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 228562306a36Sopenharmony_ci RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, 228662306a36Sopenharmony_ci RDMA_NLDEV_CMD_STAT_GET), 228762306a36Sopenharmony_ci 0, 0); 228862306a36Sopenharmony_ci if (!nlh) { 228962306a36Sopenharmony_ci ret = -EMSGSIZE; 229062306a36Sopenharmony_ci goto err_msg; 229162306a36Sopenharmony_ci } 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_ci ret = rdma_counter_get_mode(device, port, &mode, &mask); 229462306a36Sopenharmony_ci if (ret) 229562306a36Sopenharmony_ci goto err_msg; 229662306a36Sopenharmony_ci 229762306a36Sopenharmony_ci if (fill_nldev_handle(msg, device) || 229862306a36Sopenharmony_ci nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, port) || 229962306a36Sopenharmony_ci nla_put_u32(msg, RDMA_NLDEV_ATTR_STAT_MODE, mode)) { 230062306a36Sopenharmony_ci ret = -EMSGSIZE; 230162306a36Sopenharmony_ci goto err_msg; 230262306a36Sopenharmony_ci } 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_ci if ((mode == RDMA_COUNTER_MODE_AUTO) && 230562306a36Sopenharmony_ci nla_put_u32(msg, RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK, mask)) { 230662306a36Sopenharmony_ci ret = -EMSGSIZE; 230762306a36Sopenharmony_ci goto err_msg; 230862306a36Sopenharmony_ci } 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ci nlmsg_end(msg, nlh); 231162306a36Sopenharmony_ci ib_device_put(device); 231262306a36Sopenharmony_ci return rdma_nl_unicast(sock_net(skb->sk), msg, NETLINK_CB(skb).portid); 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_cierr_msg: 231562306a36Sopenharmony_ci nlmsg_free(msg); 231662306a36Sopenharmony_cierr: 231762306a36Sopenharmony_ci ib_device_put(device); 231862306a36Sopenharmony_ci return ret; 231962306a36Sopenharmony_ci} 232062306a36Sopenharmony_ci 232162306a36Sopenharmony_cistatic int nldev_stat_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh, 232262306a36Sopenharmony_ci struct netlink_ext_ack *extack) 232362306a36Sopenharmony_ci{ 232462306a36Sopenharmony_ci struct nlattr *tb[RDMA_NLDEV_ATTR_MAX]; 232562306a36Sopenharmony_ci int ret; 232662306a36Sopenharmony_ci 232762306a36Sopenharmony_ci ret = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, 232862306a36Sopenharmony_ci nldev_policy, extack); 232962306a36Sopenharmony_ci if (ret) 233062306a36Sopenharmony_ci return -EINVAL; 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci if (!tb[RDMA_NLDEV_ATTR_STAT_RES]) 233362306a36Sopenharmony_ci return stat_get_doit_default_counter(skb, nlh, extack, tb); 233462306a36Sopenharmony_ci 233562306a36Sopenharmony_ci switch (nla_get_u32(tb[RDMA_NLDEV_ATTR_STAT_RES])) { 233662306a36Sopenharmony_ci case RDMA_NLDEV_ATTR_RES_QP: 233762306a36Sopenharmony_ci ret = stat_get_doit_qp(skb, nlh, extack, tb); 233862306a36Sopenharmony_ci break; 233962306a36Sopenharmony_ci case RDMA_NLDEV_ATTR_RES_MR: 234062306a36Sopenharmony_ci ret = res_get_common_doit(skb, nlh, extack, RDMA_RESTRACK_MR, 234162306a36Sopenharmony_ci fill_stat_mr_entry); 234262306a36Sopenharmony_ci break; 234362306a36Sopenharmony_ci default: 234462306a36Sopenharmony_ci ret = -EINVAL; 234562306a36Sopenharmony_ci break; 234662306a36Sopenharmony_ci } 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_ci return ret; 234962306a36Sopenharmony_ci} 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_cistatic int nldev_stat_get_dumpit(struct sk_buff *skb, 235262306a36Sopenharmony_ci struct netlink_callback *cb) 235362306a36Sopenharmony_ci{ 235462306a36Sopenharmony_ci struct nlattr *tb[RDMA_NLDEV_ATTR_MAX]; 235562306a36Sopenharmony_ci int ret; 235662306a36Sopenharmony_ci 235762306a36Sopenharmony_ci ret = nlmsg_parse(cb->nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, 235862306a36Sopenharmony_ci nldev_policy, NULL); 235962306a36Sopenharmony_ci if (ret || !tb[RDMA_NLDEV_ATTR_STAT_RES]) 236062306a36Sopenharmony_ci return -EINVAL; 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_ci switch (nla_get_u32(tb[RDMA_NLDEV_ATTR_STAT_RES])) { 236362306a36Sopenharmony_ci case RDMA_NLDEV_ATTR_RES_QP: 236462306a36Sopenharmony_ci ret = nldev_res_get_counter_dumpit(skb, cb); 236562306a36Sopenharmony_ci break; 236662306a36Sopenharmony_ci case RDMA_NLDEV_ATTR_RES_MR: 236762306a36Sopenharmony_ci ret = res_get_common_dumpit(skb, cb, RDMA_RESTRACK_MR, 236862306a36Sopenharmony_ci fill_stat_mr_entry); 236962306a36Sopenharmony_ci break; 237062306a36Sopenharmony_ci default: 237162306a36Sopenharmony_ci ret = -EINVAL; 237262306a36Sopenharmony_ci break; 237362306a36Sopenharmony_ci } 237462306a36Sopenharmony_ci 237562306a36Sopenharmony_ci return ret; 237662306a36Sopenharmony_ci} 237762306a36Sopenharmony_ci 237862306a36Sopenharmony_cistatic int nldev_stat_get_counter_status_doit(struct sk_buff *skb, 237962306a36Sopenharmony_ci struct nlmsghdr *nlh, 238062306a36Sopenharmony_ci struct netlink_ext_ack *extack) 238162306a36Sopenharmony_ci{ 238262306a36Sopenharmony_ci struct nlattr *tb[RDMA_NLDEV_ATTR_MAX], *table, *entry; 238362306a36Sopenharmony_ci struct rdma_hw_stats *stats; 238462306a36Sopenharmony_ci struct ib_device *device; 238562306a36Sopenharmony_ci struct sk_buff *msg; 238662306a36Sopenharmony_ci u32 devid, port; 238762306a36Sopenharmony_ci int ret, i; 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci ret = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, 239062306a36Sopenharmony_ci nldev_policy, extack); 239162306a36Sopenharmony_ci if (ret || !tb[RDMA_NLDEV_ATTR_DEV_INDEX] || 239262306a36Sopenharmony_ci !tb[RDMA_NLDEV_ATTR_PORT_INDEX]) 239362306a36Sopenharmony_ci return -EINVAL; 239462306a36Sopenharmony_ci 239562306a36Sopenharmony_ci devid = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); 239662306a36Sopenharmony_ci device = ib_device_get_by_index(sock_net(skb->sk), devid); 239762306a36Sopenharmony_ci if (!device) 239862306a36Sopenharmony_ci return -EINVAL; 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci port = nla_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]); 240162306a36Sopenharmony_ci if (!rdma_is_port_valid(device, port)) { 240262306a36Sopenharmony_ci ret = -EINVAL; 240362306a36Sopenharmony_ci goto err; 240462306a36Sopenharmony_ci } 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci stats = ib_get_hw_stats_port(device, port); 240762306a36Sopenharmony_ci if (!stats) { 240862306a36Sopenharmony_ci ret = -EINVAL; 240962306a36Sopenharmony_ci goto err; 241062306a36Sopenharmony_ci } 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_ci msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 241362306a36Sopenharmony_ci if (!msg) { 241462306a36Sopenharmony_ci ret = -ENOMEM; 241562306a36Sopenharmony_ci goto err; 241662306a36Sopenharmony_ci } 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ci nlh = nlmsg_put( 241962306a36Sopenharmony_ci msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 242062306a36Sopenharmony_ci RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_STAT_GET_STATUS), 242162306a36Sopenharmony_ci 0, 0); 242262306a36Sopenharmony_ci 242362306a36Sopenharmony_ci ret = -EMSGSIZE; 242462306a36Sopenharmony_ci if (!nlh || fill_nldev_handle(msg, device) || 242562306a36Sopenharmony_ci nla_put_u32(msg, RDMA_NLDEV_ATTR_PORT_INDEX, port)) 242662306a36Sopenharmony_ci goto err_msg; 242762306a36Sopenharmony_ci 242862306a36Sopenharmony_ci table = nla_nest_start(msg, RDMA_NLDEV_ATTR_STAT_HWCOUNTERS); 242962306a36Sopenharmony_ci if (!table) 243062306a36Sopenharmony_ci goto err_msg; 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_ci mutex_lock(&stats->lock); 243362306a36Sopenharmony_ci for (i = 0; i < stats->num_counters; i++) { 243462306a36Sopenharmony_ci entry = nla_nest_start(msg, 243562306a36Sopenharmony_ci RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY); 243662306a36Sopenharmony_ci if (!entry) 243762306a36Sopenharmony_ci goto err_msg_table; 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_ci if (nla_put_string(msg, 244062306a36Sopenharmony_ci RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME, 244162306a36Sopenharmony_ci stats->descs[i].name) || 244262306a36Sopenharmony_ci nla_put_u32(msg, RDMA_NLDEV_ATTR_STAT_HWCOUNTER_INDEX, i)) 244362306a36Sopenharmony_ci goto err_msg_entry; 244462306a36Sopenharmony_ci 244562306a36Sopenharmony_ci if ((stats->descs[i].flags & IB_STAT_FLAG_OPTIONAL) && 244662306a36Sopenharmony_ci (nla_put_u8(msg, RDMA_NLDEV_ATTR_STAT_HWCOUNTER_DYNAMIC, 244762306a36Sopenharmony_ci !test_bit(i, stats->is_disabled)))) 244862306a36Sopenharmony_ci goto err_msg_entry; 244962306a36Sopenharmony_ci 245062306a36Sopenharmony_ci nla_nest_end(msg, entry); 245162306a36Sopenharmony_ci } 245262306a36Sopenharmony_ci mutex_unlock(&stats->lock); 245362306a36Sopenharmony_ci 245462306a36Sopenharmony_ci nla_nest_end(msg, table); 245562306a36Sopenharmony_ci nlmsg_end(msg, nlh); 245662306a36Sopenharmony_ci ib_device_put(device); 245762306a36Sopenharmony_ci return rdma_nl_unicast(sock_net(skb->sk), msg, NETLINK_CB(skb).portid); 245862306a36Sopenharmony_ci 245962306a36Sopenharmony_cierr_msg_entry: 246062306a36Sopenharmony_ci nla_nest_cancel(msg, entry); 246162306a36Sopenharmony_cierr_msg_table: 246262306a36Sopenharmony_ci mutex_unlock(&stats->lock); 246362306a36Sopenharmony_ci nla_nest_cancel(msg, table); 246462306a36Sopenharmony_cierr_msg: 246562306a36Sopenharmony_ci nlmsg_free(msg); 246662306a36Sopenharmony_cierr: 246762306a36Sopenharmony_ci ib_device_put(device); 246862306a36Sopenharmony_ci return ret; 246962306a36Sopenharmony_ci} 247062306a36Sopenharmony_ci 247162306a36Sopenharmony_cistatic const struct rdma_nl_cbs nldev_cb_table[RDMA_NLDEV_NUM_OPS] = { 247262306a36Sopenharmony_ci [RDMA_NLDEV_CMD_GET] = { 247362306a36Sopenharmony_ci .doit = nldev_get_doit, 247462306a36Sopenharmony_ci .dump = nldev_get_dumpit, 247562306a36Sopenharmony_ci }, 247662306a36Sopenharmony_ci [RDMA_NLDEV_CMD_GET_CHARDEV] = { 247762306a36Sopenharmony_ci .doit = nldev_get_chardev, 247862306a36Sopenharmony_ci }, 247962306a36Sopenharmony_ci [RDMA_NLDEV_CMD_SET] = { 248062306a36Sopenharmony_ci .doit = nldev_set_doit, 248162306a36Sopenharmony_ci .flags = RDMA_NL_ADMIN_PERM, 248262306a36Sopenharmony_ci }, 248362306a36Sopenharmony_ci [RDMA_NLDEV_CMD_NEWLINK] = { 248462306a36Sopenharmony_ci .doit = nldev_newlink, 248562306a36Sopenharmony_ci .flags = RDMA_NL_ADMIN_PERM, 248662306a36Sopenharmony_ci }, 248762306a36Sopenharmony_ci [RDMA_NLDEV_CMD_DELLINK] = { 248862306a36Sopenharmony_ci .doit = nldev_dellink, 248962306a36Sopenharmony_ci .flags = RDMA_NL_ADMIN_PERM, 249062306a36Sopenharmony_ci }, 249162306a36Sopenharmony_ci [RDMA_NLDEV_CMD_PORT_GET] = { 249262306a36Sopenharmony_ci .doit = nldev_port_get_doit, 249362306a36Sopenharmony_ci .dump = nldev_port_get_dumpit, 249462306a36Sopenharmony_ci }, 249562306a36Sopenharmony_ci [RDMA_NLDEV_CMD_RES_GET] = { 249662306a36Sopenharmony_ci .doit = nldev_res_get_doit, 249762306a36Sopenharmony_ci .dump = nldev_res_get_dumpit, 249862306a36Sopenharmony_ci }, 249962306a36Sopenharmony_ci [RDMA_NLDEV_CMD_RES_QP_GET] = { 250062306a36Sopenharmony_ci .doit = nldev_res_get_qp_doit, 250162306a36Sopenharmony_ci .dump = nldev_res_get_qp_dumpit, 250262306a36Sopenharmony_ci }, 250362306a36Sopenharmony_ci [RDMA_NLDEV_CMD_RES_CM_ID_GET] = { 250462306a36Sopenharmony_ci .doit = nldev_res_get_cm_id_doit, 250562306a36Sopenharmony_ci .dump = nldev_res_get_cm_id_dumpit, 250662306a36Sopenharmony_ci }, 250762306a36Sopenharmony_ci [RDMA_NLDEV_CMD_RES_CQ_GET] = { 250862306a36Sopenharmony_ci .doit = nldev_res_get_cq_doit, 250962306a36Sopenharmony_ci .dump = nldev_res_get_cq_dumpit, 251062306a36Sopenharmony_ci }, 251162306a36Sopenharmony_ci [RDMA_NLDEV_CMD_RES_MR_GET] = { 251262306a36Sopenharmony_ci .doit = nldev_res_get_mr_doit, 251362306a36Sopenharmony_ci .dump = nldev_res_get_mr_dumpit, 251462306a36Sopenharmony_ci }, 251562306a36Sopenharmony_ci [RDMA_NLDEV_CMD_RES_PD_GET] = { 251662306a36Sopenharmony_ci .doit = nldev_res_get_pd_doit, 251762306a36Sopenharmony_ci .dump = nldev_res_get_pd_dumpit, 251862306a36Sopenharmony_ci }, 251962306a36Sopenharmony_ci [RDMA_NLDEV_CMD_RES_CTX_GET] = { 252062306a36Sopenharmony_ci .doit = nldev_res_get_ctx_doit, 252162306a36Sopenharmony_ci .dump = nldev_res_get_ctx_dumpit, 252262306a36Sopenharmony_ci }, 252362306a36Sopenharmony_ci [RDMA_NLDEV_CMD_RES_SRQ_GET] = { 252462306a36Sopenharmony_ci .doit = nldev_res_get_srq_doit, 252562306a36Sopenharmony_ci .dump = nldev_res_get_srq_dumpit, 252662306a36Sopenharmony_ci }, 252762306a36Sopenharmony_ci [RDMA_NLDEV_CMD_SYS_GET] = { 252862306a36Sopenharmony_ci .doit = nldev_sys_get_doit, 252962306a36Sopenharmony_ci }, 253062306a36Sopenharmony_ci [RDMA_NLDEV_CMD_SYS_SET] = { 253162306a36Sopenharmony_ci .doit = nldev_set_sys_set_doit, 253262306a36Sopenharmony_ci .flags = RDMA_NL_ADMIN_PERM, 253362306a36Sopenharmony_ci }, 253462306a36Sopenharmony_ci [RDMA_NLDEV_CMD_STAT_SET] = { 253562306a36Sopenharmony_ci .doit = nldev_stat_set_doit, 253662306a36Sopenharmony_ci .flags = RDMA_NL_ADMIN_PERM, 253762306a36Sopenharmony_ci }, 253862306a36Sopenharmony_ci [RDMA_NLDEV_CMD_STAT_GET] = { 253962306a36Sopenharmony_ci .doit = nldev_stat_get_doit, 254062306a36Sopenharmony_ci .dump = nldev_stat_get_dumpit, 254162306a36Sopenharmony_ci }, 254262306a36Sopenharmony_ci [RDMA_NLDEV_CMD_STAT_DEL] = { 254362306a36Sopenharmony_ci .doit = nldev_stat_del_doit, 254462306a36Sopenharmony_ci .flags = RDMA_NL_ADMIN_PERM, 254562306a36Sopenharmony_ci }, 254662306a36Sopenharmony_ci [RDMA_NLDEV_CMD_RES_QP_GET_RAW] = { 254762306a36Sopenharmony_ci .doit = nldev_res_get_qp_raw_doit, 254862306a36Sopenharmony_ci .dump = nldev_res_get_qp_raw_dumpit, 254962306a36Sopenharmony_ci .flags = RDMA_NL_ADMIN_PERM, 255062306a36Sopenharmony_ci }, 255162306a36Sopenharmony_ci [RDMA_NLDEV_CMD_RES_CQ_GET_RAW] = { 255262306a36Sopenharmony_ci .doit = nldev_res_get_cq_raw_doit, 255362306a36Sopenharmony_ci .dump = nldev_res_get_cq_raw_dumpit, 255462306a36Sopenharmony_ci .flags = RDMA_NL_ADMIN_PERM, 255562306a36Sopenharmony_ci }, 255662306a36Sopenharmony_ci [RDMA_NLDEV_CMD_RES_MR_GET_RAW] = { 255762306a36Sopenharmony_ci .doit = nldev_res_get_mr_raw_doit, 255862306a36Sopenharmony_ci .dump = nldev_res_get_mr_raw_dumpit, 255962306a36Sopenharmony_ci .flags = RDMA_NL_ADMIN_PERM, 256062306a36Sopenharmony_ci }, 256162306a36Sopenharmony_ci [RDMA_NLDEV_CMD_STAT_GET_STATUS] = { 256262306a36Sopenharmony_ci .doit = nldev_stat_get_counter_status_doit, 256362306a36Sopenharmony_ci }, 256462306a36Sopenharmony_ci}; 256562306a36Sopenharmony_ci 256662306a36Sopenharmony_civoid __init nldev_init(void) 256762306a36Sopenharmony_ci{ 256862306a36Sopenharmony_ci rdma_nl_register(RDMA_NL_NLDEV, nldev_cb_table); 256962306a36Sopenharmony_ci} 257062306a36Sopenharmony_ci 257162306a36Sopenharmony_civoid nldev_exit(void) 257262306a36Sopenharmony_ci{ 257362306a36Sopenharmony_ci rdma_nl_unregister(RDMA_NL_NLDEV); 257462306a36Sopenharmony_ci} 257562306a36Sopenharmony_ci 257662306a36Sopenharmony_ciMODULE_ALIAS_RDMA_NETLINK(RDMA_NL_NLDEV, 5); 2577