net/mlx5e: Avoid unbounded peer devices when unpairing TC hairpin rules
[sfrench/cifs-2.6.git] / drivers / net / ethernet / mellanox / mlxsw / item.h
1 /* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
2 /* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */
3
4 #ifndef _MLXSW_ITEM_H
5 #define _MLXSW_ITEM_H
6
7 #include <linux/types.h>
8 #include <linux/string.h>
9 #include <linux/bitops.h>
10
11 struct mlxsw_item {
12         unsigned short  offset;         /* bytes in container */
13         short           step;           /* step in bytes for indexed items */
14         unsigned short  in_step_offset; /* offset within one step */
15         unsigned char   shift;          /* shift in bits */
16         unsigned char   element_size;   /* size of element in bit array */
17         bool            no_real_shift;
18         union {
19                 unsigned char   bits;
20                 unsigned short  bytes;
21         } size;
22         const char      *name;
23 };
24
25 static inline unsigned int
26 __mlxsw_item_offset(const struct mlxsw_item *item, unsigned short index,
27                     size_t typesize)
28 {
29         BUG_ON(index && !item->step);
30         if (item->offset % typesize != 0 ||
31             item->step % typesize != 0 ||
32             item->in_step_offset % typesize != 0) {
33                 pr_err("mlxsw: item bug (name=%s,offset=%x,step=%x,in_step_offset=%x,typesize=%zx)\n",
34                        item->name, item->offset, item->step,
35                        item->in_step_offset, typesize);
36                 BUG();
37         }
38
39         return ((item->offset + item->step * index + item->in_step_offset) /
40                 typesize);
41 }
42
43 static inline u8 __mlxsw_item_get8(const char *buf,
44                                    const struct mlxsw_item *item,
45                                    unsigned short index)
46 {
47         unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u8));
48         u8 *b = (u8 *) buf;
49         u8 tmp;
50
51         tmp = b[offset];
52         tmp >>= item->shift;
53         tmp &= GENMASK(item->size.bits - 1, 0);
54         if (item->no_real_shift)
55                 tmp <<= item->shift;
56         return tmp;
57 }
58
59 static inline void __mlxsw_item_set8(char *buf, const struct mlxsw_item *item,
60                                      unsigned short index, u8 val)
61 {
62         unsigned int offset = __mlxsw_item_offset(item, index,
63                                                   sizeof(u8));
64         u8 *b = (u8 *) buf;
65         u8 mask = GENMASK(item->size.bits - 1, 0) << item->shift;
66         u8 tmp;
67
68         if (!item->no_real_shift)
69                 val <<= item->shift;
70         val &= mask;
71         tmp = b[offset];
72         tmp &= ~mask;
73         tmp |= val;
74         b[offset] = tmp;
75 }
76
77 static inline u16 __mlxsw_item_get16(const char *buf,
78                                      const struct mlxsw_item *item,
79                                      unsigned short index)
80 {
81         unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u16));
82         __be16 *b = (__be16 *) buf;
83         u16 tmp;
84
85         tmp = be16_to_cpu(b[offset]);
86         tmp >>= item->shift;
87         tmp &= GENMASK(item->size.bits - 1, 0);
88         if (item->no_real_shift)
89                 tmp <<= item->shift;
90         return tmp;
91 }
92
93 static inline void __mlxsw_item_set16(char *buf, const struct mlxsw_item *item,
94                                       unsigned short index, u16 val)
95 {
96         unsigned int offset = __mlxsw_item_offset(item, index,
97                                                   sizeof(u16));
98         __be16 *b = (__be16 *) buf;
99         u16 mask = GENMASK(item->size.bits - 1, 0) << item->shift;
100         u16 tmp;
101
102         if (!item->no_real_shift)
103                 val <<= item->shift;
104         val &= mask;
105         tmp = be16_to_cpu(b[offset]);
106         tmp &= ~mask;
107         tmp |= val;
108         b[offset] = cpu_to_be16(tmp);
109 }
110
111 static inline u32 __mlxsw_item_get32(const char *buf,
112                                      const struct mlxsw_item *item,
113                                      unsigned short index)
114 {
115         unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u32));
116         __be32 *b = (__be32 *) buf;
117         u32 tmp;
118
119         tmp = be32_to_cpu(b[offset]);
120         tmp >>= item->shift;
121         tmp &= GENMASK(item->size.bits - 1, 0);
122         if (item->no_real_shift)
123                 tmp <<= item->shift;
124         return tmp;
125 }
126
127 static inline void __mlxsw_item_set32(char *buf, const struct mlxsw_item *item,
128                                       unsigned short index, u32 val)
129 {
130         unsigned int offset = __mlxsw_item_offset(item, index,
131                                                   sizeof(u32));
132         __be32 *b = (__be32 *) buf;
133         u32 mask = GENMASK(item->size.bits - 1, 0) << item->shift;
134         u32 tmp;
135
136         if (!item->no_real_shift)
137                 val <<= item->shift;
138         val &= mask;
139         tmp = be32_to_cpu(b[offset]);
140         tmp &= ~mask;
141         tmp |= val;
142         b[offset] = cpu_to_be32(tmp);
143 }
144
145 static inline u64 __mlxsw_item_get64(const char *buf,
146                                      const struct mlxsw_item *item,
147                                      unsigned short index)
148 {
149         unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u64));
150         __be64 *b = (__be64 *) buf;
151         u64 tmp;
152
153         tmp = be64_to_cpu(b[offset]);
154         tmp >>= item->shift;
155         tmp &= GENMASK_ULL(item->size.bits - 1, 0);
156         if (item->no_real_shift)
157                 tmp <<= item->shift;
158         return tmp;
159 }
160
161 static inline void __mlxsw_item_set64(char *buf, const struct mlxsw_item *item,
162                                       unsigned short index, u64 val)
163 {
164         unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u64));
165         __be64 *b = (__be64 *) buf;
166         u64 mask = GENMASK_ULL(item->size.bits - 1, 0) << item->shift;
167         u64 tmp;
168
169         if (!item->no_real_shift)
170                 val <<= item->shift;
171         val &= mask;
172         tmp = be64_to_cpu(b[offset]);
173         tmp &= ~mask;
174         tmp |= val;
175         b[offset] = cpu_to_be64(tmp);
176 }
177
178 static inline void __mlxsw_item_memcpy_from(const char *buf, char *dst,
179                                             const struct mlxsw_item *item,
180                                             unsigned short index)
181 {
182         unsigned int offset = __mlxsw_item_offset(item, index, sizeof(char));
183
184         memcpy(dst, &buf[offset], item->size.bytes);
185 }
186
187 static inline void __mlxsw_item_memcpy_to(char *buf, const char *src,
188                                           const struct mlxsw_item *item,
189                                           unsigned short index)
190 {
191         unsigned int offset = __mlxsw_item_offset(item, index, sizeof(char));
192
193         memcpy(&buf[offset], src, item->size.bytes);
194 }
195
196 static inline char *__mlxsw_item_data(char *buf, const struct mlxsw_item *item,
197                                       unsigned short index)
198 {
199         unsigned int offset = __mlxsw_item_offset(item, index, sizeof(char));
200
201         return &buf[offset];
202 }
203
204 static inline u16
205 __mlxsw_item_bit_array_offset(const struct mlxsw_item *item,
206                               u16 index, u8 *shift)
207 {
208         u16 max_index, be_index;
209         u16 offset;             /* byte offset inside the array */
210         u8 in_byte_index;
211
212         BUG_ON(index && !item->element_size);
213         if (item->offset % sizeof(u32) != 0 ||
214             BITS_PER_BYTE % item->element_size != 0) {
215                 pr_err("mlxsw: item bug (name=%s,offset=%x,element_size=%x)\n",
216                        item->name, item->offset, item->element_size);
217                 BUG();
218         }
219
220         max_index = (item->size.bytes << 3) / item->element_size - 1;
221         be_index = max_index - index;
222         offset = be_index * item->element_size >> 3;
223         in_byte_index  = index % (BITS_PER_BYTE / item->element_size);
224         *shift = in_byte_index * item->element_size;
225
226         return item->offset + offset;
227 }
228
229 static inline u8 __mlxsw_item_bit_array_get(const char *buf,
230                                             const struct mlxsw_item *item,
231                                             u16 index)
232 {
233         u8 shift, tmp;
234         u16 offset = __mlxsw_item_bit_array_offset(item, index, &shift);
235
236         tmp = buf[offset];
237         tmp >>= shift;
238         tmp &= GENMASK(item->element_size - 1, 0);
239         return tmp;
240 }
241
242 static inline void __mlxsw_item_bit_array_set(char *buf,
243                                               const struct mlxsw_item *item,
244                                               u16 index, u8 val)
245 {
246         u8 shift, tmp;
247         u16 offset = __mlxsw_item_bit_array_offset(item, index, &shift);
248         u8 mask = GENMASK(item->element_size - 1, 0) << shift;
249
250         val <<= shift;
251         val &= mask;
252         tmp = buf[offset];
253         tmp &= ~mask;
254         tmp |= val;
255         buf[offset] = tmp;
256 }
257
258 #define __ITEM_NAME(_type, _cname, _iname)                                      \
259         mlxsw_##_type##_##_cname##_##_iname##_item
260
261 /* _type: cmd_mbox, reg, etc.
262  * _cname: containter name (e.g. command name, register name)
263  * _iname: item name within the container
264  */
265
266 #define MLXSW_ITEM8(_type, _cname, _iname, _offset, _shift, _sizebits)          \
267 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
268         .offset = _offset,                                                      \
269         .shift = _shift,                                                        \
270         .size = {.bits = _sizebits,},                                           \
271         .name = #_type "_" #_cname "_" #_iname,                                 \
272 };                                                                              \
273 static inline u8 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf)     \
274 {                                                                               \
275         return __mlxsw_item_get8(buf, &__ITEM_NAME(_type, _cname, _iname), 0);  \
276 }                                                                               \
277 static inline void mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u8 val)\
278 {                                                                               \
279         __mlxsw_item_set8(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val);    \
280 }
281
282 #define MLXSW_ITEM8_INDEXED(_type, _cname, _iname, _offset, _shift, _sizebits,  \
283                             _step, _instepoffset, _norealshift)                 \
284 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
285         .offset = _offset,                                                      \
286         .step = _step,                                                          \
287         .in_step_offset = _instepoffset,                                        \
288         .shift = _shift,                                                        \
289         .no_real_shift = _norealshift,                                          \
290         .size = {.bits = _sizebits,},                                           \
291         .name = #_type "_" #_cname "_" #_iname,                                 \
292 };                                                                              \
293 static inline u8                                                                \
294 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, unsigned short index)\
295 {                                                                               \
296         return __mlxsw_item_get8(buf, &__ITEM_NAME(_type, _cname, _iname),      \
297                                  index);                                        \
298 }                                                                               \
299 static inline void                                                              \
300 mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index,      \
301                                           u8 val)                               \
302 {                                                                               \
303         __mlxsw_item_set8(buf, &__ITEM_NAME(_type, _cname, _iname),             \
304                           index, val);                                          \
305 }
306
307 #define MLXSW_ITEM16(_type, _cname, _iname, _offset, _shift, _sizebits)         \
308 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
309         .offset = _offset,                                                      \
310         .shift = _shift,                                                        \
311         .size = {.bits = _sizebits,},                                           \
312         .name = #_type "_" #_cname "_" #_iname,                                 \
313 };                                                                              \
314 static inline u16 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf)    \
315 {                                                                               \
316         return __mlxsw_item_get16(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \
317 }                                                                               \
318 static inline void mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u16 val)\
319 {                                                                               \
320         __mlxsw_item_set16(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val);   \
321 }
322
323 #define MLXSW_ITEM16_INDEXED(_type, _cname, _iname, _offset, _shift, _sizebits, \
324                              _step, _instepoffset, _norealshift)                \
325 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
326         .offset = _offset,                                                      \
327         .step = _step,                                                          \
328         .in_step_offset = _instepoffset,                                        \
329         .shift = _shift,                                                        \
330         .no_real_shift = _norealshift,                                          \
331         .size = {.bits = _sizebits,},                                           \
332         .name = #_type "_" #_cname "_" #_iname,                                 \
333 };                                                                              \
334 static inline u16                                                               \
335 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, unsigned short index)\
336 {                                                                               \
337         return __mlxsw_item_get16(buf, &__ITEM_NAME(_type, _cname, _iname),     \
338                                   index);                                       \
339 }                                                                               \
340 static inline void                                                              \
341 mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index,      \
342                                           u16 val)                              \
343 {                                                                               \
344         __mlxsw_item_set16(buf, &__ITEM_NAME(_type, _cname, _iname),            \
345                            index, val);                                         \
346 }
347
348 #define MLXSW_ITEM32(_type, _cname, _iname, _offset, _shift, _sizebits)         \
349 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
350         .offset = _offset,                                                      \
351         .shift = _shift,                                                        \
352         .size = {.bits = _sizebits,},                                           \
353         .name = #_type "_" #_cname "_" #_iname,                                 \
354 };                                                                              \
355 static inline u32 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf)    \
356 {                                                                               \
357         return __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \
358 }                                                                               \
359 static inline void mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u32 val)\
360 {                                                                               \
361         __mlxsw_item_set32(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val);   \
362 }
363
364 #define MLXSW_ITEM32_INDEXED(_type, _cname, _iname, _offset, _shift, _sizebits, \
365                              _step, _instepoffset, _norealshift)                \
366 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
367         .offset = _offset,                                                      \
368         .step = _step,                                                          \
369         .in_step_offset = _instepoffset,                                        \
370         .shift = _shift,                                                        \
371         .no_real_shift = _norealshift,                                          \
372         .size = {.bits = _sizebits,},                                           \
373         .name = #_type "_" #_cname "_" #_iname,                                 \
374 };                                                                              \
375 static inline u32                                                               \
376 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, unsigned short index)\
377 {                                                                               \
378         return __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, _iname),     \
379                                   index);                                       \
380 }                                                                               \
381 static inline void                                                              \
382 mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index,      \
383                                           u32 val)                              \
384 {                                                                               \
385         __mlxsw_item_set32(buf, &__ITEM_NAME(_type, _cname, _iname),            \
386                            index, val);                                         \
387 }
388
389 #define MLXSW_ITEM64(_type, _cname, _iname, _offset, _shift, _sizebits)         \
390 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
391         .offset = _offset,                                                      \
392         .shift = _shift,                                                        \
393         .size = {.bits = _sizebits,},                                           \
394         .name = #_type "_" #_cname "_" #_iname,                                 \
395 };                                                                              \
396 static inline u64 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf)    \
397 {                                                                               \
398         return __mlxsw_item_get64(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \
399 }                                                                               \
400 static inline void mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u64 val)\
401 {                                                                               \
402         __mlxsw_item_set64(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val);   \
403 }
404
405 #define MLXSW_ITEM64_INDEXED(_type, _cname, _iname, _offset, _shift,            \
406                              _sizebits, _step, _instepoffset, _norealshift)     \
407 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
408         .offset = _offset,                                                      \
409         .step = _step,                                                          \
410         .in_step_offset = _instepoffset,                                        \
411         .shift = _shift,                                                        \
412         .no_real_shift = _norealshift,                                          \
413         .size = {.bits = _sizebits,},                                           \
414         .name = #_type "_" #_cname "_" #_iname,                                 \
415 };                                                                              \
416 static inline u64                                                               \
417 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, unsigned short index)\
418 {                                                                               \
419         return __mlxsw_item_get64(buf, &__ITEM_NAME(_type, _cname, _iname),     \
420                                   index);                                       \
421 }                                                                               \
422 static inline void                                                              \
423 mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index,      \
424                                           u64 val)                              \
425 {                                                                               \
426         __mlxsw_item_set64(buf, &__ITEM_NAME(_type, _cname, _iname),            \
427                            index, val);                                         \
428 }
429
430 #define MLXSW_ITEM_BUF(_type, _cname, _iname, _offset, _sizebytes)              \
431 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
432         .offset = _offset,                                                      \
433         .size = {.bytes = _sizebytes,},                                         \
434         .name = #_type "_" #_cname "_" #_iname,                                 \
435 };                                                                              \
436 static inline void                                                              \
437 mlxsw_##_type##_##_cname##_##_iname##_memcpy_from(const char *buf, char *dst)   \
438 {                                                                               \
439         __mlxsw_item_memcpy_from(buf, dst,                                      \
440                                  &__ITEM_NAME(_type, _cname, _iname), 0);       \
441 }                                                                               \
442 static inline void                                                              \
443 mlxsw_##_type##_##_cname##_##_iname##_memcpy_to(char *buf, const char *src)     \
444 {                                                                               \
445         __mlxsw_item_memcpy_to(buf, src,                                        \
446                                &__ITEM_NAME(_type, _cname, _iname), 0);         \
447 }                                                                               \
448 static inline char *                                                            \
449 mlxsw_##_type##_##_cname##_##_iname##_data(char *buf)                           \
450 {                                                                               \
451         return __mlxsw_item_data(buf, &__ITEM_NAME(_type, _cname, _iname), 0);  \
452 }
453
454 #define MLXSW_ITEM_BUF_INDEXED(_type, _cname, _iname, _offset, _sizebytes,      \
455                                _step, _instepoffset)                            \
456 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
457         .offset = _offset,                                                      \
458         .step = _step,                                                          \
459         .in_step_offset = _instepoffset,                                        \
460         .size = {.bytes = _sizebytes,},                                         \
461         .name = #_type "_" #_cname "_" #_iname,                                 \
462 };                                                                              \
463 static inline void                                                              \
464 mlxsw_##_type##_##_cname##_##_iname##_memcpy_from(const char *buf,              \
465                                                   unsigned short index,         \
466                                                   char *dst)                    \
467 {                                                                               \
468         __mlxsw_item_memcpy_from(buf, dst,                                      \
469                                  &__ITEM_NAME(_type, _cname, _iname), index);   \
470 }                                                                               \
471 static inline void                                                              \
472 mlxsw_##_type##_##_cname##_##_iname##_memcpy_to(char *buf,                      \
473                                                 unsigned short index,           \
474                                                 const char *src)                \
475 {                                                                               \
476         __mlxsw_item_memcpy_to(buf, src,                                        \
477                                &__ITEM_NAME(_type, _cname, _iname), index);     \
478 }                                                                               \
479 static inline char *                                                            \
480 mlxsw_##_type##_##_cname##_##_iname##_data(char *buf, unsigned short index)     \
481 {                                                                               \
482         return __mlxsw_item_data(buf,                                           \
483                                  &__ITEM_NAME(_type, _cname, _iname), index);   \
484 }
485
486 #define MLXSW_ITEM_BIT_ARRAY(_type, _cname, _iname, _offset, _sizebytes,        \
487                              _element_size)                                     \
488 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
489         .offset = _offset,                                                      \
490         .element_size = _element_size,                                          \
491         .size = {.bytes = _sizebytes,},                                         \
492         .name = #_type "_" #_cname "_" #_iname,                                 \
493 };                                                                              \
494 static inline u8                                                                \
495 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, u16 index)           \
496 {                                                                               \
497         return __mlxsw_item_bit_array_get(buf,                                  \
498                                           &__ITEM_NAME(_type, _cname, _iname),  \
499                                           index);                               \
500 }                                                                               \
501 static inline void                                                              \
502 mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u16 index, u8 val)         \
503 {                                                                               \
504         return __mlxsw_item_bit_array_set(buf,                                  \
505                                           &__ITEM_NAME(_type, _cname, _iname),  \
506                                           index, val);                          \
507 }                                                                               \
508
509 #endif