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