From 5549fd684971790ec2d962a12aaa835800b0a0e3 Mon Sep 17 00:00:00 2001 From: "M. Vefa Bicakci" Date: Mon, 18 Apr 2022 21:36:37 +0000 Subject: [PATCH] Debian: Add libbnxt_re Infiniband verbs library This commit adds the libbnxt_re Infiniband verbs library to Debian-based StarlingX. In comparison to commit 9baff8aa884a ("Introduce libbnxt_re version 220.0.5.0") and commit 4112936362c6 ("libbnxt_re: Add support for rdma-core v37") that introduce the same library to CentOS-based StarlingX, the only change in this commit was to remove the use of the "stdatomic.h" header's compatibility-oriented version shipped with libbxnt_re. This header file is already provided by Debian's newer toolchain. The two patches make the library compatible with rdma-core v37 provided by Mellanox OFED's version of rdma-core. For further information, please see commit 4112936362c6 ("libbnxt_re: Add support for rdma-core v37"). Verification notes: - An ISO image with the standard kernel was successfully built with this commit and the resulting ISO image was installed onto a physical server with a quad-port Broadcom NetXtreme-E network adapter, of which the third and fourth ports were connected to each other with a loopback cable. - When we installed the Linux RDMA community's perftest package on Debian-based StarlingX with apt-get and attempted to run the benchmark programs, we encountered a dynamically-linked library error caused by the "libefa.so" Infiniband verbs library (that perftest's utilities appear to link against) not existing on the system. This occurs because the Mellanox OFED version of the rdma-core package in StarlingX does not build the libefa.so library. To work around this, we built the perftest package in a Debian Bullseye container, after having modified perftest's configure.ac file to avoid linking against libefa.so. The resulting binaries were successfully used on the aforementioned server to verify the libbnxt_re Infiniband verbs library and the bnxt_re driver. The test procedure consisted of using a server ib_write_bw instance on the 3rd port of the network adapter and another instance as a client on the 4th port of the network adapter. (Recall that ports 3 and 4 were connected to each other.) - The preempt-rt kernel was not tested due to not being able to generate a working ISO image that installed onto a virtual machine. (The installation process was aborted with a kickstart file parse error.) Story: 2009915 Task: 45139 Change-Id: I917c18ef262afdf3ddfaa7e31af2583b8f74300b Signed-off-by: M. Vefa Bicakci --- debian_pkg_dirs | 1 + .../libbnxt_re/debian/deb_folder/changelog | 7 + .../libbnxt_re/debian/deb_folder/control | 15 + .../libbnxt_re/debian/deb_folder/copyright | 48 + ...001-rc-compat-Add-headers-from-v37.3.patch | 8186 +++++++++++++++++ ....ac-Detect-rdma-core-v36-and-v37-too.patch | 118 + .../debian/deb_folder/patches/series | 2 + .../libbnxt_re/debian/deb_folder/rules | 53 + .../debian/deb_folder/source/format | 1 + userspace/broadcom/libbnxt_re/debian/dl_hook | 51 + .../broadcom/libbnxt_re/debian/meta_data.yaml | 14 + 11 files changed, 8496 insertions(+) create mode 100644 userspace/broadcom/libbnxt_re/debian/deb_folder/changelog create mode 100644 userspace/broadcom/libbnxt_re/debian/deb_folder/control create mode 100644 userspace/broadcom/libbnxt_re/debian/deb_folder/copyright create mode 100644 userspace/broadcom/libbnxt_re/debian/deb_folder/patches/0001-rc-compat-Add-headers-from-v37.3.patch create mode 100644 userspace/broadcom/libbnxt_re/debian/deb_folder/patches/0002-configure.ac-Detect-rdma-core-v36-and-v37-too.patch create mode 100644 userspace/broadcom/libbnxt_re/debian/deb_folder/patches/series create mode 100755 userspace/broadcom/libbnxt_re/debian/deb_folder/rules create mode 100644 userspace/broadcom/libbnxt_re/debian/deb_folder/source/format create mode 100755 userspace/broadcom/libbnxt_re/debian/dl_hook create mode 100644 userspace/broadcom/libbnxt_re/debian/meta_data.yaml diff --git a/debian_pkg_dirs b/debian_pkg_dirs index a3151123..cdccc9df 100644 --- a/debian_pkg_dirs +++ b/debian_pkg_dirs @@ -7,6 +7,7 @@ kernel-modules/intel-igb_uio kernel-modules/intel-opae-fpga kernel-modules/mlnx-ofa_kernel kernel-modules/qat17 +userspace/broadcom/libbnxt_re userspace/mellanox/rdma-core userspace/mellanox/mstflint userspace/mellanox/mlnx-tools diff --git a/userspace/broadcom/libbnxt_re/debian/deb_folder/changelog b/userspace/broadcom/libbnxt_re/debian/deb_folder/changelog new file mode 100644 index 00000000..b982746d --- /dev/null +++ b/userspace/broadcom/libbnxt_re/debian/deb_folder/changelog @@ -0,0 +1,7 @@ +libbnxt-re (220.0.5.0-1) unstable; urgency=medium + + * Initial release of the libbnxt_re Infiniband verbs library for StarlingX. + This library corresponds to "libbnxt_re-220.0.5.0.tar.gz" in Broadcom's + "bcm_220.0.83.0" release. + + -- M. Vefa Bicakci Mon, 18 Apr 2022 20:07:24 +0000 diff --git a/userspace/broadcom/libbnxt_re/debian/deb_folder/control b/userspace/broadcom/libbnxt_re/debian/deb_folder/control new file mode 100644 index 00000000..b75e0339 --- /dev/null +++ b/userspace/broadcom/libbnxt_re/debian/deb_folder/control @@ -0,0 +1,15 @@ +Source: libbnxt-re +Section: net +Priority: optional +Maintainer: StarlingX Developers +Build-Depends: debhelper-compat (= 13), libibverbs-dev +Standards-Version: 4.5.1 +Rules-Requires-Root: no + +Package: libbnxt-re +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: libbnxt_re Infiniband verbs library + libbnxt_re provides a device-specific userspace driver for + Broadcom NetXtreme RoCE Adapters for use with the libibverbs + library. diff --git a/userspace/broadcom/libbnxt_re/debian/deb_folder/copyright b/userspace/broadcom/libbnxt_re/debian/deb_folder/copyright new file mode 100644 index 00000000..56ed277b --- /dev/null +++ b/userspace/broadcom/libbnxt_re/debian/deb_folder/copyright @@ -0,0 +1,48 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: libbnxt_re +Upstream-Contact: Broadcom Inc. +Source: libbnxt_re-220.0.5.0.tar.gz +Comment: + Source archive is included as + bcm_220.0.83.0/Linux/Linux_RoCE/RoCE_Lib/libbnxt_re-220.0.5.0.tar.gz + in the compressed tar archive at the following address: + https://docs.broadcom.com/docs-and-downloads/ethernet-network-adapters/NXE/BRCM_220.0.83.0/bcm_220.0.83.0.tar.gz + +Files: * +Copyright: Copyright 2016-2022 Broadcom Inc. +Comment: + Documentation in the source archive indicates copyright years 2016-2021. + However, the source code was released in 2022. Hence, the copyright year above + is indicated by this file as 2016-2022. +License: GPL-2 or BSD-2-clause + +License: GPL-2 + This program is free software; you can redistribute it and/or modify it under + the terms and conditions of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., 51 Franklin + St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in the + file called "COPYING". + + On Debian-based systems the full text of the GNU General Public License + version 2 license can be found in `/usr/share/common-licenses/GPL-2'. + +License: BSD-2-clause + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. diff --git a/userspace/broadcom/libbnxt_re/debian/deb_folder/patches/0001-rc-compat-Add-headers-from-v37.3.patch b/userspace/broadcom/libbnxt_re/debian/deb_folder/patches/0001-rc-compat-Add-headers-from-v37.3.patch new file mode 100644 index 00000000..6222a40a --- /dev/null +++ b/userspace/broadcom/libbnxt_re/debian/deb_folder/patches/0001-rc-compat-Add-headers-from-v37.3.patch @@ -0,0 +1,8186 @@ +From 0ace34eb5bcc23dacc68285cd43b828331b42262 Mon Sep 17 00:00:00 2001 +From: "M. Vefa Bicakci" +Date: Thu, 31 Mar 2022 15:52:34 -0400 +Subject: [PATCH] rc-compat: Add headers from v37.3 + +All of the headers were copied from rdma-core repository tag "v37.3". We +do not copy from the v36.y tag, because Mellanox's OpenFabrics +Enterprise Distribution (OFED) package in use by StarlingX is based on +rdma-core v37, and we do not need headers from v36 as a result. + +This commit is intended to go away when the vendor releases a version of +libbnxt_re with native support for Mellanox OFED's rdma-core v37 +baseline. + +The only change to the headers were as follows: + +- Some of the #include directives in driver.h were modified to align + them to their counterparts in the v35 directory, by replacing + angle-brackets ('<' and '>') with double quotes ('"') so that the + files in the rc-compat/v37 directory would be used. + +- The following line was added to driver.h: + #define IBV_DEVICE_LIBRARY_EXTENSION rdmav34 + +- kernel-abi_ib_user_verbs.h was generated using a script in the + rdma-core repository as follows: + + python3 ../buildlib/make_abi_structs.py \ + ./rdma/ib_user_verbs.h \ + kernel-abi_ib_user_verbs.h + +- config.h was adapted from src/rc-compat/v35/config.h in libbnxt_re's + source code. + +Signed-off-by: M. Vefa Bicakci +--- + src/rc-compat/v37/ccan/array_size.h | 26 + + src/rc-compat/v37/ccan/bitmap.h | 239 ++++ + src/rc-compat/v37/ccan/build_assert.h | 40 + + src/rc-compat/v37/ccan/check_type.h | 64 + + src/rc-compat/v37/ccan/compiler.h | 230 ++++ + src/rc-compat/v37/ccan/container_of.h | 146 ++ + src/rc-compat/v37/ccan/ilog.h | 151 ++ + src/rc-compat/v37/ccan/list.h | 842 ++++++++++++ + src/rc-compat/v37/ccan/minmax.h | 65 + + src/rc-compat/v37/ccan/str.h | 228 +++ + src/rc-compat/v37/ccan/str_debug.h | 30 + + src/rc-compat/v37/cmd_ioctl.h | 412 ++++++ + src/rc-compat/v37/config.h | 56 + + src/rc-compat/v37/driver.h | 755 ++++++++++ + src/rc-compat/v37/ib_user_verbs.h | 1301 ++++++++++++++++++ + src/rc-compat/v37/kern-abi.h | 322 +++++ + src/rc-compat/v37/kernel-abi_ib_user_verbs.h | 1114 +++++++++++++++ + src/rc-compat/v37/rdma_user_ioctl_cmds.h | 87 ++ + src/rc-compat/v37/util/cl_qmap.h | 970 +++++++++++++ + src/rc-compat/v37/util/compiler.h | 54 + + src/rc-compat/v37/util/mmio.h | 267 ++++ + src/rc-compat/v37/util/node_name_map.h | 19 + + src/rc-compat/v37/util/rdma_nl.h | 52 + + src/rc-compat/v37/util/symver.h | 107 ++ + src/rc-compat/v37/util/udma_barrier.h | 267 ++++ + src/rc-compat/v37/util/util.h | 93 ++ + 26 files changed, 7937 insertions(+) + create mode 100644 src/rc-compat/v37/ccan/array_size.h + create mode 100644 src/rc-compat/v37/ccan/bitmap.h + create mode 100644 src/rc-compat/v37/ccan/build_assert.h + create mode 100644 src/rc-compat/v37/ccan/check_type.h + create mode 100644 src/rc-compat/v37/ccan/compiler.h + create mode 100644 src/rc-compat/v37/ccan/container_of.h + create mode 100644 src/rc-compat/v37/ccan/ilog.h + create mode 100644 src/rc-compat/v37/ccan/list.h + create mode 100644 src/rc-compat/v37/ccan/minmax.h + create mode 100644 src/rc-compat/v37/ccan/str.h + create mode 100644 src/rc-compat/v37/ccan/str_debug.h + create mode 100644 src/rc-compat/v37/cmd_ioctl.h + create mode 100644 src/rc-compat/v37/config.h + create mode 100644 src/rc-compat/v37/driver.h + create mode 100644 src/rc-compat/v37/ib_user_verbs.h + create mode 100644 src/rc-compat/v37/kern-abi.h + create mode 100644 src/rc-compat/v37/kernel-abi_ib_user_verbs.h + create mode 100644 src/rc-compat/v37/rdma_user_ioctl_cmds.h + create mode 100644 src/rc-compat/v37/util/cl_qmap.h + create mode 100644 src/rc-compat/v37/util/compiler.h + create mode 100644 src/rc-compat/v37/util/mmio.h + create mode 100644 src/rc-compat/v37/util/node_name_map.h + create mode 100644 src/rc-compat/v37/util/rdma_nl.h + create mode 100644 src/rc-compat/v37/util/symver.h + create mode 100644 src/rc-compat/v37/util/udma_barrier.h + create mode 100644 src/rc-compat/v37/util/util.h + +diff --git a/src/rc-compat/v37/ccan/array_size.h b/src/rc-compat/v37/ccan/array_size.h +new file mode 100644 +index 000000000000..37b200f5e239 +--- /dev/null ++++ b/src/rc-compat/v37/ccan/array_size.h +@@ -0,0 +1,26 @@ ++/* CC0 (Public domain) - see LICENSE file for details */ ++#ifndef CCAN_ARRAY_SIZE_H ++#define CCAN_ARRAY_SIZE_H ++#include "config.h" ++#include ++ ++/** ++ * ARRAY_SIZE - get the number of elements in a visible array ++ * @arr: the array whose size you want. ++ * ++ * This does not work on pointers, or arrays declared as [], or ++ * function parameters. With correct compiler support, such usage ++ * will cause a build error (see build_assert). ++ */ ++#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + _array_size_chk(arr)) ++ ++#if HAVE_BUILTIN_TYPES_COMPATIBLE_P && HAVE_TYPEOF ++/* Two gcc extensions. ++ * &a[0] degrades to a pointer: a different type from an array */ ++#define _array_size_chk(arr) \ ++ BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(typeof(arr), \ ++ typeof(&(arr)[0]))) ++#else ++#define _array_size_chk(arr) 0 ++#endif ++#endif /* CCAN_ALIGNOF_H */ +diff --git a/src/rc-compat/v37/ccan/bitmap.h b/src/rc-compat/v37/ccan/bitmap.h +new file mode 100644 +index 000000000000..ff0b8c83da46 +--- /dev/null ++++ b/src/rc-compat/v37/ccan/bitmap.h +@@ -0,0 +1,239 @@ ++/* Licensed under LGPLv2+ - see LICENSE file for details */ ++#ifndef CCAN_BITMAP_H_ ++#define CCAN_BITMAP_H_ ++ ++#include ++#include ++#include ++#include ++ ++typedef unsigned long bitmap_word; ++ ++#define BITMAP_WORD_BITS (sizeof(bitmap_word) * CHAR_BIT) ++#define BITMAP_NWORDS(_n) \ ++ (((_n) + BITMAP_WORD_BITS - 1) / BITMAP_WORD_BITS) ++ ++/* ++ * We wrap each word in a structure for type checking. ++ */ ++typedef struct { ++ bitmap_word w; ++} bitmap; ++ ++#define BITMAP_DECLARE(_name, _nbits) \ ++ bitmap (_name)[BITMAP_NWORDS(_nbits)] ++ ++static inline size_t bitmap_sizeof(unsigned long nbits) ++{ ++ return BITMAP_NWORDS(nbits) * sizeof(bitmap_word); ++} ++ ++static inline bitmap_word bitmap_bswap(bitmap_word w) ++{ ++ /* We do not need to have the bitmap in any specific endianness */ ++ return w; ++} ++ ++#define BITMAP_WORD(_bm, _n) ((_bm)[(_n) / BITMAP_WORD_BITS].w) ++#define BITMAP_WORDBIT(_n) \ ++ (bitmap_bswap(1UL << (BITMAP_WORD_BITS - ((_n) % BITMAP_WORD_BITS) - 1))) ++ ++#define BITMAP_HEADWORDS(_nbits) \ ++ ((_nbits) / BITMAP_WORD_BITS) ++#define BITMAP_HEADBYTES(_nbits) \ ++ (BITMAP_HEADWORDS(_nbits) * sizeof(bitmap_word)) ++ ++#define BITMAP_TAILWORD(_bm, _nbits) \ ++ ((_bm)[BITMAP_HEADWORDS(_nbits)].w) ++#define BITMAP_HASTAIL(_nbits) (((_nbits) % BITMAP_WORD_BITS) != 0) ++#define BITMAP_TAILBITS(_nbits) \ ++ (bitmap_bswap(~(-1UL >> ((_nbits) % BITMAP_WORD_BITS)))) ++#define BITMAP_TAIL(_bm, _nbits) \ ++ (BITMAP_TAILWORD(_bm, _nbits) & BITMAP_TAILBITS(_nbits)) ++ ++static inline void bitmap_set_bit(bitmap *bmap, unsigned long n) ++{ ++ BITMAP_WORD(bmap, n) |= BITMAP_WORDBIT(n); ++} ++ ++static inline void bitmap_clear_bit(bitmap *bmap, unsigned long n) ++{ ++ BITMAP_WORD(bmap, n) &= ~BITMAP_WORDBIT(n); ++} ++ ++static inline void bitmap_change_bit(bitmap *bmap, unsigned long n) ++{ ++ BITMAP_WORD(bmap, n) ^= BITMAP_WORDBIT(n); ++} ++ ++static inline bool bitmap_test_bit(const bitmap *bmap, unsigned long n) ++{ ++ return !!(BITMAP_WORD(bmap, n) & BITMAP_WORDBIT(n)); ++} ++ ++void bitmap_zero_range(bitmap *bmap, unsigned long n, unsigned long m); ++void bitmap_fill_range(bitmap *bmap, unsigned long n, unsigned long m); ++ ++static inline void bitmap_zero(bitmap *bmap, unsigned long nbits) ++{ ++ memset(bmap, 0, bitmap_sizeof(nbits)); ++} ++ ++static inline void bitmap_fill(bitmap *bmap, unsigned long nbits) ++{ ++ memset(bmap, 0xff, bitmap_sizeof(nbits)); ++} ++ ++static inline void bitmap_copy(bitmap *dst, const bitmap *src, ++ unsigned long nbits) ++{ ++ memcpy(dst, src, bitmap_sizeof(nbits)); ++} ++ ++#define BITMAP_DEF_BINOP(_name, _op) \ ++ static inline void bitmap_##_name(bitmap *dst, bitmap *src1, bitmap *src2, \ ++ unsigned long nbits) \ ++ { \ ++ unsigned long i = 0; \ ++ for (i = 0; i < BITMAP_NWORDS(nbits); i++) { \ ++ dst[i].w = src1[i].w _op src2[i].w; \ ++ } \ ++ } ++ ++BITMAP_DEF_BINOP(and, &) ++BITMAP_DEF_BINOP(or, |) ++BITMAP_DEF_BINOP(xor, ^) ++BITMAP_DEF_BINOP(andnot, & ~) ++ ++#undef BITMAP_DEF_BINOP ++ ++static inline void bitmap_complement(bitmap *dst, const bitmap *src, ++ unsigned long nbits) ++{ ++ unsigned long i; ++ ++ for (i = 0; i < BITMAP_NWORDS(nbits); i++) ++ dst[i].w = ~src[i].w; ++} ++ ++static inline bool bitmap_equal(const bitmap *src1, const bitmap *src2, ++ unsigned long nbits) ++{ ++ return (memcmp(src1, src2, BITMAP_HEADBYTES(nbits)) == 0) ++ && (!BITMAP_HASTAIL(nbits) ++ || (BITMAP_TAIL(src1, nbits) == BITMAP_TAIL(src2, nbits))); ++} ++ ++static inline bool bitmap_intersects(const bitmap *src1, const bitmap *src2, ++ unsigned long nbits) ++{ ++ unsigned long i; ++ ++ for (i = 0; i < BITMAP_HEADWORDS(nbits); i++) { ++ if (src1[i].w & src2[i].w) ++ return true; ++ } ++ if (BITMAP_HASTAIL(nbits) && ++ (BITMAP_TAIL(src1, nbits) & BITMAP_TAIL(src2, nbits))) ++ return true; ++ return false; ++} ++ ++static inline bool bitmap_subset(const bitmap *src1, const bitmap *src2, ++ unsigned long nbits) ++{ ++ unsigned long i; ++ ++ for (i = 0; i < BITMAP_HEADWORDS(nbits); i++) { ++ if (src1[i].w & ~src2[i].w) ++ return false; ++ } ++ if (BITMAP_HASTAIL(nbits) && ++ (BITMAP_TAIL(src1, nbits) & ~BITMAP_TAIL(src2, nbits))) ++ return false; ++ return true; ++} ++ ++static inline bool bitmap_full(const bitmap *bmap, unsigned long nbits) ++{ ++ unsigned long i; ++ ++ for (i = 0; i < BITMAP_HEADWORDS(nbits); i++) { ++ if (bmap[i].w != -1UL) ++ return false; ++ } ++ if (BITMAP_HASTAIL(nbits) && ++ (BITMAP_TAIL(bmap, nbits) != BITMAP_TAILBITS(nbits))) ++ return false; ++ ++ return true; ++} ++ ++static inline bool bitmap_empty(const bitmap *bmap, unsigned long nbits) ++{ ++ unsigned long i; ++ ++ for (i = 0; i < BITMAP_HEADWORDS(nbits); i++) { ++ if (bmap[i].w != 0) ++ return false; ++ } ++ if (BITMAP_HASTAIL(nbits) && (BITMAP_TAIL(bmap, nbits) != 0)) ++ return false; ++ ++ return true; ++} ++ ++unsigned long bitmap_ffs(const bitmap *bmap, ++ unsigned long n, unsigned long m); ++ ++/* ++ * Allocation functions ++ */ ++static inline bitmap *bitmap_alloc(unsigned long nbits) ++{ ++ return malloc(bitmap_sizeof(nbits)); ++} ++ ++static inline bitmap *bitmap_alloc0(unsigned long nbits) ++{ ++ bitmap *bmap; ++ ++ bmap = bitmap_alloc(nbits); ++ if (bmap) ++ bitmap_zero(bmap, nbits); ++ return bmap; ++} ++ ++static inline bitmap *bitmap_alloc1(unsigned long nbits) ++{ ++ bitmap *bmap; ++ ++ bmap = bitmap_alloc(nbits); ++ if (bmap) ++ bitmap_fill(bmap, nbits); ++ return bmap; ++} ++ ++static inline bitmap *bitmap_realloc0(bitmap *bmap, unsigned long obits, ++ unsigned long nbits) ++{ ++ bmap = realloc(bmap, bitmap_sizeof(nbits)); ++ ++ if ((nbits > obits) && bmap) ++ bitmap_zero_range(bmap, obits, nbits); ++ ++ return bmap; ++} ++ ++static inline bitmap *bitmap_realloc1(bitmap *bmap, unsigned long obits, ++ unsigned long nbits) ++{ ++ bmap = realloc(bmap, bitmap_sizeof(nbits)); ++ ++ if ((nbits > obits) && bmap) ++ bitmap_fill_range(bmap, obits, nbits); ++ ++ return bmap; ++} ++ ++#endif /* CCAN_BITMAP_H_ */ +diff --git a/src/rc-compat/v37/ccan/build_assert.h b/src/rc-compat/v37/ccan/build_assert.h +new file mode 100644 +index 000000000000..0ecd7ff36633 +--- /dev/null ++++ b/src/rc-compat/v37/ccan/build_assert.h +@@ -0,0 +1,40 @@ ++/* CC0 (Public domain) - see LICENSE.CC0 file for details */ ++#ifndef CCAN_BUILD_ASSERT_H ++#define CCAN_BUILD_ASSERT_H ++ ++/** ++ * BUILD_ASSERT - assert a build-time dependency. ++ * @cond: the compile-time condition which must be true. ++ * ++ * Your compile will fail if the condition isn't true, or can't be evaluated ++ * by the compiler. This can only be used within a function. ++ * ++ * Example: ++ * #include ++ * ... ++ * static char *foo_to_char(struct foo *foo) ++ * { ++ * // This code needs string to be at start of foo. ++ * BUILD_ASSERT(offsetof(struct foo, string) == 0); ++ * return (char *)foo; ++ * } ++ */ ++#define BUILD_ASSERT(cond) \ ++ do { (void) sizeof(char [1 - 2*!(cond)]); } while(0) ++ ++/** ++ * BUILD_ASSERT_OR_ZERO - assert a build-time dependency, as an expression. ++ * @cond: the compile-time condition which must be true. ++ * ++ * Your compile will fail if the condition isn't true, or can't be evaluated ++ * by the compiler. This can be used in an expression: its value is "0". ++ * ++ * Example: ++ * #define foo_to_char(foo) \ ++ * ((char *)(foo) \ ++ * + BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0)) ++ */ ++#define BUILD_ASSERT_OR_ZERO(cond) \ ++ (sizeof(char [1 - 2*!(cond)]) - 1) ++ ++#endif /* CCAN_BUILD_ASSERT_H */ +diff --git a/src/rc-compat/v37/ccan/check_type.h b/src/rc-compat/v37/ccan/check_type.h +new file mode 100644 +index 000000000000..a576a5018e01 +--- /dev/null ++++ b/src/rc-compat/v37/ccan/check_type.h +@@ -0,0 +1,64 @@ ++/* CC0 (Public domain) - see LICENSE.CC0 file for details */ ++#ifndef CCAN_CHECK_TYPE_H ++#define CCAN_CHECK_TYPE_H ++#include "config.h" ++ ++/** ++ * check_type - issue a warning or build failure if type is not correct. ++ * @expr: the expression whose type we should check (not evaluated). ++ * @type: the exact type we expect the expression to be. ++ * ++ * This macro is usually used within other macros to try to ensure that a macro ++ * argument is of the expected type. No type promotion of the expression is ++ * done: an unsigned int is not the same as an int! ++ * ++ * check_type() always evaluates to 0. ++ * ++ * If your compiler does not support typeof, then the best we can do is fail ++ * to compile if the sizes of the types are unequal (a less complete check). ++ * ++ * Example: ++ * // They should always pass a 64-bit value to _set_some_value! ++ * #define set_some_value(expr) \ ++ * _set_some_value((check_type((expr), uint64_t), (expr))) ++ */ ++ ++/** ++ * check_types_match - issue a warning or build failure if types are not same. ++ * @expr1: the first expression (not evaluated). ++ * @expr2: the second expression (not evaluated). ++ * ++ * This macro is usually used within other macros to try to ensure that ++ * arguments are of identical types. No type promotion of the expressions is ++ * done: an unsigned int is not the same as an int! ++ * ++ * check_types_match() always evaluates to 0. ++ * ++ * If your compiler does not support typeof, then the best we can do is fail ++ * to compile if the sizes of the types are unequal (a less complete check). ++ * ++ * Example: ++ * // Do subtraction to get to enclosing type, but make sure that ++ * // pointer is of correct type for that member. ++ * #define container_of(mbr_ptr, encl_type, mbr) \ ++ * (check_types_match((mbr_ptr), &((encl_type *)0)->mbr), \ ++ * ((encl_type *) \ ++ * ((char *)(mbr_ptr) - offsetof(enclosing_type, mbr)))) ++ */ ++#if HAVE_TYPEOF ++#define check_type(expr, type) \ ++ ((typeof(expr) *)0 != (type *)0) ++ ++#define check_types_match(expr1, expr2) \ ++ ((typeof(expr1) *)0 != (typeof(expr2) *)0) ++#else ++#include ++/* Without typeof, we can only test the sizes. */ ++#define check_type(expr, type) \ ++ BUILD_ASSERT_OR_ZERO(sizeof(expr) == sizeof(type)) ++ ++#define check_types_match(expr1, expr2) \ ++ BUILD_ASSERT_OR_ZERO(sizeof(expr1) == sizeof(expr2)) ++#endif /* HAVE_TYPEOF */ ++ ++#endif /* CCAN_CHECK_TYPE_H */ +diff --git a/src/rc-compat/v37/ccan/compiler.h b/src/rc-compat/v37/ccan/compiler.h +new file mode 100644 +index 000000000000..cc0d4d1af2ca +--- /dev/null ++++ b/src/rc-compat/v37/ccan/compiler.h +@@ -0,0 +1,230 @@ ++/* CC0 (Public domain) - see LICENSE file for details */ ++#ifndef CCAN_COMPILER_H ++#define CCAN_COMPILER_H ++#include "config.h" ++ ++#ifndef COLD ++/** ++ * COLD - a function is unlikely to be called. ++ * ++ * Used to mark an unlikely code path and optimize appropriately. ++ * It is usually used on logging or error routines. ++ * ++ * Example: ++ * static void COLD moan(const char *reason) ++ * { ++ * fprintf(stderr, "Error: %s (%s)\n", reason, strerror(errno)); ++ * } ++ */ ++#define COLD __attribute__((__cold__)) ++#endif ++ ++#ifndef NORETURN ++/** ++ * NORETURN - a function does not return ++ * ++ * Used to mark a function which exits; useful for suppressing warnings. ++ * ++ * Example: ++ * static void NORETURN fail(const char *reason) ++ * { ++ * fprintf(stderr, "Error: %s (%s)\n", reason, strerror(errno)); ++ * exit(1); ++ * } ++ */ ++#define NORETURN __attribute__((__noreturn__)) ++#endif ++ ++#ifndef PRINTF_FMT ++/** ++ * PRINTF_FMT - a function takes printf-style arguments ++ * @nfmt: the 1-based number of the function's format argument. ++ * @narg: the 1-based number of the function's first variable argument. ++ * ++ * This allows the compiler to check your parameters as it does for printf(). ++ * ++ * Example: ++ * void PRINTF_FMT(2,3) my_printf(const char *prefix, const char *fmt, ...); ++ */ ++#define PRINTF_FMT(nfmt, narg) \ ++ __attribute__((format(__printf__, nfmt, narg))) ++#endif ++ ++#ifndef CONST_FUNCTION ++/** ++ * CONST_FUNCTION - a function's return depends only on its argument ++ * ++ * This allows the compiler to assume that the function will return the exact ++ * same value for the exact same arguments. This implies that the function ++ * must not use global variables, or dereference pointer arguments. ++ */ ++#define CONST_FUNCTION __attribute__((__const__)) ++ ++#ifndef PURE_FUNCTION ++/** ++ * PURE_FUNCTION - a function is pure ++ * ++ * A pure function is one that has no side effects other than it's return value ++ * and uses no inputs other than it's arguments and global variables. ++ */ ++#define PURE_FUNCTION __attribute__((__pure__)) ++#endif ++#endif ++ ++#ifndef UNNEEDED ++/** ++ * UNNEEDED - a variable/function may not be needed ++ * ++ * This suppresses warnings about unused variables or functions, but tells ++ * the compiler that if it is unused it need not emit it into the source code. ++ * ++ * Example: ++ * // With some preprocessor options, this is unnecessary. ++ * static UNNEEDED int counter; ++ * ++ * // With some preprocessor options, this is unnecessary. ++ * static UNNEEDED void add_to_counter(int add) ++ * { ++ * counter += add; ++ * } ++ */ ++#define UNNEEDED __attribute__((__unused__)) ++#endif ++ ++#ifndef NEEDED ++/** ++ * NEEDED - a variable/function is needed ++ * ++ * This suppresses warnings about unused variables or functions, but tells ++ * the compiler that it must exist even if it (seems) unused. ++ * ++ * Example: ++ * // Even if this is unused, these are vital for debugging. ++ * static NEEDED int counter; ++ * static NEEDED void dump_counter(void) ++ * { ++ * printf("Counter is %i\n", counter); ++ * } ++ */ ++#define NEEDED __attribute__((__used__)) ++#endif ++ ++#ifndef UNUSED ++/** ++ * UNUSED - a parameter is unused ++ * ++ * Some compilers (eg. gcc with -W or -Wunused) warn about unused ++ * function parameters. This suppresses such warnings and indicates ++ * to the reader that it's deliberate. ++ * ++ * Example: ++ * // This is used as a callback, so needs to have this prototype. ++ * static int some_callback(void *unused UNUSED) ++ * { ++ * return 0; ++ * } ++ */ ++#define UNUSED __attribute__((__unused__)) ++#endif ++ ++#ifndef IS_COMPILE_CONSTANT ++/** ++ * IS_COMPILE_CONSTANT - does the compiler know the value of this expression? ++ * @expr: the expression to evaluate ++ * ++ * When an expression manipulation is complicated, it is usually better to ++ * implement it in a function. However, if the expression being manipulated is ++ * known at compile time, it is better to have the compiler see the entire ++ * expression so it can simply substitute the result. ++ * ++ * This can be done using the IS_COMPILE_CONSTANT() macro. ++ * ++ * Example: ++ * enum greek { ALPHA, BETA, GAMMA, DELTA, EPSILON }; ++ * ++ * // Out-of-line version. ++ * const char *greek_name(enum greek greek); ++ * ++ * // Inline version. ++ * static inline const char *_greek_name(enum greek greek) ++ * { ++ * switch (greek) { ++ * case ALPHA: return "alpha"; ++ * case BETA: return "beta"; ++ * case GAMMA: return "gamma"; ++ * case DELTA: return "delta"; ++ * case EPSILON: return "epsilon"; ++ * default: return "**INVALID**"; ++ * } ++ * } ++ * ++ * // Use inline if compiler knows answer. Otherwise call function ++ * // to avoid copies of the same code everywhere. ++ * #define greek_name(g) \ ++ * (IS_COMPILE_CONSTANT(greek) ? _greek_name(g) : greek_name(g)) ++ */ ++#define IS_COMPILE_CONSTANT(expr) __builtin_constant_p(expr) ++#endif ++ ++#ifndef WARN_UNUSED_RESULT ++/** ++ * WARN_UNUSED_RESULT - warn if a function return value is unused. ++ * ++ * Used to mark a function where it is extremely unlikely that the caller ++ * can ignore the result, eg realloc(). ++ * ++ * Example: ++ * // buf param may be freed by this; need return value! ++ * static char *WARN_UNUSED_RESULT enlarge(char *buf, unsigned *size) ++ * { ++ * return realloc(buf, (*size) *= 2); ++ * } ++ */ ++#define WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) ++#endif ++ ++ ++/** ++ * WARN_DEPRECATED - warn that a function/type/variable is deprecated when used. ++ * ++ * Used to mark a function, type or variable should not be used. ++ * ++ * Example: ++ * WARN_DEPRECATED char *oldfunc(char *buf); ++ */ ++#define WARN_DEPRECATED __attribute__((__deprecated__)) ++ ++ ++/** ++ * NO_NULL_ARGS - specify that no arguments to this function can be NULL. ++ * ++ * The compiler will warn if any pointer args are NULL. ++ * ++ * Example: ++ * NO_NULL_ARGS char *my_copy(char *buf); ++ */ ++#define NO_NULL_ARGS __attribute__((__nonnull__)) ++ ++/** ++ * NON_NULL_ARGS - specify that some arguments to this function can't be NULL. ++ * @...: 1-based argument numbers for which args can't be NULL. ++ * ++ * The compiler will warn if any of the specified pointer args are NULL. ++ * ++ * Example: ++ * char *my_copy2(char *buf, char *maybenull) NON_NULL_ARGS(1); ++ */ ++#define NON_NULL_ARGS(...) __attribute__((__nonnull__(__VA_ARGS__))) ++ ++ ++/** ++ * LAST_ARG_NULL - specify the last argument of a variadic function must be NULL. ++ * ++ * The compiler will warn if the last argument isn't NULL. ++ * ++ * Example: ++ * char *join_string(char *buf, ...) LAST_ARG_NULL; ++ */ ++#define LAST_ARG_NULL __attribute__((__sentinel__)) ++ ++#endif /* CCAN_COMPILER_H */ +diff --git a/src/rc-compat/v37/ccan/container_of.h b/src/rc-compat/v37/ccan/container_of.h +new file mode 100644 +index 000000000000..9180f37f0d15 +--- /dev/null ++++ b/src/rc-compat/v37/ccan/container_of.h +@@ -0,0 +1,146 @@ ++/* CC0 (Public domain) - see LICENSE.CC0 file for details */ ++#ifndef CCAN_CONTAINER_OF_H ++#define CCAN_CONTAINER_OF_H ++#include ++ ++#include "config.h" ++#include ++ ++/** ++ * container_of - get pointer to enclosing structure ++ * @member_ptr: pointer to the structure member ++ * @containing_type: the type this member is within ++ * @member: the name of this member within the structure. ++ * ++ * Given a pointer to a member of a structure, this macro does pointer ++ * subtraction to return the pointer to the enclosing type. ++ * ++ * Example: ++ * struct foo { ++ * int fielda, fieldb; ++ * // ... ++ * }; ++ * struct info { ++ * int some_other_field; ++ * struct foo my_foo; ++ * }; ++ * ++ * static struct info *foo_to_info(struct foo *foo) ++ * { ++ * return container_of(foo, struct info, my_foo); ++ * } ++ */ ++#ifndef container_of ++#define container_of(member_ptr, containing_type, member) \ ++ ((containing_type *) \ ++ ((char *)(member_ptr) \ ++ - container_off(containing_type, member)) \ ++ + check_types_match(*(member_ptr), ((containing_type *)0)->member)) ++#endif ++ ++/** ++ * container_of_or_null - get pointer to enclosing structure, or NULL ++ * @member_ptr: pointer to the structure member ++ * @containing_type: the type this member is within ++ * @member: the name of this member within the structure. ++ * ++ * Given a pointer to a member of a structure, this macro does pointer ++ * subtraction to return the pointer to the enclosing type, unless it ++ * is given NULL, in which case it also returns NULL. ++ * ++ * Example: ++ * struct foo { ++ * int fielda, fieldb; ++ * // ... ++ * }; ++ * struct info { ++ * int some_other_field; ++ * struct foo my_foo; ++ * }; ++ * ++ * static struct info *foo_to_info_allowing_null(struct foo *foo) ++ * { ++ * return container_of_or_null(foo, struct info, my_foo); ++ * } ++ */ ++static inline char *container_of_or_null_(void *member_ptr, size_t offset) ++{ ++ return member_ptr ? (char *)member_ptr - offset : NULL; ++} ++#define container_of_or_null(member_ptr, containing_type, member) \ ++ ((containing_type *) \ ++ container_of_or_null_(member_ptr, \ ++ container_off(containing_type, member)) \ ++ + check_types_match(*(member_ptr), ((containing_type *)0)->member)) ++ ++/** ++ * container_off - get offset to enclosing structure ++ * @containing_type: the type this member is within ++ * @member: the name of this member within the structure. ++ * ++ * Given a pointer to a member of a structure, this macro does ++ * typechecking and figures out the offset to the enclosing type. ++ * ++ * Example: ++ * struct foo { ++ * int fielda, fieldb; ++ * // ... ++ * }; ++ * struct info { ++ * int some_other_field; ++ * struct foo my_foo; ++ * }; ++ * ++ * static struct info *foo_to_info(struct foo *foo) ++ * { ++ * size_t off = container_off(struct info, my_foo); ++ * return (void *)((char *)foo - off); ++ * } ++ */ ++#define container_off(containing_type, member) \ ++ offsetof(containing_type, member) ++ ++/** ++ * container_of_var - get pointer to enclosing structure using a variable ++ * @member_ptr: pointer to the structure member ++ * @container_var: a pointer of same type as this member's container ++ * @member: the name of this member within the structure. ++ * ++ * Given a pointer to a member of a structure, this macro does pointer ++ * subtraction to return the pointer to the enclosing type. ++ * ++ * Example: ++ * static struct info *foo_to_i(struct foo *foo) ++ * { ++ * struct info *i = container_of_var(foo, i, my_foo); ++ * return i; ++ * } ++ */ ++#if HAVE_TYPEOF ++#define container_of_var(member_ptr, container_var, member) \ ++ container_of(member_ptr, typeof(*container_var), member) ++#else ++#define container_of_var(member_ptr, container_var, member) \ ++ ((void *)((char *)(member_ptr) - \ ++ container_off_var(container_var, member))) ++#endif ++ ++/** ++ * container_off_var - get offset of a field in enclosing structure ++ * @container_var: a pointer to a container structure ++ * @member: the name of a member within the structure. ++ * ++ * Given (any) pointer to a structure and a its member name, this ++ * macro does pointer subtraction to return offset of member in a ++ * structure memory layout. ++ * ++ */ ++#if HAVE_TYPEOF ++#define container_off_var(var, member) \ ++ container_off(typeof(*var), member) ++#else ++#define container_off_var(var, member) \ ++ ((const char *)&(var)->member - (const char *)(var)) ++#endif ++ ++#endif /* CCAN_CONTAINER_OF_H */ +diff --git a/src/rc-compat/v37/ccan/ilog.h b/src/rc-compat/v37/ccan/ilog.h +new file mode 100644 +index 000000000000..2793a7056afe +--- /dev/null ++++ b/src/rc-compat/v37/ccan/ilog.h +@@ -0,0 +1,151 @@ ++/* CC0 (Public domain) - see LICENSE file for details */ ++#if !defined(_ilog_H) ++# define _ilog_H (1) ++# include "config.h" ++# include ++# include ++# include ++ ++/** ++ * ilog32 - Integer binary logarithm of a 32-bit value. ++ * @_v: A 32-bit value. ++ * Returns floor(log2(_v))+1, or 0 if _v==0. ++ * This is the number of bits that would be required to represent _v in two's ++ * complement notation with all of the leading zeros stripped. ++ * Note that many uses will resolve to the fast macro version instead. ++ * ++ * See Also: ++ * ilog32_nz(), ilog64() ++ * ++ * Example: ++ * // Rounds up to next power of 2 (if not a power of 2). ++ * static uint32_t round_up32(uint32_t i) ++ * { ++ * assert(i != 0); ++ * return 1U << ilog32(i-1); ++ * } ++ */ ++int ilog32(uint32_t _v); ++ ++/** ++ * ilog32_nz - Integer binary logarithm of a non-zero 32-bit value. ++ * @_v: A 32-bit value. ++ * Returns floor(log2(_v))+1, or undefined if _v==0. ++ * This is the number of bits that would be required to represent _v in two's ++ * complement notation with all of the leading zeros stripped. ++ * Note that many uses will resolve to the fast macro version instead. ++ * See Also: ++ * ilog32(), ilog64_nz() ++ * Example: ++ * // Find Last Set (ie. highest bit set, 0 to 31). ++ * static uint32_t fls32(uint32_t i) ++ * { ++ * assert(i != 0); ++ * return ilog32_nz(i) - 1; ++ * } ++ */ ++int ilog32_nz(uint32_t _v); ++ ++/** ++ * ilog64 - Integer binary logarithm of a 64-bit value. ++ * @_v: A 64-bit value. ++ * Returns floor(log2(_v))+1, or 0 if _v==0. ++ * This is the number of bits that would be required to represent _v in two's ++ * complement notation with all of the leading zeros stripped. ++ * Note that many uses will resolve to the fast macro version instead. ++ * See Also: ++ * ilog64_nz(), ilog32() ++ */ ++int ilog64(uint64_t _v); ++ ++/** ++ * ilog64_nz - Integer binary logarithm of a non-zero 64-bit value. ++ * @_v: A 64-bit value. ++ * Returns floor(log2(_v))+1, or undefined if _v==0. ++ * This is the number of bits that would be required to represent _v in two's ++ * complement notation with all of the leading zeros stripped. ++ * Note that many uses will resolve to the fast macro version instead. ++ * See Also: ++ * ilog64(), ilog32_nz() ++ */ ++int ilog64_nz(uint64_t _v); ++ ++/** ++ * STATIC_ILOG_32 - The integer logarithm of an (unsigned, 32-bit) constant. ++ * @_v: A non-negative 32-bit constant. ++ * Returns floor(log2(_v))+1, or 0 if _v==0. ++ * This is the number of bits that would be required to represent _v in two's ++ * complement notation with all of the leading zeros stripped. ++ * This macro should only be used when you need a compile-time constant, ++ * otherwise ilog32 or ilog32_nz are just as fast and more flexible. ++ * ++ * Example: ++ * #define MY_PAGE_SIZE 4096 ++ * #define MY_PAGE_BITS (STATIC_ILOG_32(PAGE_SIZE) - 1) ++ */ ++#define STATIC_ILOG_32(_v) (STATIC_ILOG5((uint32_t)(_v))) ++ ++/** ++ * STATIC_ILOG_64 - The integer logarithm of an (unsigned, 64-bit) constant. ++ * @_v: A non-negative 64-bit constant. ++ * Returns floor(log2(_v))+1, or 0 if _v==0. ++ * This is the number of bits that would be required to represent _v in two's ++ * complement notation with all of the leading zeros stripped. ++ * This macro should only be used when you need a compile-time constant, ++ * otherwise ilog64 or ilog64_nz are just as fast and more flexible. ++ */ ++#define STATIC_ILOG_64(_v) (STATIC_ILOG6((uint64_t)(_v))) ++ ++/* Private implementation details */ ++ ++/*Note the casts to (int) below: this prevents "upgrading" ++ the type of an entire expression to an (unsigned) size_t.*/ ++#if INT_MAX>=2147483647 && HAVE_BUILTIN_CLZ ++#define builtin_ilog32_nz(v) \ ++ (((int)sizeof(unsigned)*CHAR_BIT) - __builtin_clz(v)) ++#elif LONG_MAX>=2147483647L && HAVE_BUILTIN_CLZL ++#define builtin_ilog32_nz(v) \ ++ (((int)sizeof(unsigned)*CHAR_BIT) - __builtin_clzl(v)) ++#endif ++ ++#if INT_MAX>=9223372036854775807LL && HAVE_BUILTIN_CLZ ++#define builtin_ilog64_nz(v) \ ++ (((int)sizeof(unsigned)*CHAR_BIT) - __builtin_clz(v)) ++#elif LONG_MAX>=9223372036854775807LL && HAVE_BUILTIN_CLZL ++#define builtin_ilog64_nz(v) \ ++ (((int)sizeof(unsigned long)*CHAR_BIT) - __builtin_clzl(v)) ++#elif HAVE_BUILTIN_CLZLL ++#define builtin_ilog64_nz(v) \ ++ (((int)sizeof(unsigned long long)*CHAR_BIT) - __builtin_clzll(v)) ++#endif ++ ++#ifdef builtin_ilog32_nz ++#define ilog32(_v) (builtin_ilog32_nz(_v)&-!!(_v)) ++#define ilog32_nz(_v) builtin_ilog32_nz(_v) ++#else ++#define ilog32_nz(_v) ilog32(_v) ++#define ilog32(_v) (IS_COMPILE_CONSTANT(_v) ? STATIC_ILOG_32(_v) : ilog32(_v)) ++#endif /* builtin_ilog32_nz */ ++ ++#ifdef builtin_ilog64_nz ++#define ilog64(_v) (builtin_ilog64_nz(_v)&-!!(_v)) ++#define ilog64_nz(_v) builtin_ilog64_nz(_v) ++#else ++#define ilog64_nz(_v) ilog64(_v) ++#define ilog64(_v) (IS_COMPILE_CONSTANT(_v) ? STATIC_ILOG_64(_v) : ilog64(_v)) ++#endif /* builtin_ilog64_nz */ ++ ++/* Macros for evaluating compile-time constant ilog. */ ++# define STATIC_ILOG0(_v) (!!(_v)) ++# define STATIC_ILOG1(_v) (((_v)&0x2)?2:STATIC_ILOG0(_v)) ++# define STATIC_ILOG2(_v) (((_v)&0xC)?2+STATIC_ILOG1((_v)>>2):STATIC_ILOG1(_v)) ++# define STATIC_ILOG3(_v) \ ++ (((_v)&0xF0)?4+STATIC_ILOG2((_v)>>4):STATIC_ILOG2(_v)) ++# define STATIC_ILOG4(_v) \ ++ (((_v)&0xFF00)?8+STATIC_ILOG3((_v)>>8):STATIC_ILOG3(_v)) ++# define STATIC_ILOG5(_v) \ ++ (((_v)&0xFFFF0000)?16+STATIC_ILOG4((_v)>>16):STATIC_ILOG4(_v)) ++# define STATIC_ILOG6(_v) \ ++ (((_v)&0xFFFFFFFF00000000ULL)?32+STATIC_ILOG5((_v)>>32):STATIC_ILOG5(_v)) ++ ++#endif /* _ilog_H */ +diff --git a/src/rc-compat/v37/ccan/list.h b/src/rc-compat/v37/ccan/list.h +new file mode 100644 +index 000000000000..f4006660f7ef +--- /dev/null ++++ b/src/rc-compat/v37/ccan/list.h +@@ -0,0 +1,842 @@ ++/* Licensed under MIT - see LICENSE.MIT file for details */ ++#ifndef CCAN_LIST_H ++#define CCAN_LIST_H ++//#define CCAN_LIST_DEBUG 1 ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ * struct list_node - an entry in a doubly-linked list ++ * @next: next entry (self if empty) ++ * @prev: previous entry (self if empty) ++ * ++ * This is used as an entry in a linked list. ++ * Example: ++ * struct child { ++ * const char *name; ++ * // Linked list of all us children. ++ * struct list_node list; ++ * }; ++ */ ++struct list_node ++{ ++ struct list_node *next, *prev; ++}; ++ ++/** ++ * struct list_head - the head of a doubly-linked list ++ * @h: the list_head (containing next and prev pointers) ++ * ++ * This is used as the head of a linked list. ++ * Example: ++ * struct parent { ++ * const char *name; ++ * struct list_head children; ++ * unsigned int num_children; ++ * }; ++ */ ++struct list_head ++{ ++ struct list_node n; ++}; ++ ++/** ++ * list_check - check head of a list for consistency ++ * @h: the list_head ++ * @abortstr: the location to print on aborting, or NULL. ++ * ++ * Because list_nodes have redundant information, consistency checking between ++ * the back and forward links can be done. This is useful as a debugging check. ++ * If @abortstr is non-NULL, that will be printed in a diagnostic if the list ++ * is inconsistent, and the function will abort. ++ * ++ * Returns the list head if the list is consistent, NULL if not (it ++ * can never return NULL if @abortstr is set). ++ * ++ * See also: list_check_node() ++ * ++ * Example: ++ * static void dump_parent(struct parent *p) ++ * { ++ * struct child *c; ++ * ++ * printf("%s (%u children):\n", p->name, p->num_children); ++ * list_check(&p->children, "bad child list"); ++ * list_for_each(&p->children, c, list) ++ * printf(" -> %s\n", c->name); ++ * } ++ */ ++struct list_head *list_check(const struct list_head *h, const char *abortstr); ++ ++/** ++ * list_check_node - check node of a list for consistency ++ * @n: the list_node ++ * @abortstr: the location to print on aborting, or NULL. ++ * ++ * Check consistency of the list node is in (it must be in one). ++ * ++ * See also: list_check() ++ * ++ * Example: ++ * static void dump_child(const struct child *c) ++ * { ++ * list_check_node(&c->list, "bad child list"); ++ * printf("%s\n", c->name); ++ * } ++ */ ++struct list_node *list_check_node(const struct list_node *n, ++ const char *abortstr); ++ ++#define LIST_LOC __FILE__ ":" stringify(__LINE__) ++#ifdef CCAN_LIST_DEBUG ++#define list_debug(h, loc) list_check((h), loc) ++#define list_debug_node(n, loc) list_check_node((n), loc) ++#else ++#define list_debug(h, loc) ((void)loc, h) ++#define list_debug_node(n, loc) ((void)loc, n) ++#endif ++ ++/** ++ * LIST_HEAD_INIT - initializer for an empty list_head ++ * @name: the name of the list. ++ * ++ * Explicit initializer for an empty list. ++ * ++ * See also: ++ * LIST_HEAD, list_head_init() ++ * ++ * Example: ++ * static struct list_head my_list = LIST_HEAD_INIT(my_list); ++ */ ++#define LIST_HEAD_INIT(name) { { &(name).n, &(name).n } } ++ ++/** ++ * LIST_HEAD - define and initialize an empty list_head ++ * @name: the name of the list. ++ * ++ * The LIST_HEAD macro defines a list_head and initializes it to an empty ++ * list. It can be prepended by "static" to define a static list_head. ++ * ++ * See also: ++ * LIST_HEAD_INIT, list_head_init() ++ * ++ * Example: ++ * static LIST_HEAD(my_global_list); ++ */ ++#define LIST_HEAD(name) \ ++ struct list_head name = LIST_HEAD_INIT(name) ++ ++/** ++ * list_head_init - initialize a list_head ++ * @h: the list_head to set to the empty list ++ * ++ * Example: ++ * ... ++ * struct parent *parent = malloc(sizeof(*parent)); ++ * ++ * list_head_init(&parent->children); ++ * parent->num_children = 0; ++ */ ++static inline void list_head_init(struct list_head *h) ++{ ++ h->n.next = h->n.prev = &h->n; ++} ++ ++/** ++ * list_node_init - initialize a list_node ++ * @n: the list_node to link to itself. ++ * ++ * You don't need to use this normally! But it lets you list_del(@n) ++ * safely. ++ */ ++static inline void list_node_init(struct list_node *n) ++{ ++ n->next = n->prev = n; ++} ++ ++/** ++ * list_add_after - add an entry after an existing node in a linked list ++ * @h: the list_head to add the node to (for debugging) ++ * @p: the existing list_node to add the node after ++ * @n: the new list_node to add to the list. ++ * ++ * The existing list_node must already be a member of the list. ++ * The new list_node does not need to be initialized; it will be overwritten. ++ * ++ * Example: ++ * struct child c1, c2, c3; ++ * LIST_HEAD(h); ++ * ++ * list_add_tail(&h, &c1.list); ++ * list_add_tail(&h, &c3.list); ++ * list_add_after(&h, &c1.list, &c2.list); ++ */ ++#define list_add_after(h, p, n) list_add_after_(h, p, n, LIST_LOC) ++static inline void list_add_after_(struct list_head *h, ++ struct list_node *p, ++ struct list_node *n, ++ const char *abortstr) ++{ ++ n->next = p->next; ++ n->prev = p; ++ p->next->prev = n; ++ p->next = n; ++ (void)list_debug(h, abortstr); ++} ++ ++/** ++ * list_add - add an entry at the start of a linked list. ++ * @h: the list_head to add the node to ++ * @n: the list_node to add to the list. ++ * ++ * The list_node does not need to be initialized; it will be overwritten. ++ * Example: ++ * struct child *child = malloc(sizeof(*child)); ++ * ++ * child->name = "marvin"; ++ * list_add(&parent->children, &child->list); ++ * parent->num_children++; ++ */ ++#define list_add(h, n) list_add_(h, n, LIST_LOC) ++static inline void list_add_(struct list_head *h, ++ struct list_node *n, ++ const char *abortstr) ++{ ++ list_add_after_(h, &h->n, n, abortstr); ++} ++ ++/** ++ * list_add_before - add an entry before an existing node in a linked list ++ * @h: the list_head to add the node to (for debugging) ++ * @p: the existing list_node to add the node before ++ * @n: the new list_node to add to the list. ++ * ++ * The existing list_node must already be a member of the list. ++ * The new list_node does not need to be initialized; it will be overwritten. ++ * ++ * Example: ++ * list_head_init(&h); ++ * list_add_tail(&h, &c1.list); ++ * list_add_tail(&h, &c3.list); ++ * list_add_before(&h, &c3.list, &c2.list); ++ */ ++#define list_add_before(h, p, n) list_add_before_(h, p, n, LIST_LOC) ++static inline void list_add_before_(struct list_head *h, ++ struct list_node *p, ++ struct list_node *n, ++ const char *abortstr) ++{ ++ n->next = p; ++ n->prev = p->prev; ++ p->prev->next = n; ++ p->prev = n; ++ (void)list_debug(h, abortstr); ++} ++ ++/** ++ * list_add_tail - add an entry at the end of a linked list. ++ * @h: the list_head to add the node to ++ * @n: the list_node to add to the list. ++ * ++ * The list_node does not need to be initialized; it will be overwritten. ++ * Example: ++ * list_add_tail(&parent->children, &child->list); ++ * parent->num_children++; ++ */ ++#define list_add_tail(h, n) list_add_tail_(h, n, LIST_LOC) ++static inline void list_add_tail_(struct list_head *h, ++ struct list_node *n, ++ const char *abortstr) ++{ ++ list_add_before_(h, &h->n, n, abortstr); ++} ++ ++/** ++ * list_empty - is a list empty? ++ * @h: the list_head ++ * ++ * If the list is empty, returns true. ++ * ++ * Example: ++ * assert(list_empty(&parent->children) == (parent->num_children == 0)); ++ */ ++#define list_empty(h) list_empty_(h, LIST_LOC) ++static inline bool list_empty_(const struct list_head *h, const char* abortstr) ++{ ++ (void)list_debug(h, abortstr); ++ return h->n.next == &h->n; ++} ++ ++/** ++ * list_empty_nodebug - is a list empty (and don't perform debug checks)? ++ * @h: the list_head ++ * ++ * If the list is empty, returns true. ++ * This differs from list_empty() in that if CCAN_LIST_DEBUG is set it ++ * will NOT perform debug checks. Only use this function if you REALLY ++ * know what you're doing. ++ * ++ * Example: ++ * assert(list_empty_nodebug(&parent->children) == (parent->num_children == 0)); ++ */ ++#ifndef CCAN_LIST_DEBUG ++#define list_empty_nodebug(h) list_empty(h) ++#else ++static inline bool list_empty_nodebug(const struct list_head *h) ++{ ++ return h->n.next == &h->n; ++} ++#endif ++ ++/** ++ * list_empty_nocheck - is a list empty? ++ * @h: the list_head ++ * ++ * If the list is empty, returns true. This doesn't perform any ++ * debug check for list consistency, so it can be called without ++ * locks, racing with the list being modified. This is ok for ++ * checks where an incorrect result is not an issue (optimized ++ * bail out path for example). ++ */ ++static inline bool list_empty_nocheck(const struct list_head *h) ++{ ++ return h->n.next == &h->n; ++} ++ ++/** ++ * list_del - delete an entry from an (unknown) linked list. ++ * @n: the list_node to delete from the list. ++ * ++ * Note that this leaves @n in an undefined state; it can be added to ++ * another list, but not deleted again. ++ * ++ * See also: ++ * list_del_from(), list_del_init() ++ * ++ * Example: ++ * list_del(&child->list); ++ * parent->num_children--; ++ */ ++#define list_del(n) list_del_(n, LIST_LOC) ++static inline void list_del_(struct list_node *n, const char* abortstr) ++{ ++ (void)list_debug_node(n, abortstr); ++ n->next->prev = n->prev; ++ n->prev->next = n->next; ++#ifdef CCAN_LIST_DEBUG ++ /* Catch use-after-del. */ ++ n->next = n->prev = NULL; ++#endif ++} ++ ++/** ++ * list_del_init - delete a node, and reset it so it can be deleted again. ++ * @n: the list_node to be deleted. ++ * ++ * list_del(@n) or list_del_init() again after this will be safe, ++ * which can be useful in some cases. ++ * ++ * See also: ++ * list_del_from(), list_del() ++ * ++ * Example: ++ * list_del_init(&child->list); ++ * parent->num_children--; ++ */ ++#define list_del_init(n) list_del_init_(n, LIST_LOC) ++static inline void list_del_init_(struct list_node *n, const char *abortstr) ++{ ++ list_del_(n, abortstr); ++ list_node_init(n); ++} ++ ++/** ++ * list_del_from - delete an entry from a known linked list. ++ * @h: the list_head the node is in. ++ * @n: the list_node to delete from the list. ++ * ++ * This explicitly indicates which list a node is expected to be in, ++ * which is better documentation and can catch more bugs. ++ * ++ * See also: list_del() ++ * ++ * Example: ++ * list_del_from(&parent->children, &child->list); ++ * parent->num_children--; ++ */ ++static inline void list_del_from(struct list_head *h, struct list_node *n) ++{ ++#ifdef CCAN_LIST_DEBUG ++ { ++ /* Thorough check: make sure it was in list! */ ++ struct list_node *i; ++ for (i = h->n.next; i != n; i = i->next) ++ assert(i != &h->n); ++ } ++#endif /* CCAN_LIST_DEBUG */ ++ ++ /* Quick test that catches a surprising number of bugs. */ ++ assert(!list_empty(h)); ++ list_del(n); ++} ++ ++/** ++ * list_swap - swap out an entry from an (unknown) linked list for a new one. ++ * @o: the list_node to replace from the list. ++ * @n: the list_node to insert in place of the old one. ++ * ++ * Note that this leaves @o in an undefined state; it can be added to ++ * another list, but not deleted/swapped again. ++ * ++ * See also: ++ * list_del() ++ * ++ * Example: ++ * struct child x1, x2; ++ * LIST_HEAD(xh); ++ * ++ * list_add(&xh, &x1.list); ++ * list_swap(&x1.list, &x2.list); ++ */ ++#define list_swap(o, n) list_swap_(o, n, LIST_LOC) ++static inline void list_swap_(struct list_node *o, ++ struct list_node *n, ++ const char* abortstr) ++{ ++ (void)list_debug_node(o, abortstr); ++ *n = *o; ++ n->next->prev = n; ++ n->prev->next = n; ++#ifdef CCAN_LIST_DEBUG ++ /* Catch use-after-del. */ ++ o->next = o->prev = NULL; ++#endif ++} ++ ++/** ++ * list_entry - convert a list_node back into the structure containing it. ++ * @n: the list_node ++ * @type: the type of the entry ++ * @member: the list_node member of the type ++ * ++ * Example: ++ * // First list entry is children.next; convert back to child. ++ * child = list_entry(parent->children.n.next, struct child, list); ++ * ++ * See Also: ++ * list_top(), list_for_each() ++ */ ++#define list_entry(n, type, member) container_of(n, type, member) ++ ++/** ++ * list_top - get the first entry in a list ++ * @h: the list_head ++ * @type: the type of the entry ++ * @member: the list_node member of the type ++ * ++ * If the list is empty, returns NULL. ++ * ++ * Example: ++ * struct child *first; ++ * first = list_top(&parent->children, struct child, list); ++ * if (!first) ++ * printf("Empty list!\n"); ++ */ ++#define list_top(h, type, member) \ ++ ((type *)list_top_((h), list_off_(type, member))) ++ ++static inline const void *list_top_(const struct list_head *h, size_t off) ++{ ++ if (list_empty(h)) ++ return NULL; ++ return (const char *)h->n.next - off; ++} ++ ++/** ++ * list_pop - remove the first entry in a list ++ * @h: the list_head ++ * @type: the type of the entry ++ * @member: the list_node member of the type ++ * ++ * If the list is empty, returns NULL. ++ * ++ * Example: ++ * struct child *one; ++ * one = list_pop(&parent->children, struct child, list); ++ * if (!one) ++ * printf("Empty list!\n"); ++ */ ++#define list_pop(h, type, member) \ ++ ((type *)list_pop_((h), list_off_(type, member))) ++ ++static inline const void *list_pop_(const struct list_head *h, size_t off) ++{ ++ struct list_node *n; ++ ++ if (list_empty(h)) ++ return NULL; ++ n = h->n.next; ++ list_del(n); ++ return (const char *)n - off; ++} ++ ++/** ++ * list_tail - get the last entry in a list ++ * @h: the list_head ++ * @type: the type of the entry ++ * @member: the list_node member of the type ++ * ++ * If the list is empty, returns NULL. ++ * ++ * Example: ++ * struct child *last; ++ * last = list_tail(&parent->children, struct child, list); ++ * if (!last) ++ * printf("Empty list!\n"); ++ */ ++#define list_tail(h, type, member) \ ++ ((type *)list_tail_((h), list_off_(type, member))) ++ ++static inline const void *list_tail_(const struct list_head *h, size_t off) ++{ ++ if (list_empty(h)) ++ return NULL; ++ return (const char *)h->n.prev - off; ++} ++ ++/** ++ * list_for_each - iterate through a list. ++ * @h: the list_head (warning: evaluated multiple times!) ++ * @i: the structure containing the list_node ++ * @member: the list_node member of the structure ++ * ++ * This is a convenient wrapper to iterate @i over the entire list. It's ++ * a for loop, so you can break and continue as normal. ++ * ++ * Example: ++ * list_for_each(&parent->children, child, list) ++ * printf("Name: %s\n", child->name); ++ */ ++#define list_for_each(h, i, member) \ ++ list_for_each_off(h, i, list_off_var_(i, member)) ++ ++/** ++ * list_for_each_rev - iterate through a list backwards. ++ * @h: the list_head ++ * @i: the structure containing the list_node ++ * @member: the list_node member of the structure ++ * ++ * This is a convenient wrapper to iterate @i over the entire list. It's ++ * a for loop, so you can break and continue as normal. ++ * ++ * Example: ++ * list_for_each_rev(&parent->children, child, list) ++ * printf("Name: %s\n", child->name); ++ */ ++#define list_for_each_rev(h, i, member) \ ++ list_for_each_rev_off(h, i, list_off_var_(i, member)) ++ ++/** ++ * list_for_each_rev_safe - iterate through a list backwards, ++ * maybe during deletion ++ * @h: the list_head ++ * @i: the structure containing the list_node ++ * @nxt: the structure containing the list_node ++ * @member: the list_node member of the structure ++ * ++ * This is a convenient wrapper to iterate @i over the entire list backwards. ++ * It's a for loop, so you can break and continue as normal. The extra ++ * variable * @nxt is used to hold the next element, so you can delete @i ++ * from the list. ++ * ++ * Example: ++ * struct child *next; ++ * list_for_each_rev_safe(&parent->children, child, next, list) { ++ * printf("Name: %s\n", child->name); ++ * } ++ */ ++#define list_for_each_rev_safe(h, i, nxt, member) \ ++ list_for_each_rev_safe_off(h, i, nxt, list_off_var_(i, member)) ++ ++/** ++ * list_for_each_safe - iterate through a list, maybe during deletion ++ * @h: the list_head ++ * @i: the structure containing the list_node ++ * @nxt: the structure containing the list_node ++ * @member: the list_node member of the structure ++ * ++ * This is a convenient wrapper to iterate @i over the entire list. It's ++ * a for loop, so you can break and continue as normal. The extra variable ++ * @nxt is used to hold the next element, so you can delete @i from the list. ++ * ++ * Example: ++ * list_for_each_safe(&parent->children, child, next, list) { ++ * list_del(&child->list); ++ * parent->num_children--; ++ * } ++ */ ++#define list_for_each_safe(h, i, nxt, member) \ ++ list_for_each_safe_off(h, i, nxt, list_off_var_(i, member)) ++ ++/** ++ * list_next - get the next entry in a list ++ * @h: the list_head ++ * @i: a pointer to an entry in the list. ++ * @member: the list_node member of the structure ++ * ++ * If @i was the last entry in the list, returns NULL. ++ * ++ * Example: ++ * struct child *second; ++ * second = list_next(&parent->children, first, list); ++ * if (!second) ++ * printf("No second child!\n"); ++ */ ++#define list_next(h, i, member) \ ++ ((list_typeof(i))list_entry_or_null(list_debug(h, \ ++ __FILE__ ":" stringify(__LINE__)), \ ++ (i)->member.next, \ ++ list_off_var_((i), member))) ++ ++/** ++ * list_prev - get the previous entry in a list ++ * @h: the list_head ++ * @i: a pointer to an entry in the list. ++ * @member: the list_node member of the structure ++ * ++ * If @i was the first entry in the list, returns NULL. ++ * ++ * Example: ++ * first = list_prev(&parent->children, second, list); ++ * if (!first) ++ * printf("Can't go back to first child?!\n"); ++ */ ++#define list_prev(h, i, member) \ ++ ((list_typeof(i))list_entry_or_null(list_debug(h, \ ++ __FILE__ ":" stringify(__LINE__)), \ ++ (i)->member.prev, \ ++ list_off_var_((i), member))) ++ ++/** ++ * list_append_list - empty one list onto the end of another. ++ * @to: the list to append into ++ * @from: the list to empty. ++ * ++ * This takes the entire contents of @from and moves it to the end of ++ * @to. After this @from will be empty. ++ * ++ * Example: ++ * struct list_head adopter; ++ * ++ * list_append_list(&adopter, &parent->children); ++ * assert(list_empty(&parent->children)); ++ * parent->num_children = 0; ++ */ ++#define list_append_list(t, f) list_append_list_(t, f, \ ++ __FILE__ ":" stringify(__LINE__)) ++static inline void list_append_list_(struct list_head *to, ++ struct list_head *from, ++ const char *abortstr) ++{ ++ struct list_node *from_tail = list_debug(from, abortstr)->n.prev; ++ struct list_node *to_tail = list_debug(to, abortstr)->n.prev; ++ ++ /* Sew in head and entire list. */ ++ to->n.prev = from_tail; ++ from_tail->next = &to->n; ++ to_tail->next = &from->n; ++ from->n.prev = to_tail; ++ ++ /* Now remove head. */ ++ list_del(&from->n); ++ list_head_init(from); ++} ++ ++/** ++ * list_prepend_list - empty one list into the start of another. ++ * @to: the list to prepend into ++ * @from: the list to empty. ++ * ++ * This takes the entire contents of @from and moves it to the start ++ * of @to. After this @from will be empty. ++ * ++ * Example: ++ * list_prepend_list(&adopter, &parent->children); ++ * assert(list_empty(&parent->children)); ++ * parent->num_children = 0; ++ */ ++#define list_prepend_list(t, f) list_prepend_list_(t, f, LIST_LOC) ++static inline void list_prepend_list_(struct list_head *to, ++ struct list_head *from, ++ const char *abortstr) ++{ ++ struct list_node *from_tail = list_debug(from, abortstr)->n.prev; ++ struct list_node *to_head = list_debug(to, abortstr)->n.next; ++ ++ /* Sew in head and entire list. */ ++ to->n.next = &from->n; ++ from->n.prev = &to->n; ++ to_head->prev = from_tail; ++ from_tail->next = to_head; ++ ++ /* Now remove head. */ ++ list_del(&from->n); ++ list_head_init(from); ++} ++ ++/* internal macros, do not use directly */ ++#define list_for_each_off_dir_(h, i, off, dir) \ ++ for (i = list_node_to_off_(list_debug(h, LIST_LOC)->n.dir, \ ++ (off)); \ ++ list_node_from_off_((void *)i, (off)) != &(h)->n; \ ++ i = list_node_to_off_(list_node_from_off_((void *)i, (off))->dir, \ ++ (off))) ++ ++#define list_for_each_safe_off_dir_(h, i, nxt, off, dir) \ ++ for (i = list_node_to_off_(list_debug(h, LIST_LOC)->n.dir, \ ++ (off)), \ ++ nxt = list_node_to_off_(list_node_from_off_(i, (off))->dir, \ ++ (off)); \ ++ list_node_from_off_(i, (off)) != &(h)->n; \ ++ i = nxt, \ ++ nxt = list_node_to_off_(list_node_from_off_(i, (off))->dir, \ ++ (off))) ++ ++/** ++ * list_for_each_off - iterate through a list of memory regions. ++ * @h: the list_head ++ * @i: the pointer to a memory region wich contains list node data. ++ * @off: offset(relative to @i) at which list node data resides. ++ * ++ * This is a low-level wrapper to iterate @i over the entire list, used to ++ * implement all oher, more high-level, for-each constructs. It's a for loop, ++ * so you can break and continue as normal. ++ * ++ * WARNING! Being the low-level macro that it is, this wrapper doesn't know ++ * nor care about the type of @i. The only assumtion made is that @i points ++ * to a chunk of memory that at some @offset, relative to @i, contains a ++ * properly filled `struct node_list' which in turn contains pointers to ++ * memory chunks and it's turtles all the way down. Whith all that in mind ++ * remember that given the wrong pointer/offset couple this macro will ++ * happilly churn all you memory untill SEGFAULT stops it, in other words ++ * caveat emptor. ++ * ++ * It is worth mentioning that one of legitimate use-cases for that wrapper ++ * is operation on opaque types with known offset for `struct list_node' ++ * member(preferably 0), because it allows you not to disclose the type of ++ * @i. ++ * ++ * Example: ++ * list_for_each_off(&parent->children, child, ++ * offsetof(struct child, list)) ++ * printf("Name: %s\n", child->name); ++ */ ++#define list_for_each_off(h, i, off) \ ++ list_for_each_off_dir_((h),(i),(off),next) ++ ++/** ++ * list_for_each_rev_off - iterate through a list of memory regions backwards ++ * @h: the list_head ++ * @i: the pointer to a memory region wich contains list node data. ++ * @off: offset(relative to @i) at which list node data resides. ++ * ++ * See list_for_each_off for details ++ */ ++#define list_for_each_rev_off(h, i, off) \ ++ list_for_each_off_dir_((h),(i),(off),prev) ++ ++/** ++ * list_for_each_safe_off - iterate through a list of memory regions, maybe ++ * during deletion ++ * @h: the list_head ++ * @i: the pointer to a memory region wich contains list node data. ++ * @nxt: the structure containing the list_node ++ * @off: offset(relative to @i) at which list node data resides. ++ * ++ * For details see `list_for_each_off' and `list_for_each_safe' ++ * descriptions. ++ * ++ * Example: ++ * list_for_each_safe_off(&parent->children, child, ++ * next, offsetof(struct child, list)) ++ * printf("Name: %s\n", child->name); ++ */ ++#define list_for_each_safe_off(h, i, nxt, off) \ ++ list_for_each_safe_off_dir_((h),(i),(nxt),(off),next) ++ ++/** ++ * list_for_each_rev_safe_off - iterate backwards through a list of ++ * memory regions, maybe during deletion ++ * @h: the list_head ++ * @i: the pointer to a memory region wich contains list node data. ++ * @nxt: the structure containing the list_node ++ * @off: offset(relative to @i) at which list node data resides. ++ * ++ * For details see `list_for_each_rev_off' and `list_for_each_rev_safe' ++ * descriptions. ++ * ++ * Example: ++ * list_for_each_rev_safe_off(&parent->children, child, ++ * next, offsetof(struct child, list)) ++ * printf("Name: %s\n", child->name); ++ */ ++#define list_for_each_rev_safe_off(h, i, nxt, off) \ ++ list_for_each_safe_off_dir_((h),(i),(nxt),(off),prev) ++ ++/* Other -off variants. */ ++#define list_entry_off(n, type, off) \ ++ ((type *)list_node_from_off_((n), (off))) ++ ++#define list_head_off(h, type, off) \ ++ ((type *)list_head_off((h), (off))) ++ ++#define list_tail_off(h, type, off) \ ++ ((type *)list_tail_((h), (off))) ++ ++#define list_add_off(h, n, off) \ ++ list_add((h), list_node_from_off_((n), (off))) ++ ++#define list_del_off(n, off) \ ++ list_del(list_node_from_off_((n), (off))) ++ ++#define list_del_from_off(h, n, off) \ ++ list_del_from(h, list_node_from_off_((n), (off))) ++ ++/* Offset helper functions so we only single-evaluate. */ ++static inline void *list_node_to_off_(struct list_node *node, size_t off) ++{ ++ return (void *)((char *)node - off); ++} ++static inline struct list_node *list_node_from_off_(void *ptr, size_t off) ++{ ++ return (struct list_node *)((char *)ptr + off); ++} ++ ++/* Get the offset of the member, but make sure it's a list_node. */ ++#define list_off_(type, member) \ ++ (container_off(type, member) + \ ++ check_type(((type *)0)->member, struct list_node)) ++ ++#define list_off_var_(var, member) \ ++ (container_off_var(var, member) + \ ++ check_type(var->member, struct list_node)) ++ ++#if HAVE_TYPEOF ++#define list_typeof(var) typeof(var) ++#else ++#define list_typeof(var) void * ++#endif ++ ++/* Returns member, or NULL if at end of list. */ ++static inline void *list_entry_or_null(const struct list_head *h, ++ const struct list_node *n, ++ size_t off) ++{ ++ if (n == &h->n) ++ return NULL; ++ return (char *)n - off; ++} ++#endif /* CCAN_LIST_H */ +diff --git a/src/rc-compat/v37/ccan/minmax.h b/src/rc-compat/v37/ccan/minmax.h +new file mode 100644 +index 000000000000..ab6c55472b9a +--- /dev/null ++++ b/src/rc-compat/v37/ccan/minmax.h +@@ -0,0 +1,65 @@ ++/* CC0 (Public domain) - see LICENSE.CC0 file for details */ ++#ifndef CCAN_MINMAX_H ++#define CCAN_MINMAX_H ++ ++#include "config.h" ++ ++#include ++ ++#if !HAVE_STATEMENT_EXPR || !HAVE_TYPEOF ++/* ++ * Without these, there's no way to avoid unsafe double evaluation of ++ * the arguments ++ */ ++#error Sorry, minmax module requires statement expressions and typeof ++#endif ++ ++#if HAVE_BUILTIN_TYPES_COMPATIBLE_P ++#define MINMAX_ASSERT_COMPATIBLE(a, b) \ ++ BUILD_ASSERT(__builtin_types_compatible_p(a, b)) ++#else ++#define MINMAX_ASSERT_COMPATIBLE(a, b) \ ++ do { } while (0) ++#endif ++ ++#define min(a, b) \ ++ ({ \ ++ typeof(a) _a = (a); \ ++ typeof(b) _b = (b); \ ++ MINMAX_ASSERT_COMPATIBLE(typeof(_a), typeof(_b)); \ ++ _a < _b ? _a : _b; \ ++ }) ++ ++#define max(a, b) \ ++ ({ \ ++ typeof(a) _a = (a); \ ++ typeof(b) _b = (b); \ ++ MINMAX_ASSERT_COMPATIBLE(typeof(_a), typeof(_b)); \ ++ _a > _b ? _a : _b; \ ++ }) ++ ++#define clamp(v, f, c) (max(min((v), (c)), (f))) ++ ++ ++#define min_t(t, a, b) \ ++ ({ \ ++ t _ta = (a); \ ++ t _tb = (b); \ ++ min(_ta, _tb); \ ++ }) ++#define max_t(t, a, b) \ ++ ({ \ ++ t _ta = (a); \ ++ t _tb = (b); \ ++ max(_ta, _tb); \ ++ }) ++ ++#define clamp_t(t, v, f, c) \ ++ ({ \ ++ t _tv = (v); \ ++ t _tf = (f); \ ++ t _tc = (c); \ ++ clamp(_tv, _tf, _tc); \ ++ }) ++ ++#endif /* CCAN_MINMAX_H */ +diff --git a/src/rc-compat/v37/ccan/str.h b/src/rc-compat/v37/ccan/str.h +new file mode 100644 +index 000000000000..68c8a518b700 +--- /dev/null ++++ b/src/rc-compat/v37/ccan/str.h +@@ -0,0 +1,228 @@ ++/* CC0 (Public domain) - see LICENSE.CC0 file for details */ ++#ifndef CCAN_STR_H ++#define CCAN_STR_H ++#include "config.h" ++#include ++#include ++#include ++#include ++ ++/** ++ * streq - Are two strings equal? ++ * @a: first string ++ * @b: first string ++ * ++ * This macro is arguably more readable than "!strcmp(a, b)". ++ * ++ * Example: ++ * if (streq(somestring, "")) ++ * printf("String is empty!\n"); ++ */ ++#define streq(a,b) (strcmp((a),(b)) == 0) ++ ++/** ++ * strstarts - Does this string start with this prefix? ++ * @str: string to test ++ * @prefix: prefix to look for at start of str ++ * ++ * Example: ++ * if (strstarts(somestring, "foo")) ++ * printf("String %s begins with 'foo'!\n", somestring); ++ */ ++#define strstarts(str,prefix) (strncmp((str),(prefix),strlen(prefix)) == 0) ++ ++/** ++ * strends - Does this string end with this postfix? ++ * @str: string to test ++ * @postfix: postfix to look for at end of str ++ * ++ * Example: ++ * if (strends(somestring, "foo")) ++ * printf("String %s end with 'foo'!\n", somestring); ++ */ ++static inline bool strends(const char *str, const char *postfix) ++{ ++ if (strlen(str) < strlen(postfix)) ++ return false; ++ ++ return streq(str + strlen(str) - strlen(postfix), postfix); ++} ++ ++/** ++ * stringify - Turn expression into a string literal ++ * @expr: any C expression ++ * ++ * Example: ++ * #define PRINT_COND_IF_FALSE(cond) \ ++ * ((cond) || printf("%s is false!", stringify(cond))) ++ */ ++#define stringify(expr) stringify_1(expr) ++/* Double-indirection required to stringify expansions */ ++#define stringify_1(expr) #expr ++ ++/** ++ * strcount - Count number of (non-overlapping) occurrences of a substring. ++ * @haystack: a C string ++ * @needle: a substring ++ * ++ * Example: ++ * assert(strcount("aaa aaa", "a") == 6); ++ * assert(strcount("aaa aaa", "ab") == 0); ++ * assert(strcount("aaa aaa", "aa") == 2); ++ */ ++size_t strcount(const char *haystack, const char *needle); ++ ++/** ++ * STR_MAX_CHARS - Maximum possible size of numeric string for this type. ++ * @type_or_expr: a pointer or integer type or expression. ++ * ++ * This provides enough space for a nul-terminated string which represents the ++ * largest possible value for the type or expression. ++ * ++ * Note: The implementation adds extra space so hex values or negative ++ * values will fit (eg. sprintf(... "%p"). ) ++ * ++ * Example: ++ * char str[STR_MAX_CHARS(int)]; ++ * ++ * sprintf(str, "%i", 7); ++ */ ++#define STR_MAX_CHARS(type_or_expr) \ ++ ((sizeof(type_or_expr) * CHAR_BIT + 8) / 9 * 3 + 2 \ ++ + STR_MAX_CHARS_TCHECK_(type_or_expr)) ++ ++#if HAVE_TYPEOF ++/* Only a simple type can have 0 assigned, so test that. */ ++#define STR_MAX_CHARS_TCHECK_(type_or_expr) \ ++ ({ typeof(type_or_expr) x = 0; (void)x; 0; }) ++#else ++#define STR_MAX_CHARS_TCHECK_(type_or_expr) 0 ++#endif ++ ++/** ++ * cisalnum - isalnum() which takes a char (and doesn't accept EOF) ++ * @c: a character ++ * ++ * Surprisingly, the standard ctype.h isalnum() takes an int, which ++ * must have the value of EOF (-1) or an unsigned char. This variant ++ * takes a real char, and doesn't accept EOF. ++ */ ++static inline bool cisalnum(char c) ++{ ++ return isalnum((unsigned char)c); ++} ++static inline bool cisalpha(char c) ++{ ++ return isalpha((unsigned char)c); ++} ++static inline bool cisascii(char c) ++{ ++ return isascii((unsigned char)c); ++} ++#if HAVE_ISBLANK ++static inline bool cisblank(char c) ++{ ++ return isblank((unsigned char)c); ++} ++#endif ++static inline bool ciscntrl(char c) ++{ ++ return iscntrl((unsigned char)c); ++} ++static inline bool cisdigit(char c) ++{ ++ return isdigit((unsigned char)c); ++} ++static inline bool cisgraph(char c) ++{ ++ return isgraph((unsigned char)c); ++} ++static inline bool cislower(char c) ++{ ++ return islower((unsigned char)c); ++} ++static inline bool cisprint(char c) ++{ ++ return isprint((unsigned char)c); ++} ++static inline bool cispunct(char c) ++{ ++ return ispunct((unsigned char)c); ++} ++static inline bool cisspace(char c) ++{ ++ return isspace((unsigned char)c); ++} ++static inline bool cisupper(char c) ++{ ++ return isupper((unsigned char)c); ++} ++static inline bool cisxdigit(char c) ++{ ++ return isxdigit((unsigned char)c); ++} ++ ++#include ++ ++/* These checks force things out of line, hence they are under DEBUG. */ ++#ifdef CCAN_STR_DEBUG ++#include ++ ++/* These are commonly misused: they take -1 or an *unsigned* char value. */ ++#undef isalnum ++#undef isalpha ++#undef isascii ++#undef isblank ++#undef iscntrl ++#undef isdigit ++#undef isgraph ++#undef islower ++#undef isprint ++#undef ispunct ++#undef isspace ++#undef isupper ++#undef isxdigit ++ ++/* You can use a char if char is unsigned. */ ++#if HAVE_BUILTIN_TYPES_COMPATIBLE_P && HAVE_TYPEOF ++#define str_check_arg_(i) \ ++ ((i) + BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(typeof(i), \ ++ char) \ ++ || (char)255 > 0)) ++#else ++#define str_check_arg_(i) (i) ++#endif ++ ++#define isalnum(i) str_isalnum(str_check_arg_(i)) ++#define isalpha(i) str_isalpha(str_check_arg_(i)) ++#define isascii(i) str_isascii(str_check_arg_(i)) ++#if HAVE_ISBLANK ++#define isblank(i) str_isblank(str_check_arg_(i)) ++#endif ++#define iscntrl(i) str_iscntrl(str_check_arg_(i)) ++#define isdigit(i) str_isdigit(str_check_arg_(i)) ++#define isgraph(i) str_isgraph(str_check_arg_(i)) ++#define islower(i) str_islower(str_check_arg_(i)) ++#define isprint(i) str_isprint(str_check_arg_(i)) ++#define ispunct(i) str_ispunct(str_check_arg_(i)) ++#define isspace(i) str_isspace(str_check_arg_(i)) ++#define isupper(i) str_isupper(str_check_arg_(i)) ++#define isxdigit(i) str_isxdigit(str_check_arg_(i)) ++ ++#if HAVE_TYPEOF ++/* With GNU magic, we can make const-respecting standard string functions. */ ++#undef strstr ++#undef strchr ++#undef strrchr ++ ++/* + 0 is needed to decay array into pointer. */ ++#define strstr(haystack, needle) \ ++ ((typeof((haystack) + 0))str_strstr((haystack), (needle))) ++#define strchr(haystack, c) \ ++ ((typeof((haystack) + 0))str_strchr((haystack), (c))) ++#define strrchr(haystack, c) \ ++ ((typeof((haystack) + 0))str_strrchr((haystack), (c))) ++#endif ++#endif /* CCAN_STR_DEBUG */ ++ ++#endif /* CCAN_STR_H */ +diff --git a/src/rc-compat/v37/ccan/str_debug.h b/src/rc-compat/v37/ccan/str_debug.h +new file mode 100644 +index 000000000000..7a3343816f7f +--- /dev/null ++++ b/src/rc-compat/v37/ccan/str_debug.h +@@ -0,0 +1,30 @@ ++/* CC0 (Public domain) - see LICENSE.CC0 file for details */ ++#ifndef CCAN_STR_DEBUG_H ++#define CCAN_STR_DEBUG_H ++ ++/* #define CCAN_STR_DEBUG 1 */ ++ ++#ifdef CCAN_STR_DEBUG ++/* Because we mug the real ones with macros, we need our own wrappers. */ ++int str_isalnum(int i); ++int str_isalpha(int i); ++int str_isascii(int i); ++#if HAVE_ISBLANK ++int str_isblank(int i); ++#endif ++int str_iscntrl(int i); ++int str_isdigit(int i); ++int str_isgraph(int i); ++int str_islower(int i); ++int str_isprint(int i); ++int str_ispunct(int i); ++int str_isspace(int i); ++int str_isupper(int i); ++int str_isxdigit(int i); ++ ++char *str_strstr(const char *haystack, const char *needle); ++char *str_strchr(const char *s, int c); ++char *str_strrchr(const char *s, int c); ++#endif /* CCAN_STR_DEBUG */ ++ ++#endif /* CCAN_STR_DEBUG_H */ +diff --git a/src/rc-compat/v37/cmd_ioctl.h b/src/rc-compat/v37/cmd_ioctl.h +new file mode 100644 +index 000000000000..d5889a16ecc3 +--- /dev/null ++++ b/src/rc-compat/v37/cmd_ioctl.h +@@ -0,0 +1,412 @@ ++/* ++ * Copyright (c) 2018 Mellanox Technologies, Ltd. All rights reserved. ++ * ++ * This software is available to you under a choice of one of two ++ * licenses. You may choose to be licensed under the terms of the GNU ++ * General Public License (GPL) Version 2, available from the file ++ * COPYING in the main directory of this source tree, or the ++ * OpenIB.org BSD license below: ++ * ++ * Redistribution and use in source and binary forms, with or ++ * without modification, are permitted provided that the following ++ * conditions are met: ++ * ++ * - Redistributions of source code must retain the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer. ++ * ++ * - Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials ++ * provided with the distribution. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS ++ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. ++ */ ++ ++#ifndef __INFINIBAND_VERBS_IOCTL_H ++#define __INFINIBAND_VERBS_IOCTL_H ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static inline uint64_t ioctl_ptr_to_u64(const void *ptr) ++{ ++ if (sizeof(ptr) == sizeof(uint64_t)) ++ return (uintptr_t)ptr; ++ ++ /* ++ * Some CPU architectures require sign extension when converting from ++ * a 32 bit to 64 bit pointer. This should match the kernel ++ * implementation of compat_ptr() for the architecture. ++ */ ++#if defined(__tilegx__) ++ return (int64_t)(intptr_t)ptr; ++#else ++ return (uintptr_t)ptr; ++#endif ++} ++ ++static inline void _scrub_ptr_attr(void **ptr) ++{ ++#if UINTPTR_MAX == UINT64_MAX ++ /* Do nothing */ ++#else ++ RDMA_UAPI_PTR(void *, data) *scrub_data; ++ ++ scrub_data = container_of(ptr, typeof(*scrub_data), data); ++ scrub_data->data_data_u64 = ioctl_ptr_to_u64(scrub_data->data); ++#endif ++} ++ ++#define scrub_ptr_attr(ptr) _scrub_ptr_attr((void **)(&ptr)) ++ ++/* ++ * The command buffer is organized as a linked list of blocks of attributes. ++ * Each stack frame allocates its block and then calls up toward to core code ++ * which will do the ioctl. The frame that does the ioctl calls the special ++ * FINAL variant which will allocate enough space to linearize the attribute ++ * buffer for the kernel. ++ * ++ * The current range of attributes to fill is next_attr -> last_attr. ++ */ ++struct ibv_command_buffer { ++ struct ibv_command_buffer *next; ++ struct ib_uverbs_attr *next_attr; ++ struct ib_uverbs_attr *last_attr; ++ /* ++ * Used by the legacy write interface to keep track of where the UHW ++ * buffer is located and the 'headroom' space that the common code ++ * uses to construct the command header and common command struct ++ * directly before the drivers' UHW. ++ */ ++ uint8_t uhw_in_idx; ++ uint8_t uhw_out_idx; ++ uint8_t uhw_in_headroom_dwords; ++ uint8_t uhw_out_headroom_dwords; ++ ++ uint8_t buffer_error:1; ++ /* ++ * These flags control what execute_ioctl_fallback does if the kernel ++ * does not support ioctl ++ */ ++ uint8_t fallback_require_ex:1; ++ uint8_t fallback_ioctl_only:1; ++ struct ib_uverbs_ioctl_hdr hdr; ++}; ++ ++enum {_UHW_NO_INDEX = 0xFF}; ++ ++/* ++ * Constructing an array of ibv_command_buffer is a reasonable way to expand ++ * the VLA in hdr.attrs on the stack and also allocate some internal state in ++ * a single contiguous stack memory region. It will over-allocate the region in ++ * some cases, but this approach allows the number of elements to be dynamic, ++ * and not fixed as a compile time constant. ++ */ ++#define _IOCTL_NUM_CMDB(_num_attrs) \ ++ ((sizeof(struct ibv_command_buffer) + \ ++ sizeof(struct ib_uverbs_attr) * (_num_attrs) + \ ++ sizeof(struct ibv_command_buffer) - 1) / \ ++ sizeof(struct ibv_command_buffer)) ++ ++unsigned int __ioctl_final_num_attrs(unsigned int num_attrs, ++ struct ibv_command_buffer *link); ++ ++/* If the user doesn't provide a link then don't create a VLA */ ++#define _ioctl_final_num_attrs(_num_attrs, _link) \ ++ ((__builtin_constant_p(!(_link)) && !(_link)) \ ++ ? (_num_attrs) \ ++ : __ioctl_final_num_attrs(_num_attrs, _link)) ++ ++#define _COMMAND_BUFFER_INIT(_hdr, _object_id, _method_id, _num_attrs, _link) \ ++ ((struct ibv_command_buffer){ \ ++ .hdr = \ ++ { \ ++ .object_id = (_object_id), \ ++ .method_id = (_method_id), \ ++ }, \ ++ .next = _link, \ ++ .uhw_in_idx = _UHW_NO_INDEX, \ ++ .uhw_out_idx = _UHW_NO_INDEX, \ ++ .next_attr = (_hdr).attrs, \ ++ .last_attr = (_hdr).attrs + _num_attrs}) ++ ++/* ++ * C99 does not permit an initializer for VLAs, so this function does the init ++ * instead. It is called in the wonky way so that DELCARE_COMMAND_BUFFER can ++ * still be a 'variable', and we so we don't require C11 mode. ++ */ ++static inline int _ioctl_init_cmdb(struct ibv_command_buffer *cmd, ++ uint16_t object_id, uint16_t method_id, ++ size_t num_attrs, ++ struct ibv_command_buffer *link) ++{ ++ *cmd = _COMMAND_BUFFER_INIT(cmd->hdr, object_id, method_id, num_attrs, ++ link); ++ return 0; ++} ++ ++/* ++ * Construct an IOCTL command buffer on the stack with enough space for ++ * _num_attrs elements. _num_attrs does not have to be a compile time constant. ++ * _link is a previous COMMAND_BUFFER in the call chain. ++ */ ++#ifndef __CHECKER__ ++#define DECLARE_COMMAND_BUFFER_LINK(_name, _object_id, _method_id, _num_attrs, \ ++ _link) \ ++ const unsigned int __##_name##total = \ ++ _ioctl_final_num_attrs(_num_attrs, _link); \ ++ struct ibv_command_buffer _name[_IOCTL_NUM_CMDB(__##_name##total)]; \ ++ int __attribute__((unused)) __##_name##dummy = _ioctl_init_cmdb( \ ++ _name, _object_id, _method_id, __##_name##total, _link) ++#else ++/* ++ * sparse enforces kernel rules which forbids VLAs. Make the VLA into a static ++ * array when running sparse. Don't actually run the sparse compile result. ++ */ ++#define DECLARE_COMMAND_BUFFER_LINK(_name, _object_id, _method_id, _num_attrs, \ ++ _link) \ ++ struct ibv_command_buffer _name[10]; \ ++ int __attribute__((unused)) __##_name##dummy = \ ++ _ioctl_init_cmdb(_name, _object_id, _method_id, 10, _link) ++#endif ++ ++#define DECLARE_COMMAND_BUFFER(_name, _object_id, _method_id, _num_attrs) \ ++ DECLARE_COMMAND_BUFFER_LINK(_name, _object_id, _method_id, _num_attrs, \ ++ NULL) ++ ++int execute_ioctl(struct ibv_context *context, struct ibv_command_buffer *cmd); ++ ++static inline struct ib_uverbs_attr * ++_ioctl_next_attr(struct ibv_command_buffer *cmd, uint16_t attr_id) ++{ ++ struct ib_uverbs_attr *attr; ++ ++ assert(cmd->next_attr < cmd->last_attr); ++ attr = cmd->next_attr++; ++ ++ *attr = (struct ib_uverbs_attr){ ++ .attr_id = attr_id, ++ /* ++ * All attributes default to mandatory. Wrapper the fill_* ++ * call in attr_optional() to make it optional. ++ */ ++ .flags = UVERBS_ATTR_F_MANDATORY, ++ }; ++ ++ return attr; ++} ++ ++/* ++ * This construction is insane, an expression with a side effect that returns ++ * from the calling function, but it is a non-invasive way to get the compiler ++ * to elide the IOCTL support in the backwards compat command functions ++ * without disturbing native ioctl support. ++ * ++ * A command function will set last_attr on the stack to NULL, and if it is ++ * coded properly, the compiler will prove that last_attr is never changed and ++ * elide the function. Unfortunately this penalizes native ioctl uses with the ++ * extra if overhead. ++ * ++ * For this reason, _ioctl_next_attr must never be called outside a fill ++ * function. ++ */ ++#if VERBS_WRITE_ONLY ++#define _ioctl_next_attr(cmd, attr_id) \ ++ ({ \ ++ if (!((cmd)->last_attr)) \ ++ return NULL; \ ++ _ioctl_next_attr(cmd, attr_id); \ ++ }) ++#endif ++ ++/* Make the attribute optional. */ ++static inline struct ib_uverbs_attr *attr_optional(struct ib_uverbs_attr *attr) ++{ ++ if (!attr) ++ return attr; ++ ++ attr->flags &= ~UVERBS_ATTR_F_MANDATORY; ++ return attr; ++} ++ ++/* Send attributes of kernel type UVERBS_ATTR_TYPE_IDR */ ++static inline struct ib_uverbs_attr * ++fill_attr_in_obj(struct ibv_command_buffer *cmd, uint16_t attr_id, uint32_t idr) ++{ ++ struct ib_uverbs_attr *attr = _ioctl_next_attr(cmd, attr_id); ++ ++ /* UVERBS_ATTR_TYPE_IDR uses a 64 bit value for the idr # */ ++ attr->data = idr; ++ return attr; ++} ++ ++static inline struct ib_uverbs_attr * ++fill_attr_out_obj(struct ibv_command_buffer *cmd, uint16_t attr_id) ++{ ++ return fill_attr_in_obj(cmd, attr_id, 0); ++} ++ ++static inline uint32_t read_attr_obj(uint16_t attr_id, ++ struct ib_uverbs_attr *attr) ++{ ++ assert(attr->attr_id == attr_id); ++ return attr->data; ++} ++ ++/* Send attributes of kernel type UVERBS_ATTR_TYPE_PTR_IN */ ++static inline struct ib_uverbs_attr * ++fill_attr_in(struct ibv_command_buffer *cmd, uint16_t attr_id, const void *data, ++ size_t len) ++{ ++ struct ib_uverbs_attr *attr = _ioctl_next_attr(cmd, attr_id); ++ ++ if (unlikely(len > UINT16_MAX)) ++ cmd->buffer_error = 1; ++ ++ attr->len = len; ++ if (len <= sizeof(uint64_t)) ++ memcpy(&attr->data, data, len); ++ else ++ attr->data = ioctl_ptr_to_u64(data); ++ ++ return attr; ++} ++ ++#define fill_attr_in_ptr(cmd, attr_id, ptr) \ ++ fill_attr_in(cmd, attr_id, ptr, sizeof(*ptr)) ++ ++/* Send attributes of various inline kernel types */ ++ ++static inline struct ib_uverbs_attr * ++fill_attr_in_uint64(struct ibv_command_buffer *cmd, uint16_t attr_id, ++ uint64_t data) ++{ ++ struct ib_uverbs_attr *attr = _ioctl_next_attr(cmd, attr_id); ++ ++ attr->len = sizeof(data); ++ attr->data = data; ++ ++ return attr; ++} ++ ++#define fill_attr_const_in(cmd, attr_id, _data) \ ++ fill_attr_in_uint64(cmd, attr_id, _data) ++ ++static inline struct ib_uverbs_attr * ++fill_attr_in_uint32(struct ibv_command_buffer *cmd, uint16_t attr_id, ++ uint32_t data) ++{ ++ struct ib_uverbs_attr *attr = _ioctl_next_attr(cmd, attr_id); ++ ++ attr->len = sizeof(data); ++ memcpy(&attr->data, &data, sizeof(data)); ++ ++ return attr; ++} ++ ++static inline struct ib_uverbs_attr * ++fill_attr_in_fd(struct ibv_command_buffer *cmd, uint16_t attr_id, int fd) ++{ ++ struct ib_uverbs_attr *attr; ++ ++ if (fd == -1) ++ return NULL; ++ ++ attr = _ioctl_next_attr(cmd, attr_id); ++ /* UVERBS_ATTR_TYPE_FD uses a 64 bit value for the idr # */ ++ attr->data = fd; ++ return attr; ++} ++ ++static inline struct ib_uverbs_attr * ++fill_attr_out_fd(struct ibv_command_buffer *cmd, uint16_t attr_id, int fd) ++{ ++ struct ib_uverbs_attr *attr = _ioctl_next_attr(cmd, attr_id); ++ ++ attr->data = 0; ++ return attr; ++} ++ ++static inline int read_attr_fd(uint16_t attr_id, struct ib_uverbs_attr *attr) ++{ ++ assert(attr->attr_id == attr_id); ++ /* The kernel cannot fail to create a FD here, it never returns -1 */ ++ return attr->data; ++} ++ ++/* Send attributes of kernel type UVERBS_ATTR_TYPE_PTR_OUT */ ++static inline struct ib_uverbs_attr * ++fill_attr_out(struct ibv_command_buffer *cmd, uint16_t attr_id, void *data, ++ size_t len) ++{ ++ struct ib_uverbs_attr *attr = _ioctl_next_attr(cmd, attr_id); ++ ++ if (unlikely(len > UINT16_MAX)) ++ cmd->buffer_error = 1; ++ ++ attr->len = len; ++ attr->data = ioctl_ptr_to_u64(data); ++ ++ return attr; ++} ++ ++#define fill_attr_out_ptr(cmd, attr_id, ptr) \ ++ fill_attr_out(cmd, attr_id, ptr, sizeof(*(ptr))) ++ ++/* If size*nelems overflows size_t this returns SIZE_MAX */ ++static inline size_t _array_len(size_t size, size_t nelems) ++{ ++ if (size != 0 && ++ SIZE_MAX / size <= nelems) ++ return SIZE_MAX; ++ return size * nelems; ++} ++ ++#define fill_attr_out_ptr_array(cmd, attr_id, ptr, nelems) \ ++ fill_attr_out(cmd, attr_id, ptr, _array_len(sizeof(*ptr), nelems)) ++ ++#define fill_attr_in_ptr_array(cmd, attr_id, ptr, nelems) \ ++ fill_attr_in(cmd, attr_id, ptr, _array_len(sizeof(*ptr), nelems)) ++ ++static inline size_t __check_divide(size_t val, unsigned int div) ++{ ++ assert(val % div == 0); ++ return val / div; ++} ++ ++static inline struct ib_uverbs_attr * ++fill_attr_in_enum(struct ibv_command_buffer *cmd, uint16_t attr_id, ++ uint8_t elem_id, const void *data, size_t len) ++{ ++ struct ib_uverbs_attr *attr; ++ ++ attr = fill_attr_in(cmd, attr_id, data, len); ++ attr->attr_data.enum_data.elem_id = elem_id; ++ ++ return attr; ++} ++ ++/* Send attributes of kernel type UVERBS_ATTR_TYPE_IDRS_ARRAY */ ++static inline struct ib_uverbs_attr * ++fill_attr_in_objs_arr(struct ibv_command_buffer *cmd, uint16_t attr_id, ++ const uint32_t *idrs_arr, size_t nelems) ++{ ++ return fill_attr_in(cmd, attr_id, idrs_arr, ++ _array_len(sizeof(*idrs_arr), nelems)); ++} ++ ++#endif +diff --git a/src/rc-compat/v37/config.h b/src/rc-compat/v37/config.h +new file mode 100644 +index 000000000000..4a63336a8a0d +--- /dev/null ++++ b/src/rc-compat/v37/config.h +@@ -0,0 +1,56 @@ ++#ifndef CONFIG_H_IN ++#define CONFIG_H_IN ++ ++#define HAVE_STATEMENT_EXPR 1 ++#define HAVE_BUILTIN_TYPES_COMPATIBLE_P 1 ++#define HAVE_TYPEOF 1 ++#define HAVE_ISBLANK 1 ++#define HAVE_BUILTIN_CLZ 1 ++#define HAVE_BUILTIN_CLZL 1 ++ ++//#define PACKAGE_VERSION "37.3" ++ ++// FIXME: Remove this, The cmake version hard-requires new style CLOEXEC support ++#define STREAM_CLOEXEC "e" ++ ++#define RDMA_CDEV_DIR "/dev/infiniband" ++ ++#define VERBS_PROVIDER_SUFFIX "-rdmav34.so" ++#define IBVERBS_PABI_VERSION 34 ++ ++// FIXME This has been supported in compilers forever, we should just fail to build on such old systems. ++#define HAVE_FUNC_ATTRIBUTE_ALWAYS_INLINE 1 ++ ++#define HAVE_FUNC_ATTRIBUTE_IFUNC 1 ++ ++/* #undef HAVE_FUNC_ATTRIBUTE_SYMVER */ ++ ++#define HAVE_WORKING_IF_H 1 ++ ++// Operating mode for symbol versions ++#define HAVE_FULL_SYMBOL_VERSIONS 1 ++/* #undef HAVE_LIMITED_SYMBOL_VERSIONS */ ++ ++#define SIZEOF_LONG 8 ++ ++#if 3 == 1 ++# define VERBS_IOCTL_ONLY 1 ++# define VERBS_WRITE_ONLY 0 ++#elif 3 == 2 ++# define VERBS_IOCTL_ONLY 0 ++# define VERBS_WRITE_ONLY 1 ++#elif 3 == 3 ++# define VERBS_IOCTL_ONLY 0 ++# define VERBS_WRITE_ONLY 0 ++#endif ++ ++// Configuration defaults ++ ++#define IBACM_SERVER_MODE_UNIX 0 ++#define IBACM_SERVER_MODE_LOOP 1 ++#define IBACM_SERVER_MODE_OPEN 2 ++#define IBACM_SERVER_MODE_DEFAULT IBACM_SERVER_MODE_UNIX ++ ++#define IBACM_ACME_PLUS_KERNEL_ONLY_DEFAULT 0 ++ ++#endif +diff --git a/src/rc-compat/v37/driver.h b/src/rc-compat/v37/driver.h +new file mode 100644 +index 000000000000..46406cc433f6 +--- /dev/null ++++ b/src/rc-compat/v37/driver.h +@@ -0,0 +1,755 @@ ++/* ++ * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. ++ * Copyright (c) 2005, 2006 Cisco Systems, Inc. All rights reserved. ++ * Copyright (c) 2005 PathScale, Inc. All rights reserved. ++ * Copyright (c) 2020 Intel Corporation. All rights reserved. ++ * ++ * This software is available to you under a choice of one of two ++ * licenses. You may choose to be licensed under the terms of the GNU ++ * General Public License (GPL) Version 2, available from the file ++ * COPYING in the main directory of this source tree, or the ++ * OpenIB.org BSD license below: ++ * ++ * Redistribution and use in source and binary forms, with or ++ * without modification, are permitted provided that the following ++ * conditions are met: ++ * ++ * - Redistributions of source code must retain the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer. ++ * ++ * - Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials ++ * provided with the distribution. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS ++ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. ++ */ ++ ++#ifndef INFINIBAND_DRIVER_H ++#define INFINIBAND_DRIVER_H ++ ++#include ++#include ++#include "kern-abi.h" ++#include "cmd_ioctl.h" ++#include ++#include "config.h" ++#include ++#include ++#include "cmd_ioctl.h" ++#include ++ ++/* NOTE: Start of StarlingX addition */ ++#define IBV_DEVICE_LIBRARY_EXTENSION rdmav34 ++/* NOTE: End of StarlingX addition */ ++ ++struct verbs_device; ++ ++enum { ++ VERBS_LOG_LEVEL_NONE, ++ VERBS_LOG_ERR, ++ VERBS_LOG_WARN, ++ VERBS_LOG_INFO, ++ VERBS_LOG_DEBUG, ++}; ++ ++void __verbs_log(struct verbs_context *ctx, uint32_t level, ++ const char *fmt, ...); ++ ++#define verbs_log(ctx, level, format, arg...) \ ++do { \ ++ int tmp = errno; \ ++ __verbs_log(ctx, level, "%s: %s:%d: " format, \ ++ (ctx)->context.device->name, __func__, __LINE__, ##arg); \ ++ errno = tmp; \ ++} while (0) ++ ++#define verbs_debug(ctx, format, arg...) \ ++ verbs_log(ctx, VERBS_LOG_DEBUG, format, ##arg) ++ ++#define verbs_info(ctx, format, arg...) \ ++ verbs_log(ctx, VERBS_LOG_INFO, format, ##arg) ++ ++#define verbs_warn(ctx, format, arg...) \ ++ verbs_log(ctx, VERBS_LOG_WARN, format, ##arg) ++ ++#define verbs_err(ctx, format, arg...) \ ++ verbs_log(ctx, VERBS_LOG_ERR, format, ##arg) ++ ++#ifdef VERBS_DEBUG ++#define verbs_log_datapath(ctx, level, format, arg...) \ ++ verbs_log(ctx, level, format, ##arg) ++#else ++#define verbs_log_datapath(ctx, level, format, arg...) {} ++#endif ++ ++#define verbs_debug_datapath(ctx, format, arg...) \ ++ verbs_log_datapath(ctx, VERBS_LOG_DEBUG, format, ##arg) ++ ++#define verbs_info_datapath(ctx, format, arg...) \ ++ verbs_log_datapath(ctx, VERBS_LOG_INFO, format, ##arg) ++ ++#define verbs_warn_datapath(ctx, format, arg...) \ ++ verbs_log_datapath(ctx, VERBS_LOG_WARN, format, ##arg) ++ ++#define verbs_err_datapath(ctx, format, arg...) \ ++ verbs_log_datapath(ctx, VERBS_LOG_ERR, format, ##arg) ++ ++enum verbs_xrcd_mask { ++ VERBS_XRCD_HANDLE = 1 << 0, ++ VERBS_XRCD_RESERVED = 1 << 1 ++}; ++ ++enum create_cq_cmd_flags { ++ CREATE_CQ_CMD_FLAGS_TS_IGNORED_EX = 1 << 0, ++}; ++ ++struct verbs_xrcd { ++ struct ibv_xrcd xrcd; ++ uint32_t comp_mask; ++ uint32_t handle; ++}; ++ ++struct verbs_srq { ++ struct ibv_srq srq; ++ enum ibv_srq_type srq_type; ++ struct verbs_xrcd *xrcd; ++ struct ibv_cq *cq; ++ uint32_t srq_num; ++}; ++ ++enum verbs_qp_mask { ++ VERBS_QP_XRCD = 1 << 0, ++ VERBS_QP_EX = 1 << 1, ++}; ++ ++enum ibv_gid_type_sysfs { ++ IBV_GID_TYPE_SYSFS_IB_ROCE_V1, ++ IBV_GID_TYPE_SYSFS_ROCE_V2, ++}; ++ ++enum verbs_query_gid_attr_mask { ++ VERBS_QUERY_GID_ATTR_GID = 1 << 0, ++ VERBS_QUERY_GID_ATTR_TYPE = 1 << 1, ++ VERBS_QUERY_GID_ATTR_NDEV_IFINDEX = 1 << 2, ++}; ++ ++enum ibv_mr_type { ++ IBV_MR_TYPE_MR, ++ IBV_MR_TYPE_NULL_MR, ++ IBV_MR_TYPE_IMPORTED_MR, ++ IBV_MR_TYPE_DMABUF_MR, ++}; ++ ++struct verbs_mr { ++ struct ibv_mr ibv_mr; ++ enum ibv_mr_type mr_type; ++ int access; ++}; ++ ++static inline struct verbs_mr *verbs_get_mr(struct ibv_mr *mr) ++{ ++ return container_of(mr, struct verbs_mr, ibv_mr); ++} ++ ++struct verbs_qp { ++ union { ++ struct ibv_qp qp; ++ struct ibv_qp_ex qp_ex; ++ }; ++ uint32_t comp_mask; ++ struct verbs_xrcd *xrcd; ++}; ++static_assert(offsetof(struct ibv_qp_ex, qp_base) == 0, "Invalid qp layout"); ++ ++struct verbs_cq { ++ union { ++ struct ibv_cq cq; ++ struct ibv_cq_ex cq_ex; ++ }; ++}; ++ ++enum ibv_flow_action_type { ++ IBV_FLOW_ACTION_UNSPECIFIED, ++ IBV_FLOW_ACTION_ESP = 1, ++}; ++ ++struct verbs_flow_action { ++ struct ibv_flow_action action; ++ uint32_t handle; ++ enum ibv_flow_action_type type; ++}; ++ ++struct verbs_dm { ++ struct ibv_dm dm; ++ uint32_t handle; ++}; ++ ++enum { ++ VERBS_MATCH_SENTINEL = 0, ++ VERBS_MATCH_PCI = 1, ++ VERBS_MATCH_MODALIAS = 2, ++ VERBS_MATCH_DRIVER_ID = 3, ++}; ++ ++struct verbs_match_ent { ++ void *driver_data; ++ union { ++ const char *modalias; ++ uint64_t driver_id; ++ } u; ++ uint16_t vendor; ++ uint16_t device; ++ uint8_t kind; ++}; ++#define VERBS_DRIVER_ID(_id) \ ++ { \ ++ .u.driver_id = (_id), .kind = VERBS_MATCH_DRIVER_ID, \ ++ } ++/* Note: New drivers should only use VERBS_DRIVER_ID, the below are for legacy ++ * drivers ++ */ ++#define VERBS_PCI_MATCH(_vendor, _device, _data) \ ++ { \ ++ .driver_data = (void *)(_data), \ ++ .vendor = (_vendor), \ ++ .device = (_device), \ ++ .kind = VERBS_MATCH_PCI, \ ++ } ++ ++#define VERBS_MODALIAS_MATCH(_mod_str, _data) \ ++ { \ ++ .driver_data = (void *)(_data), \ ++ .u.modalias = (_mod_str), \ ++ .kind = VERBS_MATCH_MODALIAS, \ ++ } ++ ++/* Matching on the IB device name is STRONGLY discouraged. This will only ++ * match if there is no device/modalias file available, and it will eventually ++ * be disabled entirely if the kernel supports renaming. Use is strongly ++ * discouraged. ++ */ ++#define VERBS_NAME_MATCH(_name_prefix, _data) \ ++ { \ ++ .driver_data = (_data), \ ++ .u.modalias = "rdma_device:*N" _name_prefix "*", \ ++ .kind = VERBS_MATCH_MODALIAS, \ ++ } ++ ++enum { ++ VSYSFS_READ_MODALIAS = 1 << 0, ++ VSYSFS_READ_NODE_GUID = 1 << 1, ++}; ++ ++/* An rdma device detected in sysfs */ ++struct verbs_sysfs_dev { ++ struct list_node entry; ++ void *provider_data; ++ const struct verbs_match_ent *match; ++ unsigned int flags; ++ char sysfs_name[IBV_SYSFS_NAME_MAX]; ++ dev_t sysfs_cdev; ++ char ibdev_name[IBV_SYSFS_NAME_MAX]; ++ char ibdev_path[IBV_SYSFS_PATH_MAX]; ++ char modalias[512]; ++ uint64_t node_guid; ++ uint32_t driver_id; ++ enum ibv_node_type node_type; ++ int ibdev_idx; ++ uint32_t num_ports; ++ uint32_t abi_ver; ++ struct timespec time_created; ++}; ++ ++/* Must change the PRIVATE IBVERBS_PRIVATE_ symbol if this is changed */ ++struct verbs_device_ops { ++ const char *name; ++ ++ uint32_t match_min_abi_version; ++ uint32_t match_max_abi_version; ++ const struct verbs_match_ent *match_table; ++ const struct verbs_device_ops **static_providers; ++ ++ bool (*match_device)(struct verbs_sysfs_dev *sysfs_dev); ++ ++ struct verbs_context *(*alloc_context)(struct ibv_device *device, ++ int cmd_fd, ++ void *private_data); ++ struct verbs_context *(*import_context)(struct ibv_device *device, ++ int cmd_fd); ++ ++ struct verbs_device *(*alloc_device)(struct verbs_sysfs_dev *sysfs_dev); ++ void (*uninit_device)(struct verbs_device *device); ++}; ++ ++/* Must change the PRIVATE IBVERBS_PRIVATE_ symbol if this is changed */ ++struct verbs_device { ++ struct ibv_device device; /* Must be first */ ++ const struct verbs_device_ops *ops; ++ atomic_int refcount; ++ struct list_node entry; ++ struct verbs_sysfs_dev *sysfs; ++ uint64_t core_support; ++}; ++ ++struct verbs_counters { ++ struct ibv_counters counters; ++ uint32_t handle; ++}; ++ ++/* ++ * Must change the PRIVATE IBVERBS_PRIVATE_ symbol if this is changed. This is ++ * the union of every op the driver can support. If new elements are added to ++ * this structure then verbs_dummy_ops must also be updated. ++ * ++ * Keep sorted. ++ */ ++struct verbs_context_ops { ++ int (*advise_mr)(struct ibv_pd *pd, ++ enum ibv_advise_mr_advice advice, ++ uint32_t flags, ++ struct ibv_sge *sg_list, ++ uint32_t num_sges); ++ struct ibv_dm *(*alloc_dm)(struct ibv_context *context, ++ struct ibv_alloc_dm_attr *attr); ++ struct ibv_mw *(*alloc_mw)(struct ibv_pd *pd, enum ibv_mw_type type); ++ struct ibv_mr *(*alloc_null_mr)(struct ibv_pd *pd); ++ struct ibv_pd *(*alloc_parent_domain)( ++ struct ibv_context *context, ++ struct ibv_parent_domain_init_attr *attr); ++ struct ibv_pd *(*alloc_pd)(struct ibv_context *context); ++ struct ibv_td *(*alloc_td)(struct ibv_context *context, ++ struct ibv_td_init_attr *init_attr); ++ void (*async_event)(struct ibv_context *context, struct ibv_async_event *event); ++ int (*attach_counters_point_flow)(struct ibv_counters *counters, ++ struct ibv_counter_attach_attr *attr, ++ struct ibv_flow *flow); ++ int (*attach_mcast)(struct ibv_qp *qp, const union ibv_gid *gid, ++ uint16_t lid); ++ int (*bind_mw)(struct ibv_qp *qp, struct ibv_mw *mw, ++ struct ibv_mw_bind *mw_bind); ++ int (*close_xrcd)(struct ibv_xrcd *xrcd); ++ void (*cq_event)(struct ibv_cq *cq); ++ struct ibv_ah *(*create_ah)(struct ibv_pd *pd, ++ struct ibv_ah_attr *attr); ++ struct ibv_counters *(*create_counters)(struct ibv_context *context, ++ struct ibv_counters_init_attr *init_attr); ++ struct ibv_cq *(*create_cq)(struct ibv_context *context, int cqe, ++ struct ibv_comp_channel *channel, ++ int comp_vector); ++ struct ibv_cq_ex *(*create_cq_ex)( ++ struct ibv_context *context, ++ struct ibv_cq_init_attr_ex *init_attr); ++ struct ibv_flow *(*create_flow)(struct ibv_qp *qp, ++ struct ibv_flow_attr *flow_attr); ++ struct ibv_flow_action *(*create_flow_action_esp)(struct ibv_context *context, ++ struct ibv_flow_action_esp_attr *attr); ++ struct ibv_qp *(*create_qp)(struct ibv_pd *pd, ++ struct ibv_qp_init_attr *attr); ++ struct ibv_qp *(*create_qp_ex)( ++ struct ibv_context *context, ++ struct ibv_qp_init_attr_ex *qp_init_attr_ex); ++ struct ibv_rwq_ind_table *(*create_rwq_ind_table)( ++ struct ibv_context *context, ++ struct ibv_rwq_ind_table_init_attr *init_attr); ++ struct ibv_srq *(*create_srq)(struct ibv_pd *pd, ++ struct ibv_srq_init_attr *srq_init_attr); ++ struct ibv_srq *(*create_srq_ex)( ++ struct ibv_context *context, ++ struct ibv_srq_init_attr_ex *srq_init_attr_ex); ++ struct ibv_wq *(*create_wq)(struct ibv_context *context, ++ struct ibv_wq_init_attr *wq_init_attr); ++ int (*dealloc_mw)(struct ibv_mw *mw); ++ int (*dealloc_pd)(struct ibv_pd *pd); ++ int (*dealloc_td)(struct ibv_td *td); ++ int (*dereg_mr)(struct verbs_mr *vmr); ++ int (*destroy_ah)(struct ibv_ah *ah); ++ int (*destroy_counters)(struct ibv_counters *counters); ++ int (*destroy_cq)(struct ibv_cq *cq); ++ int (*destroy_flow)(struct ibv_flow *flow); ++ int (*destroy_flow_action)(struct ibv_flow_action *action); ++ int (*destroy_qp)(struct ibv_qp *qp); ++ int (*destroy_rwq_ind_table)(struct ibv_rwq_ind_table *rwq_ind_table); ++ int (*destroy_srq)(struct ibv_srq *srq); ++ int (*destroy_wq)(struct ibv_wq *wq); ++ int (*detach_mcast)(struct ibv_qp *qp, const union ibv_gid *gid, ++ uint16_t lid); ++ void (*free_context)(struct ibv_context *context); ++ int (*free_dm)(struct ibv_dm *dm); ++ int (*get_srq_num)(struct ibv_srq *srq, uint32_t *srq_num); ++ struct ibv_dm *(*import_dm)(struct ibv_context *context, ++ uint32_t dm_handle); ++ struct ibv_mr *(*import_mr)(struct ibv_pd *pd, ++ uint32_t mr_handle); ++ struct ibv_pd *(*import_pd)(struct ibv_context *context, ++ uint32_t pd_handle); ++ int (*modify_cq)(struct ibv_cq *cq, struct ibv_modify_cq_attr *attr); ++ int (*modify_flow_action_esp)(struct ibv_flow_action *action, ++ struct ibv_flow_action_esp_attr *attr); ++ int (*modify_qp)(struct ibv_qp *qp, struct ibv_qp_attr *attr, ++ int attr_mask); ++ int (*modify_qp_rate_limit)(struct ibv_qp *qp, ++ struct ibv_qp_rate_limit_attr *attr); ++ int (*modify_srq)(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr, ++ int srq_attr_mask); ++ int (*modify_wq)(struct ibv_wq *wq, struct ibv_wq_attr *wq_attr); ++ struct ibv_qp *(*open_qp)(struct ibv_context *context, ++ struct ibv_qp_open_attr *attr); ++ struct ibv_xrcd *(*open_xrcd)( ++ struct ibv_context *context, ++ struct ibv_xrcd_init_attr *xrcd_init_attr); ++ int (*poll_cq)(struct ibv_cq *cq, int num_entries, struct ibv_wc *wc); ++ int (*post_recv)(struct ibv_qp *qp, struct ibv_recv_wr *wr, ++ struct ibv_recv_wr **bad_wr); ++ int (*post_send)(struct ibv_qp *qp, struct ibv_send_wr *wr, ++ struct ibv_send_wr **bad_wr); ++ int (*post_srq_ops)(struct ibv_srq *srq, struct ibv_ops_wr *op, ++ struct ibv_ops_wr **bad_op); ++ int (*post_srq_recv)(struct ibv_srq *srq, struct ibv_recv_wr *recv_wr, ++ struct ibv_recv_wr **bad_recv_wr); ++ int (*query_device_ex)(struct ibv_context *context, ++ const struct ibv_query_device_ex_input *input, ++ struct ibv_device_attr_ex *attr, ++ size_t attr_size); ++ int (*query_ece)(struct ibv_qp *qp, struct ibv_ece *ece); ++ int (*query_port)(struct ibv_context *context, uint8_t port_num, ++ struct ibv_port_attr *port_attr); ++ int (*query_qp)(struct ibv_qp *qp, struct ibv_qp_attr *attr, ++ int attr_mask, struct ibv_qp_init_attr *init_attr); ++ int (*query_qp_data_in_order)(struct ibv_qp *qp, enum ibv_wr_opcode op, ++ uint32_t flags); ++ int (*query_rt_values)(struct ibv_context *context, ++ struct ibv_values_ex *values); ++ int (*query_srq)(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr); ++ int (*read_counters)(struct ibv_counters *counters, ++ uint64_t *counters_value, ++ uint32_t ncounters, ++ uint32_t flags); ++ struct ibv_mr *(*reg_dm_mr)(struct ibv_pd *pd, struct ibv_dm *dm, ++ uint64_t dm_offset, size_t length, ++ unsigned int access); ++ struct ibv_mr *(*reg_dmabuf_mr)(struct ibv_pd *pd, uint64_t offset, ++ size_t length, uint64_t iova, ++ int fd, int access); ++ struct ibv_mr *(*reg_mr)(struct ibv_pd *pd, void *addr, size_t length, ++ uint64_t hca_va, int access); ++ int (*req_notify_cq)(struct ibv_cq *cq, int solicited_only); ++ int (*rereg_mr)(struct verbs_mr *vmr, int flags, struct ibv_pd *pd, ++ void *addr, size_t length, int access); ++ int (*resize_cq)(struct ibv_cq *cq, int cqe); ++ int (*set_ece)(struct ibv_qp *qp, struct ibv_ece *ece); ++ void (*unimport_dm)(struct ibv_dm *dm); ++ void (*unimport_mr)(struct ibv_mr *mr); ++ void (*unimport_pd)(struct ibv_pd *pd); ++}; ++ ++static inline struct verbs_device * ++verbs_get_device(const struct ibv_device *dev) ++{ ++ return container_of(dev, struct verbs_device, device); ++} ++ ++typedef struct verbs_device *(*verbs_driver_init_func)(const char *uverbs_sys_path, ++ int abi_version); ++ ++/* Wire the IBVERBS_PRIVATE version number into the verbs_register_driver ++ * symbol name. This guarentees we link to the correct set of symbols even if ++ * statically linking or using a dynmic linker with symbol versioning turned ++ * off. ++ */ ++#define ___make_verbs_register_driver(x) verbs_register_driver_ ## x ++#define __make_verbs_register_driver(x) ___make_verbs_register_driver(x) ++#define verbs_register_driver __make_verbs_register_driver(IBVERBS_PABI_VERSION) ++ ++void verbs_register_driver(const struct verbs_device_ops *ops); ++ ++/* ++ * Macro for providers to use to supply verbs_device_ops to the core code. ++ * This creates a global symbol for the provider structure to be used by the ++ * ibv_static_providers() machinery, and a global constructor for the dlopen ++ * machinery. ++ */ ++#define PROVIDER_DRIVER(provider_name, drv_struct) \ ++ extern const struct verbs_device_ops verbs_provider_##provider_name \ ++ __attribute__((alias(stringify(drv_struct)))); \ ++ static __attribute__((constructor)) void drv##__register_driver(void) \ ++ { \ ++ verbs_register_driver(&drv_struct); \ ++ } ++ ++void *_verbs_init_and_alloc_context(struct ibv_device *device, int cmd_fd, ++ size_t alloc_size, ++ struct verbs_context *context_offset, ++ uint32_t driver_id); ++ ++#define verbs_init_and_alloc_context(ibdev, cmd_fd, drv_ctx_ptr, ctx_memb, \ ++ driver_id) \ ++ ((typeof(drv_ctx_ptr))_verbs_init_and_alloc_context( \ ++ ibdev, cmd_fd, sizeof(*drv_ctx_ptr), \ ++ &((typeof(drv_ctx_ptr))NULL)->ctx_memb, (driver_id))) ++ ++int verbs_init_context(struct verbs_context *context_ex, ++ struct ibv_device *device, int cmd_fd, ++ uint32_t driver_id); ++void verbs_uninit_context(struct verbs_context *context); ++void verbs_set_ops(struct verbs_context *vctx, ++ const struct verbs_context_ops *ops); ++ ++void verbs_init_cq(struct ibv_cq *cq, struct ibv_context *context, ++ struct ibv_comp_channel *channel, ++ void *cq_context); ++ ++struct ibv_context *verbs_open_device(struct ibv_device *device, ++ void *private_data); ++int ibv_cmd_get_context(struct verbs_context *context, ++ struct ibv_get_context *cmd, size_t cmd_size, ++ struct ib_uverbs_get_context_resp *resp, size_t resp_size); ++int ibv_cmd_query_context(struct ibv_context *ctx, ++ struct ibv_command_buffer *driver); ++int ibv_cmd_create_flow_action_esp(struct ibv_context *ctx, ++ struct ibv_flow_action_esp_attr *attr, ++ struct verbs_flow_action *flow_action, ++ struct ibv_command_buffer *driver); ++int ibv_cmd_modify_flow_action_esp(struct verbs_flow_action *flow_action, ++ struct ibv_flow_action_esp_attr *attr, ++ struct ibv_command_buffer *driver); ++int ibv_cmd_query_device_any(struct ibv_context *context, ++ const struct ibv_query_device_ex_input *input, ++ struct ibv_device_attr_ex *attr, size_t attr_size, ++ struct ib_uverbs_ex_query_device_resp *resp, ++ size_t *resp_size); ++int ibv_cmd_query_port(struct ibv_context *context, uint8_t port_num, ++ struct ibv_port_attr *port_attr, ++ struct ibv_query_port *cmd, size_t cmd_size); ++int ibv_cmd_alloc_async_fd(struct ibv_context *context); ++int ibv_cmd_alloc_pd(struct ibv_context *context, struct ibv_pd *pd, ++ struct ibv_alloc_pd *cmd, size_t cmd_size, ++ struct ib_uverbs_alloc_pd_resp *resp, size_t resp_size); ++int ibv_cmd_dealloc_pd(struct ibv_pd *pd); ++int ibv_cmd_open_xrcd(struct ibv_context *context, struct verbs_xrcd *xrcd, ++ int vxrcd_size, ++ struct ibv_xrcd_init_attr *attr, ++ struct ibv_open_xrcd *cmd, size_t cmd_size, ++ struct ib_uverbs_open_xrcd_resp *resp, size_t resp_size); ++int ibv_cmd_close_xrcd(struct verbs_xrcd *xrcd); ++int ibv_cmd_reg_mr(struct ibv_pd *pd, void *addr, size_t length, ++ uint64_t hca_va, int access, ++ struct verbs_mr *vmr, struct ibv_reg_mr *cmd, ++ size_t cmd_size, ++ struct ib_uverbs_reg_mr_resp *resp, size_t resp_size); ++int ibv_cmd_rereg_mr(struct verbs_mr *vmr, uint32_t flags, void *addr, ++ size_t length, uint64_t hca_va, int access, ++ struct ibv_pd *pd, struct ibv_rereg_mr *cmd, ++ size_t cmd_sz, struct ib_uverbs_rereg_mr_resp *resp, ++ size_t resp_sz); ++int ibv_cmd_dereg_mr(struct verbs_mr *vmr); ++int ibv_cmd_query_mr(struct ibv_pd *pd, struct verbs_mr *vmr, ++ uint32_t mr_handle); ++int ibv_cmd_advise_mr(struct ibv_pd *pd, ++ enum ibv_advise_mr_advice advice, ++ uint32_t flags, ++ struct ibv_sge *sg_list, ++ uint32_t num_sge); ++int ibv_cmd_reg_dmabuf_mr(struct ibv_pd *pd, uint64_t offset, size_t length, ++ uint64_t iova, int fd, int access, ++ struct verbs_mr *vmr); ++int ibv_cmd_alloc_mw(struct ibv_pd *pd, enum ibv_mw_type type, ++ struct ibv_mw *mw, struct ibv_alloc_mw *cmd, ++ size_t cmd_size, ++ struct ib_uverbs_alloc_mw_resp *resp, size_t resp_size); ++int ibv_cmd_dealloc_mw(struct ibv_mw *mw); ++int ibv_cmd_create_cq(struct ibv_context *context, int cqe, ++ struct ibv_comp_channel *channel, ++ int comp_vector, struct ibv_cq *cq, ++ struct ibv_create_cq *cmd, size_t cmd_size, ++ struct ib_uverbs_create_cq_resp *resp, size_t resp_size); ++int ibv_cmd_create_cq_ex(struct ibv_context *context, ++ const struct ibv_cq_init_attr_ex *cq_attr, ++ struct verbs_cq *cq, ++ struct ibv_create_cq_ex *cmd, ++ size_t cmd_size, ++ struct ib_uverbs_ex_create_cq_resp *resp, ++ size_t resp_size, ++ uint32_t cmd_flags); ++int ibv_cmd_poll_cq(struct ibv_cq *cq, int ne, struct ibv_wc *wc); ++int ibv_cmd_req_notify_cq(struct ibv_cq *cq, int solicited_only); ++int ibv_cmd_resize_cq(struct ibv_cq *cq, int cqe, ++ struct ibv_resize_cq *cmd, size_t cmd_size, ++ struct ib_uverbs_resize_cq_resp *resp, size_t resp_size); ++int ibv_cmd_destroy_cq(struct ibv_cq *cq); ++int ibv_cmd_modify_cq(struct ibv_cq *cq, ++ struct ibv_modify_cq_attr *attr, ++ struct ibv_modify_cq *cmd, ++ size_t cmd_size); ++ ++int ibv_cmd_create_srq(struct ibv_pd *pd, ++ struct ibv_srq *srq, struct ibv_srq_init_attr *attr, ++ struct ibv_create_srq *cmd, size_t cmd_size, ++ struct ib_uverbs_create_srq_resp *resp, size_t resp_size); ++int ibv_cmd_create_srq_ex(struct ibv_context *context, ++ struct verbs_srq *srq, ++ struct ibv_srq_init_attr_ex *attr_ex, ++ struct ibv_create_xsrq *cmd, size_t cmd_size, ++ struct ib_uverbs_create_srq_resp *resp, size_t resp_size); ++int ibv_cmd_modify_srq(struct ibv_srq *srq, ++ struct ibv_srq_attr *srq_attr, ++ int srq_attr_mask, ++ struct ibv_modify_srq *cmd, size_t cmd_size); ++int ibv_cmd_query_srq(struct ibv_srq *srq, ++ struct ibv_srq_attr *srq_attr, ++ struct ibv_query_srq *cmd, size_t cmd_size); ++int ibv_cmd_destroy_srq(struct ibv_srq *srq); ++ ++int ibv_cmd_create_qp(struct ibv_pd *pd, ++ struct ibv_qp *qp, struct ibv_qp_init_attr *attr, ++ struct ibv_create_qp *cmd, size_t cmd_size, ++ struct ib_uverbs_create_qp_resp *resp, size_t resp_size); ++int ibv_cmd_create_qp_ex(struct ibv_context *context, ++ struct verbs_qp *qp, ++ struct ibv_qp_init_attr_ex *attr_ex, ++ struct ibv_create_qp *cmd, size_t cmd_size, ++ struct ib_uverbs_create_qp_resp *resp, size_t resp_size); ++int ibv_cmd_create_qp_ex2(struct ibv_context *context, ++ struct verbs_qp *qp, ++ struct ibv_qp_init_attr_ex *qp_attr, ++ struct ibv_create_qp_ex *cmd, ++ size_t cmd_size, ++ struct ib_uverbs_ex_create_qp_resp *resp, ++ size_t resp_size); ++int ibv_cmd_open_qp(struct ibv_context *context, ++ struct verbs_qp *qp, int vqp_sz, ++ struct ibv_qp_open_attr *attr, ++ struct ibv_open_qp *cmd, size_t cmd_size, ++ struct ib_uverbs_create_qp_resp *resp, size_t resp_size); ++int ibv_cmd_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *qp_attr, ++ int attr_mask, ++ struct ibv_qp_init_attr *qp_init_attr, ++ struct ibv_query_qp *cmd, size_t cmd_size); ++int ibv_cmd_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, ++ int attr_mask, ++ struct ibv_modify_qp *cmd, size_t cmd_size); ++int ibv_cmd_modify_qp_ex(struct ibv_qp *qp, struct ibv_qp_attr *attr, ++ int attr_mask, struct ibv_modify_qp_ex *cmd, ++ size_t cmd_size, ++ struct ib_uverbs_ex_modify_qp_resp *resp, ++ size_t resp_size); ++int ibv_cmd_destroy_qp(struct ibv_qp *qp); ++int ibv_cmd_post_send(struct ibv_qp *ibqp, struct ibv_send_wr *wr, ++ struct ibv_send_wr **bad_wr); ++int ibv_cmd_post_recv(struct ibv_qp *ibqp, struct ibv_recv_wr *wr, ++ struct ibv_recv_wr **bad_wr); ++int ibv_cmd_post_srq_recv(struct ibv_srq *srq, struct ibv_recv_wr *wr, ++ struct ibv_recv_wr **bad_wr); ++int ibv_cmd_create_ah(struct ibv_pd *pd, struct ibv_ah *ah, ++ struct ibv_ah_attr *attr, ++ struct ib_uverbs_create_ah_resp *resp, ++ size_t resp_size); ++int ibv_cmd_destroy_ah(struct ibv_ah *ah); ++int ibv_cmd_attach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, uint16_t lid); ++int ibv_cmd_detach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, uint16_t lid); ++ ++int ibv_cmd_create_flow(struct ibv_qp *qp, ++ struct ibv_flow *flow_id, ++ struct ibv_flow_attr *flow_attr, ++ void *ucmd, ++ size_t ucmd_size); ++int ibv_cmd_destroy_flow(struct ibv_flow *flow_id); ++int ibv_cmd_create_wq(struct ibv_context *context, ++ struct ibv_wq_init_attr *wq_init_attr, ++ struct ibv_wq *wq, ++ struct ibv_create_wq *cmd, ++ size_t cmd_size, ++ struct ib_uverbs_ex_create_wq_resp *resp, ++ size_t resp_size); ++ ++int ibv_cmd_destroy_flow_action(struct verbs_flow_action *action); ++int ibv_cmd_modify_wq(struct ibv_wq *wq, struct ibv_wq_attr *attr, ++ struct ibv_modify_wq *cmd, size_t cmd_size); ++int ibv_cmd_destroy_wq(struct ibv_wq *wq); ++int ibv_cmd_create_rwq_ind_table(struct ibv_context *context, ++ struct ibv_rwq_ind_table_init_attr *init_attr, ++ struct ibv_rwq_ind_table *rwq_ind_table, ++ struct ib_uverbs_ex_create_rwq_ind_table_resp *resp, ++ size_t resp_size); ++int ibv_cmd_destroy_rwq_ind_table(struct ibv_rwq_ind_table *rwq_ind_table); ++int ibv_cmd_create_counters(struct ibv_context *context, ++ struct ibv_counters_init_attr *init_attr, ++ struct verbs_counters *vcounters, ++ struct ibv_command_buffer *link); ++int ibv_cmd_destroy_counters(struct verbs_counters *vcounters); ++int ibv_cmd_read_counters(struct verbs_counters *vcounters, ++ uint64_t *counters_value, ++ uint32_t ncounters, ++ uint32_t flags, ++ struct ibv_command_buffer *link); ++int ibv_dontfork_range(void *base, size_t size); ++int ibv_dofork_range(void *base, size_t size); ++int ibv_cmd_alloc_dm(struct ibv_context *ctx, ++ const struct ibv_alloc_dm_attr *dm_attr, ++ struct verbs_dm *dm, ++ struct ibv_command_buffer *link); ++int ibv_cmd_free_dm(struct verbs_dm *dm); ++int ibv_cmd_reg_dm_mr(struct ibv_pd *pd, struct verbs_dm *dm, ++ uint64_t offset, size_t length, ++ unsigned int access, struct verbs_mr *vmr, ++ struct ibv_command_buffer *link); ++ ++int __ibv_query_gid_ex(struct ibv_context *context, uint32_t port_num, ++ uint32_t gid_index, struct ibv_gid_entry *entry, ++ uint32_t flags, size_t entry_size, ++ uint32_t fallback_attr_mask); ++ ++/* ++ * sysfs helper functions ++ */ ++const char *ibv_get_sysfs_path(void); ++ ++int ibv_read_sysfs_file(const char *dir, const char *file, ++ char *buf, size_t size); ++int ibv_read_sysfs_file_at(int dirfd, const char *file, char *buf, size_t size); ++int ibv_read_ibdev_sysfs_file(char *buf, size_t size, ++ struct verbs_sysfs_dev *sysfs_dev, ++ const char *fnfmt, ...) ++ __attribute__((format(printf, 4, 5))); ++ ++static inline bool check_comp_mask(uint64_t input, uint64_t supported) ++{ ++ return (input & ~supported) == 0; ++} ++ ++int ibv_query_gid_type(struct ibv_context *context, uint8_t port_num, ++ unsigned int index, enum ibv_gid_type_sysfs *type); ++ ++static inline int ++ibv_check_alloc_parent_domain(struct ibv_parent_domain_init_attr *attr) ++{ ++ /* A valid protection domain must be set */ ++ if (!attr->pd) { ++ errno = EINVAL; ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Initialize the ibv_pd which is being used as a parent_domain. From the ++ * perspective of the core code the new ibv_pd is completely interchangeable ++ * with the passed contained_pd. ++ */ ++static inline void ibv_initialize_parent_domain(struct ibv_pd *parent_domain, ++ struct ibv_pd *contained_pd) ++{ ++ parent_domain->context = contained_pd->context; ++ parent_domain->handle = contained_pd->handle; ++} ++ ++#endif /* INFINIBAND_DRIVER_H */ +diff --git a/src/rc-compat/v37/ib_user_verbs.h b/src/rc-compat/v37/ib_user_verbs.h +new file mode 100644 +index 000000000000..7ee73a0652f1 +--- /dev/null ++++ b/src/rc-compat/v37/ib_user_verbs.h +@@ -0,0 +1,1301 @@ ++/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR Linux-OpenIB) */ ++/* ++ * Copyright (c) 2005 Topspin Communications. All rights reserved. ++ * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved. ++ * Copyright (c) 2005 PathScale, Inc. All rights reserved. ++ * Copyright (c) 2006 Mellanox Technologies. All rights reserved. ++ * ++ * This software is available to you under a choice of one of two ++ * licenses. You may choose to be licensed under the terms of the GNU ++ * General Public License (GPL) Version 2, available from the file ++ * COPYING in the main directory of this source tree, or the ++ * OpenIB.org BSD license below: ++ * ++ * Redistribution and use in source and binary forms, with or ++ * without modification, are permitted provided that the following ++ * conditions are met: ++ * ++ * - Redistributions of source code must retain the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer. ++ * ++ * - Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials ++ * provided with the distribution. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS ++ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. ++ */ ++ ++#ifndef IB_USER_VERBS_H ++#define IB_USER_VERBS_H ++ ++#include ++ ++/* ++ * Increment this value if any changes that break userspace ABI ++ * compatibility are made. ++ */ ++#define IB_USER_VERBS_ABI_VERSION 6 ++#define IB_USER_VERBS_CMD_THRESHOLD 50 ++ ++enum ib_uverbs_write_cmds { ++ IB_USER_VERBS_CMD_GET_CONTEXT, ++ IB_USER_VERBS_CMD_QUERY_DEVICE, ++ IB_USER_VERBS_CMD_QUERY_PORT, ++ IB_USER_VERBS_CMD_ALLOC_PD, ++ IB_USER_VERBS_CMD_DEALLOC_PD, ++ IB_USER_VERBS_CMD_CREATE_AH, ++ IB_USER_VERBS_CMD_MODIFY_AH, ++ IB_USER_VERBS_CMD_QUERY_AH, ++ IB_USER_VERBS_CMD_DESTROY_AH, ++ IB_USER_VERBS_CMD_REG_MR, ++ IB_USER_VERBS_CMD_REG_SMR, ++ IB_USER_VERBS_CMD_REREG_MR, ++ IB_USER_VERBS_CMD_QUERY_MR, ++ IB_USER_VERBS_CMD_DEREG_MR, ++ IB_USER_VERBS_CMD_ALLOC_MW, ++ IB_USER_VERBS_CMD_BIND_MW, ++ IB_USER_VERBS_CMD_DEALLOC_MW, ++ IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL, ++ IB_USER_VERBS_CMD_CREATE_CQ, ++ IB_USER_VERBS_CMD_RESIZE_CQ, ++ IB_USER_VERBS_CMD_DESTROY_CQ, ++ IB_USER_VERBS_CMD_POLL_CQ, ++ IB_USER_VERBS_CMD_PEEK_CQ, ++ IB_USER_VERBS_CMD_REQ_NOTIFY_CQ, ++ IB_USER_VERBS_CMD_CREATE_QP, ++ IB_USER_VERBS_CMD_QUERY_QP, ++ IB_USER_VERBS_CMD_MODIFY_QP, ++ IB_USER_VERBS_CMD_DESTROY_QP, ++ IB_USER_VERBS_CMD_POST_SEND, ++ IB_USER_VERBS_CMD_POST_RECV, ++ IB_USER_VERBS_CMD_ATTACH_MCAST, ++ IB_USER_VERBS_CMD_DETACH_MCAST, ++ IB_USER_VERBS_CMD_CREATE_SRQ, ++ IB_USER_VERBS_CMD_MODIFY_SRQ, ++ IB_USER_VERBS_CMD_QUERY_SRQ, ++ IB_USER_VERBS_CMD_DESTROY_SRQ, ++ IB_USER_VERBS_CMD_POST_SRQ_RECV, ++ IB_USER_VERBS_CMD_OPEN_XRCD, ++ IB_USER_VERBS_CMD_CLOSE_XRCD, ++ IB_USER_VERBS_CMD_CREATE_XSRQ, ++ IB_USER_VERBS_CMD_OPEN_QP, ++}; ++ ++enum { ++ IB_USER_VERBS_EX_CMD_QUERY_DEVICE = IB_USER_VERBS_CMD_QUERY_DEVICE, ++ IB_USER_VERBS_EX_CMD_CREATE_CQ = IB_USER_VERBS_CMD_CREATE_CQ, ++ IB_USER_VERBS_EX_CMD_CREATE_QP = IB_USER_VERBS_CMD_CREATE_QP, ++ IB_USER_VERBS_EX_CMD_MODIFY_QP = IB_USER_VERBS_CMD_MODIFY_QP, ++ IB_USER_VERBS_EX_CMD_CREATE_FLOW = IB_USER_VERBS_CMD_THRESHOLD, ++ IB_USER_VERBS_EX_CMD_DESTROY_FLOW, ++ IB_USER_VERBS_EX_CMD_CREATE_WQ, ++ IB_USER_VERBS_EX_CMD_MODIFY_WQ, ++ IB_USER_VERBS_EX_CMD_DESTROY_WQ, ++ IB_USER_VERBS_EX_CMD_CREATE_RWQ_IND_TBL, ++ IB_USER_VERBS_EX_CMD_DESTROY_RWQ_IND_TBL, ++ IB_USER_VERBS_EX_CMD_MODIFY_CQ ++}; ++ ++/* ++ * Make sure that all structs defined in this file remain laid out so ++ * that they pack the same way on 32-bit and 64-bit architectures (to ++ * avoid incompatibility between 32-bit userspace and 64-bit kernels). ++ * Specifically: ++ * - Do not use pointer types -- pass pointers in __u64 instead. ++ * - Make sure that any structure larger than 4 bytes is padded to a ++ * multiple of 8 bytes. Otherwise the structure size will be ++ * different between 32-bit and 64-bit architectures. ++ */ ++ ++struct ib_uverbs_async_event_desc { ++ __aligned_u64 element; ++ __u32 event_type; /* enum ib_event_type */ ++ __u32 reserved; ++}; ++ ++struct ib_uverbs_comp_event_desc { ++ __aligned_u64 cq_handle; ++}; ++ ++struct ib_uverbs_cq_moderation_caps { ++ __u16 max_cq_moderation_count; ++ __u16 max_cq_moderation_period; ++ __u32 reserved; ++}; ++ ++/* ++ * All commands from userspace should start with a __u32 command field ++ * followed by __u16 in_words and out_words fields (which give the ++ * length of the command block and response buffer if any in 32-bit ++ * words). The kernel driver will read these fields first and read ++ * the rest of the command struct based on these value. ++ */ ++ ++#define IB_USER_VERBS_CMD_COMMAND_MASK 0xff ++#define IB_USER_VERBS_CMD_FLAG_EXTENDED 0x80000000u ++ ++struct ib_uverbs_cmd_hdr { ++ __u32 command; ++ __u16 in_words; ++ __u16 out_words; ++}; ++ ++struct ib_uverbs_ex_cmd_hdr { ++ __aligned_u64 response; ++ __u16 provider_in_words; ++ __u16 provider_out_words; ++ __u32 cmd_hdr_reserved; ++}; ++ ++struct ib_uverbs_get_context { ++ __aligned_u64 response; ++ __aligned_u64 driver_data[0]; ++}; ++ ++struct ib_uverbs_get_context_resp { ++ __u32 async_fd; ++ __u32 num_comp_vectors; ++ __aligned_u64 driver_data[0]; ++}; ++ ++struct ib_uverbs_query_device { ++ __aligned_u64 response; ++ __aligned_u64 driver_data[0]; ++}; ++ ++struct ib_uverbs_query_device_resp { ++ __aligned_u64 fw_ver; ++ __be64 node_guid; ++ __be64 sys_image_guid; ++ __aligned_u64 max_mr_size; ++ __aligned_u64 page_size_cap; ++ __u32 vendor_id; ++ __u32 vendor_part_id; ++ __u32 hw_ver; ++ __u32 max_qp; ++ __u32 max_qp_wr; ++ __u32 device_cap_flags; ++ __u32 max_sge; ++ __u32 max_sge_rd; ++ __u32 max_cq; ++ __u32 max_cqe; ++ __u32 max_mr; ++ __u32 max_pd; ++ __u32 max_qp_rd_atom; ++ __u32 max_ee_rd_atom; ++ __u32 max_res_rd_atom; ++ __u32 max_qp_init_rd_atom; ++ __u32 max_ee_init_rd_atom; ++ __u32 atomic_cap; ++ __u32 max_ee; ++ __u32 max_rdd; ++ __u32 max_mw; ++ __u32 max_raw_ipv6_qp; ++ __u32 max_raw_ethy_qp; ++ __u32 max_mcast_grp; ++ __u32 max_mcast_qp_attach; ++ __u32 max_total_mcast_qp_attach; ++ __u32 max_ah; ++ __u32 max_fmr; ++ __u32 max_map_per_fmr; ++ __u32 max_srq; ++ __u32 max_srq_wr; ++ __u32 max_srq_sge; ++ __u16 max_pkeys; ++ __u8 local_ca_ack_delay; ++ __u8 phys_port_cnt; ++ __u8 reserved[4]; ++}; ++ ++struct ib_uverbs_ex_query_device { ++ __u32 comp_mask; ++ __u32 reserved; ++}; ++ ++struct ib_uverbs_odp_caps { ++ __aligned_u64 general_caps; ++ struct { ++ __u32 rc_odp_caps; ++ __u32 uc_odp_caps; ++ __u32 ud_odp_caps; ++ } per_transport_caps; ++ __u32 reserved; ++}; ++ ++struct ib_uverbs_rss_caps { ++ /* Corresponding bit will be set if qp type from ++ * 'enum ib_qp_type' is supported, e.g. ++ * supported_qpts |= 1 << IB_QPT_UD ++ */ ++ __u32 supported_qpts; ++ __u32 max_rwq_indirection_tables; ++ __u32 max_rwq_indirection_table_size; ++ __u32 reserved; ++}; ++ ++struct ib_uverbs_tm_caps { ++ /* Max size of rendezvous request message */ ++ __u32 max_rndv_hdr_size; ++ /* Max number of entries in tag matching list */ ++ __u32 max_num_tags; ++ /* TM flags */ ++ __u32 flags; ++ /* Max number of outstanding list operations */ ++ __u32 max_ops; ++ /* Max number of SGE in tag matching entry */ ++ __u32 max_sge; ++ __u32 reserved; ++}; ++ ++struct ib_uverbs_ex_query_device_resp { ++ struct ib_uverbs_query_device_resp base; ++ __u32 comp_mask; ++ __u32 response_length; ++ struct ib_uverbs_odp_caps odp_caps; ++ __aligned_u64 timestamp_mask; ++ __aligned_u64 hca_core_clock; /* in KHZ */ ++ __aligned_u64 device_cap_flags_ex; ++ struct ib_uverbs_rss_caps rss_caps; ++ __u32 max_wq_type_rq; ++ __u32 raw_packet_caps; ++ struct ib_uverbs_tm_caps tm_caps; ++ struct ib_uverbs_cq_moderation_caps cq_moderation_caps; ++ __aligned_u64 max_dm_size; ++ __u32 xrc_odp_caps; ++ __u32 reserved; ++}; ++ ++struct ib_uverbs_query_port { ++ __aligned_u64 response; ++ __u8 port_num; ++ __u8 reserved[7]; ++ __aligned_u64 driver_data[0]; ++}; ++ ++struct ib_uverbs_query_port_resp { ++ __u32 port_cap_flags; /* see ib_uverbs_query_port_cap_flags */ ++ __u32 max_msg_sz; ++ __u32 bad_pkey_cntr; ++ __u32 qkey_viol_cntr; ++ __u32 gid_tbl_len; ++ __u16 pkey_tbl_len; ++ __u16 lid; ++ __u16 sm_lid; ++ __u8 state; ++ __u8 max_mtu; ++ __u8 active_mtu; ++ __u8 lmc; ++ __u8 max_vl_num; ++ __u8 sm_sl; ++ __u8 subnet_timeout; ++ __u8 init_type_reply; ++ __u8 active_width; ++ __u8 active_speed; ++ __u8 phys_state; ++ __u8 link_layer; ++ __u8 flags; /* see ib_uverbs_query_port_flags */ ++ __u8 reserved; ++}; ++ ++struct ib_uverbs_alloc_pd { ++ __aligned_u64 response; ++ __aligned_u64 driver_data[0]; ++}; ++ ++struct ib_uverbs_alloc_pd_resp { ++ __u32 pd_handle; ++ __u32 driver_data[0]; ++}; ++ ++struct ib_uverbs_dealloc_pd { ++ __u32 pd_handle; ++}; ++ ++struct ib_uverbs_open_xrcd { ++ __aligned_u64 response; ++ __u32 fd; ++ __u32 oflags; ++ __aligned_u64 driver_data[0]; ++}; ++ ++struct ib_uverbs_open_xrcd_resp { ++ __u32 xrcd_handle; ++ __u32 driver_data[0]; ++}; ++ ++struct ib_uverbs_close_xrcd { ++ __u32 xrcd_handle; ++}; ++ ++struct ib_uverbs_reg_mr { ++ __aligned_u64 response; ++ __aligned_u64 start; ++ __aligned_u64 length; ++ __aligned_u64 hca_va; ++ __u32 pd_handle; ++ __u32 access_flags; ++ __aligned_u64 driver_data[0]; ++}; ++ ++struct ib_uverbs_reg_mr_resp { ++ __u32 mr_handle; ++ __u32 lkey; ++ __u32 rkey; ++ __u32 driver_data[0]; ++}; ++ ++struct ib_uverbs_rereg_mr { ++ __aligned_u64 response; ++ __u32 mr_handle; ++ __u32 flags; ++ __aligned_u64 start; ++ __aligned_u64 length; ++ __aligned_u64 hca_va; ++ __u32 pd_handle; ++ __u32 access_flags; ++ __aligned_u64 driver_data[0]; ++}; ++ ++struct ib_uverbs_rereg_mr_resp { ++ __u32 lkey; ++ __u32 rkey; ++ __aligned_u64 driver_data[0]; ++}; ++ ++struct ib_uverbs_dereg_mr { ++ __u32 mr_handle; ++}; ++ ++struct ib_uverbs_alloc_mw { ++ __aligned_u64 response; ++ __u32 pd_handle; ++ __u8 mw_type; ++ __u8 reserved[3]; ++ __aligned_u64 driver_data[0]; ++}; ++ ++struct ib_uverbs_alloc_mw_resp { ++ __u32 mw_handle; ++ __u32 rkey; ++ __aligned_u64 driver_data[0]; ++}; ++ ++struct ib_uverbs_dealloc_mw { ++ __u32 mw_handle; ++}; ++ ++struct ib_uverbs_create_comp_channel { ++ __aligned_u64 response; ++}; ++ ++struct ib_uverbs_create_comp_channel_resp { ++ __u32 fd; ++}; ++ ++struct ib_uverbs_create_cq { ++ __aligned_u64 response; ++ __aligned_u64 user_handle; ++ __u32 cqe; ++ __u32 comp_vector; ++ __s32 comp_channel; ++ __u32 reserved; ++ __aligned_u64 driver_data[0]; ++}; ++ ++enum ib_uverbs_ex_create_cq_flags { ++ IB_UVERBS_CQ_FLAGS_TIMESTAMP_COMPLETION = 1 << 0, ++ IB_UVERBS_CQ_FLAGS_IGNORE_OVERRUN = 1 << 1, ++}; ++ ++struct ib_uverbs_ex_create_cq { ++ __aligned_u64 user_handle; ++ __u32 cqe; ++ __u32 comp_vector; ++ __s32 comp_channel; ++ __u32 comp_mask; ++ __u32 flags; /* bitmask of ib_uverbs_ex_create_cq_flags */ ++ __u32 reserved; ++}; ++ ++struct ib_uverbs_create_cq_resp { ++ __u32 cq_handle; ++ __u32 cqe; ++ __aligned_u64 driver_data[0]; ++}; ++ ++struct ib_uverbs_ex_create_cq_resp { ++ struct ib_uverbs_create_cq_resp base; ++ __u32 comp_mask; ++ __u32 response_length; ++}; ++ ++struct ib_uverbs_resize_cq { ++ __aligned_u64 response; ++ __u32 cq_handle; ++ __u32 cqe; ++ __aligned_u64 driver_data[0]; ++}; ++ ++struct ib_uverbs_resize_cq_resp { ++ __u32 cqe; ++ __u32 reserved; ++ __aligned_u64 driver_data[0]; ++}; ++ ++struct ib_uverbs_poll_cq { ++ __aligned_u64 response; ++ __u32 cq_handle; ++ __u32 ne; ++}; ++ ++enum ib_uverbs_wc_opcode { ++ IB_UVERBS_WC_SEND = 0, ++ IB_UVERBS_WC_RDMA_WRITE = 1, ++ IB_UVERBS_WC_RDMA_READ = 2, ++ IB_UVERBS_WC_COMP_SWAP = 3, ++ IB_UVERBS_WC_FETCH_ADD = 4, ++ IB_UVERBS_WC_BIND_MW = 5, ++ IB_UVERBS_WC_LOCAL_INV = 6, ++ IB_UVERBS_WC_TSO = 7, ++}; ++ ++struct ib_uverbs_wc { ++ __aligned_u64 wr_id; ++ __u32 status; ++ __u32 opcode; ++ __u32 vendor_err; ++ __u32 byte_len; ++ union { ++ __be32 imm_data; ++ __u32 invalidate_rkey; ++ } ex; ++ __u32 qp_num; ++ __u32 src_qp; ++ __u32 wc_flags; ++ __u16 pkey_index; ++ __u16 slid; ++ __u8 sl; ++ __u8 dlid_path_bits; ++ __u8 port_num; ++ __u8 reserved; ++}; ++ ++struct ib_uverbs_poll_cq_resp { ++ __u32 count; ++ __u32 reserved; ++ struct ib_uverbs_wc wc[0]; ++}; ++ ++struct ib_uverbs_req_notify_cq { ++ __u32 cq_handle; ++ __u32 solicited_only; ++}; ++ ++struct ib_uverbs_destroy_cq { ++ __aligned_u64 response; ++ __u32 cq_handle; ++ __u32 reserved; ++}; ++ ++struct ib_uverbs_destroy_cq_resp { ++ __u32 comp_events_reported; ++ __u32 async_events_reported; ++}; ++ ++struct ib_uverbs_global_route { ++ __u8 dgid[16]; ++ __u32 flow_label; ++ __u8 sgid_index; ++ __u8 hop_limit; ++ __u8 traffic_class; ++ __u8 reserved; ++}; ++ ++struct ib_uverbs_ah_attr { ++ struct ib_uverbs_global_route grh; ++ __u16 dlid; ++ __u8 sl; ++ __u8 src_path_bits; ++ __u8 static_rate; ++ __u8 is_global; ++ __u8 port_num; ++ __u8 reserved; ++}; ++ ++struct ib_uverbs_qp_attr { ++ __u32 qp_attr_mask; ++ __u32 qp_state; ++ __u32 cur_qp_state; ++ __u32 path_mtu; ++ __u32 path_mig_state; ++ __u32 qkey; ++ __u32 rq_psn; ++ __u32 sq_psn; ++ __u32 dest_qp_num; ++ __u32 qp_access_flags; ++ ++ struct ib_uverbs_ah_attr ah_attr; ++ struct ib_uverbs_ah_attr alt_ah_attr; ++ ++ /* ib_qp_cap */ ++ __u32 max_send_wr; ++ __u32 max_recv_wr; ++ __u32 max_send_sge; ++ __u32 max_recv_sge; ++ __u32 max_inline_data; ++ ++ __u16 pkey_index; ++ __u16 alt_pkey_index; ++ __u8 en_sqd_async_notify; ++ __u8 sq_draining; ++ __u8 max_rd_atomic; ++ __u8 max_dest_rd_atomic; ++ __u8 min_rnr_timer; ++ __u8 port_num; ++ __u8 timeout; ++ __u8 retry_cnt; ++ __u8 rnr_retry; ++ __u8 alt_port_num; ++ __u8 alt_timeout; ++ __u8 reserved[5]; ++}; ++ ++struct ib_uverbs_create_qp { ++ __aligned_u64 response; ++ __aligned_u64 user_handle; ++ __u32 pd_handle; ++ __u32 send_cq_handle; ++ __u32 recv_cq_handle; ++ __u32 srq_handle; ++ __u32 max_send_wr; ++ __u32 max_recv_wr; ++ __u32 max_send_sge; ++ __u32 max_recv_sge; ++ __u32 max_inline_data; ++ __u8 sq_sig_all; ++ __u8 qp_type; ++ __u8 is_srq; ++ __u8 reserved; ++ __aligned_u64 driver_data[0]; ++}; ++ ++enum ib_uverbs_create_qp_mask { ++ IB_UVERBS_CREATE_QP_MASK_IND_TABLE = 1UL << 0, ++}; ++ ++enum { ++ IB_UVERBS_CREATE_QP_SUP_COMP_MASK = IB_UVERBS_CREATE_QP_MASK_IND_TABLE, ++}; ++ ++struct ib_uverbs_ex_create_qp { ++ __aligned_u64 user_handle; ++ __u32 pd_handle; ++ __u32 send_cq_handle; ++ __u32 recv_cq_handle; ++ __u32 srq_handle; ++ __u32 max_send_wr; ++ __u32 max_recv_wr; ++ __u32 max_send_sge; ++ __u32 max_recv_sge; ++ __u32 max_inline_data; ++ __u8 sq_sig_all; ++ __u8 qp_type; ++ __u8 is_srq; ++ __u8 reserved; ++ __u32 comp_mask; ++ __u32 create_flags; ++ __u32 rwq_ind_tbl_handle; ++ __u32 source_qpn; ++}; ++ ++struct ib_uverbs_open_qp { ++ __aligned_u64 response; ++ __aligned_u64 user_handle; ++ __u32 pd_handle; ++ __u32 qpn; ++ __u8 qp_type; ++ __u8 reserved[7]; ++ __aligned_u64 driver_data[0]; ++}; ++ ++/* also used for open response */ ++struct ib_uverbs_create_qp_resp { ++ __u32 qp_handle; ++ __u32 qpn; ++ __u32 max_send_wr; ++ __u32 max_recv_wr; ++ __u32 max_send_sge; ++ __u32 max_recv_sge; ++ __u32 max_inline_data; ++ __u32 reserved; ++ __u32 driver_data[0]; ++}; ++ ++struct ib_uverbs_ex_create_qp_resp { ++ struct ib_uverbs_create_qp_resp base; ++ __u32 comp_mask; ++ __u32 response_length; ++}; ++ ++/* ++ * This struct needs to remain a multiple of 8 bytes to keep the ++ * alignment of the modify QP parameters. ++ */ ++struct ib_uverbs_qp_dest { ++ __u8 dgid[16]; ++ __u32 flow_label; ++ __u16 dlid; ++ __u16 reserved; ++ __u8 sgid_index; ++ __u8 hop_limit; ++ __u8 traffic_class; ++ __u8 sl; ++ __u8 src_path_bits; ++ __u8 static_rate; ++ __u8 is_global; ++ __u8 port_num; ++}; ++ ++struct ib_uverbs_query_qp { ++ __aligned_u64 response; ++ __u32 qp_handle; ++ __u32 attr_mask; ++ __aligned_u64 driver_data[0]; ++}; ++ ++struct ib_uverbs_query_qp_resp { ++ struct ib_uverbs_qp_dest dest; ++ struct ib_uverbs_qp_dest alt_dest; ++ __u32 max_send_wr; ++ __u32 max_recv_wr; ++ __u32 max_send_sge; ++ __u32 max_recv_sge; ++ __u32 max_inline_data; ++ __u32 qkey; ++ __u32 rq_psn; ++ __u32 sq_psn; ++ __u32 dest_qp_num; ++ __u32 qp_access_flags; ++ __u16 pkey_index; ++ __u16 alt_pkey_index; ++ __u8 qp_state; ++ __u8 cur_qp_state; ++ __u8 path_mtu; ++ __u8 path_mig_state; ++ __u8 sq_draining; ++ __u8 max_rd_atomic; ++ __u8 max_dest_rd_atomic; ++ __u8 min_rnr_timer; ++ __u8 port_num; ++ __u8 timeout; ++ __u8 retry_cnt; ++ __u8 rnr_retry; ++ __u8 alt_port_num; ++ __u8 alt_timeout; ++ __u8 sq_sig_all; ++ __u8 reserved[5]; ++ __aligned_u64 driver_data[0]; ++}; ++ ++struct ib_uverbs_modify_qp { ++ struct ib_uverbs_qp_dest dest; ++ struct ib_uverbs_qp_dest alt_dest; ++ __u32 qp_handle; ++ __u32 attr_mask; ++ __u32 qkey; ++ __u32 rq_psn; ++ __u32 sq_psn; ++ __u32 dest_qp_num; ++ __u32 qp_access_flags; ++ __u16 pkey_index; ++ __u16 alt_pkey_index; ++ __u8 qp_state; ++ __u8 cur_qp_state; ++ __u8 path_mtu; ++ __u8 path_mig_state; ++ __u8 en_sqd_async_notify; ++ __u8 max_rd_atomic; ++ __u8 max_dest_rd_atomic; ++ __u8 min_rnr_timer; ++ __u8 port_num; ++ __u8 timeout; ++ __u8 retry_cnt; ++ __u8 rnr_retry; ++ __u8 alt_port_num; ++ __u8 alt_timeout; ++ __u8 reserved[2]; ++ __aligned_u64 driver_data[0]; ++}; ++ ++struct ib_uverbs_ex_modify_qp { ++ struct ib_uverbs_modify_qp base; ++ __u32 rate_limit; ++ __u32 reserved; ++}; ++ ++struct ib_uverbs_ex_modify_qp_resp { ++ __u32 comp_mask; ++ __u32 response_length; ++}; ++ ++struct ib_uverbs_destroy_qp { ++ __aligned_u64 response; ++ __u32 qp_handle; ++ __u32 reserved; ++}; ++ ++struct ib_uverbs_destroy_qp_resp { ++ __u32 events_reported; ++}; ++ ++/* ++ * The ib_uverbs_sge structure isn't used anywhere, since we assume ++ * the ib_sge structure is packed the same way on 32-bit and 64-bit ++ * architectures in both kernel and user space. It's just here to ++ * document the ABI. ++ */ ++struct ib_uverbs_sge { ++ __aligned_u64 addr; ++ __u32 length; ++ __u32 lkey; ++}; ++ ++enum ib_uverbs_wr_opcode { ++ IB_UVERBS_WR_RDMA_WRITE = 0, ++ IB_UVERBS_WR_RDMA_WRITE_WITH_IMM = 1, ++ IB_UVERBS_WR_SEND = 2, ++ IB_UVERBS_WR_SEND_WITH_IMM = 3, ++ IB_UVERBS_WR_RDMA_READ = 4, ++ IB_UVERBS_WR_ATOMIC_CMP_AND_SWP = 5, ++ IB_UVERBS_WR_ATOMIC_FETCH_AND_ADD = 6, ++ IB_UVERBS_WR_LOCAL_INV = 7, ++ IB_UVERBS_WR_BIND_MW = 8, ++ IB_UVERBS_WR_SEND_WITH_INV = 9, ++ IB_UVERBS_WR_TSO = 10, ++ IB_UVERBS_WR_RDMA_READ_WITH_INV = 11, ++ IB_UVERBS_WR_MASKED_ATOMIC_CMP_AND_SWP = 12, ++ IB_UVERBS_WR_MASKED_ATOMIC_FETCH_AND_ADD = 13, ++ /* Review enum ib_wr_opcode before modifying this */ ++}; ++ ++struct ib_uverbs_send_wr { ++ __aligned_u64 wr_id; ++ __u32 num_sge; ++ __u32 opcode; /* see enum ib_uverbs_wr_opcode */ ++ __u32 send_flags; ++ union { ++ __be32 imm_data; ++ __u32 invalidate_rkey; ++ } ex; ++ union { ++ struct { ++ __aligned_u64 remote_addr; ++ __u32 rkey; ++ __u32 reserved; ++ } rdma; ++ struct { ++ __aligned_u64 remote_addr; ++ __aligned_u64 compare_add; ++ __aligned_u64 swap; ++ __u32 rkey; ++ __u32 reserved; ++ } atomic; ++ struct { ++ __u32 ah; ++ __u32 remote_qpn; ++ __u32 remote_qkey; ++ __u32 reserved; ++ } ud; ++ } wr; ++}; ++ ++struct ib_uverbs_post_send { ++ __aligned_u64 response; ++ __u32 qp_handle; ++ __u32 wr_count; ++ __u32 sge_count; ++ __u32 wqe_size; ++ struct ib_uverbs_send_wr send_wr[0]; ++}; ++ ++struct ib_uverbs_post_send_resp { ++ __u32 bad_wr; ++}; ++ ++struct ib_uverbs_recv_wr { ++ __aligned_u64 wr_id; ++ __u32 num_sge; ++ __u32 reserved; ++}; ++ ++struct ib_uverbs_post_recv { ++ __aligned_u64 response; ++ __u32 qp_handle; ++ __u32 wr_count; ++ __u32 sge_count; ++ __u32 wqe_size; ++ struct ib_uverbs_recv_wr recv_wr[0]; ++}; ++ ++struct ib_uverbs_post_recv_resp { ++ __u32 bad_wr; ++}; ++ ++struct ib_uverbs_post_srq_recv { ++ __aligned_u64 response; ++ __u32 srq_handle; ++ __u32 wr_count; ++ __u32 sge_count; ++ __u32 wqe_size; ++ struct ib_uverbs_recv_wr recv[0]; ++}; ++ ++struct ib_uverbs_post_srq_recv_resp { ++ __u32 bad_wr; ++}; ++ ++struct ib_uverbs_create_ah { ++ __aligned_u64 response; ++ __aligned_u64 user_handle; ++ __u32 pd_handle; ++ __u32 reserved; ++ struct ib_uverbs_ah_attr attr; ++ __aligned_u64 driver_data[0]; ++}; ++ ++struct ib_uverbs_create_ah_resp { ++ __u32 ah_handle; ++ __u32 driver_data[0]; ++}; ++ ++struct ib_uverbs_destroy_ah { ++ __u32 ah_handle; ++}; ++ ++struct ib_uverbs_attach_mcast { ++ __u8 gid[16]; ++ __u32 qp_handle; ++ __u16 mlid; ++ __u16 reserved; ++ __aligned_u64 driver_data[0]; ++}; ++ ++struct ib_uverbs_detach_mcast { ++ __u8 gid[16]; ++ __u32 qp_handle; ++ __u16 mlid; ++ __u16 reserved; ++ __aligned_u64 driver_data[0]; ++}; ++ ++struct ib_uverbs_flow_spec_hdr { ++ __u32 type; ++ __u16 size; ++ __u16 reserved; ++ /* followed by flow_spec */ ++ __aligned_u64 flow_spec_data[0]; ++}; ++ ++struct ib_uverbs_flow_eth_filter { ++ __u8 dst_mac[6]; ++ __u8 src_mac[6]; ++ __be16 ether_type; ++ __be16 vlan_tag; ++}; ++ ++struct ib_uverbs_flow_spec_eth { ++ union { ++ struct ib_uverbs_flow_spec_hdr hdr; ++ struct { ++ __u32 type; ++ __u16 size; ++ __u16 reserved; ++ }; ++ }; ++ struct ib_uverbs_flow_eth_filter val; ++ struct ib_uverbs_flow_eth_filter mask; ++}; ++ ++struct ib_uverbs_flow_ipv4_filter { ++ __be32 src_ip; ++ __be32 dst_ip; ++ __u8 proto; ++ __u8 tos; ++ __u8 ttl; ++ __u8 flags; ++}; ++ ++struct ib_uverbs_flow_spec_ipv4 { ++ union { ++ struct ib_uverbs_flow_spec_hdr hdr; ++ struct { ++ __u32 type; ++ __u16 size; ++ __u16 reserved; ++ }; ++ }; ++ struct ib_uverbs_flow_ipv4_filter val; ++ struct ib_uverbs_flow_ipv4_filter mask; ++}; ++ ++struct ib_uverbs_flow_tcp_udp_filter { ++ __be16 dst_port; ++ __be16 src_port; ++}; ++ ++struct ib_uverbs_flow_spec_tcp_udp { ++ union { ++ struct ib_uverbs_flow_spec_hdr hdr; ++ struct { ++ __u32 type; ++ __u16 size; ++ __u16 reserved; ++ }; ++ }; ++ struct ib_uverbs_flow_tcp_udp_filter val; ++ struct ib_uverbs_flow_tcp_udp_filter mask; ++}; ++ ++struct ib_uverbs_flow_ipv6_filter { ++ __u8 src_ip[16]; ++ __u8 dst_ip[16]; ++ __be32 flow_label; ++ __u8 next_hdr; ++ __u8 traffic_class; ++ __u8 hop_limit; ++ __u8 reserved; ++}; ++ ++struct ib_uverbs_flow_spec_ipv6 { ++ union { ++ struct ib_uverbs_flow_spec_hdr hdr; ++ struct { ++ __u32 type; ++ __u16 size; ++ __u16 reserved; ++ }; ++ }; ++ struct ib_uverbs_flow_ipv6_filter val; ++ struct ib_uverbs_flow_ipv6_filter mask; ++}; ++ ++struct ib_uverbs_flow_spec_action_tag { ++ union { ++ struct ib_uverbs_flow_spec_hdr hdr; ++ struct { ++ __u32 type; ++ __u16 size; ++ __u16 reserved; ++ }; ++ }; ++ __u32 tag_id; ++ __u32 reserved1; ++}; ++ ++struct ib_uverbs_flow_spec_action_drop { ++ union { ++ struct ib_uverbs_flow_spec_hdr hdr; ++ struct { ++ __u32 type; ++ __u16 size; ++ __u16 reserved; ++ }; ++ }; ++}; ++ ++struct ib_uverbs_flow_spec_action_handle { ++ union { ++ struct ib_uverbs_flow_spec_hdr hdr; ++ struct { ++ __u32 type; ++ __u16 size; ++ __u16 reserved; ++ }; ++ }; ++ __u32 handle; ++ __u32 reserved1; ++}; ++ ++struct ib_uverbs_flow_spec_action_count { ++ union { ++ struct ib_uverbs_flow_spec_hdr hdr; ++ struct { ++ __u32 type; ++ __u16 size; ++ __u16 reserved; ++ }; ++ }; ++ __u32 handle; ++ __u32 reserved1; ++}; ++ ++struct ib_uverbs_flow_tunnel_filter { ++ __be32 tunnel_id; ++}; ++ ++struct ib_uverbs_flow_spec_tunnel { ++ union { ++ struct ib_uverbs_flow_spec_hdr hdr; ++ struct { ++ __u32 type; ++ __u16 size; ++ __u16 reserved; ++ }; ++ }; ++ struct ib_uverbs_flow_tunnel_filter val; ++ struct ib_uverbs_flow_tunnel_filter mask; ++}; ++ ++struct ib_uverbs_flow_spec_esp_filter { ++ __u32 spi; ++ __u32 seq; ++}; ++ ++struct ib_uverbs_flow_spec_esp { ++ union { ++ struct ib_uverbs_flow_spec_hdr hdr; ++ struct { ++ __u32 type; ++ __u16 size; ++ __u16 reserved; ++ }; ++ }; ++ struct ib_uverbs_flow_spec_esp_filter val; ++ struct ib_uverbs_flow_spec_esp_filter mask; ++}; ++ ++struct ib_uverbs_flow_gre_filter { ++ /* c_ks_res0_ver field is bits 0-15 in offset 0 of a standard GRE header: ++ * bit 0 - C - checksum bit. ++ * bit 1 - reserved. set to 0. ++ * bit 2 - key bit. ++ * bit 3 - sequence number bit. ++ * bits 4:12 - reserved. set to 0. ++ * bits 13:15 - GRE version. ++ */ ++ __be16 c_ks_res0_ver; ++ __be16 protocol; ++ __be32 key; ++}; ++ ++struct ib_uverbs_flow_spec_gre { ++ union { ++ struct ib_uverbs_flow_spec_hdr hdr; ++ struct { ++ __u32 type; ++ __u16 size; ++ __u16 reserved; ++ }; ++ }; ++ struct ib_uverbs_flow_gre_filter val; ++ struct ib_uverbs_flow_gre_filter mask; ++}; ++ ++struct ib_uverbs_flow_mpls_filter { ++ /* The field includes the entire MPLS label: ++ * bits 0:19 - label field. ++ * bits 20:22 - traffic class field. ++ * bits 23 - bottom of stack bit. ++ * bits 24:31 - ttl field. ++ */ ++ __be32 label; ++}; ++ ++struct ib_uverbs_flow_spec_mpls { ++ union { ++ struct ib_uverbs_flow_spec_hdr hdr; ++ struct { ++ __u32 type; ++ __u16 size; ++ __u16 reserved; ++ }; ++ }; ++ struct ib_uverbs_flow_mpls_filter val; ++ struct ib_uverbs_flow_mpls_filter mask; ++}; ++ ++struct ib_uverbs_flow_attr { ++ __u32 type; ++ __u16 size; ++ __u16 priority; ++ __u8 num_of_specs; ++ __u8 reserved[2]; ++ __u8 port; ++ __u32 flags; ++ /* Following are the optional layers according to user request ++ * struct ib_flow_spec_xxx ++ * struct ib_flow_spec_yyy ++ */ ++ struct ib_uverbs_flow_spec_hdr flow_specs[0]; ++}; ++ ++struct ib_uverbs_create_flow { ++ __u32 comp_mask; ++ __u32 qp_handle; ++ struct ib_uverbs_flow_attr flow_attr; ++}; ++ ++struct ib_uverbs_create_flow_resp { ++ __u32 comp_mask; ++ __u32 flow_handle; ++}; ++ ++struct ib_uverbs_destroy_flow { ++ __u32 comp_mask; ++ __u32 flow_handle; ++}; ++ ++struct ib_uverbs_create_srq { ++ __aligned_u64 response; ++ __aligned_u64 user_handle; ++ __u32 pd_handle; ++ __u32 max_wr; ++ __u32 max_sge; ++ __u32 srq_limit; ++ __aligned_u64 driver_data[0]; ++}; ++ ++struct ib_uverbs_create_xsrq { ++ __aligned_u64 response; ++ __aligned_u64 user_handle; ++ __u32 srq_type; ++ __u32 pd_handle; ++ __u32 max_wr; ++ __u32 max_sge; ++ __u32 srq_limit; ++ __u32 max_num_tags; ++ __u32 xrcd_handle; ++ __u32 cq_handle; ++ __aligned_u64 driver_data[0]; ++}; ++ ++struct ib_uverbs_create_srq_resp { ++ __u32 srq_handle; ++ __u32 max_wr; ++ __u32 max_sge; ++ __u32 srqn; ++ __u32 driver_data[0]; ++}; ++ ++struct ib_uverbs_modify_srq { ++ __u32 srq_handle; ++ __u32 attr_mask; ++ __u32 max_wr; ++ __u32 srq_limit; ++ __aligned_u64 driver_data[0]; ++}; ++ ++struct ib_uverbs_query_srq { ++ __aligned_u64 response; ++ __u32 srq_handle; ++ __u32 reserved; ++ __aligned_u64 driver_data[0]; ++}; ++ ++struct ib_uverbs_query_srq_resp { ++ __u32 max_wr; ++ __u32 max_sge; ++ __u32 srq_limit; ++ __u32 reserved; ++}; ++ ++struct ib_uverbs_destroy_srq { ++ __aligned_u64 response; ++ __u32 srq_handle; ++ __u32 reserved; ++}; ++ ++struct ib_uverbs_destroy_srq_resp { ++ __u32 events_reported; ++}; ++ ++struct ib_uverbs_ex_create_wq { ++ __u32 comp_mask; ++ __u32 wq_type; ++ __aligned_u64 user_handle; ++ __u32 pd_handle; ++ __u32 cq_handle; ++ __u32 max_wr; ++ __u32 max_sge; ++ __u32 create_flags; /* Use enum ib_wq_flags */ ++ __u32 reserved; ++}; ++ ++struct ib_uverbs_ex_create_wq_resp { ++ __u32 comp_mask; ++ __u32 response_length; ++ __u32 wq_handle; ++ __u32 max_wr; ++ __u32 max_sge; ++ __u32 wqn; ++}; ++ ++struct ib_uverbs_ex_destroy_wq { ++ __u32 comp_mask; ++ __u32 wq_handle; ++}; ++ ++struct ib_uverbs_ex_destroy_wq_resp { ++ __u32 comp_mask; ++ __u32 response_length; ++ __u32 events_reported; ++ __u32 reserved; ++}; ++ ++struct ib_uverbs_ex_modify_wq { ++ __u32 attr_mask; ++ __u32 wq_handle; ++ __u32 wq_state; ++ __u32 curr_wq_state; ++ __u32 flags; /* Use enum ib_wq_flags */ ++ __u32 flags_mask; /* Use enum ib_wq_flags */ ++}; ++ ++/* Prevent memory allocation rather than max expected size */ ++#define IB_USER_VERBS_MAX_LOG_IND_TBL_SIZE 0x0d ++struct ib_uverbs_ex_create_rwq_ind_table { ++ __u32 comp_mask; ++ __u32 log_ind_tbl_size; ++ /* Following are the wq handles according to log_ind_tbl_size ++ * wq_handle1 ++ * wq_handle2 ++ */ ++ __u32 wq_handles[0]; ++}; ++ ++struct ib_uverbs_ex_create_rwq_ind_table_resp { ++ __u32 comp_mask; ++ __u32 response_length; ++ __u32 ind_tbl_handle; ++ __u32 ind_tbl_num; ++}; ++ ++struct ib_uverbs_ex_destroy_rwq_ind_table { ++ __u32 comp_mask; ++ __u32 ind_tbl_handle; ++}; ++ ++struct ib_uverbs_cq_moderation { ++ __u16 cq_count; ++ __u16 cq_period; ++}; ++ ++struct ib_uverbs_ex_modify_cq { ++ __u32 cq_handle; ++ __u32 attr_mask; ++ struct ib_uverbs_cq_moderation attr; ++ __u32 reserved; ++}; ++ ++#define IB_DEVICE_NAME_MAX 64 ++ ++#endif /* IB_USER_VERBS_H */ +diff --git a/src/rc-compat/v37/kern-abi.h b/src/rc-compat/v37/kern-abi.h +new file mode 100644 +index 000000000000..570b05fec462 +--- /dev/null ++++ b/src/rc-compat/v37/kern-abi.h +@@ -0,0 +1,322 @@ ++/* ++ * Copyright (c) 2005 Topspin Communications. All rights reserved. ++ * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved. ++ * Copyright (c) 2005 PathScale, Inc. All rights reserved. ++ * ++ * This software is available to you under a choice of one of two ++ * licenses. You may choose to be licensed under the terms of the GNU ++ * General Public License (GPL) Version 2, available from the file ++ * COPYING in the main directory of this source tree, or the ++ * OpenIB.org BSD license below: ++ * ++ * Redistribution and use in source and binary forms, with or ++ * without modification, are permitted provided that the following ++ * conditions are met: ++ * ++ * - Redistributions of source code must retain the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer. ++ * ++ * - Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials ++ * provided with the distribution. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS ++ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. ++ */ ++ ++#ifndef KERN_ABI_H ++#define KERN_ABI_H ++ ++#include ++#include ++#include ++ ++#include ++#include "kernel-abi_ib_user_verbs.h" ++ ++/* ++ * The minimum and maximum kernel ABI that we can handle. ++ */ ++#define IB_USER_VERBS_MIN_ABI_VERSION 3 ++#define IB_USER_VERBS_MAX_ABI_VERSION 6 ++ ++struct ex_hdr { ++ struct ib_uverbs_cmd_hdr hdr; ++ struct ib_uverbs_ex_cmd_hdr ex_hdr; ++}; ++ ++/* ++ * These macros expand to type names that refer to the ABI structure type ++ * associated with the given enum string. ++ */ ++#define IBV_ABI_REQ(_enum) _ABI_REQ_STRUCT_##_enum ++#define IBV_KABI_REQ(_enum) _KABI_REQ_STRUCT_##_enum ++#define IBV_KABI_RESP(_enum) _KABI_RESP_STRUCT_##_enum ++ ++#define IBV_ABI_ALIGN(_enum) _ABI_ALIGN_##_enum ++ ++/* ++ * Historically the code had copied the data in the kernel headers, modified ++ * it and placed them in structs. To avoid recoding eveything we continue to ++ * preserve the same struct layout, with the kernel struct 'loose' inside the ++ * modified userspace struct. ++ * ++ * This is automated with the make_abi_structs.py script which produces the ++ * _STRUCT_xx macro that produces a tagless version of the kernel struct. The ++ * tagless struct produces a layout that matches the original code. ++ */ ++#define DECLARE_CMDX(_enum, _name, _kabi, _kabi_resp) \ ++ struct _name { \ ++ struct ib_uverbs_cmd_hdr hdr; \ ++ union { \ ++ _STRUCT_##_kabi; \ ++ struct _kabi core_payload; \ ++ }; \ ++ }; \ ++ typedef struct _name IBV_ABI_REQ(_enum); \ ++ typedef struct _kabi IBV_KABI_REQ(_enum); \ ++ typedef struct _kabi_resp IBV_KABI_RESP(_enum); \ ++ enum { IBV_ABI_ALIGN(_enum) = 4 }; \ ++ static_assert(sizeof(struct _kabi_resp) % 4 == 0, \ ++ "Bad resp alignment"); \ ++ static_assert(_enum != -1, "Bad enum"); \ ++ static_assert(sizeof(struct _name) == \ ++ sizeof(struct ib_uverbs_cmd_hdr) + \ ++ sizeof(struct _kabi), \ ++ "Bad size") ++ ++#define DECLARE_CMD(_enum, _name, _kabi) \ ++ DECLARE_CMDX(_enum, _name, _kabi, _kabi##_resp) ++ ++#define DECLARE_CMD_EXX(_enum, _name, _kabi, _kabi_resp) \ ++ struct _name { \ ++ struct ex_hdr hdr; \ ++ union { \ ++ _STRUCT_##_kabi; \ ++ struct _kabi core_payload; \ ++ }; \ ++ }; \ ++ typedef struct _name IBV_ABI_REQ(_enum); \ ++ typedef struct _kabi IBV_KABI_REQ(_enum); \ ++ typedef struct _kabi_resp IBV_KABI_RESP(_enum); \ ++ enum { IBV_ABI_ALIGN(_enum) = 8 }; \ ++ static_assert(_enum != -1, "Bad enum"); \ ++ static_assert(sizeof(struct _kabi) % 8 == 0, "Bad req alignment"); \ ++ static_assert(sizeof(struct _kabi_resp) % 8 == 0, \ ++ "Bad resp alignment"); \ ++ static_assert(sizeof(struct _name) == \ ++ sizeof(struct ex_hdr) + sizeof(struct _kabi), \ ++ "Bad size"); \ ++ static_assert(sizeof(struct _name) % 8 == 0, "Bad alignment") ++#define DECLARE_CMD_EX(_enum, _name, _kabi) \ ++ DECLARE_CMD_EXX(_enum, _name, _kabi, _kabi##_resp) ++ ++/* Drivers may use 'empty' for _kabi to signal no struct */ ++struct empty {}; ++#define _STRUCT_empty struct {} ++ ++/* ++ * Define the ABI struct for use by the driver. The internal cmd APIs require ++ * this layout. The driver specifies the enum # they wish to define for and ++ * the base name, and the macros figure out the rest correctly. ++ * ++ * The static asserts check that the layout produced by the wrapper struct has ++ * no implicit padding in strange places, specifically between the core ++ * structure and the driver structure and between the driver structure and the ++ * end of the struct. ++ * ++ * Implicit padding can arise in various cases where the structs are not sizes ++ * to a multiple of 8 bytes. ++ */ ++#define DECLARE_DRV_CMD(_name, _enum, _kabi_req, _kabi_resp) \ ++ struct _name { \ ++ IBV_ABI_REQ(_enum) ibv_cmd; \ ++ union { \ ++ _STRUCT_##_kabi_req; \ ++ struct _kabi_req drv_payload; \ ++ }; \ ++ }; \ ++ struct _name##_resp { \ ++ IBV_KABI_RESP(_enum) ibv_resp; \ ++ union { \ ++ _STRUCT_##_kabi_resp; \ ++ struct _kabi_resp drv_payload; \ ++ }; \ ++ }; \ ++ static_assert(sizeof(IBV_KABI_REQ(_enum)) % \ ++ __alignof__(struct _kabi_req) == \ ++ 0, \ ++ "Bad kabi req struct length"); \ ++ static_assert(sizeof(struct _name) == \ ++ sizeof(IBV_ABI_REQ(_enum)) + \ ++ sizeof(struct _kabi_req), \ ++ "Bad req size"); \ ++ static_assert(sizeof(struct _name) % IBV_ABI_ALIGN(_enum) == 0, \ ++ "Bad kabi req alignment"); \ ++ static_assert(sizeof(IBV_KABI_RESP(_enum)) % \ ++ __alignof__(struct _kabi_resp) == \ ++ 0, \ ++ "Bad kabi resp struct length"); \ ++ static_assert(sizeof(struct _name##_resp) == \ ++ sizeof(IBV_KABI_RESP(_enum)) + \ ++ sizeof(struct _kabi_resp), \ ++ "Bad resp size"); \ ++ static_assert(sizeof(struct _name##_resp) % IBV_ABI_ALIGN(_enum) == 0, \ ++ "Bad kabi resp alignment"); ++ ++DECLARE_CMD(IB_USER_VERBS_CMD_ALLOC_MW, ibv_alloc_mw, ib_uverbs_alloc_mw); ++DECLARE_CMD(IB_USER_VERBS_CMD_ALLOC_PD, ibv_alloc_pd, ib_uverbs_alloc_pd); ++DECLARE_CMDX(IB_USER_VERBS_CMD_ATTACH_MCAST, ibv_attach_mcast, ib_uverbs_attach_mcast, empty); ++DECLARE_CMDX(IB_USER_VERBS_CMD_CLOSE_XRCD, ibv_close_xrcd, ib_uverbs_close_xrcd, empty); ++DECLARE_CMD(IB_USER_VERBS_CMD_CREATE_AH, ibv_create_ah, ib_uverbs_create_ah); ++DECLARE_CMD(IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL, ibv_create_comp_channel, ib_uverbs_create_comp_channel); ++DECLARE_CMD(IB_USER_VERBS_CMD_CREATE_CQ, ibv_create_cq, ib_uverbs_create_cq); ++DECLARE_CMD(IB_USER_VERBS_CMD_CREATE_QP, ibv_create_qp, ib_uverbs_create_qp); ++DECLARE_CMD(IB_USER_VERBS_CMD_CREATE_SRQ, ibv_create_srq, ib_uverbs_create_srq); ++DECLARE_CMDX(IB_USER_VERBS_CMD_CREATE_XSRQ, ibv_create_xsrq, ib_uverbs_create_xsrq, ib_uverbs_create_srq_resp); ++DECLARE_CMDX(IB_USER_VERBS_CMD_DEALLOC_MW, ibv_dealloc_mw, ib_uverbs_dealloc_mw, empty); ++DECLARE_CMDX(IB_USER_VERBS_CMD_DEALLOC_PD, ibv_dealloc_pd, ib_uverbs_dealloc_pd, empty); ++DECLARE_CMDX(IB_USER_VERBS_CMD_DEREG_MR, ibv_dereg_mr, ib_uverbs_dereg_mr, empty); ++DECLARE_CMDX(IB_USER_VERBS_CMD_DESTROY_AH, ibv_destroy_ah, ib_uverbs_destroy_ah, empty); ++DECLARE_CMD(IB_USER_VERBS_CMD_DESTROY_CQ, ibv_destroy_cq, ib_uverbs_destroy_cq); ++DECLARE_CMD(IB_USER_VERBS_CMD_DESTROY_QP, ibv_destroy_qp, ib_uverbs_destroy_qp); ++DECLARE_CMD(IB_USER_VERBS_CMD_DESTROY_SRQ, ibv_destroy_srq, ib_uverbs_destroy_srq); ++DECLARE_CMDX(IB_USER_VERBS_CMD_DETACH_MCAST, ibv_detach_mcast, ib_uverbs_detach_mcast, empty); ++DECLARE_CMD(IB_USER_VERBS_CMD_GET_CONTEXT, ibv_get_context, ib_uverbs_get_context); ++DECLARE_CMDX(IB_USER_VERBS_CMD_MODIFY_QP, ibv_modify_qp, ib_uverbs_modify_qp, empty); ++DECLARE_CMDX(IB_USER_VERBS_CMD_MODIFY_SRQ, ibv_modify_srq, ib_uverbs_modify_srq, empty); ++DECLARE_CMDX(IB_USER_VERBS_CMD_OPEN_QP, ibv_open_qp, ib_uverbs_open_qp, ib_uverbs_create_qp_resp); ++DECLARE_CMD(IB_USER_VERBS_CMD_OPEN_XRCD, ibv_open_xrcd, ib_uverbs_open_xrcd); ++DECLARE_CMD(IB_USER_VERBS_CMD_POLL_CQ, ibv_poll_cq, ib_uverbs_poll_cq); ++DECLARE_CMD(IB_USER_VERBS_CMD_POST_RECV, ibv_post_recv, ib_uverbs_post_recv); ++DECLARE_CMD(IB_USER_VERBS_CMD_POST_SEND, ibv_post_send, ib_uverbs_post_send); ++DECLARE_CMD(IB_USER_VERBS_CMD_POST_SRQ_RECV, ibv_post_srq_recv, ib_uverbs_post_srq_recv); ++DECLARE_CMD(IB_USER_VERBS_CMD_QUERY_DEVICE, ibv_query_device, ib_uverbs_query_device); ++DECLARE_CMD(IB_USER_VERBS_CMD_QUERY_PORT, ibv_query_port, ib_uverbs_query_port); ++DECLARE_CMD(IB_USER_VERBS_CMD_QUERY_QP, ibv_query_qp, ib_uverbs_query_qp); ++DECLARE_CMD(IB_USER_VERBS_CMD_QUERY_SRQ, ibv_query_srq, ib_uverbs_query_srq); ++DECLARE_CMD(IB_USER_VERBS_CMD_REG_MR, ibv_reg_mr, ib_uverbs_reg_mr); ++DECLARE_CMDX(IB_USER_VERBS_CMD_REQ_NOTIFY_CQ, ibv_req_notify_cq, ib_uverbs_req_notify_cq, empty); ++DECLARE_CMD(IB_USER_VERBS_CMD_REREG_MR, ibv_rereg_mr, ib_uverbs_rereg_mr); ++DECLARE_CMD(IB_USER_VERBS_CMD_RESIZE_CQ, ibv_resize_cq, ib_uverbs_resize_cq); ++ ++DECLARE_CMD_EX(IB_USER_VERBS_EX_CMD_CREATE_CQ, ibv_create_cq_ex, ib_uverbs_ex_create_cq); ++DECLARE_CMD_EX(IB_USER_VERBS_EX_CMD_CREATE_FLOW, ibv_create_flow, ib_uverbs_create_flow); ++DECLARE_CMD_EX(IB_USER_VERBS_EX_CMD_CREATE_QP, ibv_create_qp_ex, ib_uverbs_ex_create_qp); ++DECLARE_CMD_EX(IB_USER_VERBS_EX_CMD_CREATE_RWQ_IND_TBL, ibv_create_rwq_ind_table, ib_uverbs_ex_create_rwq_ind_table); ++DECLARE_CMD_EX(IB_USER_VERBS_EX_CMD_CREATE_WQ, ibv_create_wq, ib_uverbs_ex_create_wq); ++DECLARE_CMD_EXX(IB_USER_VERBS_EX_CMD_DESTROY_FLOW, ibv_destroy_flow, ib_uverbs_destroy_flow, empty); ++DECLARE_CMD_EXX(IB_USER_VERBS_EX_CMD_DESTROY_RWQ_IND_TBL, ibv_destroy_rwq_ind_table, ib_uverbs_ex_destroy_rwq_ind_table, empty); ++DECLARE_CMD_EX(IB_USER_VERBS_EX_CMD_DESTROY_WQ, ibv_destroy_wq, ib_uverbs_ex_destroy_wq); ++DECLARE_CMD_EXX(IB_USER_VERBS_EX_CMD_MODIFY_CQ, ibv_modify_cq, ib_uverbs_ex_modify_cq, empty); ++DECLARE_CMD_EX(IB_USER_VERBS_EX_CMD_MODIFY_QP, ibv_modify_qp_ex, ib_uverbs_ex_modify_qp); ++DECLARE_CMD_EXX(IB_USER_VERBS_EX_CMD_MODIFY_WQ, ibv_modify_wq, ib_uverbs_ex_modify_wq, empty); ++DECLARE_CMD_EX(IB_USER_VERBS_EX_CMD_QUERY_DEVICE, ibv_query_device_ex, ib_uverbs_ex_query_device); ++ ++/* ++ * Both ib_uverbs_create_qp and ib_uverbs_ex_create_qp start with the same ++ * structure, this function converts the ex version into the normal version ++ */ ++static inline struct ib_uverbs_create_qp * ++ibv_create_qp_ex_to_reg(struct ibv_create_qp_ex *cmd_ex) ++{ ++ /* ++ * user_handle is the start in both places, note that the ex ++ * does not have response located in the same place, so response ++ * cannot be touched. ++ */ ++ return container_of(&cmd_ex->user_handle, struct ib_uverbs_create_qp, ++ user_handle); ++} ++ ++/* ++ * This file contains copied data from the kernel's include/uapi/rdma/ib_user_verbs.h, ++ * now included above. ++ * ++ * Whenever possible use the definition from the kernel header and avoid ++ * copying from that header into this file. ++ */ ++ ++struct ibv_kern_ipv4_filter { ++ __u32 src_ip; ++ __u32 dst_ip; ++}; ++ ++struct ibv_kern_spec_ipv4 { ++ __u32 type; ++ __u16 size; ++ __u16 reserved; ++ struct ibv_kern_ipv4_filter val; ++ struct ibv_kern_ipv4_filter mask; ++}; ++ ++struct ibv_kern_spec { ++ union { ++ struct ib_uverbs_flow_spec_hdr hdr; ++ struct ib_uverbs_flow_spec_eth eth; ++ struct ibv_kern_spec_ipv4 ipv4; ++ struct ib_uverbs_flow_spec_ipv4 ipv4_ext; ++ struct ib_uverbs_flow_spec_esp esp; ++ struct ib_uverbs_flow_spec_tcp_udp tcp_udp; ++ struct ib_uverbs_flow_spec_ipv6 ipv6; ++ struct ib_uverbs_flow_spec_gre gre; ++ struct ib_uverbs_flow_spec_tunnel tunnel; ++ struct ib_uverbs_flow_spec_mpls mpls; ++ struct ib_uverbs_flow_spec_action_tag flow_tag; ++ struct ib_uverbs_flow_spec_action_drop drop; ++ struct ib_uverbs_flow_spec_action_handle handle; ++ struct ib_uverbs_flow_spec_action_count flow_count; ++ }; ++}; ++ ++struct ib_uverbs_modify_srq_v3 { ++ __u32 srq_handle; ++ __u32 attr_mask; ++ __u32 max_wr; ++ __u32 max_sge; ++ __u32 srq_limit; ++ __u32 reserved; ++}; ++#define _STRUCT_ib_uverbs_modify_srq_v3 ++enum { IB_USER_VERBS_CMD_MODIFY_SRQ_V3 = IB_USER_VERBS_CMD_MODIFY_SRQ }; ++DECLARE_CMDX(IB_USER_VERBS_CMD_MODIFY_SRQ_V3, ibv_modify_srq_v3, ib_uverbs_modify_srq_v3, empty); ++ ++struct ibv_create_qp_resp_v3 { ++ __u32 qp_handle; ++ __u32 qpn; ++}; ++ ++struct ibv_create_qp_resp_v4 { ++ __u32 qp_handle; ++ __u32 qpn; ++ __u32 max_send_wr; ++ __u32 max_recv_wr; ++ __u32 max_send_sge; ++ __u32 max_recv_sge; ++ __u32 max_inline_data; ++}; ++ ++struct ibv_create_srq_resp_v5 { ++ __u32 srq_handle; ++}; ++ ++#define _STRUCT_ib_uverbs_create_srq_v5 ++enum { IB_USER_VERBS_CMD_CREATE_SRQ_V5 = IB_USER_VERBS_CMD_CREATE_SRQ }; ++DECLARE_CMDX(IB_USER_VERBS_CMD_CREATE_SRQ_V5, ibv_create_srq_v5, ib_uverbs_create_srq, ibv_create_srq_resp_v5); ++ ++#define _STRUCT_ib_uverbs_create_qp_v4 ++enum { IB_USER_VERBS_CMD_CREATE_QP_V4 = IB_USER_VERBS_CMD_CREATE_QP }; ++DECLARE_CMDX(IB_USER_VERBS_CMD_CREATE_QP_V4, ibv_create_qp_v4, ib_uverbs_create_qp, ibv_create_qp_resp_v4); ++ ++#define _STRUCT_ib_uverbs_create_qp_v3 ++enum { IB_USER_VERBS_CMD_CREATE_QP_V3 = IB_USER_VERBS_CMD_CREATE_QP }; ++DECLARE_CMDX(IB_USER_VERBS_CMD_CREATE_QP_V3, ibv_create_qp_v3, ib_uverbs_create_qp, ibv_create_qp_resp_v3); ++#endif /* KERN_ABI_H */ +diff --git a/src/rc-compat/v37/kernel-abi_ib_user_verbs.h b/src/rc-compat/v37/kernel-abi_ib_user_verbs.h +new file mode 100644 +index 000000000000..fbe4ae635b84 +--- /dev/null ++++ b/src/rc-compat/v37/kernel-abi_ib_user_verbs.h +@@ -0,0 +1,1114 @@ ++#define _STRUCT_ib_uverbs_async_event_desc struct { \ ++__aligned_u64 element; \ ++__u32 event_type; \ ++__u32 reserved; \ ++} ++ ++#define _STRUCT_ib_uverbs_comp_event_desc struct { \ ++__aligned_u64 cq_handle; \ ++} ++ ++#define _STRUCT_ib_uverbs_cq_moderation_caps struct { \ ++__u16 max_cq_moderation_count; \ ++__u16 max_cq_moderation_period; \ ++__u32 reserved; \ ++} ++ ++#define _STRUCT_ib_uverbs_cmd_hdr struct { \ ++__u32 command; \ ++__u16 in_words; \ ++__u16 out_words; \ ++} ++ ++#define _STRUCT_ib_uverbs_ex_cmd_hdr struct { \ ++__aligned_u64 response; \ ++__u16 provider_in_words; \ ++__u16 provider_out_words; \ ++__u32 cmd_hdr_reserved; \ ++} ++ ++#define _STRUCT_ib_uverbs_get_context struct { \ ++__aligned_u64 response; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_get_context_resp struct { \ ++__u32 async_fd; \ ++__u32 num_comp_vectors; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_query_device struct { \ ++__aligned_u64 response; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_query_device_resp struct { \ ++__aligned_u64 fw_ver; \ ++__be64 node_guid; \ ++__be64 sys_image_guid; \ ++__aligned_u64 max_mr_size; \ ++__aligned_u64 page_size_cap; \ ++__u32 vendor_id; \ ++__u32 vendor_part_id; \ ++__u32 hw_ver; \ ++__u32 max_qp; \ ++__u32 max_qp_wr; \ ++__u32 device_cap_flags; \ ++__u32 max_sge; \ ++__u32 max_sge_rd; \ ++__u32 max_cq; \ ++__u32 max_cqe; \ ++__u32 max_mr; \ ++__u32 max_pd; \ ++__u32 max_qp_rd_atom; \ ++__u32 max_ee_rd_atom; \ ++__u32 max_res_rd_atom; \ ++__u32 max_qp_init_rd_atom; \ ++__u32 max_ee_init_rd_atom; \ ++__u32 atomic_cap; \ ++__u32 max_ee; \ ++__u32 max_rdd; \ ++__u32 max_mw; \ ++__u32 max_raw_ipv6_qp; \ ++__u32 max_raw_ethy_qp; \ ++__u32 max_mcast_grp; \ ++__u32 max_mcast_qp_attach; \ ++__u32 max_total_mcast_qp_attach; \ ++__u32 max_ah; \ ++__u32 max_fmr; \ ++__u32 max_map_per_fmr; \ ++__u32 max_srq; \ ++__u32 max_srq_wr; \ ++__u32 max_srq_sge; \ ++__u16 max_pkeys; \ ++__u8 local_ca_ack_delay; \ ++__u8 phys_port_cnt; \ ++__u8 reserved[4]; \ ++} ++ ++#define _STRUCT_ib_uverbs_ex_query_device struct { \ ++__u32 comp_mask; \ ++__u32 reserved; \ ++} ++ ++#define _STRUCT_ib_uverbs_odp_caps struct { \ ++__aligned_u64 general_caps; \ ++struct { \ ++__u32 rc_odp_caps; \ ++__u32 uc_odp_caps; \ ++__u32 ud_odp_caps; \ ++} per_transport_caps; \ ++__u32 reserved; \ ++} ++ ++#define _STRUCT_ib_uverbs_rss_caps struct { \ ++/* Corresponding bit will be set if qp type from \ ++* 'enum ib_qp_type' is supported, e.g. \ ++* supported_qpts |= 1 << IB_QPT_UD \ ++*/ \ ++__u32 supported_qpts; \ ++__u32 max_rwq_indirection_tables; \ ++__u32 max_rwq_indirection_table_size; \ ++__u32 reserved; \ ++} ++ ++#define _STRUCT_ib_uverbs_tm_caps struct { \ ++ \ ++__u32 max_rndv_hdr_size; \ ++ \ ++__u32 max_num_tags; \ ++ \ ++__u32 flags; \ ++ \ ++__u32 max_ops; \ ++ \ ++__u32 max_sge; \ ++__u32 reserved; \ ++} ++ ++#define _STRUCT_ib_uverbs_ex_query_device_resp struct { \ ++struct ib_uverbs_query_device_resp base; \ ++__u32 comp_mask; \ ++__u32 response_length; \ ++struct ib_uverbs_odp_caps odp_caps; \ ++__aligned_u64 timestamp_mask; \ ++__aligned_u64 hca_core_clock; \ ++__aligned_u64 device_cap_flags_ex; \ ++struct ib_uverbs_rss_caps rss_caps; \ ++__u32 max_wq_type_rq; \ ++__u32 raw_packet_caps; \ ++struct ib_uverbs_tm_caps tm_caps; \ ++struct ib_uverbs_cq_moderation_caps cq_moderation_caps; \ ++__aligned_u64 max_dm_size; \ ++__u32 xrc_odp_caps; \ ++__u32 reserved; \ ++} ++ ++#define _STRUCT_ib_uverbs_query_port struct { \ ++__aligned_u64 response; \ ++__u8 port_num; \ ++__u8 reserved[7]; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_query_port_resp struct { \ ++__u32 port_cap_flags; \ ++__u32 max_msg_sz; \ ++__u32 bad_pkey_cntr; \ ++__u32 qkey_viol_cntr; \ ++__u32 gid_tbl_len; \ ++__u16 pkey_tbl_len; \ ++__u16 lid; \ ++__u16 sm_lid; \ ++__u8 state; \ ++__u8 max_mtu; \ ++__u8 active_mtu; \ ++__u8 lmc; \ ++__u8 max_vl_num; \ ++__u8 sm_sl; \ ++__u8 subnet_timeout; \ ++__u8 init_type_reply; \ ++__u8 active_width; \ ++__u8 active_speed; \ ++__u8 phys_state; \ ++__u8 link_layer; \ ++__u8 flags; \ ++__u8 reserved; \ ++} ++ ++#define _STRUCT_ib_uverbs_alloc_pd struct { \ ++__aligned_u64 response; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_alloc_pd_resp struct { \ ++__u32 pd_handle; \ ++__u32 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_dealloc_pd struct { \ ++__u32 pd_handle; \ ++} ++ ++#define _STRUCT_ib_uverbs_open_xrcd struct { \ ++__aligned_u64 response; \ ++__u32 fd; \ ++__u32 oflags; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_open_xrcd_resp struct { \ ++__u32 xrcd_handle; \ ++__u32 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_close_xrcd struct { \ ++__u32 xrcd_handle; \ ++} ++ ++#define _STRUCT_ib_uverbs_reg_mr struct { \ ++__aligned_u64 response; \ ++__aligned_u64 start; \ ++__aligned_u64 length; \ ++__aligned_u64 hca_va; \ ++__u32 pd_handle; \ ++__u32 access_flags; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_reg_mr_resp struct { \ ++__u32 mr_handle; \ ++__u32 lkey; \ ++__u32 rkey; \ ++__u32 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_rereg_mr struct { \ ++__aligned_u64 response; \ ++__u32 mr_handle; \ ++__u32 flags; \ ++__aligned_u64 start; \ ++__aligned_u64 length; \ ++__aligned_u64 hca_va; \ ++__u32 pd_handle; \ ++__u32 access_flags; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_rereg_mr_resp struct { \ ++__u32 lkey; \ ++__u32 rkey; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_dereg_mr struct { \ ++__u32 mr_handle; \ ++} ++ ++#define _STRUCT_ib_uverbs_alloc_mw struct { \ ++__aligned_u64 response; \ ++__u32 pd_handle; \ ++__u8 mw_type; \ ++__u8 reserved[3]; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_alloc_mw_resp struct { \ ++__u32 mw_handle; \ ++__u32 rkey; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_dealloc_mw struct { \ ++__u32 mw_handle; \ ++} ++ ++#define _STRUCT_ib_uverbs_create_comp_channel struct { \ ++__aligned_u64 response; \ ++} ++ ++#define _STRUCT_ib_uverbs_create_comp_channel_resp struct { \ ++__u32 fd; \ ++} ++ ++#define _STRUCT_ib_uverbs_create_cq struct { \ ++__aligned_u64 response; \ ++__aligned_u64 user_handle; \ ++__u32 cqe; \ ++__u32 comp_vector; \ ++__s32 comp_channel; \ ++__u32 reserved; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_ex_create_cq struct { \ ++__aligned_u64 user_handle; \ ++__u32 cqe; \ ++__u32 comp_vector; \ ++__s32 comp_channel; \ ++__u32 comp_mask; \ ++__u32 flags; \ ++__u32 reserved; \ ++} ++ ++#define _STRUCT_ib_uverbs_create_cq_resp struct { \ ++__u32 cq_handle; \ ++__u32 cqe; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_ex_create_cq_resp struct { \ ++struct ib_uverbs_create_cq_resp base; \ ++__u32 comp_mask; \ ++__u32 response_length; \ ++} ++ ++#define _STRUCT_ib_uverbs_resize_cq struct { \ ++__aligned_u64 response; \ ++__u32 cq_handle; \ ++__u32 cqe; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_resize_cq_resp struct { \ ++__u32 cqe; \ ++__u32 reserved; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_poll_cq struct { \ ++__aligned_u64 response; \ ++__u32 cq_handle; \ ++__u32 ne; \ ++} ++ ++#define _STRUCT_ib_uverbs_wc struct { \ ++__aligned_u64 wr_id; \ ++__u32 status; \ ++__u32 opcode; \ ++__u32 vendor_err; \ ++__u32 byte_len; \ ++union { \ ++__be32 imm_data; \ ++__u32 invalidate_rkey; \ ++} ex; \ ++__u32 qp_num; \ ++__u32 src_qp; \ ++__u32 wc_flags; \ ++__u16 pkey_index; \ ++__u16 slid; \ ++__u8 sl; \ ++__u8 dlid_path_bits; \ ++__u8 port_num; \ ++__u8 reserved; \ ++} ++ ++#define _STRUCT_ib_uverbs_poll_cq_resp struct { \ ++__u32 count; \ ++__u32 reserved; \ ++struct ib_uverbs_wc wc[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_req_notify_cq struct { \ ++__u32 cq_handle; \ ++__u32 solicited_only; \ ++} ++ ++#define _STRUCT_ib_uverbs_destroy_cq struct { \ ++__aligned_u64 response; \ ++__u32 cq_handle; \ ++__u32 reserved; \ ++} ++ ++#define _STRUCT_ib_uverbs_destroy_cq_resp struct { \ ++__u32 comp_events_reported; \ ++__u32 async_events_reported; \ ++} ++ ++#define _STRUCT_ib_uverbs_global_route struct { \ ++__u8 dgid[16]; \ ++__u32 flow_label; \ ++__u8 sgid_index; \ ++__u8 hop_limit; \ ++__u8 traffic_class; \ ++__u8 reserved; \ ++} ++ ++#define _STRUCT_ib_uverbs_ah_attr struct { \ ++struct ib_uverbs_global_route grh; \ ++__u16 dlid; \ ++__u8 sl; \ ++__u8 src_path_bits; \ ++__u8 static_rate; \ ++__u8 is_global; \ ++__u8 port_num; \ ++__u8 reserved; \ ++} ++ ++#define _STRUCT_ib_uverbs_qp_attr struct { \ ++__u32 qp_attr_mask; \ ++__u32 qp_state; \ ++__u32 cur_qp_state; \ ++__u32 path_mtu; \ ++__u32 path_mig_state; \ ++__u32 qkey; \ ++__u32 rq_psn; \ ++__u32 sq_psn; \ ++__u32 dest_qp_num; \ ++__u32 qp_access_flags; \ ++ \ ++struct ib_uverbs_ah_attr ah_attr; \ ++struct ib_uverbs_ah_attr alt_ah_attr; \ ++ \ ++ \ ++__u32 max_send_wr; \ ++__u32 max_recv_wr; \ ++__u32 max_send_sge; \ ++__u32 max_recv_sge; \ ++__u32 max_inline_data; \ ++ \ ++__u16 pkey_index; \ ++__u16 alt_pkey_index; \ ++__u8 en_sqd_async_notify; \ ++__u8 sq_draining; \ ++__u8 max_rd_atomic; \ ++__u8 max_dest_rd_atomic; \ ++__u8 min_rnr_timer; \ ++__u8 port_num; \ ++__u8 timeout; \ ++__u8 retry_cnt; \ ++__u8 rnr_retry; \ ++__u8 alt_port_num; \ ++__u8 alt_timeout; \ ++__u8 reserved[5]; \ ++} ++ ++#define _STRUCT_ib_uverbs_create_qp struct { \ ++__aligned_u64 response; \ ++__aligned_u64 user_handle; \ ++__u32 pd_handle; \ ++__u32 send_cq_handle; \ ++__u32 recv_cq_handle; \ ++__u32 srq_handle; \ ++__u32 max_send_wr; \ ++__u32 max_recv_wr; \ ++__u32 max_send_sge; \ ++__u32 max_recv_sge; \ ++__u32 max_inline_data; \ ++__u8 sq_sig_all; \ ++__u8 qp_type; \ ++__u8 is_srq; \ ++__u8 reserved; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_ex_create_qp struct { \ ++__aligned_u64 user_handle; \ ++__u32 pd_handle; \ ++__u32 send_cq_handle; \ ++__u32 recv_cq_handle; \ ++__u32 srq_handle; \ ++__u32 max_send_wr; \ ++__u32 max_recv_wr; \ ++__u32 max_send_sge; \ ++__u32 max_recv_sge; \ ++__u32 max_inline_data; \ ++__u8 sq_sig_all; \ ++__u8 qp_type; \ ++__u8 is_srq; \ ++__u8 reserved; \ ++__u32 comp_mask; \ ++__u32 create_flags; \ ++__u32 rwq_ind_tbl_handle; \ ++__u32 source_qpn; \ ++} ++ ++#define _STRUCT_ib_uverbs_open_qp struct { \ ++__aligned_u64 response; \ ++__aligned_u64 user_handle; \ ++__u32 pd_handle; \ ++__u32 qpn; \ ++__u8 qp_type; \ ++__u8 reserved[7]; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_create_qp_resp struct { \ ++__u32 qp_handle; \ ++__u32 qpn; \ ++__u32 max_send_wr; \ ++__u32 max_recv_wr; \ ++__u32 max_send_sge; \ ++__u32 max_recv_sge; \ ++__u32 max_inline_data; \ ++__u32 reserved; \ ++__u32 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_ex_create_qp_resp struct { \ ++struct ib_uverbs_create_qp_resp base; \ ++__u32 comp_mask; \ ++__u32 response_length; \ ++} ++ ++#define _STRUCT_ib_uverbs_qp_dest struct { \ ++__u8 dgid[16]; \ ++__u32 flow_label; \ ++__u16 dlid; \ ++__u16 reserved; \ ++__u8 sgid_index; \ ++__u8 hop_limit; \ ++__u8 traffic_class; \ ++__u8 sl; \ ++__u8 src_path_bits; \ ++__u8 static_rate; \ ++__u8 is_global; \ ++__u8 port_num; \ ++} ++ ++#define _STRUCT_ib_uverbs_query_qp struct { \ ++__aligned_u64 response; \ ++__u32 qp_handle; \ ++__u32 attr_mask; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_query_qp_resp struct { \ ++struct ib_uverbs_qp_dest dest; \ ++struct ib_uverbs_qp_dest alt_dest; \ ++__u32 max_send_wr; \ ++__u32 max_recv_wr; \ ++__u32 max_send_sge; \ ++__u32 max_recv_sge; \ ++__u32 max_inline_data; \ ++__u32 qkey; \ ++__u32 rq_psn; \ ++__u32 sq_psn; \ ++__u32 dest_qp_num; \ ++__u32 qp_access_flags; \ ++__u16 pkey_index; \ ++__u16 alt_pkey_index; \ ++__u8 qp_state; \ ++__u8 cur_qp_state; \ ++__u8 path_mtu; \ ++__u8 path_mig_state; \ ++__u8 sq_draining; \ ++__u8 max_rd_atomic; \ ++__u8 max_dest_rd_atomic; \ ++__u8 min_rnr_timer; \ ++__u8 port_num; \ ++__u8 timeout; \ ++__u8 retry_cnt; \ ++__u8 rnr_retry; \ ++__u8 alt_port_num; \ ++__u8 alt_timeout; \ ++__u8 sq_sig_all; \ ++__u8 reserved[5]; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_modify_qp struct { \ ++struct ib_uverbs_qp_dest dest; \ ++struct ib_uverbs_qp_dest alt_dest; \ ++__u32 qp_handle; \ ++__u32 attr_mask; \ ++__u32 qkey; \ ++__u32 rq_psn; \ ++__u32 sq_psn; \ ++__u32 dest_qp_num; \ ++__u32 qp_access_flags; \ ++__u16 pkey_index; \ ++__u16 alt_pkey_index; \ ++__u8 qp_state; \ ++__u8 cur_qp_state; \ ++__u8 path_mtu; \ ++__u8 path_mig_state; \ ++__u8 en_sqd_async_notify; \ ++__u8 max_rd_atomic; \ ++__u8 max_dest_rd_atomic; \ ++__u8 min_rnr_timer; \ ++__u8 port_num; \ ++__u8 timeout; \ ++__u8 retry_cnt; \ ++__u8 rnr_retry; \ ++__u8 alt_port_num; \ ++__u8 alt_timeout; \ ++__u8 reserved[2]; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_ex_modify_qp struct { \ ++struct ib_uverbs_modify_qp base; \ ++__u32 rate_limit; \ ++__u32 reserved; \ ++} ++ ++#define _STRUCT_ib_uverbs_ex_modify_qp_resp struct { \ ++__u32 comp_mask; \ ++__u32 response_length; \ ++} ++ ++#define _STRUCT_ib_uverbs_destroy_qp struct { \ ++__aligned_u64 response; \ ++__u32 qp_handle; \ ++__u32 reserved; \ ++} ++ ++#define _STRUCT_ib_uverbs_destroy_qp_resp struct { \ ++__u32 events_reported; \ ++} ++ ++#define _STRUCT_ib_uverbs_sge struct { \ ++__aligned_u64 addr; \ ++__u32 length; \ ++__u32 lkey; \ ++} ++ ++#define _STRUCT_ib_uverbs_send_wr struct { \ ++__aligned_u64 wr_id; \ ++__u32 num_sge; \ ++__u32 opcode; \ ++__u32 send_flags; \ ++union { \ ++__be32 imm_data; \ ++__u32 invalidate_rkey; \ ++} ex; \ ++union { \ ++struct { \ ++__aligned_u64 remote_addr; \ ++__u32 rkey; \ ++__u32 reserved; \ ++} rdma; \ ++struct { \ ++__aligned_u64 remote_addr; \ ++__aligned_u64 compare_add; \ ++__aligned_u64 swap; \ ++__u32 rkey; \ ++__u32 reserved; \ ++} atomic; \ ++struct { \ ++__u32 ah; \ ++__u32 remote_qpn; \ ++__u32 remote_qkey; \ ++__u32 reserved; \ ++} ud; \ ++} wr; \ ++} ++ ++#define _STRUCT_ib_uverbs_post_send struct { \ ++__aligned_u64 response; \ ++__u32 qp_handle; \ ++__u32 wr_count; \ ++__u32 sge_count; \ ++__u32 wqe_size; \ ++struct ib_uverbs_send_wr send_wr[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_post_send_resp struct { \ ++__u32 bad_wr; \ ++} ++ ++#define _STRUCT_ib_uverbs_recv_wr struct { \ ++__aligned_u64 wr_id; \ ++__u32 num_sge; \ ++__u32 reserved; \ ++} ++ ++#define _STRUCT_ib_uverbs_post_recv struct { \ ++__aligned_u64 response; \ ++__u32 qp_handle; \ ++__u32 wr_count; \ ++__u32 sge_count; \ ++__u32 wqe_size; \ ++struct ib_uverbs_recv_wr recv_wr[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_post_recv_resp struct { \ ++__u32 bad_wr; \ ++} ++ ++#define _STRUCT_ib_uverbs_post_srq_recv struct { \ ++__aligned_u64 response; \ ++__u32 srq_handle; \ ++__u32 wr_count; \ ++__u32 sge_count; \ ++__u32 wqe_size; \ ++struct ib_uverbs_recv_wr recv[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_post_srq_recv_resp struct { \ ++__u32 bad_wr; \ ++} ++ ++#define _STRUCT_ib_uverbs_create_ah struct { \ ++__aligned_u64 response; \ ++__aligned_u64 user_handle; \ ++__u32 pd_handle; \ ++__u32 reserved; \ ++struct ib_uverbs_ah_attr attr; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_create_ah_resp struct { \ ++__u32 ah_handle; \ ++__u32 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_destroy_ah struct { \ ++__u32 ah_handle; \ ++} ++ ++#define _STRUCT_ib_uverbs_attach_mcast struct { \ ++__u8 gid[16]; \ ++__u32 qp_handle; \ ++__u16 mlid; \ ++__u16 reserved; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_detach_mcast struct { \ ++__u8 gid[16]; \ ++__u32 qp_handle; \ ++__u16 mlid; \ ++__u16 reserved; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_flow_spec_hdr struct { \ ++__u32 type; \ ++__u16 size; \ ++__u16 reserved; \ ++ \ ++__aligned_u64 flow_spec_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_flow_eth_filter struct { \ ++__u8 dst_mac[6]; \ ++__u8 src_mac[6]; \ ++__be16 ether_type; \ ++__be16 vlan_tag; \ ++} ++ ++#define _STRUCT_ib_uverbs_flow_spec_eth struct { \ ++union { \ ++struct ib_uverbs_flow_spec_hdr hdr; \ ++struct { \ ++__u32 type; \ ++__u16 size; \ ++__u16 reserved; \ ++}; \ ++}; \ ++struct ib_uverbs_flow_eth_filter val; \ ++struct ib_uverbs_flow_eth_filter mask; \ ++} ++ ++#define _STRUCT_ib_uverbs_flow_ipv4_filter struct { \ ++__be32 src_ip; \ ++__be32 dst_ip; \ ++__u8 proto; \ ++__u8 tos; \ ++__u8 ttl; \ ++__u8 flags; \ ++} ++ ++#define _STRUCT_ib_uverbs_flow_spec_ipv4 struct { \ ++union { \ ++struct ib_uverbs_flow_spec_hdr hdr; \ ++struct { \ ++__u32 type; \ ++__u16 size; \ ++__u16 reserved; \ ++}; \ ++}; \ ++struct ib_uverbs_flow_ipv4_filter val; \ ++struct ib_uverbs_flow_ipv4_filter mask; \ ++} ++ ++#define _STRUCT_ib_uverbs_flow_tcp_udp_filter struct { \ ++__be16 dst_port; \ ++__be16 src_port; \ ++} ++ ++#define _STRUCT_ib_uverbs_flow_spec_tcp_udp struct { \ ++union { \ ++struct ib_uverbs_flow_spec_hdr hdr; \ ++struct { \ ++__u32 type; \ ++__u16 size; \ ++__u16 reserved; \ ++}; \ ++}; \ ++struct ib_uverbs_flow_tcp_udp_filter val; \ ++struct ib_uverbs_flow_tcp_udp_filter mask; \ ++} ++ ++#define _STRUCT_ib_uverbs_flow_ipv6_filter struct { \ ++__u8 src_ip[16]; \ ++__u8 dst_ip[16]; \ ++__be32 flow_label; \ ++__u8 next_hdr; \ ++__u8 traffic_class; \ ++__u8 hop_limit; \ ++__u8 reserved; \ ++} ++ ++#define _STRUCT_ib_uverbs_flow_spec_ipv6 struct { \ ++union { \ ++struct ib_uverbs_flow_spec_hdr hdr; \ ++struct { \ ++__u32 type; \ ++__u16 size; \ ++__u16 reserved; \ ++}; \ ++}; \ ++struct ib_uverbs_flow_ipv6_filter val; \ ++struct ib_uverbs_flow_ipv6_filter mask; \ ++} ++ ++#define _STRUCT_ib_uverbs_flow_spec_action_tag struct { \ ++union { \ ++struct ib_uverbs_flow_spec_hdr hdr; \ ++struct { \ ++__u32 type; \ ++__u16 size; \ ++__u16 reserved; \ ++}; \ ++}; \ ++__u32 tag_id; \ ++__u32 reserved1; \ ++} ++ ++#define _STRUCT_ib_uverbs_flow_spec_action_drop struct { \ ++union { \ ++struct ib_uverbs_flow_spec_hdr hdr; \ ++struct { \ ++__u32 type; \ ++__u16 size; \ ++__u16 reserved; \ ++}; \ ++}; \ ++} ++ ++#define _STRUCT_ib_uverbs_flow_spec_action_handle struct { \ ++union { \ ++struct ib_uverbs_flow_spec_hdr hdr; \ ++struct { \ ++__u32 type; \ ++__u16 size; \ ++__u16 reserved; \ ++}; \ ++}; \ ++__u32 handle; \ ++__u32 reserved1; \ ++} ++ ++#define _STRUCT_ib_uverbs_flow_spec_action_count struct { \ ++union { \ ++struct ib_uverbs_flow_spec_hdr hdr; \ ++struct { \ ++__u32 type; \ ++__u16 size; \ ++__u16 reserved; \ ++}; \ ++}; \ ++__u32 handle; \ ++__u32 reserved1; \ ++} ++ ++#define _STRUCT_ib_uverbs_flow_tunnel_filter struct { \ ++__be32 tunnel_id; \ ++} ++ ++#define _STRUCT_ib_uverbs_flow_spec_tunnel struct { \ ++union { \ ++struct ib_uverbs_flow_spec_hdr hdr; \ ++struct { \ ++__u32 type; \ ++__u16 size; \ ++__u16 reserved; \ ++}; \ ++}; \ ++struct ib_uverbs_flow_tunnel_filter val; \ ++struct ib_uverbs_flow_tunnel_filter mask; \ ++} ++ ++#define _STRUCT_ib_uverbs_flow_spec_esp_filter struct { \ ++__u32 spi; \ ++__u32 seq; \ ++} ++ ++#define _STRUCT_ib_uverbs_flow_spec_esp struct { \ ++union { \ ++struct ib_uverbs_flow_spec_hdr hdr; \ ++struct { \ ++__u32 type; \ ++__u16 size; \ ++__u16 reserved; \ ++}; \ ++}; \ ++struct ib_uverbs_flow_spec_esp_filter val; \ ++struct ib_uverbs_flow_spec_esp_filter mask; \ ++} ++ ++#define _STRUCT_ib_uverbs_flow_gre_filter struct { \ ++/* c_ks_res0_ver field is bits 0-15 in offset 0 of a standard GRE header: \ ++* bit 0 - C - checksum bit. \ ++* bit 1 - reserved. set to 0. \ ++* bit 2 - key bit. \ ++* bit 3 - sequence number bit. \ ++* bits 4:12 - reserved. set to 0. \ ++* bits 13:15 - GRE version. \ ++*/ \ ++__be16 c_ks_res0_ver; \ ++__be16 protocol; \ ++__be32 key; \ ++} ++ ++#define _STRUCT_ib_uverbs_flow_spec_gre struct { \ ++union { \ ++struct ib_uverbs_flow_spec_hdr hdr; \ ++struct { \ ++__u32 type; \ ++__u16 size; \ ++__u16 reserved; \ ++}; \ ++}; \ ++struct ib_uverbs_flow_gre_filter val; \ ++struct ib_uverbs_flow_gre_filter mask; \ ++} ++ ++#define _STRUCT_ib_uverbs_flow_mpls_filter struct { \ ++/* The field includes the entire MPLS label: \ ++* bits 0:19 - label field. \ ++* bits 20:22 - traffic class field. \ ++* bits 23 - bottom of stack bit. \ ++* bits 24:31 - ttl field. \ ++*/ \ ++__be32 label; \ ++} ++ ++#define _STRUCT_ib_uverbs_flow_spec_mpls struct { \ ++union { \ ++struct ib_uverbs_flow_spec_hdr hdr; \ ++struct { \ ++__u32 type; \ ++__u16 size; \ ++__u16 reserved; \ ++}; \ ++}; \ ++struct ib_uverbs_flow_mpls_filter val; \ ++struct ib_uverbs_flow_mpls_filter mask; \ ++} ++ ++#define _STRUCT_ib_uverbs_flow_attr struct { \ ++__u32 type; \ ++__u16 size; \ ++__u16 priority; \ ++__u8 num_of_specs; \ ++__u8 reserved[2]; \ ++__u8 port; \ ++__u32 flags; \ ++/* Following are the optional layers according to user request \ ++* struct ib_flow_spec_xxx \ ++* struct ib_flow_spec_yyy \ ++*/ \ ++struct ib_uverbs_flow_spec_hdr flow_specs[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_create_flow struct { \ ++__u32 comp_mask; \ ++__u32 qp_handle; \ ++struct ib_uverbs_flow_attr flow_attr; \ ++} ++ ++#define _STRUCT_ib_uverbs_create_flow_resp struct { \ ++__u32 comp_mask; \ ++__u32 flow_handle; \ ++} ++ ++#define _STRUCT_ib_uverbs_destroy_flow struct { \ ++__u32 comp_mask; \ ++__u32 flow_handle; \ ++} ++ ++#define _STRUCT_ib_uverbs_create_srq struct { \ ++__aligned_u64 response; \ ++__aligned_u64 user_handle; \ ++__u32 pd_handle; \ ++__u32 max_wr; \ ++__u32 max_sge; \ ++__u32 srq_limit; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_create_xsrq struct { \ ++__aligned_u64 response; \ ++__aligned_u64 user_handle; \ ++__u32 srq_type; \ ++__u32 pd_handle; \ ++__u32 max_wr; \ ++__u32 max_sge; \ ++__u32 srq_limit; \ ++__u32 max_num_tags; \ ++__u32 xrcd_handle; \ ++__u32 cq_handle; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_create_srq_resp struct { \ ++__u32 srq_handle; \ ++__u32 max_wr; \ ++__u32 max_sge; \ ++__u32 srqn; \ ++__u32 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_modify_srq struct { \ ++__u32 srq_handle; \ ++__u32 attr_mask; \ ++__u32 max_wr; \ ++__u32 srq_limit; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_query_srq struct { \ ++__aligned_u64 response; \ ++__u32 srq_handle; \ ++__u32 reserved; \ ++__aligned_u64 driver_data[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_query_srq_resp struct { \ ++__u32 max_wr; \ ++__u32 max_sge; \ ++__u32 srq_limit; \ ++__u32 reserved; \ ++} ++ ++#define _STRUCT_ib_uverbs_destroy_srq struct { \ ++__aligned_u64 response; \ ++__u32 srq_handle; \ ++__u32 reserved; \ ++} ++ ++#define _STRUCT_ib_uverbs_destroy_srq_resp struct { \ ++__u32 events_reported; \ ++} ++ ++#define _STRUCT_ib_uverbs_ex_create_wq struct { \ ++__u32 comp_mask; \ ++__u32 wq_type; \ ++__aligned_u64 user_handle; \ ++__u32 pd_handle; \ ++__u32 cq_handle; \ ++__u32 max_wr; \ ++__u32 max_sge; \ ++__u32 create_flags; \ ++__u32 reserved; \ ++} ++ ++#define _STRUCT_ib_uverbs_ex_create_wq_resp struct { \ ++__u32 comp_mask; \ ++__u32 response_length; \ ++__u32 wq_handle; \ ++__u32 max_wr; \ ++__u32 max_sge; \ ++__u32 wqn; \ ++} ++ ++#define _STRUCT_ib_uverbs_ex_destroy_wq struct { \ ++__u32 comp_mask; \ ++__u32 wq_handle; \ ++} ++ ++#define _STRUCT_ib_uverbs_ex_destroy_wq_resp struct { \ ++__u32 comp_mask; \ ++__u32 response_length; \ ++__u32 events_reported; \ ++__u32 reserved; \ ++} ++ ++#define _STRUCT_ib_uverbs_ex_modify_wq struct { \ ++__u32 attr_mask; \ ++__u32 wq_handle; \ ++__u32 wq_state; \ ++__u32 curr_wq_state; \ ++__u32 flags; \ ++__u32 flags_mask; \ ++} ++ ++#define _STRUCT_ib_uverbs_ex_create_rwq_ind_table struct { \ ++__u32 comp_mask; \ ++__u32 log_ind_tbl_size; \ ++/* Following are the wq handles according to log_ind_tbl_size \ ++* wq_handle1 \ ++* wq_handle2 \ ++*/ \ ++__u32 wq_handles[0]; \ ++} ++ ++#define _STRUCT_ib_uverbs_ex_create_rwq_ind_table_resp struct { \ ++__u32 comp_mask; \ ++__u32 response_length; \ ++__u32 ind_tbl_handle; \ ++__u32 ind_tbl_num; \ ++} ++ ++#define _STRUCT_ib_uverbs_ex_destroy_rwq_ind_table struct { \ ++__u32 comp_mask; \ ++__u32 ind_tbl_handle; \ ++} ++ ++#define _STRUCT_ib_uverbs_cq_moderation struct { \ ++__u16 cq_count; \ ++__u16 cq_period; \ ++} ++ ++#define _STRUCT_ib_uverbs_ex_modify_cq struct { \ ++__u32 cq_handle; \ ++__u32 attr_mask; \ ++struct ib_uverbs_cq_moderation attr; \ ++__u32 reserved; \ ++} ++ +diff --git a/src/rc-compat/v37/rdma_user_ioctl_cmds.h b/src/rc-compat/v37/rdma_user_ioctl_cmds.h +new file mode 100644 +index 000000000000..38ab7accb7be +--- /dev/null ++++ b/src/rc-compat/v37/rdma_user_ioctl_cmds.h +@@ -0,0 +1,87 @@ ++/* ++ * Copyright (c) 2018, Mellanox Technologies inc. All rights reserved. ++ * ++ * This software is available to you under a choice of one of two ++ * licenses. You may choose to be licensed under the terms of the GNU ++ * General Public License (GPL) Version 2, available from the file ++ * COPYING in the main directory of this source tree, or the ++ * OpenIB.org BSD license below: ++ * ++ * Redistribution and use in source and binary forms, with or ++ * without modification, are permitted provided that the following ++ * conditions are met: ++ * ++ * - Redistributions of source code must retain the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer. ++ * ++ * - Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials ++ * provided with the distribution. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS ++ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. ++ */ ++ ++#ifndef RDMA_USER_IOCTL_CMDS_H ++#define RDMA_USER_IOCTL_CMDS_H ++ ++#include ++#include ++ ++/* Documentation/userspace-api/ioctl/ioctl-number.rst */ ++#define RDMA_IOCTL_MAGIC 0x1b ++#define RDMA_VERBS_IOCTL \ ++ _IOWR(RDMA_IOCTL_MAGIC, 1, struct ib_uverbs_ioctl_hdr) ++ ++enum { ++ /* User input */ ++ UVERBS_ATTR_F_MANDATORY = 1U << 0, ++ /* ++ * Valid output bit should be ignored and considered set in ++ * mandatory fields. This bit is kernel output. ++ */ ++ UVERBS_ATTR_F_VALID_OUTPUT = 1U << 1, ++}; ++ ++struct ib_uverbs_attr { ++ __u16 attr_id; /* command specific type attribute */ ++ __u16 len; /* only for pointers and IDRs array */ ++ __u16 flags; /* combination of UVERBS_ATTR_F_XXXX */ ++ union { ++ struct { ++ __u8 elem_id; ++ __u8 reserved; ++ } enum_data; ++ __u16 reserved; ++ } attr_data; ++ union { ++ /* ++ * ptr to command, inline data, idr/fd or ++ * ptr to __u32 array of IDRs ++ */ ++ __aligned_u64 data; ++ /* Used by FD_IN and FD_OUT */ ++ __s64 data_s64; ++ }; ++}; ++ ++struct ib_uverbs_ioctl_hdr { ++ __u16 length; ++ __u16 object_id; ++ __u16 method_id; ++ __u16 num_attrs; ++ __aligned_u64 reserved1; ++ __u32 driver_id; ++ __u32 reserved2; ++ struct ib_uverbs_attr attrs[0]; ++}; ++ ++#endif +diff --git a/src/rc-compat/v37/util/cl_qmap.h b/src/rc-compat/v37/util/cl_qmap.h +new file mode 100644 +index 000000000000..1a800f2c8fec +--- /dev/null ++++ b/src/rc-compat/v37/util/cl_qmap.h +@@ -0,0 +1,970 @@ ++/* ++ * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. ++ * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. ++ * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. ++ * ++ * This software is available to you under a choice of one of two ++ * licenses. You may choose to be licensed under the terms of the GNU ++ * General Public License (GPL) Version 2, available from the file ++ * COPYING in the main directory of this source tree, or the ++ * OpenIB.org BSD license below: ++ * ++ * Redistribution and use in source and binary forms, with or ++ * without modification, are permitted provided that the following ++ * conditions are met: ++ * ++ * - Redistributions of source code must retain the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer. ++ * ++ * - Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials ++ * provided with the distribution. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS ++ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. ++ * ++ */ ++ ++/* ++ * Abstract: ++ * Declaration of quick map, a binary tree where the caller always provides ++ * all necessary storage. ++ */ ++ ++#ifndef _CL_QMAP_H_ ++#define _CL_QMAP_H_ ++ ++#include ++#include ++#include ++#include ++ ++typedef struct _cl_list_item { ++ struct _cl_list_item *p_next; ++ struct _cl_list_item *p_prev; ++} cl_list_item_t; ++ ++typedef struct _cl_pool_item { ++ cl_list_item_t list_item; ++} cl_pool_item_t; ++ ++/****h* Component Library/Quick Map ++* NAME ++* Quick Map ++* ++* DESCRIPTION ++* Quick map implements a binary tree that stores user provided cl_map_item_t ++* structures. Each item stored in a quick map has a unique 64-bit key ++* (duplicates are not allowed). Quick map provides the ability to ++* efficiently search for an item given a key. ++* ++* Quick map does not allocate any memory, and can therefore not fail ++* any operations due to insufficient memory. Quick map can thus be useful ++* in minimizing the error paths in code. ++* ++* Quick map is not thread safe, and users must provide serialization when ++* adding and removing items from the map. ++* ++* The quick map functions operate on a cl_qmap_t structure which should be ++* treated as opaque and should be manipulated only through the provided ++* functions. ++* ++* SEE ALSO ++* Structures: ++* cl_qmap_t, cl_map_item_t, cl_map_obj_t ++* ++* Callbacks: ++* cl_pfn_qmap_apply_t ++* ++* Item Manipulation: ++* cl_qmap_set_obj, cl_qmap_obj, cl_qmap_key ++* ++* Initialization: ++* cl_qmap_init ++* ++* Iteration: ++* cl_qmap_end, cl_qmap_head, cl_qmap_tail, cl_qmap_next, cl_qmap_prev ++* ++* Manipulation: ++* cl_qmap_insert, cl_qmap_get, cl_qmap_remove_item, cl_qmap_remove, ++* cl_qmap_remove_all, cl_qmap_merge, cl_qmap_delta, cl_qmap_get_next ++* ++* Search: ++* cl_qmap_apply_func ++* ++* Attributes: ++* cl_qmap_count, cl_is_qmap_empty, ++*********/ ++/****i* Component Library: Quick Map/cl_map_color_t ++* NAME ++* cl_map_color_t ++* ++* DESCRIPTION ++* The cl_map_color_t enumerated type is used to note the color of ++* nodes in a map. ++* ++* SYNOPSIS ++*/ ++typedef enum _cl_map_color { ++ CL_MAP_RED, ++ CL_MAP_BLACK ++} cl_map_color_t; ++/* ++* VALUES ++* CL_MAP_RED ++* The node in the map is red. ++* ++* CL_MAP_BLACK ++* The node in the map is black. ++* ++* SEE ALSO ++* Quick Map, cl_map_item_t ++*********/ ++ ++/****s* Component Library: Quick Map/cl_map_item_t ++* NAME ++* cl_map_item_t ++* ++* DESCRIPTION ++* The cl_map_item_t structure is used by maps to store objects. ++* ++* The cl_map_item_t structure should be treated as opaque and should ++* be manipulated only through the provided functions. ++* ++* SYNOPSIS ++*/ ++typedef struct _cl_map_item { ++ /* Must be first to allow casting. */ ++ cl_pool_item_t pool_item; ++ struct _cl_map_item *p_left; ++ struct _cl_map_item *p_right; ++ struct _cl_map_item *p_up; ++ cl_map_color_t color; ++ uint64_t key; ++#ifdef _DEBUG_ ++ struct _cl_qmap *p_map; ++#endif ++} cl_map_item_t; ++/* ++* FIELDS ++* pool_item ++* Used to store the item in a doubly linked list, allowing more ++* efficient map traversal. ++* ++* p_left ++* Pointer to the map item that is a child to the left of the node. ++* ++* p_right ++* Pointer to the map item that is a child to the right of the node. ++* ++* p_up ++* Pointer to the map item that is the parent of the node. ++* ++* color ++* Indicates whether a node is red or black in the map. ++* ++* key ++* Value that uniquely represents a node in a map. This value is ++* set by calling cl_qmap_insert and can be retrieved by calling ++* cl_qmap_key. ++* ++* NOTES ++* None of the fields of this structure should be manipulated by users, as ++* they are crititcal to the proper operation of the map in which they ++* are stored. ++* ++* To allow storing items in either a quick list, a quick pool, or a quick ++* map, the map implementation guarantees that the map item can be safely ++* cast to a pool item used for storing an object in a quick pool, or cast ++* to a list item used for storing an object in a quick list. This removes ++* the need to embed a map item, a list item, and a pool item in objects ++* that need to be stored in a quick list, a quick pool, and a quick map. ++* ++* SEE ALSO ++* Quick Map, cl_qmap_insert, cl_qmap_key, cl_pool_item_t, cl_list_item_t ++*********/ ++ ++/****s* Component Library: Quick Map/cl_map_obj_t ++* NAME ++* cl_map_obj_t ++* ++* DESCRIPTION ++* The cl_map_obj_t structure is used to store objects in maps. ++* ++* The cl_map_obj_t structure should be treated as opaque and should ++* be manipulated only through the provided functions. ++* ++* SYNOPSIS ++*/ ++typedef struct _cl_map_obj { ++ cl_map_item_t item; ++ const void *p_object; ++} cl_map_obj_t; ++/* ++* FIELDS ++* item ++* Map item used by internally by the map to store an object. ++* ++* p_object ++* User defined context. Users should not access this field directly. ++* Use cl_qmap_set_obj and cl_qmap_obj to set and retrieve the value ++* of this field. ++* ++* NOTES ++* None of the fields of this structure should be manipulated by users, as ++* they are crititcal to the proper operation of the map in which they ++* are stored. ++* ++* Use cl_qmap_set_obj and cl_qmap_obj to set and retrieve the object ++* stored in a map item, respectively. ++* ++* SEE ALSO ++* Quick Map, cl_qmap_set_obj, cl_qmap_obj, cl_map_item_t ++*********/ ++ ++/****s* Component Library: Quick Map/cl_qmap_t ++* NAME ++* cl_qmap_t ++* ++* DESCRIPTION ++* Quick map structure. ++* ++* The cl_qmap_t structure should be treated as opaque and should ++* be manipulated only through the provided functions. ++* ++* SYNOPSIS ++*/ ++typedef struct _cl_qmap { ++ cl_map_item_t root; ++ cl_map_item_t nil; ++ size_t count; ++} cl_qmap_t; ++/* ++* PARAMETERS ++* root ++* Map item that serves as root of the map. The root is set up to ++* always have itself as parent. The left pointer is set to point ++* to the item at the root. ++* ++* nil ++* Map item that serves as terminator for all leaves, as well as ++* providing the list item used as quick list for storing map items ++* in a list for faster traversal. ++* ++* state ++* State of the map, used to verify that operations are permitted. ++* ++* count ++* Number of items in the map. ++* ++* SEE ALSO ++* Quick Map ++*********/ ++ ++/****d* Component Library: Quick Map/cl_pfn_qmap_apply_t ++* NAME ++* cl_pfn_qmap_apply_t ++* ++* DESCRIPTION ++* The cl_pfn_qmap_apply_t function type defines the prototype for ++* functions used to iterate items in a quick map. ++* ++* SYNOPSIS ++*/ ++typedef void ++ (*cl_pfn_qmap_apply_t) (cl_map_item_t * const p_map_item, void *context); ++/* ++* PARAMETERS ++* p_map_item ++* [in] Pointer to a cl_map_item_t structure. ++* ++* context ++* [in] Value passed to the callback function. ++* ++* RETURN VALUE ++* This function does not return a value. ++* ++* NOTES ++* This function type is provided as function prototype reference for the ++* function provided by users as a parameter to the cl_qmap_apply_func ++* function. ++* ++* SEE ALSO ++* Quick Map, cl_qmap_apply_func ++*********/ ++ ++/****f* Component Library: Quick Map/cl_qmap_count ++* NAME ++* cl_qmap_count ++* ++* DESCRIPTION ++* The cl_qmap_count function returns the number of items stored ++* in a quick map. ++* ++* SYNOPSIS ++*/ ++static inline uint32_t cl_qmap_count(const cl_qmap_t * const p_map) ++{ ++ assert(p_map); ++ return ((uint32_t) p_map->count); ++} ++ ++/* ++* PARAMETERS ++* p_map ++* [in] Pointer to a cl_qmap_t structure whose item count to return. ++* ++* RETURN VALUE ++* Returns the number of items stored in the map. ++* ++* SEE ALSO ++* Quick Map, cl_is_qmap_empty ++*********/ ++ ++/****f* Component Library: Quick Map/cl_is_qmap_empty ++* NAME ++* cl_is_qmap_empty ++* ++* DESCRIPTION ++* The cl_is_qmap_empty function returns whether a quick map is empty. ++* ++* SYNOPSIS ++*/ ++static inline bool cl_is_qmap_empty(const cl_qmap_t * const p_map) ++{ ++ assert(p_map); ++ ++ return (p_map->count == 0); ++} ++ ++/* ++* PARAMETERS ++* p_map ++* [in] Pointer to a cl_qmap_t structure to test for emptiness. ++* ++* RETURN VALUES ++* TRUE if the quick map is empty. ++* ++* FALSE otherwise. ++* ++* SEE ALSO ++* Quick Map, cl_qmap_count, cl_qmap_remove_all ++*********/ ++ ++/****f* Component Library: Quick Map/cl_qmap_set_obj ++* NAME ++* cl_qmap_set_obj ++* ++* DESCRIPTION ++* The cl_qmap_set_obj function sets the object stored in a map object. ++* ++* SYNOPSIS ++*/ ++static inline void ++cl_qmap_set_obj(cl_map_obj_t * const p_map_obj, ++ const void *const p_object) ++{ ++ assert(p_map_obj); ++ p_map_obj->p_object = p_object; ++} ++ ++/* ++* PARAMETERS ++* p_map_obj ++* [in] Pointer to a map object stucture whose object pointer ++* is to be set. ++* ++* p_object ++* [in] User defined context. ++* ++* RETURN VALUE ++* This function does not return a value. ++* ++* SEE ALSO ++* Quick Map, cl_qmap_obj ++*********/ ++ ++/****f* Component Library: Quick Map/cl_qmap_obj ++* NAME ++* cl_qmap_obj ++* ++* DESCRIPTION ++* The cl_qmap_obj function returns the object stored in a map object. ++* ++* SYNOPSIS ++*/ ++static inline void *cl_qmap_obj(const cl_map_obj_t * const p_map_obj) ++{ ++ assert(p_map_obj); ++ return ((void *)p_map_obj->p_object); ++} ++ ++/* ++* PARAMETERS ++* p_map_obj ++* [in] Pointer to a map object stucture whose object pointer to return. ++* ++* RETURN VALUE ++* Returns the value of the object pointer stored in the map object. ++* ++* SEE ALSO ++* Quick Map, cl_qmap_set_obj ++*********/ ++ ++/****f* Component Library: Quick Map/cl_qmap_key ++* NAME ++* cl_qmap_key ++* ++* DESCRIPTION ++* The cl_qmap_key function retrieves the key value of a map item. ++* ++* SYNOPSIS ++*/ ++static inline uint64_t cl_qmap_key(const cl_map_item_t * const p_item) ++{ ++ assert(p_item); ++ return (p_item->key); ++} ++ ++/* ++* PARAMETERS ++* p_item ++* [in] Pointer to a map item whose key value to return. ++* ++* RETURN VALUE ++* Returns the 64-bit key value for the specified map item. ++* ++* NOTES ++* The key value is set in a call to cl_qmap_insert. ++* ++* SEE ALSO ++* Quick Map, cl_qmap_insert ++*********/ ++ ++/****f* Component Library: Quick Map/cl_qmap_init ++* NAME ++* cl_qmap_init ++* ++* DESCRIPTION ++* The cl_qmap_init function initialized a quick map for use. ++* ++* SYNOPSIS ++*/ ++void cl_qmap_init(cl_qmap_t * const p_map); ++/* ++* PARAMETERS ++* p_map ++* [in] Pointer to a cl_qmap_t structure to initialize. ++* ++* RETURN VALUES ++* This function does not return a value. ++* ++* NOTES ++* Allows calling quick map manipulation functions. ++* ++* SEE ALSO ++* Quick Map, cl_qmap_insert, cl_qmap_remove ++*********/ ++ ++/****f* Component Library: Quick Map/cl_qmap_end ++* NAME ++* cl_qmap_end ++* ++* DESCRIPTION ++* The cl_qmap_end function returns the end of a quick map. ++* ++* SYNOPSIS ++*/ ++static inline const cl_map_item_t *cl_qmap_end(const cl_qmap_t * const p_map) ++{ ++ assert(p_map); ++ /* Nil is the end of the map. */ ++ return (&p_map->nil); ++} ++ ++/* ++* PARAMETERS ++* p_map ++* [in] Pointer to a cl_qmap_t structure whose end to return. ++* ++* RETURN VALUE ++* Pointer to the end of the map. ++* ++* NOTES ++* cl_qmap_end is useful for determining the validity of map items returned ++* by cl_qmap_head, cl_qmap_tail, cl_qmap_next, or cl_qmap_prev. If the ++* map item pointer returned by any of these functions compares to the end, ++* the end of the map was encoutered. ++* When using cl_qmap_head or cl_qmap_tail, this condition indicates that ++* the map is empty. ++* ++* SEE ALSO ++* Quick Map, cl_qmap_head, cl_qmap_tail, cl_qmap_next, cl_qmap_prev ++*********/ ++ ++/****f* Component Library: Quick Map/cl_qmap_head ++* NAME ++* cl_qmap_head ++* ++* DESCRIPTION ++* The cl_qmap_head function returns the map item with the lowest key ++* value stored in a quick map. ++* ++* SYNOPSIS ++*/ ++static inline cl_map_item_t *cl_qmap_head(const cl_qmap_t * const p_map) ++{ ++ assert(p_map); ++ return ((cl_map_item_t *) p_map->nil.pool_item.list_item.p_next); ++} ++ ++/* ++* PARAMETERS ++* p_map ++* [in] Pointer to a cl_qmap_t structure whose item with the lowest ++* key is returned. ++* ++* RETURN VALUES ++* Pointer to the map item with the lowest key in the quick map. ++* ++* Pointer to the map end if the quick map was empty. ++* ++* NOTES ++* cl_qmap_head does not remove the item from the map. ++* ++* SEE ALSO ++* Quick Map, cl_qmap_tail, cl_qmap_next, cl_qmap_prev, cl_qmap_end, ++* cl_qmap_item_t ++*********/ ++ ++/****f* Component Library: Quick Map/cl_qmap_tail ++* NAME ++* cl_qmap_tail ++* ++* DESCRIPTION ++* The cl_qmap_tail function returns the map item with the highest key ++* value stored in a quick map. ++* ++* SYNOPSIS ++*/ ++static inline cl_map_item_t *cl_qmap_tail(const cl_qmap_t * const p_map) ++{ ++ assert(p_map); ++ return ((cl_map_item_t *) p_map->nil.pool_item.list_item.p_prev); ++} ++ ++/* ++* PARAMETERS ++* p_map ++* [in] Pointer to a cl_qmap_t structure whose item with the ++* highest key is returned. ++* ++* RETURN VALUES ++* Pointer to the map item with the highest key in the quick map. ++* ++* Pointer to the map end if the quick map was empty. ++* ++* NOTES ++* cl_qmap_end does not remove the item from the map. ++* ++* SEE ALSO ++* Quick Map, cl_qmap_head, cl_qmap_next, cl_qmap_prev, cl_qmap_end, ++* cl_qmap_item_t ++*********/ ++ ++/****f* Component Library: Quick Map/cl_qmap_next ++* NAME ++* cl_qmap_next ++* ++* DESCRIPTION ++* The cl_qmap_next function returns the map item with the next higher ++* key value than a specified map item. ++* ++* SYNOPSIS ++*/ ++static inline cl_map_item_t *cl_qmap_next(const cl_map_item_t * const p_item) ++{ ++ assert(p_item); ++ return ((cl_map_item_t *) p_item->pool_item.list_item.p_next); ++} ++ ++/* ++* PARAMETERS ++* p_item ++* [in] Pointer to a map item whose successor to return. ++* ++* RETURN VALUES ++* Pointer to the map item with the next higher key value in a quick map. ++* ++* Pointer to the map end if the specified item was the last item in ++* the quick map. ++* ++* SEE ALSO ++* Quick Map, cl_qmap_head, cl_qmap_tail, cl_qmap_prev, cl_qmap_end, ++* cl_map_item_t ++*********/ ++ ++/****f* Component Library: Quick Map/cl_qmap_prev ++* NAME ++* cl_qmap_prev ++* ++* DESCRIPTION ++* The cl_qmap_prev function returns the map item with the next lower ++* key value than a precified map item. ++* ++* SYNOPSIS ++*/ ++static inline cl_map_item_t *cl_qmap_prev(const cl_map_item_t * const p_item) ++{ ++ assert(p_item); ++ return ((cl_map_item_t *) p_item->pool_item.list_item.p_prev); ++} ++ ++/* ++* PARAMETERS ++* p_item ++* [in] Pointer to a map item whose predecessor to return. ++* ++* RETURN VALUES ++* Pointer to the map item with the next lower key value in a quick map. ++* ++* Pointer to the map end if the specifid item was the first item in ++* the quick map. ++* ++* SEE ALSO ++* Quick Map, cl_qmap_head, cl_qmap_tail, cl_qmap_next, cl_qmap_end, ++* cl_map_item_t ++*********/ ++ ++/****f* Component Library: Quick Map/cl_qmap_insert ++* NAME ++* cl_qmap_insert ++* ++* DESCRIPTION ++* The cl_qmap_insert function inserts a map item into a quick map. ++* NOTE: Only if such a key does not alerady exist in the map !!!! ++* ++* SYNOPSIS ++*/ ++cl_map_item_t *cl_qmap_insert(cl_qmap_t * const p_map, ++ const uint64_t key, ++ cl_map_item_t * const p_item); ++/* ++* PARAMETERS ++* p_map ++* [in] Pointer to a cl_qmap_t structure into which to add the item. ++* ++* key ++* [in] Value to assign to the item. ++* ++* p_item ++* [in] Pointer to a cl_map_item_t stucture to insert into the quick map. ++* ++* RETURN VALUE ++* Pointer to the item in the map with the specified key. If insertion ++* was successful, this is the pointer to the item. If an item with the ++* specified key already exists in the map, the pointer to that item is ++* returned - but the new key is NOT inserted... ++* ++* NOTES ++* Insertion operations may cause the quick map to rebalance. ++* ++* SEE ALSO ++* Quick Map, cl_qmap_remove, cl_map_item_t ++*********/ ++ ++/****f* Component Library: Quick Map/cl_qmap_get ++* NAME ++* cl_qmap_get ++* ++* DESCRIPTION ++* The cl_qmap_get function returns the map item associated with a key. ++* ++* SYNOPSIS ++*/ ++cl_map_item_t *cl_qmap_get(const cl_qmap_t * const p_map, ++ const uint64_t key); ++/* ++* PARAMETERS ++* p_map ++* [in] Pointer to a cl_qmap_t structure from which to retrieve the ++* item with the specified key. ++* ++* key ++* [in] Key value used to search for the desired map item. ++* ++* RETURN VALUES ++* Pointer to the map item with the desired key value. ++* ++* Pointer to the map end if there was no item with the desired key value ++* stored in the quick map. ++* ++* NOTES ++* cl_qmap_get does not remove the item from the quick map. ++* ++* SEE ALSO ++* Quick Map, cl_qmap_get_next, cl_qmap_remove ++*********/ ++ ++/****f* Component Library: Quick Map/cl_qmap_get_next ++* NAME ++* cl_qmap_get_next ++* ++* DESCRIPTION ++* The cl_qmap_get_next function returns the first map item associated with a ++* key > the key specified. ++* ++* SYNOPSIS ++*/ ++cl_map_item_t *cl_qmap_get_next(const cl_qmap_t * const p_map, ++ const uint64_t key); ++/* ++* PARAMETERS ++* p_map ++* [in] Pointer to a cl_qmap_t structure from which to retrieve the ++* first item with a key > the specified key. ++* ++* key ++* [in] Key value used to search for the desired map item. ++* ++* RETURN VALUES ++* Pointer to the first map item with a key > the desired key value. ++* ++* Pointer to the map end if there was no item with a key > the desired key ++* value stored in the quick map. ++* ++* NOTES ++* cl_qmap_get_next does not remove the item from the quick map. ++* ++* SEE ALSO ++* Quick Map, cl_qmap_get, cl_qmap_remove ++*********/ ++ ++/****f* Component Library: Quick Map/cl_qmap_remove_item ++* NAME ++* cl_qmap_remove_item ++* ++* DESCRIPTION ++* The cl_qmap_remove_item function removes the specified map item ++* from a quick map. ++* ++* SYNOPSIS ++*/ ++void ++cl_qmap_remove_item(cl_qmap_t * const p_map, ++ cl_map_item_t * const p_item); ++/* ++* PARAMETERS ++* p_map ++* [in] Pointer to a cl_qmap_t structure from which to ++* remove item. ++* ++* p_item ++* [in] Pointer to a map item to remove from its quick map. ++* ++* RETURN VALUES ++* This function does not return a value. ++* ++* In a debug build, cl_qmap_remove_item asserts that the item being removed ++* is in the specified map. ++* ++* NOTES ++* Removes the map item pointed to by p_item from its quick map. ++* ++* SEE ALSO ++* Quick Map, cl_qmap_remove, cl_qmap_remove_all, cl_qmap_insert ++*********/ ++ ++/****f* Component Library: Quick Map/cl_qmap_remove ++* NAME ++* cl_qmap_remove ++* ++* DESCRIPTION ++* The cl_qmap_remove function removes the map item with the specified key ++* from a quick map. ++* ++* SYNOPSIS ++*/ ++cl_map_item_t *cl_qmap_remove(cl_qmap_t * const p_map, ++ const uint64_t key); ++/* ++* PARAMETERS ++* p_map ++* [in] Pointer to a cl_qmap_t structure from which to remove the item ++* with the specified key. ++* ++* key ++* [in] Key value used to search for the map item to remove. ++* ++* RETURN VALUES ++* Pointer to the removed map item if it was found. ++* ++* Pointer to the map end if no item with the specified key exists in the ++* quick map. ++* ++* SEE ALSO ++* Quick Map, cl_qmap_remove_item, cl_qmap_remove_all, cl_qmap_insert ++*********/ ++ ++/****f* Component Library: Quick Map/cl_qmap_remove_all ++* NAME ++* cl_qmap_remove_all ++* ++* DESCRIPTION ++* The cl_qmap_remove_all function removes all items in a quick map, ++* leaving it empty. ++* ++* SYNOPSIS ++*/ ++static inline void cl_qmap_remove_all(cl_qmap_t * const p_map) ++{ ++ assert(p_map); ++ ++ p_map->root.p_left = &p_map->nil; ++ p_map->nil.pool_item.list_item.p_next = &p_map->nil.pool_item.list_item; ++ p_map->nil.pool_item.list_item.p_prev = &p_map->nil.pool_item.list_item; ++ p_map->count = 0; ++} ++ ++/* ++* PARAMETERS ++* p_map ++* [in] Pointer to a cl_qmap_t structure to empty. ++* ++* RETURN VALUES ++* This function does not return a value. ++* ++* SEE ALSO ++* Quick Map, cl_qmap_remove, cl_qmap_remove_item ++*********/ ++ ++/****f* Component Library: Quick Map/cl_qmap_merge ++* NAME ++* cl_qmap_merge ++* ++* DESCRIPTION ++* The cl_qmap_merge function moves all items from one map to another, ++* excluding duplicates. ++* ++* SYNOPSIS ++*/ ++void ++cl_qmap_merge(cl_qmap_t * const p_dest_map, ++ cl_qmap_t * const p_src_map); ++/* ++* PARAMETERS ++* p_dest_map ++* [out] Pointer to a cl_qmap_t structure to which items should be added. ++* ++* p_src_map ++* [in/out] Pointer to a cl_qmap_t structure whose items to add ++* to p_dest_map. ++* ++* RETURN VALUES ++* This function does not return a value. ++* ++* NOTES ++* Items are evaluated based on their keys only. ++* ++* Upon return from cl_qmap_merge, the quick map referenced by p_src_map ++* contains all duplicate items. ++* ++* SEE ALSO ++* Quick Map, cl_qmap_delta ++*********/ ++ ++/****f* Component Library: Quick Map/cl_qmap_delta ++* NAME ++* cl_qmap_delta ++* ++* DESCRIPTION ++* The cl_qmap_delta function computes the differences between two maps. ++* ++* SYNOPSIS ++*/ ++void ++cl_qmap_delta(cl_qmap_t * const p_map1, ++ cl_qmap_t * const p_map2, ++ cl_qmap_t * const p_new, cl_qmap_t * const p_old); ++/* ++* PARAMETERS ++* p_map1 ++* [in/out] Pointer to the first of two cl_qmap_t structures whose ++* differences to compute. ++* ++* p_map2 ++* [in/out] Pointer to the second of two cl_qmap_t structures whose ++* differences to compute. ++* ++* p_new ++* [out] Pointer to an empty cl_qmap_t structure that contains the ++* items unique to p_map2 upon return from the function. ++* ++* p_old ++* [out] Pointer to an empty cl_qmap_t structure that contains the ++* items unique to p_map1 upon return from the function. ++* ++* RETURN VALUES ++* This function does not return a value. ++* ++* NOTES ++* Items are evaluated based on their keys. Items that exist in both ++* p_map1 and p_map2 remain in their respective maps. Items that ++* exist only p_map1 are moved to p_old. Likewise, items that exist only ++* in p_map2 are moved to p_new. This function can be useful in evaluating ++* changes between two maps. ++* ++* Both maps pointed to by p_new and p_old must be empty on input. This ++* requirement removes the possibility of failures. ++* ++* SEE ALSO ++* Quick Map, cl_qmap_merge ++*********/ ++ ++/****f* Component Library: Quick Map/cl_qmap_apply_func ++* NAME ++* cl_qmap_apply_func ++* ++* DESCRIPTION ++* The cl_qmap_apply_func function executes a specified function ++* for every item stored in a quick map. ++* ++* SYNOPSIS ++*/ ++void ++cl_qmap_apply_func(const cl_qmap_t * const p_map, ++ cl_pfn_qmap_apply_t pfn_func, ++ const void *const context); ++/* ++* PARAMETERS ++* p_map ++* [in] Pointer to a cl_qmap_t structure. ++* ++* pfn_func ++* [in] Function invoked for every item in the quick map. ++* See the cl_pfn_qmap_apply_t function type declaration for ++* details about the callback function. ++* ++* context ++* [in] Value to pass to the callback functions to provide context. ++* ++* RETURN VALUE ++* This function does not return a value. ++* ++* NOTES ++* The function provided must not perform any map operations, as these ++* would corrupt the quick map. ++* ++* SEE ALSO ++* Quick Map, cl_pfn_qmap_apply_t ++*********/ ++ ++#endif /* _CL_QMAP_H_ */ +diff --git a/src/rc-compat/v37/util/compiler.h b/src/rc-compat/v37/util/compiler.h +new file mode 100644 +index 000000000000..dfce82f18841 +--- /dev/null ++++ b/src/rc-compat/v37/util/compiler.h +@@ -0,0 +1,54 @@ ++/* GPLv2 or OpenIB.org BSD (MIT) See COPYING file */ ++#ifndef UTIL_COMPILER_H ++#define UTIL_COMPILER_H ++ ++/* Use to tag a variable that causes compiler warnings. Use as: ++ int uninitialized_var(sz) ++ ++ This is only enabled for old compilers. gcc 6.x and beyond have excellent ++ static flow analysis. If code solicits a warning from 6.x it is almost ++ certainly too complex for a human to understand. For some reason powerpc ++ uses a different scheme than gcc for flow analysis. ++*/ ++#if (__GNUC__ >= 6 && !defined(__powerpc__)) || defined(__clang__) ++#define uninitialized_var(x) x ++#else ++#define uninitialized_var(x) x = x ++#endif ++ ++#ifndef likely ++#ifdef __GNUC__ ++#define likely(x) __builtin_expect(!!(x), 1) ++#else ++#define likely(x) (x) ++#endif ++#endif ++ ++#ifndef unlikely ++#ifdef __GNUC__ ++#define unlikely(x) __builtin_expect(!!(x), 0) ++#else ++#define unlikely(x) (x) ++#endif ++#endif ++ ++#ifdef HAVE_FUNC_ATTRIBUTE_ALWAYS_INLINE ++#define ALWAYS_INLINE __attribute__((always_inline)) ++#else ++#define ALWAYS_INLINE ++#endif ++ ++/* Use to mark fall through on switch statements as desired. */ ++#if __GNUC__ >= 7 ++#define SWITCH_FALLTHROUGH __attribute__ ((fallthrough)) ++#else ++#define SWITCH_FALLTHROUGH ++#endif ++ ++#ifdef __CHECKER__ ++# define __force __attribute__((force)) ++#else ++# define __force ++#endif ++ ++#endif +diff --git a/src/rc-compat/v37/util/mmio.h b/src/rc-compat/v37/util/mmio.h +new file mode 100644 +index 000000000000..101af9dd332d +--- /dev/null ++++ b/src/rc-compat/v37/util/mmio.h +@@ -0,0 +1,267 @@ ++/* GPLv2 or OpenIB.org BSD (MIT) See COPYING file ++ ++ These accessors always map to PCI-E TLPs in predictable ways. Translation ++ to other buses should follow similar definitions. ++ ++ write32(mem, 1) ++ Produce a 4 byte MemWr TLP with bit 0 of DW byte offset 0 set ++ write32_be(mem, htobe32(1)) ++ Produce a 4 byte MemWr TLP with bit 0 of DW byte offset 3 set ++ write32_le(mem, htole32(1)) ++ Produce a 4 byte MemWr TLP with bit 0 of DW byte offset 0 set ++ ++ For ordering these accessors are similar to the Kernel's concept of ++ writel_relaxed(). When working with UC memory the following hold: ++ ++ 1) Strong ordering is required when talking to the same device (eg BAR), ++ and combining is not permitted: ++ ++ write32(mem, 1); ++ write32(mem + 4, 1); ++ write32(mem, 1); ++ ++ Must produce three TLPs, in order. ++ ++ 2) Ordering ignores all pthread locking: ++ ++ pthread_spin_lock(&lock); ++ write32(mem, global++); ++ pthread_spin_unlock(&lock); ++ ++ When run concurrently on all CPUs the device must observe all stores, ++ but the data value will not be strictly increasing. ++ ++ 3) Interaction with DMA is not ordered. Explicit use of a barrier from ++ udma_barriers is required: ++ ++ *dma_mem = 1; ++ udma_to_device_barrier(); ++ write32(mem, GO_DMA); ++ ++ 4) Access out of program order (eg speculation), either by the CPU or ++ compiler is not permitted: ++ ++ if (cond) ++ read32(); ++ ++ Must not issue a read TLP if cond is false. ++ ++ If these are used with WC memory then #1 and #4 do not apply, and all WC ++ accesses must be bracketed with mmio_wc_start() // mmio_flush_writes() ++*/ ++ ++#ifndef __UTIL_MMIO_H ++#define __UTIL_MMIO_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* The first step is to define the 'raw' accessors. To make this very safe ++ with sparse we define two versions of each, a le and a be - however the ++ code is always identical. ++*/ ++#ifdef __s390x__ ++#include ++#include ++ ++/* s390 requires a privileged instruction to access IO memory, these syscalls ++ perform that instruction using a memory buffer copy semantic. ++*/ ++static inline void s390_mmio_write(void *mmio_addr, const void *val, ++ size_t length) ++{ ++ // FIXME: Check for error and call abort? ++ syscall(__NR_s390_pci_mmio_write, mmio_addr, val, length); ++} ++ ++static inline void s390_mmio_read(const void *mmio_addr, void *val, ++ size_t length) ++{ ++ // FIXME: Check for error and call abort? ++ syscall(__NR_s390_pci_mmio_read, mmio_addr, val, length); ++} ++ ++#define MAKE_WRITE(_NAME_, _SZ_) \ ++ static inline void _NAME_##_be(void *addr, __be##_SZ_ value) \ ++ { \ ++ s390_mmio_write(addr, &value, sizeof(value)); \ ++ } \ ++ static inline void _NAME_##_le(void *addr, __le##_SZ_ value) \ ++ { \ ++ s390_mmio_write(addr, &value, sizeof(value)); \ ++ } ++#define MAKE_READ(_NAME_, _SZ_) \ ++ static inline __be##_SZ_ _NAME_##_be(const void *addr) \ ++ { \ ++ __be##_SZ_ res; \ ++ s390_mmio_read(addr, &res, sizeof(res)); \ ++ return res; \ ++ } \ ++ static inline __le##_SZ_ _NAME_##_le(const void *addr) \ ++ { \ ++ __le##_SZ_ res; \ ++ s390_mmio_read(addr, &res, sizeof(res)); \ ++ return res; \ ++ } ++ ++static inline void mmio_write8(void *addr, uint8_t value) ++{ ++ s390_mmio_write(addr, &value, sizeof(value)); ++} ++ ++static inline uint8_t mmio_read8(const void *addr) ++{ ++ uint8_t res; ++ s390_mmio_read(addr, &res, sizeof(res)); ++ return res; ++} ++ ++#else /* __s390x__ */ ++ ++#define MAKE_WRITE(_NAME_, _SZ_) \ ++ static inline void _NAME_##_be(void *addr, __be##_SZ_ value) \ ++ { \ ++ atomic_store_explicit((_Atomic(uint##_SZ_##_t) *)addr, \ ++ (__force uint##_SZ_##_t)value, \ ++ memory_order_relaxed); \ ++ } \ ++ static inline void _NAME_##_le(void *addr, __le##_SZ_ value) \ ++ { \ ++ atomic_store_explicit((_Atomic(uint##_SZ_##_t) *)addr, \ ++ (__force uint##_SZ_##_t)value, \ ++ memory_order_relaxed); \ ++ } ++#define MAKE_READ(_NAME_, _SZ_) \ ++ static inline __be##_SZ_ _NAME_##_be(const void *addr) \ ++ { \ ++ return (__force __be##_SZ_)atomic_load_explicit( \ ++ (_Atomic(uint##_SZ_##_t) *)addr, memory_order_relaxed); \ ++ } \ ++ static inline __le##_SZ_ _NAME_##_le(const void *addr) \ ++ { \ ++ return (__force __le##_SZ_)atomic_load_explicit( \ ++ (_Atomic(uint##_SZ_##_t) *)addr, memory_order_relaxed); \ ++ } ++ ++static inline void mmio_write8(void *addr, uint8_t value) ++{ ++ atomic_store_explicit((_Atomic(uint8_t) *)addr, value, ++ memory_order_relaxed); ++} ++static inline uint8_t mmio_read8(const void *addr) ++{ ++ return atomic_load_explicit((_Atomic(uint32_t) *)addr, ++ memory_order_relaxed); ++} ++#endif /* __s390x__ */ ++ ++MAKE_WRITE(mmio_write16, 16) ++MAKE_WRITE(mmio_write32, 32) ++ ++MAKE_READ(mmio_read16, 16) ++MAKE_READ(mmio_read32, 32) ++ ++#if SIZEOF_LONG == 8 ++MAKE_WRITE(mmio_write64, 64) ++MAKE_READ(mmio_read64, 64) ++#else ++void mmio_write64_be(void *addr, __be64 val); ++static inline void mmio_write64_le(void *addr, __le64 val) ++{ ++ mmio_write64_be(addr, (__be64 __force)val); ++} ++ ++/* There is no way to do read64 atomically, rather than provide some sketchy ++ implementation we leave these functions undefined, users should not call ++ them if SIZEOF_LONG != 8, but instead implement an appropriate version. ++*/ ++__be64 mmio_read64_be(const void *addr); ++__le64 mmio_read64_le(const void *addr); ++#endif /* SIZEOF_LONG == 8 */ ++ ++#undef MAKE_WRITE ++#undef MAKE_READ ++ ++/* Now we can define the host endian versions of the operator, this just includes ++ a call to htole. ++*/ ++#define MAKE_WRITE(_NAME_, _SZ_) \ ++ static inline void _NAME_(void *addr, uint##_SZ_##_t value) \ ++ { \ ++ _NAME_##_le(addr, htole##_SZ_(value)); \ ++ } ++#define MAKE_READ(_NAME_, _SZ_) \ ++ static inline uint##_SZ_##_t _NAME_(const void *addr) \ ++ { \ ++ return le##_SZ_##toh(_NAME_##_le(addr)); \ ++ } ++ ++/* This strictly guarantees the order of TLP generation for the memory copy to ++ be in ascending address order. ++*/ ++#ifdef __s390x__ ++static inline void mmio_memcpy_x64(void *dest, const void *src, size_t bytecnt) ++{ ++ s390_mmio_write(dest, src, bytecnt); ++} ++#else ++ ++/* Transfer is some multiple of 64 bytes */ ++static inline void mmio_memcpy_x64(void *dest, const void *src, size_t bytecnt) ++{ ++ uintptr_t *dst_p = dest; ++ ++ /* Caller must guarantee: ++ assert(bytecnt != 0); ++ assert((bytecnt % 64) == 0); ++ assert(((uintptr_t)dest) % __alignof__(*dst) == 0); ++ assert(((uintptr_t)src) % __alignof__(*dst) == 0); ++ */ ++ ++ /* Use the native word size for the copy */ ++ if (sizeof(*dst_p) == 8) { ++ const __be64 *src_p = src; ++ ++ do { ++ /* Do 64 bytes at a time */ ++ mmio_write64_be(dst_p++, *src_p++); ++ mmio_write64_be(dst_p++, *src_p++); ++ mmio_write64_be(dst_p++, *src_p++); ++ mmio_write64_be(dst_p++, *src_p++); ++ mmio_write64_be(dst_p++, *src_p++); ++ mmio_write64_be(dst_p++, *src_p++); ++ mmio_write64_be(dst_p++, *src_p++); ++ mmio_write64_be(dst_p++, *src_p++); ++ ++ bytecnt -= 8 * sizeof(*dst_p); ++ } while (bytecnt > 0); ++ } else if (sizeof(*dst_p) == 4) { ++ const __be32 *src_p = src; ++ ++ do { ++ mmio_write32_be(dst_p++, *src_p++); ++ mmio_write32_be(dst_p++, *src_p++); ++ bytecnt -= 2 * sizeof(*dst_p); ++ } while (bytecnt > 0); ++ } ++} ++#endif ++ ++MAKE_WRITE(mmio_write16, 16) ++MAKE_WRITE(mmio_write32, 32) ++MAKE_WRITE(mmio_write64, 64) ++ ++MAKE_READ(mmio_read16, 16) ++MAKE_READ(mmio_read32, 32) ++MAKE_READ(mmio_read64, 64) ++ ++#undef MAKE_WRITE ++#undef MAKE_READ ++ ++#endif +diff --git a/src/rc-compat/v37/util/node_name_map.h b/src/rc-compat/v37/util/node_name_map.h +new file mode 100644 +index 000000000000..e78d274b116e +--- /dev/null ++++ b/src/rc-compat/v37/util/node_name_map.h +@@ -0,0 +1,19 @@ ++/* Copyright (c) 2019 Mellanox Technologies. All rights reserved. ++ * ++ * Connect to opensm's cl_nodenamemap.h if it is available. ++ */ ++#ifndef __LIBUTIL_NODE_NAME_MAP_H__ ++#define __LIBUTIL_NODE_NAME_MAP_H__ ++ ++#include ++ ++struct nn_map; ++typedef struct nn_map nn_map_t; ++ ++nn_map_t *open_node_name_map(const char *node_name_map); ++void close_node_name_map(nn_map_t *map); ++/* NOTE: parameter "nodedesc" may be modified here. */ ++char *remap_node_name(nn_map_t *map, uint64_t target_guid, char *nodedesc); ++char *clean_nodedesc(char *nodedesc); ++ ++#endif +diff --git a/src/rc-compat/v37/util/rdma_nl.h b/src/rc-compat/v37/util/rdma_nl.h +new file mode 100644 +index 000000000000..9c0916978283 +--- /dev/null ++++ b/src/rc-compat/v37/util/rdma_nl.h +@@ -0,0 +1,52 @@ ++/* ++ * Copyright (c) 2019, Mellanox Technologies. All rights reserved. ++ * ++ * This software is available to you under a choice of one of two ++ * licenses. You may choose to be licensed under the terms of the GNU ++ * General Public License (GPL) Version 2, available from the file ++ * COPYING in the main directory of this source tree, or the ++ * OpenIB.org BSD license below: ++ * ++ * Redistribution and use in source and binary forms, with or ++ * without modification, are permitted provided that the following ++ * conditions are met: ++ * ++ * - Redistributions of source code must retain the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer. ++ * ++ * - Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials ++ * provided with the distribution. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS ++ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. ++ */ ++#ifndef UTIL_RDMA_NL_H ++#define UTIL_RDMA_NL_H ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++extern struct nla_policy rdmanl_policy[RDMA_NLDEV_ATTR_MAX]; ++struct nl_sock *rdmanl_socket_alloc(void); ++int rdmanl_get_devices(struct nl_sock *nl, nl_recvmsg_msg_cb_t cb_func, ++ void *data); ++int rdmanl_get_chardev(struct nl_sock *nl, int ibidx, const char *name, ++ nl_recvmsg_msg_cb_t cb_func, void *data); ++bool get_copy_on_fork(void); ++int rdmanl_get_copy_on_fork(struct nl_sock *nl, nl_recvmsg_msg_cb_t cb_func, ++ void *data); ++ ++#endif +diff --git a/src/rc-compat/v37/util/symver.h b/src/rc-compat/v37/util/symver.h +new file mode 100644 +index 000000000000..eb14c57ebdc1 +--- /dev/null ++++ b/src/rc-compat/v37/util/symver.h +@@ -0,0 +1,107 @@ ++/* GPLv2 or OpenIB.org BSD (MIT) See COPYING file ++ ++ These definitions help using the ELF symbol version feature, and must be ++ used in conjunction with the library's map file. ++ */ ++ ++#ifndef __UTIL_SYMVER_H ++#define __UTIL_SYMVER_H ++ ++#include ++#include ++ ++/* ++ These macros should only be used if the library is defining compatibility ++ symbols, eg: ++ ++ 213: 000000000000a650 315 FUNC GLOBAL DEFAULT 13 ibv_get_device_list@IBVERBS_1.0 ++ 214: 000000000000b020 304 FUNC GLOBAL DEFAULT 13 ibv_get_device_list@@IBVERBS_1.1 ++ ++ Symbols which have only a single implementation should use a normal extern ++ function and be placed in the correct stanza in the linker map file. ++ ++ Follow this pattern to use this feature: ++ public.h: ++ struct ibv_device **ibv_get_device_list(int *num_devices); ++ foo.c: ++ // Implement the latest version ++ LATEST_SYMVER_FUNC(ibv_get_device_list, 1_1, "IBVERBS_1.1", ++ struct ibv_device **, ++ int *num_devices) ++ { ++ ... ++ } ++ ++ // Implement the compat version ++ COMPAT_SYMVER_FUNC(ibv_get_device_list, 1_0, "IBVERBS_1.0", ++ struct ibv_device_1_0 **, ++ int *num_devices) ++ { ++ ... ++ } ++ ++ As well as matching information in the map file. ++ ++ These macros deal with the various uglyness in gcc surrounding symbol ++ versions ++ ++ - The internal name __public_1_x is synthesized by the macro ++ - A prototype for the internal name is created by the macro ++ - If statically linking the latest symbol expands into a normal function ++ definition ++ - If statically linking the compat symbols expand into unused static ++ functions are are discarded by the compiler. ++ - The prototype of the latest symbol is checked against the public ++ prototype (only when compiling statically) ++ ++ The extra prototypes are included only to avoid -Wmissing-prototypes ++ warnings. See also Documentation/versioning.md ++*/ ++ ++#if HAVE_FUNC_ATTRIBUTE_SYMVER ++#define _MAKE_SYMVER(_local_sym, _public_sym, _ver_str) \ ++ __attribute__((__symver__(#_public_sym "@" _ver_str))) ++#else ++#define _MAKE_SYMVER(_local_sym, _public_sym, _ver_str) \ ++ asm(".symver " #_local_sym "," #_public_sym "@" _ver_str); ++#endif ++#define _MAKE_SYMVER_FUNC(_public_sym, _uniq, _ver_str, _ret, ...) \ ++ _ret __##_public_sym##_##_uniq(__VA_ARGS__); \ ++ _MAKE_SYMVER(__##_public_sym##_##_uniq, _public_sym, _ver_str) \ ++ _ret __##_public_sym##_##_uniq(__VA_ARGS__) ++ ++#if defined(HAVE_FULL_SYMBOL_VERSIONS) && !defined(_STATIC_LIBRARY_BUILD_) ++ ++ // Produce all symbol versions for dynamic linking ++ ++# define COMPAT_SYMVER_FUNC(_public_sym, _uniq, _ver_str, _ret, ...) \ ++ _MAKE_SYMVER_FUNC(_public_sym, _uniq, _ver_str, _ret, __VA_ARGS__) ++# define LATEST_SYMVER_FUNC(_public_sym, _uniq, _ver_str, _ret, ...) \ ++ _MAKE_SYMVER_FUNC(_public_sym, _uniq, "@" _ver_str, _ret, __VA_ARGS__) ++ ++#elif defined(HAVE_LIMITED_SYMBOL_VERSIONS) && !defined(_STATIC_LIBRARY_BUILD_) ++ ++ /* Produce only implemenations for the latest symbol and tag it with the ++ * correct symbol versions. This supports dynamic linkers that do not ++ * understand symbol versions ++ */ ++# define COMPAT_SYMVER_FUNC(_public_sym, _uniq, _ver_str, _ret, ...) \ ++ static inline _ret __##_public_sym##_##_uniq(__VA_ARGS__) ++# define LATEST_SYMVER_FUNC(_public_sym, _uniq, _ver_str, _ret, ...) \ ++ _MAKE_SYMVER_FUNC(_public_sym, _uniq, "@" _ver_str, _ret, __VA_ARGS__) ++ ++#else ++ ++ // Static linking, or linker does not support symbol versions ++#define COMPAT_SYMVER_FUNC(_public_sym, _uniq, _ver_str, _ret, ...) \ ++ static inline __attribute__((unused)) \ ++ _ret __##_public_sym##_##_uniq(__VA_ARGS__) ++#define LATEST_SYMVER_FUNC(_public_sym, _uniq, _ver_str, _ret, ...) \ ++ static __attribute__((unused)) \ ++ _ret __##_public_sym##_##_uniq(__VA_ARGS__) \ ++ __attribute__((alias(stringify(_public_sym)))); \ ++ extern _ret _public_sym(__VA_ARGS__) ++ ++#endif ++ ++#endif +diff --git a/src/rc-compat/v37/util/udma_barrier.h b/src/rc-compat/v37/util/udma_barrier.h +new file mode 100644 +index 000000000000..5730576e6356 +--- /dev/null ++++ b/src/rc-compat/v37/util/udma_barrier.h +@@ -0,0 +1,267 @@ ++/* ++ * Copyright (c) 2005 Topspin Communications. All rights reserved. ++ * ++ * This software is available to you under a choice of one of two ++ * licenses. You may choose to be licensed under the terms of the GNU ++ * General Public License (GPL) Version 2, available from the file ++ * COPYING in the main directory of this source tree, or the ++ * OpenIB.org BSD license below: ++ * ++ * Redistribution and use in source and binary forms, with or ++ * without modification, are permitted provided that the following ++ * conditions are met: ++ * ++ * - Redistributions of source code must retain the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer. ++ * ++ * - Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials ++ * provided with the distribution. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS ++ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. ++ */ ++ ++#ifndef __UTIL_UDMA_BARRIER_H ++#define __UTIL_UDMA_BARRIER_H ++ ++#include ++ ++/* Barriers for DMA. ++ ++ These barriers are expliclty only for use with user DMA operations. If you ++ are looking for barriers to use with cache-coherent multi-threaded ++ consitency then look in stdatomic.h. If you need both kinds of synchronicity ++ for the same address then use an atomic operation followed by one ++ of these barriers. ++ ++ When reasoning about these barriers there are two objects: ++ - CPU attached address space (the CPU memory could be a range of things: ++ cached/uncached/non-temporal CPU DRAM, uncached MMIO space in another ++ device, pMEM). Generally speaking the ordering is only relative ++ to the local CPU's view of the system. Eg if the local CPU ++ is not guaranteed to see a write from another CPU then it is also ++ OK for the DMA device to also not see the write after the barrier. ++ - A DMA initiator on a bus. For instance a PCI-E device issuing ++ MemRd/MemWr TLPs. ++ ++ The ordering guarantee is always stated between those two streams. Eg what ++ happens if a MemRd TLP is sent in via PCI-E relative to a CPU WRITE to the ++ same memory location. ++ ++ The providers have a very regular and predictable use of these barriers, ++ to make things very clear each narrow use is given a name and the proper ++ name should be used in the provider as a form of documentation. ++*/ ++ ++/* Ensure that the device's view of memory matches the CPU's view of memory. ++ This should be placed before any MMIO store that could trigger the device ++ to begin doing DMA, such as a device doorbell ring. ++ ++ eg ++ *dma_buf = 1; ++ udma_to_device_barrier(); ++ mmio_write(DO_DMA_REG, dma_buf); ++ Must ensure that the device sees the '1'. ++ ++ This is required to fence writes created by the libibverbs user. Those ++ writes could be to any CPU mapped memory object with any cachability mode. ++ ++ NOTE: x86 has historically used a weaker semantic for this barrier, and ++ only fenced normal stores to normal memory. libibverbs users using other ++ memory types or non-temporal stores are required to use SFENCE in their own ++ code prior to calling verbs to start a DMA. ++*/ ++#if defined(__i386__) ++#define udma_to_device_barrier() asm volatile("" ::: "memory") ++#elif defined(__x86_64__) ++#define udma_to_device_barrier() asm volatile("" ::: "memory") ++#elif defined(__PPC64__) ++#define udma_to_device_barrier() asm volatile("sync" ::: "memory") ++#elif defined(__PPC__) ++#define udma_to_device_barrier() asm volatile("sync" ::: "memory") ++#elif defined(__ia64__) ++#define udma_to_device_barrier() asm volatile("mf" ::: "memory") ++#elif defined(__sparc_v9__) ++#define udma_to_device_barrier() asm volatile("membar #StoreStore" ::: "memory") ++#elif defined(__aarch64__) ++#define udma_to_device_barrier() asm volatile("dsb st" ::: "memory"); ++#elif defined(__sparc__) || defined(__s390x__) ++#define udma_to_device_barrier() asm volatile("" ::: "memory") ++#elif defined(__loongarch__) ++#define udma_to_device_barrier() asm volatile("dbar 0" ::: "memory") ++#else ++#error No architecture specific memory barrier defines found! ++#endif ++ ++/* Ensure that all ordered stores from the device are observable from the ++ CPU. This only makes sense after something that observes an ordered store ++ from the device - eg by reading a MMIO register or seeing that CPU memory is ++ updated. ++ ++ This guarantees that all reads that follow the barrier see the ordered ++ stores that preceded the observation. ++ ++ For instance, this would be used after testing a valid bit in a memory ++ that is a DMA target, to ensure that the following reads see the ++ data written before the MemWr TLP that set the valid bit. ++*/ ++#if defined(__i386__) ++#define udma_from_device_barrier() asm volatile("lock; addl $0,0(%%esp) " ::: "memory") ++#elif defined(__x86_64__) ++#define udma_from_device_barrier() asm volatile("lfence" ::: "memory") ++#elif defined(__PPC64__) ++#define udma_from_device_barrier() asm volatile("lwsync" ::: "memory") ++#elif defined(__PPC__) ++#define udma_from_device_barrier() asm volatile("sync" ::: "memory") ++#elif defined(__ia64__) ++#define udma_from_device_barrier() asm volatile("mf" ::: "memory") ++#elif defined(__sparc_v9__) ++#define udma_from_device_barrier() asm volatile("membar #LoadLoad" ::: "memory") ++#elif defined(__aarch64__) ++#define udma_from_device_barrier() asm volatile("dsb ld" ::: "memory"); ++#elif defined(__sparc__) || defined(__s390x__) ++#define udma_from_device_barrier() asm volatile("" ::: "memory") ++#elif defined(__loongarch__) ++#define udma_from_device_barrier() asm volatile("dbar 0" ::: "memory") ++#else ++#error No architecture specific memory barrier defines found! ++#endif ++ ++/* Order writes to CPU memory so that a DMA device cannot view writes after ++ the barrier without also seeing all writes before the barrier. This does ++ not guarantee any writes are visible to DMA. ++ ++ This would be used in cases where a DMA buffer might have a valid bit and ++ data, this barrier is placed after writing the data but before writing the ++ valid bit to ensure the DMA device cannot observe a set valid bit with ++ unwritten data. ++ ++ Compared to udma_to_device_barrier() this barrier is not required to fence ++ anything but normal stores to normal malloc memory. Usage should be: ++ ++ write_wqe ++ udma_to_device_barrier(); // Get user memory ready for DMA ++ wqe->addr = ...; ++ wqe->flags = ...; ++ udma_ordering_write_barrier(); // Guarantee WQE written in order ++ wqe->valid = 1; ++*/ ++#define udma_ordering_write_barrier() udma_to_device_barrier() ++ ++/* Promptly flush writes to MMIO Write Cominbing memory. ++ This should be used after a write to WC memory. This is both a barrier ++ and a hint to the CPU to flush any buffers to reduce latency to TLP ++ generation. ++ ++ This is not required to have any effect on CPU memory. ++ ++ If done while holding a lock then the ordering of MMIO writes across CPUs ++ must be guaranteed to follow the natural ordering implied by the lock. ++ ++ This must also act as a barrier that prevents write combining, eg ++ *wc_mem = 1; ++ mmio_flush_writes(); ++ *wc_mem = 2; ++ Must always produce two MemWr TLPs, '1' and '2'. Without the barrier ++ the CPU is allowed to produce a single TLP '2'. ++ ++ Note that there is no order guarantee for writes to WC memory without ++ barriers. ++ ++ This is intended to be used in conjunction with WC memory to generate large ++ PCI-E MemWr TLPs from the CPU. ++*/ ++#if defined(__i386__) ++#define mmio_flush_writes() asm volatile("lock; addl $0,0(%%esp) " ::: "memory") ++#elif defined(__x86_64__) ++#define mmio_flush_writes() asm volatile("sfence" ::: "memory") ++#elif defined(__PPC64__) ++#define mmio_flush_writes() asm volatile("sync" ::: "memory") ++#elif defined(__PPC__) ++#define mmio_flush_writes() asm volatile("sync" ::: "memory") ++#elif defined(__ia64__) ++#define mmio_flush_writes() asm volatile("fwb" ::: "memory") ++#elif defined(__sparc_v9__) ++#define mmio_flush_writes() asm volatile("membar #StoreStore" ::: "memory") ++#elif defined(__aarch64__) ++#define mmio_flush_writes() asm volatile("dsb st" ::: "memory"); ++#elif defined(__sparc__) || defined(__s390x__) ++#define mmio_flush_writes() asm volatile("" ::: "memory") ++#elif defined(__loongarch__) ++#define mmio_flush_writes() asm volatile("dbar 0" ::: "memory") ++#else ++#error No architecture specific memory barrier defines found! ++#endif ++ ++/* Prevent WC writes from being re-ordered relative to other MMIO ++ writes. This should be used before a write to WC memory. ++ ++ This must act as a barrier to prevent write re-ordering from different ++ memory types: ++ *mmio_mem = 1; ++ mmio_flush_writes(); ++ *wc_mem = 2; ++ Must always produce a TLP '1' followed by '2'. ++ ++ This barrier implies udma_to_device_barrier() ++ ++ This is intended to be used in conjunction with WC memory to generate large ++ PCI-E MemWr TLPs from the CPU. ++*/ ++#define mmio_wc_start() mmio_flush_writes() ++ ++/* Keep MMIO writes in order. ++ Currently we lack writel macros that universally guarantee MMIO ++ writes happen in order, like the kernel does. Even worse many ++ providers haphazardly open code writes to MMIO memory omitting even ++ volatile. ++ ++ Until this can be fixed with a proper writel macro, this barrier ++ is a stand in to indicate places where MMIO writes should be switched ++ to some future writel. ++*/ ++#define mmio_ordered_writes_hack() mmio_flush_writes() ++ ++/* Write Combining Spinlock primitive ++ ++ Any access to a multi-value WC region must ensure that multiple cpus do not ++ write to the same values concurrently, these macros make that ++ straightforward and efficient if the choosen exclusion is a spinlock. ++ ++ The spinlock guarantees that the WC writes issued within the critical ++ section are made visible as TLP to the device. The TLP must be seen by the ++ device strictly in the order that the spinlocks are acquired, and combining ++ WC writes between different sections is not permitted. ++ ++ Use of these macros allow the fencing inside the spinlock to be combined ++ with the fencing required for DMA. ++ */ ++static inline void mmio_wc_spinlock(pthread_spinlock_t *lock) ++{ ++ pthread_spin_lock(lock); ++#if !defined(__i386__) && !defined(__x86_64__) ++ /* For x86 the serialization within the spin lock is enough to ++ * strongly order WC and other memory types. */ ++ mmio_wc_start(); ++#endif ++} ++ ++static inline void mmio_wc_spinunlock(pthread_spinlock_t *lock) ++{ ++ /* It is possible that on x86 the atomic in the lock is strong enough ++ * to force-flush the WC buffers quickly, and this SFENCE can be ++ * omitted too. */ ++ mmio_flush_writes(); ++ pthread_spin_unlock(lock); ++} ++ ++#endif +diff --git a/src/rc-compat/v37/util/util.h b/src/rc-compat/v37/util/util.h +new file mode 100644 +index 000000000000..45f50658519a +--- /dev/null ++++ b/src/rc-compat/v37/util/util.h +@@ -0,0 +1,93 @@ ++/* GPLv2 or OpenIB.org BSD (MIT) See COPYING file */ ++#ifndef UTIL_UTIL_H ++#define UTIL_UTIL_H ++ ++#include ++#include ++#include ++#include ++ ++/* Return true if the snprintf succeeded, false if there was truncation or ++ * error */ ++static inline bool __good_snprintf(size_t len, int rc) ++{ ++ return (rc < len && rc >= 0); ++} ++ ++#define check_snprintf(buf, len, fmt, ...) \ ++ __good_snprintf(len, snprintf(buf, len, fmt, ##__VA_ARGS__)) ++ ++/* a CMP b. See also the BSD macro timercmp(). */ ++#define ts_cmp(a, b, CMP) \ ++ (((a)->tv_sec == (b)->tv_sec) ? \ ++ ((a)->tv_nsec CMP (b)->tv_nsec) : \ ++ ((a)->tv_sec CMP (b)->tv_sec)) ++ ++#define offsetofend(_type, _member) \ ++ (offsetof(_type, _member) + sizeof(((_type *)0)->_member)) ++ ++#define BITS_PER_LONG (8 * sizeof(long)) ++#define BITS_PER_LONG_LONG (8 * sizeof(long long)) ++ ++#define GENMASK(h, l) \ ++ (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ++#define GENMASK_ULL(h, l) \ ++ (((~0ULL) << (l)) & (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h)))) ++ ++#define BIT(nr) (1UL << (nr)) ++#define BIT_ULL(nr) (1ULL << (nr)) ++ ++#define __bf_shf(x) (__builtin_ffsll(x) - 1) ++ ++/** ++ * FIELD_PREP() - prepare a bitfield element ++ * @_mask: shifted mask defining the field's length and position ++ * @_val: value to put in the field ++ * ++ * FIELD_PREP() masks and shifts up the value. The result should ++ * be combined with other fields of the bitfield using logical OR. ++ */ ++#define FIELD_PREP(_mask, _val) \ ++ ({ \ ++ ((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \ ++ }) ++ ++/** ++ * FIELD_GET() - extract a bitfield element ++ * @_mask: shifted mask defining the field's length and position ++ * @_reg: value of entire bitfield ++ * ++ * FIELD_GET() extracts the field specified by @_mask from the ++ * bitfield passed in as @_reg by masking and shifting it down. ++ */ ++#define FIELD_GET(_mask, _reg) \ ++ ({ \ ++ (typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \ ++ }) ++ ++static inline unsigned long align(unsigned long val, unsigned long align) ++{ ++ return (val + align - 1) & ~(align - 1); ++} ++ ++static inline unsigned long align_down(unsigned long val, unsigned long _align) ++{ ++ return align(val - (_align - 1), _align); ++} ++ ++static inline uint64_t roundup_pow_of_two(uint64_t n) ++{ ++ return n == 1 ? 1 : 1ULL << ilog64(n - 1); ++} ++ ++static inline unsigned long DIV_ROUND_UP(unsigned long n, unsigned long d) ++{ ++ return (n + d - 1) / d; ++} ++ ++int set_fd_nonblock(int fd, bool nonblock); ++ ++int open_cdev(const char *devname_hint, dev_t cdev); ++ ++unsigned int get_random(void); ++#endif +-- +2.29.2 + diff --git a/userspace/broadcom/libbnxt_re/debian/deb_folder/patches/0002-configure.ac-Detect-rdma-core-v36-and-v37-too.patch b/userspace/broadcom/libbnxt_re/debian/deb_folder/patches/0002-configure.ac-Detect-rdma-core-v36-and-v37-too.patch new file mode 100644 index 00000000..b7056f53 --- /dev/null +++ b/userspace/broadcom/libbnxt_re/debian/deb_folder/patches/0002-configure.ac-Detect-rdma-core-v36-and-v37-too.patch @@ -0,0 +1,118 @@ +From ffd1f85f70551c897e6e62b89acf8b170c1c82ea Mon Sep 17 00:00:00 2001 +From: "M. Vefa Bicakci" +Date: Thu, 31 Mar 2022 16:14:22 -0400 +Subject: [PATCH] configure.ac: Detect rdma-core v36 and v37 too + +This commit makes the configure.ac script detect rdma-core v36 and v37 +as well. Of these, we are only interested in v37, because Mellanox's +OpenFabrics Enterprise Distribution is based on rdma-core v37. + +Signed-off-by: M. Vefa Bicakci +--- + configure.ac | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 75 insertions(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index 9e4e980886d4..3ece437e664a 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -68,6 +68,10 @@ m4_define([rcore_version],[m4_esyscmd(rc=$(grep -o \ + _ibv_device_ops verbsincpath/include/infiniband/verbs.h | \ + tail -1); \ + if test ! -z "$rc"; then \ ++ rcverv37=$(grep "IBV_WC_DRIVER3" \ ++ verbsincpath/include/infiniband/verbs.h|tail -1); \ ++ rcverv36=$(grep "ibv_query_qp_data_in_order" \ ++ verbsincpath/include/infiniband/verbs.h|tail -1); \ + rcverv35=$(grep "ibv_is_fork_initialized" \ + verbsincpath/include/infiniband/verbs.h|tail -1); \ + rcverv34=$(grep "ibv_reg_dmabuf_mr" \ +@@ -90,7 +94,11 @@ m4_define([rcore_version],[m4_esyscmd(rc=$(grep -o \ + verbsincpath/include/infiniband/verbs.h|tail -1); \ + rcverv17=$(grep -o ibv_alloc_td \ + verbsincpath/include/infiniband/verbs.h|tail -1); \ +- if test ! -z "$rcverv35"; then \ ++ if test ! -z "$rcverv37"; then \ ++ echo -n "v37"; \ ++ elif test ! -z "$rcverv36"; then \ ++ echo -n "v36"; \ ++ elif test ! -z "$rcverv35"; then \ + echo -n "v35"; \ + elif test ! -z "$rcverv34"; then \ + echo -n "v34"; \ +@@ -175,6 +183,72 @@ if test "$rc" != ""; then + AC_DEFINE([HAVE_IBV_CMD_MODIFY_QP_EX],[1],[ibv_cmd_modify_qp_ex supported]) + RDMA_CORE_HEADERS=`echo -n __include_path__` + case "$(echo -n rcore_version)" in ++ v37) ++ AC_MSG_RESULT(yes using v37) ++ AC_DEFINE([IBV_WC_DRIVER3_IN_IBV_WC_OPCODE],[1], ++ [Rdma-Core Package has IBV_WC_DRIVER3 in ibv_wc_opcode enum]) ++ AC_DEFINE([IBV_WC_DRIVER2_IN_IBV_WC_OPCODE],[1], ++ [Rdma-Core Package has IBV_WC_DRIVER2 in ibv_wc_opcode enum]) ++ AC_DEFINE([IBV_QUERY_QP_DATA_IN_ORDER_IN_CONTEXT_OPS],[1], ++ [Rdma-Core Package has query_qp_data_in_order in verbs_context_ops]) ++ AC_DEFINE([VERBS_ONLY_QUERY_DEVICE_EX_DEFINED],[1], ++ [Rdma-Core Package has only query_device_ex]) ++ AC_DEFINE([IBV_CMD_MODIFY_QP_EX_HAS_7_ARG],[1], ++ [Rdma-Core Package ibv_cmd_modify_qp_ex has 7 arguments]) ++ AC_DEFINE([IBV_FREE_CONTEXT_IN_CONTEXT_OPS],[1], ++ [Rdma-Core Package has free context in ibv_context_ops]) ++ AC_DEFINE([REG_MR_VERB_HAS_5_ARG],[1], ++ [Rdma-Core Package reg_mr has 5 argument]) ++ AC_DEFINE([IBV_CMD_ALLOC_MW_HAS_1_ARG],[1], ++ [Rdma-Core Package ibv_cmd_alloc_mw has single argument]) ++ AC_DEFINE([PROVIDER_DRIVER_HAS_2_ARGS],[1], ++ [Rdma-Core Package PROVIDER_DRIVER macro has 2 arguments]) ++ AC_DEFINE([ALLOC_CONTEXT_HAS_PRIVATE_DATA],[1], ++ [Rdma-Core Package alloc_context has private data]) ++ AC_DEFINE([VERBS_MR_DEFINED],[1], ++ [Rdma-Core Package has verbs_mr defined]) ++ AC_DEFINE([VERBS_INIT_AND_ALLOC_CONTEXT_HAS_5_ARG],[1], ++ [Rdma-Core Package has 5 Arg for verbs_init_and_alloc_context macro]) ++ AC_DEFINE([RCP_HAS_PROVIDER_DRIVER],[1], ++ [Rdma-Core Package has PROVIDER_DRIVER macro]) ++ AC_DEFINE([RCP_USE_IB_UVERBS],[1], ++ [Rdma-Core Package uses IB user verbs API]) ++ AC_DEFINE([RCP_USE_ALLOC_CONTEXT],[1], ++ [Rdma-Core Package uses alloc_context instead of init_context]) ++ rc=`grep -o ibv_read_sysfs_file src/rc-compat/v37/driver.h|tail -1` ++ ;; ++ v36) ++ AC_MSG_RESULT(yes using v36) ++ AC_DEFINE([IBV_WC_DRIVER2_IN_IBV_WC_OPCODE],[1], ++ [Rdma-Core Package has IBV_WC_DRIVER2 in ibv_wc_opcode enum]) ++ AC_DEFINE([IBV_QUERY_QP_DATA_IN_ORDER_IN_CONTEXT_OPS],[1], ++ [Rdma-Core Package has query_qp_data_in_order in verbs_context_ops]) ++ AC_DEFINE([VERBS_ONLY_QUERY_DEVICE_EX_DEFINED],[1], ++ [Rdma-Core Package has only query_device_ex]) ++ AC_DEFINE([IBV_CMD_MODIFY_QP_EX_HAS_7_ARG],[1], ++ [Rdma-Core Package ibv_cmd_modify_qp_ex has 7 arguments]) ++ AC_DEFINE([IBV_FREE_CONTEXT_IN_CONTEXT_OPS],[1], ++ [Rdma-Core Package has free context in ibv_context_ops]) ++ AC_DEFINE([REG_MR_VERB_HAS_5_ARG],[1], ++ [Rdma-Core Package reg_mr has 5 argument]) ++ AC_DEFINE([IBV_CMD_ALLOC_MW_HAS_1_ARG],[1], ++ [Rdma-Core Package ibv_cmd_alloc_mw has single argument]) ++ AC_DEFINE([PROVIDER_DRIVER_HAS_2_ARGS],[1], ++ [Rdma-Core Package PROVIDER_DRIVER macro has 2 arguments]) ++ AC_DEFINE([ALLOC_CONTEXT_HAS_PRIVATE_DATA],[1], ++ [Rdma-Core Package alloc_context has private data]) ++ AC_DEFINE([VERBS_MR_DEFINED],[1], ++ [Rdma-Core Package has verbs_mr defined]) ++ AC_DEFINE([VERBS_INIT_AND_ALLOC_CONTEXT_HAS_5_ARG],[1], ++ [Rdma-Core Package has 5 Arg for verbs_init_and_alloc_context macro]) ++ AC_DEFINE([RCP_HAS_PROVIDER_DRIVER],[1], ++ [Rdma-Core Package has PROVIDER_DRIVER macro]) ++ AC_DEFINE([RCP_USE_IB_UVERBS],[1], ++ [Rdma-Core Package uses IB user verbs API]) ++ AC_DEFINE([RCP_USE_ALLOC_CONTEXT],[1], ++ [Rdma-Core Package uses alloc_context instead of init_context]) ++ rc=`grep -o ibv_read_sysfs_file src/rc-compat/v36/driver.h|tail -1` ++ ;; + v35) + AC_MSG_RESULT(yes using v35) + AC_DEFINE([VERBS_ONLY_QUERY_DEVICE_EX_DEFINED],[1], +-- +2.29.2 + diff --git a/userspace/broadcom/libbnxt_re/debian/deb_folder/patches/series b/userspace/broadcom/libbnxt_re/debian/deb_folder/patches/series new file mode 100644 index 00000000..dcb9a3bf --- /dev/null +++ b/userspace/broadcom/libbnxt_re/debian/deb_folder/patches/series @@ -0,0 +1,2 @@ +0001-rc-compat-Add-headers-from-v37.3.patch +0002-configure.ac-Detect-rdma-core-v36-and-v37-too.patch diff --git a/userspace/broadcom/libbnxt_re/debian/deb_folder/rules b/userspace/broadcom/libbnxt_re/debian/deb_folder/rules new file mode 100755 index 00000000..9c5db1fc --- /dev/null +++ b/userspace/broadcom/libbnxt_re/debian/deb_folder/rules @@ -0,0 +1,53 @@ +#!/usr/bin/make -f +# +# Copyright (c) 2022 Wind River Systems, Inc. +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. The ASF licenses this +# file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# output every command that modifies files on the build system. +#export DH_VERBOSE = 1 + +include /usr/share/dpkg/architecture.mk + +libdir=/usr/lib/$(DEB_HOST_MULTIARCH) +debdir=debian/libbnxt-re + +%: + dh $@ + +override_dh_auto_install: + dh_auto_install + # Now, the following symbolic link exists: + # /usr/lib/x86_64-linux-gnu/libbnxt_re.so -> libbnxt_re-rdmav34.so + # + # We need to create the following symbolic link as well: + # /usr/lib/x86_64-linux-gnu/libibverbs/libbnxt_re-rdmav34.so -> ../libbnxt_re-rdmav34.so + # + # To avoid hard-coding the version (v34), read the link. + libname="$$(readlink "$(debdir)/$(libdir)/libbnxt_re.so")" && \ + mkdir -p "$(debdir)/$(libdir)/libibverbs/" && \ + ln -s "../$${libname}" "$(debdir)/$(libdir)/libibverbs/$${libname}" + # Remove static library and libtool archive files. + # - Static library is not necessary given that no other packages statically + # link against the libbnxt_re library. + # - Libtool archive files (*.la) are not recommended to be included in + # Debian packages: + # https://www.debian.org/doc/manuals/maint-guide/advanced.en.html#library + # https://wiki.debian.org/ReleaseGoals/LAFileRemoval + rm -vf \ + $(debdir)/$(libdir)/libbnxt_re.a \ + $(debdir)/$(libdir)/libbnxt_re.la diff --git a/userspace/broadcom/libbnxt_re/debian/deb_folder/source/format b/userspace/broadcom/libbnxt_re/debian/deb_folder/source/format new file mode 100644 index 00000000..163aaf8d --- /dev/null +++ b/userspace/broadcom/libbnxt_re/debian/deb_folder/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/userspace/broadcom/libbnxt_re/debian/dl_hook b/userspace/broadcom/libbnxt_re/debian/dl_hook new file mode 100755 index 00000000..d9919f88 --- /dev/null +++ b/userspace/broadcom/libbnxt_re/debian/dl_hook @@ -0,0 +1,51 @@ +#!/bin/bash +# +# Copyright (c) 2022 Wind River Systems, Inc. +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. The ASF licenses this +# file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# The only parameter is the name of the new directory that will contain +# the extracted source code. Be aware that this new directory will be +# created in the same directory as where this script is located when +# building. +# Tools needed: mkdir, rm, tar + +DL_TARBALL=bcm_220.0.83.0.tar.gz +SRC_TARBALL=Linux/Linux_RoCE/RoCE_Lib/libbnxt_re-220.0.5.0.tar.gz +TMPDIR="bcm_tmp" + +DESTDIR="${1}" +if test -z "${DESTDIR}"; then + echo "Missing destination directory on command line." + exit 1 +fi + +rm -rf "${TMPDIR}" +mkdir -p "${TMPDIR}" + +if ! tar -C "${TMPDIR}" --strip-components=1 -xvf "${DL_TARBALL}"; then + echo "Could not extract into ${TMPDIR}: ${DL_TARBALL}" + exit 1 +fi + +mkdir -p "${DESTDIR}" +if ! tar -C "${DESTDIR}" --strip-components=1 -xvf "${TMPDIR}/${SRC_TARBALL}"; then + echo "Could not extract into ${DESTDIR}: ${TMPDIR}/${SRC_TARBALL}" + exit 1 +fi + +rm -rf "${TMPDIR}" diff --git a/userspace/broadcom/libbnxt_re/debian/meta_data.yaml b/userspace/broadcom/libbnxt_re/debian/meta_data.yaml new file mode 100644 index 00000000..f9012a0a --- /dev/null +++ b/userspace/broadcom/libbnxt_re/debian/meta_data.yaml @@ -0,0 +1,14 @@ +--- +debver: 220.0.5.0 +debname: libbnxt-re +dl_hook: dl_hook +dl_files: + bcm_220.0.83.0.tar.gz: + topdir: null + url: "https://docs.broadcom.com/docs-and-downloads/\ + ethernet-network-adapters/NXE/BRCM_220.0.83.0/\ + bcm_220.0.83.0.tar.gz" + sha256sum: 85bdfc30b4bd3e184e3b57a48055c11085e3b97593f7b4a8347fa50a9d571336 +revision: + dist: $STX_DIST + PKG_GITREVCOUNT: true