| 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
| 2 | /* Copyright (C) 2024 Intel Corporation */ |
| 3 | |
| 4 | #ifndef __LIBETH_CACHE_H |
| 5 | #define __LIBETH_CACHE_H |
| 6 | |
| 7 | #include <linux/cache.h> |
| 8 | |
| 9 | /** |
| 10 | * libeth_cacheline_group_assert - make sure cacheline group size is expected |
| 11 | * @type: type of the structure containing the group |
| 12 | * @grp: group name inside the struct |
| 13 | * @sz: expected group size |
| 14 | */ |
| 15 | #if defined(CONFIG_64BIT) && SMP_CACHE_BYTES == 64 |
| 16 | #define libeth_cacheline_group_assert(type, grp, sz) \ |
| 17 | static_assert(offsetof(type, __cacheline_group_end__##grp) - \ |
| 18 | offsetofend(type, __cacheline_group_begin__##grp) == \ |
| 19 | (sz)) |
| 20 | #define __libeth_cacheline_struct_assert(type, sz) \ |
| 21 | static_assert(sizeof(type) == (sz)) |
| 22 | #else /* !CONFIG_64BIT || SMP_CACHE_BYTES != 64 */ |
| 23 | #define libeth_cacheline_group_assert(type, grp, sz) \ |
| 24 | static_assert(offsetof(type, __cacheline_group_end__##grp) - \ |
| 25 | offsetofend(type, __cacheline_group_begin__##grp) <= \ |
| 26 | (sz)) |
| 27 | #define __libeth_cacheline_struct_assert(type, sz) \ |
| 28 | static_assert(sizeof(type) <= (sz)) |
| 29 | #endif /* !CONFIG_64BIT || SMP_CACHE_BYTES != 64 */ |
| 30 | |
| 31 | #define __libeth_cls1(sz1) SMP_CACHE_ALIGN(sz1) |
| 32 | #define __libeth_cls2(sz1, sz2) (SMP_CACHE_ALIGN(sz1) + SMP_CACHE_ALIGN(sz2)) |
| 33 | #define __libeth_cls3(sz1, sz2, sz3) \ |
| 34 | (SMP_CACHE_ALIGN(sz1) + SMP_CACHE_ALIGN(sz2) + SMP_CACHE_ALIGN(sz3)) |
| 35 | #define __libeth_cls(...) \ |
| 36 | CONCATENATE(__libeth_cls, COUNT_ARGS(__VA_ARGS__))(__VA_ARGS__) |
| 37 | |
| 38 | /** |
| 39 | * libeth_cacheline_struct_assert - make sure CL-based struct size is expected |
| 40 | * @type: type of the struct |
| 41 | * @...: from 1 to 3 CL group sizes (read-mostly, read-write, cold) |
| 42 | * |
| 43 | * When a struct contains several CL groups, it's difficult to predict its size |
| 44 | * on different architectures. The macro instead takes sizes of all of the |
| 45 | * groups the structure contains and generates the final struct size. |
| 46 | */ |
| 47 | #define libeth_cacheline_struct_assert(type, ...) \ |
| 48 | __libeth_cacheline_struct_assert(type, __libeth_cls(__VA_ARGS__)); \ |
| 49 | static_assert(__alignof(type) >= SMP_CACHE_BYTES) |
| 50 | |
| 51 | /** |
| 52 | * libeth_cacheline_set_assert - make sure CL-based struct layout is expected |
| 53 | * @type: type of the struct |
| 54 | * @ro: expected size of the read-mostly group |
| 55 | * @rw: expected size of the read-write group |
| 56 | * @c: expected size of the cold group |
| 57 | * |
| 58 | * Check that each group size is expected and then do final struct size check. |
| 59 | */ |
| 60 | #define libeth_cacheline_set_assert(type, ro, rw, c) \ |
| 61 | libeth_cacheline_group_assert(type, read_mostly, ro); \ |
| 62 | libeth_cacheline_group_assert(type, read_write, rw); \ |
| 63 | libeth_cacheline_group_assert(type, cold, c); \ |
| 64 | libeth_cacheline_struct_assert(type, ro, rw, c) |
| 65 | |
| 66 | #endif /* __LIBETH_CACHE_H */ |
| 67 | |