]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/net/ethernet/mellanox/mlxsw/item.h
mlxsw: item: Add MLXSW_ITEM_BUF_INDEXED helper
[karo-tx-linux.git] / drivers / net / ethernet / mellanox / mlxsw / item.h
1 /*
2  * drivers/net/ethernet/mellanox/mlxsw/item.h
3  * Copyright (c) 2015 Mellanox Technologies. All rights reserved.
4  * Copyright (c) 2015 Jiri Pirko <jiri@mellanox.com>
5  * Copyright (c) 2015 Ido Schimmel <idosch@mellanox.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the names of the copyright holders nor the names of its
16  *    contributors may be used to endorse or promote products derived from
17  *    this software without specific prior written permission.
18  *
19  * Alternatively, this software may be distributed under the terms of the
20  * GNU General Public License ("GPL") version 2 as published by the Free
21  * Software Foundation.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  */
35
36 #ifndef _MLXSW_ITEM_H
37 #define _MLXSW_ITEM_H
38
39 #include <linux/types.h>
40 #include <linux/string.h>
41 #include <linux/bitops.h>
42
43 struct mlxsw_item {
44         unsigned short  offset;         /* bytes in container */
45         unsigned short  step;           /* step in bytes for indexed items */
46         unsigned short  in_step_offset; /* offset within one step */
47         unsigned char   shift;          /* shift in bits */
48         unsigned char   element_size;   /* size of element in bit array */
49         bool            no_real_shift;
50         union {
51                 unsigned char   bits;
52                 unsigned short  bytes;
53         } size;
54         const char      *name;
55 };
56
57 static inline unsigned int
58 __mlxsw_item_offset(struct mlxsw_item *item, unsigned short index,
59                     size_t typesize)
60 {
61         BUG_ON(index && !item->step);
62         if (item->offset % typesize != 0 ||
63             item->step % typesize != 0 ||
64             item->in_step_offset % typesize != 0) {
65                 pr_err("mlxsw: item bug (name=%s,offset=%x,step=%x,in_step_offset=%x,typesize=%zx)\n",
66                        item->name, item->offset, item->step,
67                        item->in_step_offset, typesize);
68                 BUG();
69         }
70
71         return ((item->offset + item->step * index + item->in_step_offset) /
72                 typesize);
73 }
74
75 static inline u16 __mlxsw_item_get16(char *buf, struct mlxsw_item *item,
76                                      unsigned short index)
77 {
78         unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u16));
79         __be16 *b = (__be16 *) buf;
80         u16 tmp;
81
82         tmp = be16_to_cpu(b[offset]);
83         tmp >>= item->shift;
84         tmp &= GENMASK(item->size.bits - 1, 0);
85         if (item->no_real_shift)
86                 tmp <<= item->shift;
87         return tmp;
88 }
89
90 static inline void __mlxsw_item_set16(char *buf, struct mlxsw_item *item,
91                                       unsigned short index, u16 val)
92 {
93         unsigned int offset = __mlxsw_item_offset(item, index,
94                                                   sizeof(u16));
95         __be16 *b = (__be16 *) buf;
96         u16 mask = GENMASK(item->size.bits - 1, 0) << item->shift;
97         u16 tmp;
98
99         if (!item->no_real_shift)
100                 val <<= item->shift;
101         val &= mask;
102         tmp = be16_to_cpu(b[offset]);
103         tmp &= ~mask;
104         tmp |= val;
105         b[offset] = cpu_to_be16(tmp);
106 }
107
108 static inline u32 __mlxsw_item_get32(char *buf, struct mlxsw_item *item,
109                                      unsigned short index)
110 {
111         unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u32));
112         __be32 *b = (__be32 *) buf;
113         u32 tmp;
114
115         tmp = be32_to_cpu(b[offset]);
116         tmp >>= item->shift;
117         tmp &= GENMASK(item->size.bits - 1, 0);
118         if (item->no_real_shift)
119                 tmp <<= item->shift;
120         return tmp;
121 }
122
123 static inline void __mlxsw_item_set32(char *buf, struct mlxsw_item *item,
124                                       unsigned short index, u32 val)
125 {
126         unsigned int offset = __mlxsw_item_offset(item, index,
127                                                   sizeof(u32));
128         __be32 *b = (__be32 *) buf;
129         u32 mask = GENMASK(item->size.bits - 1, 0) << item->shift;
130         u32 tmp;
131
132         if (!item->no_real_shift)
133                 val <<= item->shift;
134         val &= mask;
135         tmp = be32_to_cpu(b[offset]);
136         tmp &= ~mask;
137         tmp |= val;
138         b[offset] = cpu_to_be32(tmp);
139 }
140
141 static inline u64 __mlxsw_item_get64(char *buf, struct mlxsw_item *item,
142                                      unsigned short index)
143 {
144         unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u64));
145         __be64 *b = (__be64 *) buf;
146         u64 tmp;
147
148         tmp = be64_to_cpu(b[offset]);
149         tmp >>= item->shift;
150         tmp &= GENMASK_ULL(item->size.bits - 1, 0);
151         if (item->no_real_shift)
152                 tmp <<= item->shift;
153         return tmp;
154 }
155
156 static inline void __mlxsw_item_set64(char *buf, struct mlxsw_item *item,
157                                       unsigned short index, u64 val)
158 {
159         unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u64));
160         __be64 *b = (__be64 *) buf;
161         u64 mask = GENMASK_ULL(item->size.bits - 1, 0) << item->shift;
162         u64 tmp;
163
164         if (!item->no_real_shift)
165                 val <<= item->shift;
166         val &= mask;
167         tmp = be64_to_cpu(b[offset]);
168         tmp &= ~mask;
169         tmp |= val;
170         b[offset] = cpu_to_be64(tmp);
171 }
172
173 static inline void __mlxsw_item_memcpy_from(char *buf, char *dst,
174                                             struct mlxsw_item *item,
175                                             unsigned short index)
176 {
177         unsigned int offset = __mlxsw_item_offset(item, index, sizeof(char));
178
179         memcpy(dst, &buf[offset], item->size.bytes);
180 }
181
182 static inline void __mlxsw_item_memcpy_to(char *buf, const char *src,
183                                           struct mlxsw_item *item,
184                                           unsigned short index)
185 {
186         unsigned int offset = __mlxsw_item_offset(item, index, sizeof(char));
187
188         memcpy(&buf[offset], src, item->size.bytes);
189 }
190
191 static inline u16
192 __mlxsw_item_bit_array_offset(struct mlxsw_item *item, u16 index, u8 *shift)
193 {
194         u16 max_index, be_index;
195         u16 offset;             /* byte offset inside the array */
196
197         BUG_ON(index && !item->element_size);
198         if (item->offset % sizeof(u32) != 0 ||
199             BITS_PER_BYTE % item->element_size != 0) {
200                 pr_err("mlxsw: item bug (name=%s,offset=%x,element_size=%x)\n",
201                        item->name, item->offset, item->element_size);
202                 BUG();
203         }
204
205         max_index = (item->size.bytes << 3) / item->element_size - 1;
206         be_index = max_index - index;
207         offset = be_index * item->element_size >> 3;
208         *shift = index % (BITS_PER_BYTE / item->element_size) << 1;
209
210         return item->offset + offset;
211 }
212
213 static inline u8 __mlxsw_item_bit_array_get(char *buf, struct mlxsw_item *item,
214                                             u16 index)
215 {
216         u8 shift, tmp;
217         u16 offset = __mlxsw_item_bit_array_offset(item, index, &shift);
218
219         tmp = buf[offset];
220         tmp >>= shift;
221         tmp &= GENMASK(item->element_size - 1, 0);
222         return tmp;
223 }
224
225 static inline void __mlxsw_item_bit_array_set(char *buf, struct mlxsw_item *item,
226                                               u16 index, u8 val)
227 {
228         u8 shift, tmp;
229         u16 offset = __mlxsw_item_bit_array_offset(item, index, &shift);
230         u8 mask = GENMASK(item->element_size - 1, 0) << shift;
231
232         val <<= shift;
233         val &= mask;
234         tmp = buf[offset];
235         tmp &= ~mask;
236         tmp |= val;
237         buf[offset] = tmp;
238 }
239
240 #define __ITEM_NAME(_type, _cname, _iname)                                      \
241         mlxsw_##_type##_##_cname##_##_iname##_item
242
243 /* _type: cmd_mbox, reg, etc.
244  * _cname: containter name (e.g. command name, register name)
245  * _iname: item name within the container
246  */
247
248 #define MLXSW_ITEM16(_type, _cname, _iname, _offset, _shift, _sizebits)         \
249 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
250         .offset = _offset,                                                      \
251         .shift = _shift,                                                        \
252         .size = {.bits = _sizebits,},                                           \
253         .name = #_type "_" #_cname "_" #_iname,                                 \
254 };                                                                              \
255 static inline u16 mlxsw_##_type##_##_cname##_##_iname##_get(char *buf)          \
256 {                                                                               \
257         return __mlxsw_item_get16(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \
258 }                                                                               \
259 static inline void mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u16 val)\
260 {                                                                               \
261         __mlxsw_item_set16(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val);   \
262 }
263
264 #define MLXSW_ITEM16_INDEXED(_type, _cname, _iname, _offset, _shift, _sizebits, \
265                              _step, _instepoffset, _norealshift)                \
266 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
267         .offset = _offset,                                                      \
268         .step = _step,                                                          \
269         .in_step_offset = _instepoffset,                                        \
270         .shift = _shift,                                                        \
271         .no_real_shift = _norealshift,                                          \
272         .size = {.bits = _sizebits,},                                           \
273         .name = #_type "_" #_cname "_" #_iname,                                 \
274 };                                                                              \
275 static inline u16                                                               \
276 mlxsw_##_type##_##_cname##_##_iname##_get(char *buf, unsigned short index)      \
277 {                                                                               \
278         return __mlxsw_item_get16(buf, &__ITEM_NAME(_type, _cname, _iname),     \
279                                   index);                                       \
280 }                                                                               \
281 static inline void                                                              \
282 mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index,      \
283                                           u16 val)                              \
284 {                                                                               \
285         __mlxsw_item_set16(buf, &__ITEM_NAME(_type, _cname, _iname),            \
286                            index, val);                                         \
287 }
288
289 #define MLXSW_ITEM32(_type, _cname, _iname, _offset, _shift, _sizebits)         \
290 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
291         .offset = _offset,                                                      \
292         .shift = _shift,                                                        \
293         .size = {.bits = _sizebits,},                                           \
294         .name = #_type "_" #_cname "_" #_iname,                                 \
295 };                                                                              \
296 static inline u32 mlxsw_##_type##_##_cname##_##_iname##_get(char *buf)          \
297 {                                                                               \
298         return __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \
299 }                                                                               \
300 static inline void mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u32 val)\
301 {                                                                               \
302         __mlxsw_item_set32(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val);   \
303 }
304
305 #define MLXSW_ITEM32_INDEXED(_type, _cname, _iname, _offset, _shift, _sizebits, \
306                              _step, _instepoffset, _norealshift)                \
307 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
308         .offset = _offset,                                                      \
309         .step = _step,                                                          \
310         .in_step_offset = _instepoffset,                                        \
311         .shift = _shift,                                                        \
312         .no_real_shift = _norealshift,                                          \
313         .size = {.bits = _sizebits,},                                           \
314         .name = #_type "_" #_cname "_" #_iname,                                 \
315 };                                                                              \
316 static inline u32                                                               \
317 mlxsw_##_type##_##_cname##_##_iname##_get(char *buf, unsigned short index)      \
318 {                                                                               \
319         return __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, _iname),     \
320                                   index);                                       \
321 }                                                                               \
322 static inline void                                                              \
323 mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index,      \
324                                           u32 val)                              \
325 {                                                                               \
326         __mlxsw_item_set32(buf, &__ITEM_NAME(_type, _cname, _iname),            \
327                            index, val);                                         \
328 }
329
330 #define MLXSW_ITEM64(_type, _cname, _iname, _offset, _shift, _sizebits)         \
331 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
332         .offset = _offset,                                                      \
333         .shift = _shift,                                                        \
334         .size = {.bits = _sizebits,},                                           \
335         .name = #_type "_" #_cname "_" #_iname,                                 \
336 };                                                                              \
337 static inline u64 mlxsw_##_type##_##_cname##_##_iname##_get(char *buf)          \
338 {                                                                               \
339         return __mlxsw_item_get64(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \
340 }                                                                               \
341 static inline void mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u64 val)\
342 {                                                                               \
343         __mlxsw_item_set64(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val);   \
344 }
345
346 #define MLXSW_ITEM64_INDEXED(_type, _cname, _iname, _offset, _shift,            \
347                              _sizebits, _step, _instepoffset, _norealshift)     \
348 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
349         .offset = _offset,                                                      \
350         .step = _step,                                                          \
351         .in_step_offset = _instepoffset,                                        \
352         .shift = _shift,                                                        \
353         .no_real_shift = _norealshift,                                          \
354         .size = {.bits = _sizebits,},                                           \
355         .name = #_type "_" #_cname "_" #_iname,                                 \
356 };                                                                              \
357 static inline u64                                                               \
358 mlxsw_##_type##_##_cname##_##_iname##_get(char *buf, unsigned short index)      \
359 {                                                                               \
360         return __mlxsw_item_get64(buf, &__ITEM_NAME(_type, _cname, _iname),     \
361                                   index);                                       \
362 }                                                                               \
363 static inline void                                                              \
364 mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index,      \
365                                           u64 val)                              \
366 {                                                                               \
367         __mlxsw_item_set64(buf, &__ITEM_NAME(_type, _cname, _iname),            \
368                            index, val);                                         \
369 }
370
371 #define MLXSW_ITEM_BUF(_type, _cname, _iname, _offset, _sizebytes)              \
372 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
373         .offset = _offset,                                                      \
374         .size = {.bytes = _sizebytes,},                                         \
375         .name = #_type "_" #_cname "_" #_iname,                                 \
376 };                                                                              \
377 static inline void                                                              \
378 mlxsw_##_type##_##_cname##_##_iname##_memcpy_from(char *buf, char *dst)         \
379 {                                                                               \
380         __mlxsw_item_memcpy_from(buf, dst,                                      \
381                                  &__ITEM_NAME(_type, _cname, _iname), 0);       \
382 }                                                                               \
383 static inline void                                                              \
384 mlxsw_##_type##_##_cname##_##_iname##_memcpy_to(char *buf, const char *src)     \
385 {                                                                               \
386         __mlxsw_item_memcpy_to(buf, src,                                        \
387                                &__ITEM_NAME(_type, _cname, _iname), 0);         \
388 }
389
390 #define MLXSW_ITEM_BUF_INDEXED(_type, _cname, _iname, _offset, _sizebytes,      \
391                                _step, _instepoffset)                            \
392 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
393         .offset = _offset,                                                      \
394         .step = _step,                                                          \
395         .in_step_offset = _instepoffset,                                        \
396         .size = {.bytes = _sizebytes,},                                         \
397         .name = #_type "_" #_cname "_" #_iname,                                 \
398 };                                                                              \
399 static inline void                                                              \
400 mlxsw_##_type##_##_cname##_##_iname##_memcpy_from(char *buf,                    \
401                                                   unsigned short index,         \
402                                                   char *dst)                    \
403 {                                                                               \
404         __mlxsw_item_memcpy_from(buf, dst,                                      \
405                                  &__ITEM_NAME(_type, _cname, _iname), index);   \
406 }                                                                               \
407 static inline void                                                              \
408 mlxsw_##_type##_##_cname##_##_iname##_memcpy_to(char *buf,                      \
409                                                 unsigned short index,           \
410                                                 const char *src)                \
411 {                                                                               \
412         __mlxsw_item_memcpy_to(buf, src,                                        \
413                                &__ITEM_NAME(_type, _cname, _iname), index);     \
414 }
415
416 #define MLXSW_ITEM_BIT_ARRAY(_type, _cname, _iname, _offset, _sizebytes,        \
417                              _element_size)                                     \
418 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
419         .offset = _offset,                                                      \
420         .element_size = _element_size,                                          \
421         .size = {.bytes = _sizebytes,},                                         \
422         .name = #_type "_" #_cname "_" #_iname,                                 \
423 };                                                                              \
424 static inline u8                                                                \
425 mlxsw_##_type##_##_cname##_##_iname##_get(char *buf, u16 index)                 \
426 {                                                                               \
427         return __mlxsw_item_bit_array_get(buf,                                  \
428                                           &__ITEM_NAME(_type, _cname, _iname),  \
429                                           index);                               \
430 }                                                                               \
431 static inline void                                                              \
432 mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u16 index, u8 val)         \
433 {                                                                               \
434         return __mlxsw_item_bit_array_set(buf,                                  \
435                                           &__ITEM_NAME(_type, _cname, _iname),  \
436                                           index, val);                          \
437 }                                                                               \
438
439 #endif