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