1d05d4ac4SLeon Romanovsky /* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
2d05d4ac4SLeon Romanovsky /*
3d05d4ac4SLeon Romanovsky * Copyright (c) 2020, Mellanox Technologies inc. All rights reserved.
4d05d4ac4SLeon Romanovsky */
5d05d4ac4SLeon Romanovsky #ifndef _IBA_DEFS_H_
6d05d4ac4SLeon Romanovsky #define _IBA_DEFS_H_
7d05d4ac4SLeon Romanovsky
8d05d4ac4SLeon Romanovsky #include <linux/kernel.h>
9d05d4ac4SLeon Romanovsky #include <linux/bitfield.h>
10d05d4ac4SLeon Romanovsky #include <asm/unaligned.h>
11d05d4ac4SLeon Romanovsky
_iba_get8(const u8 * ptr)12d05d4ac4SLeon Romanovsky static inline u32 _iba_get8(const u8 *ptr)
13d05d4ac4SLeon Romanovsky {
14d05d4ac4SLeon Romanovsky return *ptr;
15d05d4ac4SLeon Romanovsky }
16d05d4ac4SLeon Romanovsky
_iba_set8(u8 * ptr,u32 mask,u32 prep_value)17d05d4ac4SLeon Romanovsky static inline void _iba_set8(u8 *ptr, u32 mask, u32 prep_value)
18d05d4ac4SLeon Romanovsky {
19d05d4ac4SLeon Romanovsky *ptr = (*ptr & ~mask) | prep_value;
20d05d4ac4SLeon Romanovsky }
21d05d4ac4SLeon Romanovsky
_iba_get16(const __be16 * ptr)22d05d4ac4SLeon Romanovsky static inline u16 _iba_get16(const __be16 *ptr)
23d05d4ac4SLeon Romanovsky {
24d05d4ac4SLeon Romanovsky return be16_to_cpu(*ptr);
25d05d4ac4SLeon Romanovsky }
26d05d4ac4SLeon Romanovsky
_iba_set16(__be16 * ptr,u16 mask,u16 prep_value)27d05d4ac4SLeon Romanovsky static inline void _iba_set16(__be16 *ptr, u16 mask, u16 prep_value)
28d05d4ac4SLeon Romanovsky {
29d05d4ac4SLeon Romanovsky *ptr = cpu_to_be16((be16_to_cpu(*ptr) & ~mask) | prep_value);
30d05d4ac4SLeon Romanovsky }
31d05d4ac4SLeon Romanovsky
_iba_get32(const __be32 * ptr)32d05d4ac4SLeon Romanovsky static inline u32 _iba_get32(const __be32 *ptr)
33d05d4ac4SLeon Romanovsky {
34d05d4ac4SLeon Romanovsky return be32_to_cpu(*ptr);
35d05d4ac4SLeon Romanovsky }
36d05d4ac4SLeon Romanovsky
_iba_set32(__be32 * ptr,u32 mask,u32 prep_value)37d05d4ac4SLeon Romanovsky static inline void _iba_set32(__be32 *ptr, u32 mask, u32 prep_value)
38d05d4ac4SLeon Romanovsky {
39d05d4ac4SLeon Romanovsky *ptr = cpu_to_be32((be32_to_cpu(*ptr) & ~mask) | prep_value);
40d05d4ac4SLeon Romanovsky }
41d05d4ac4SLeon Romanovsky
_iba_get64(const __be64 * ptr)42d05d4ac4SLeon Romanovsky static inline u64 _iba_get64(const __be64 *ptr)
43d05d4ac4SLeon Romanovsky {
44d05d4ac4SLeon Romanovsky /*
45d05d4ac4SLeon Romanovsky * The mads are constructed so that 32 bit and smaller are naturally
46d05d4ac4SLeon Romanovsky * aligned, everything larger has a max alignment of 4 bytes.
47d05d4ac4SLeon Romanovsky */
48d05d4ac4SLeon Romanovsky return be64_to_cpu(get_unaligned(ptr));
49d05d4ac4SLeon Romanovsky }
50d05d4ac4SLeon Romanovsky
_iba_set64(__be64 * ptr,u64 mask,u64 prep_value)51d05d4ac4SLeon Romanovsky static inline void _iba_set64(__be64 *ptr, u64 mask, u64 prep_value)
52d05d4ac4SLeon Romanovsky {
53d05d4ac4SLeon Romanovsky put_unaligned(cpu_to_be64((_iba_get64(ptr) & ~mask) | prep_value), ptr);
54d05d4ac4SLeon Romanovsky }
55d05d4ac4SLeon Romanovsky
56d05d4ac4SLeon Romanovsky #define _IBA_SET(field_struct, field_offset, field_mask, num_bits, ptr, value) \
57d05d4ac4SLeon Romanovsky ({ \
58d05d4ac4SLeon Romanovsky field_struct *_ptr = ptr; \
59d05d4ac4SLeon Romanovsky _iba_set##num_bits((void *)_ptr + (field_offset), field_mask, \
60d05d4ac4SLeon Romanovsky FIELD_PREP(field_mask, value)); \
61d05d4ac4SLeon Romanovsky })
62d05d4ac4SLeon Romanovsky #define IBA_SET(field, ptr, value) _IBA_SET(field, ptr, value)
63d05d4ac4SLeon Romanovsky
64d05d4ac4SLeon Romanovsky #define _IBA_GET_MEM_PTR(field_struct, field_offset, type, num_bits, ptr) \
65d05d4ac4SLeon Romanovsky ({ \
66d05d4ac4SLeon Romanovsky field_struct *_ptr = ptr; \
67d05d4ac4SLeon Romanovsky (type *)((void *)_ptr + (field_offset)); \
68d05d4ac4SLeon Romanovsky })
69d05d4ac4SLeon Romanovsky #define IBA_GET_MEM_PTR(field, ptr) _IBA_GET_MEM_PTR(field, ptr)
70d05d4ac4SLeon Romanovsky
71d05d4ac4SLeon Romanovsky /* FIXME: A set should always set the entire field, meaning we should zero the trailing bytes */
72d05d4ac4SLeon Romanovsky #define _IBA_SET_MEM(field_struct, field_offset, type, num_bits, ptr, in, \
73d05d4ac4SLeon Romanovsky bytes) \
74d05d4ac4SLeon Romanovsky ({ \
75d05d4ac4SLeon Romanovsky const type *_in_ptr = in; \
76d05d4ac4SLeon Romanovsky WARN_ON(bytes * 8 > num_bits); \
77d05d4ac4SLeon Romanovsky if (in && bytes) \
78d05d4ac4SLeon Romanovsky memcpy(_IBA_GET_MEM_PTR(field_struct, field_offset, \
79d05d4ac4SLeon Romanovsky type, num_bits, ptr), \
80d05d4ac4SLeon Romanovsky _in_ptr, bytes); \
81d05d4ac4SLeon Romanovsky })
82d05d4ac4SLeon Romanovsky #define IBA_SET_MEM(field, ptr, in, bytes) _IBA_SET_MEM(field, ptr, in, bytes)
83d05d4ac4SLeon Romanovsky
84d05d4ac4SLeon Romanovsky #define _IBA_GET(field_struct, field_offset, field_mask, num_bits, ptr) \
85d05d4ac4SLeon Romanovsky ({ \
86d05d4ac4SLeon Romanovsky const field_struct *_ptr = ptr; \
87d05d4ac4SLeon Romanovsky (u##num_bits) FIELD_GET( \
88d05d4ac4SLeon Romanovsky field_mask, _iba_get##num_bits((const void *)_ptr + \
89d05d4ac4SLeon Romanovsky (field_offset))); \
90d05d4ac4SLeon Romanovsky })
91d05d4ac4SLeon Romanovsky #define IBA_GET(field, ptr) _IBA_GET(field, ptr)
92d05d4ac4SLeon Romanovsky
93d05d4ac4SLeon Romanovsky #define _IBA_GET_MEM(field_struct, field_offset, type, num_bits, ptr, out, \
94d05d4ac4SLeon Romanovsky bytes) \
95d05d4ac4SLeon Romanovsky ({ \
96d05d4ac4SLeon Romanovsky type *_out_ptr = out; \
97d05d4ac4SLeon Romanovsky WARN_ON(bytes * 8 > num_bits); \
98d05d4ac4SLeon Romanovsky if (out && bytes) \
99d05d4ac4SLeon Romanovsky memcpy(_out_ptr, \
100d05d4ac4SLeon Romanovsky _IBA_GET_MEM_PTR(field_struct, field_offset, \
101d05d4ac4SLeon Romanovsky type, num_bits, ptr), \
102d05d4ac4SLeon Romanovsky bytes); \
103d05d4ac4SLeon Romanovsky })
104d05d4ac4SLeon Romanovsky #define IBA_GET_MEM(field, ptr, out, bytes) _IBA_GET_MEM(field, ptr, out, bytes)
105d05d4ac4SLeon Romanovsky
106d05d4ac4SLeon Romanovsky /*
107d05d4ac4SLeon Romanovsky * The generated list becomes the parameters to the macros, the order is:
108d05d4ac4SLeon Romanovsky * - struct this applies to
109d05d4ac4SLeon Romanovsky * - starting offset of the max
110d05d4ac4SLeon Romanovsky * - GENMASK or GENMASK_ULL in CPU order
111d05d4ac4SLeon Romanovsky * - The width of data the mask operations should work on, in bits
112d05d4ac4SLeon Romanovsky */
113d05d4ac4SLeon Romanovsky
114d05d4ac4SLeon Romanovsky /*
115d05d4ac4SLeon Romanovsky * Extraction using a tabular description like table 106. bit_offset is from
116d05d4ac4SLeon Romanovsky * the Byte[Bit] notation.
117d05d4ac4SLeon Romanovsky */
118d05d4ac4SLeon Romanovsky #define IBA_FIELD_BLOC(field_struct, byte_offset, bit_offset, num_bits) \
119d05d4ac4SLeon Romanovsky field_struct, byte_offset, \
120d05d4ac4SLeon Romanovsky GENMASK(7 - (bit_offset), 7 - (bit_offset) - (num_bits - 1)), \
121d05d4ac4SLeon Romanovsky 8
122d05d4ac4SLeon Romanovsky #define IBA_FIELD8_LOC(field_struct, byte_offset, num_bits) \
123d05d4ac4SLeon Romanovsky IBA_FIELD_BLOC(field_struct, byte_offset, 0, num_bits)
124d05d4ac4SLeon Romanovsky
125d05d4ac4SLeon Romanovsky #define IBA_FIELD16_LOC(field_struct, byte_offset, num_bits) \
126d05d4ac4SLeon Romanovsky field_struct, (byte_offset)&0xFFFE, \
127d05d4ac4SLeon Romanovsky GENMASK(15 - (((byte_offset) % 2) * 8), \
128d05d4ac4SLeon Romanovsky 15 - (((byte_offset) % 2) * 8) - (num_bits - 1)), \
129d05d4ac4SLeon Romanovsky 16
130d05d4ac4SLeon Romanovsky
131d05d4ac4SLeon Romanovsky #define IBA_FIELD32_LOC(field_struct, byte_offset, num_bits) \
132d05d4ac4SLeon Romanovsky field_struct, (byte_offset)&0xFFFC, \
133d05d4ac4SLeon Romanovsky GENMASK(31 - (((byte_offset) % 4) * 8), \
134d05d4ac4SLeon Romanovsky 31 - (((byte_offset) % 4) * 8) - (num_bits - 1)), \
135d05d4ac4SLeon Romanovsky 32
136d05d4ac4SLeon Romanovsky
137d05d4ac4SLeon Romanovsky #define IBA_FIELD64_LOC(field_struct, byte_offset) \
138d05d4ac4SLeon Romanovsky field_struct, byte_offset, GENMASK_ULL(63, 0), 64
139d05d4ac4SLeon Romanovsky /*
140d05d4ac4SLeon Romanovsky * In IBTA spec, everything that is more than 64bits is multiple
141d05d4ac4SLeon Romanovsky * of bytes without leftover bits.
142d05d4ac4SLeon Romanovsky */
143d05d4ac4SLeon Romanovsky #define IBA_FIELD_MLOC(field_struct, byte_offset, num_bits, type) \
144d05d4ac4SLeon Romanovsky field_struct, byte_offset, type, num_bits
145d05d4ac4SLeon Romanovsky
146d05d4ac4SLeon Romanovsky #endif /* _IBA_DEFS_H_ */
147