linux/drivers/net/ethernet/mellanox/mlxsw/item.h
<<
>>
Prefs
   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
  11struct 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
  25static 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
  43static 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
  59static 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
  77static 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
  93static 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
 111static 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
 127static 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
 145static 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
 161static 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
 178static 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
 187static 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
 196static 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
 204static 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
 229static 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
 242static 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)          \
 267static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
 268        .offset = _offset,                                                      \
 269        .shift = _shift,                                                        \
 270        .size = {.bits = _sizebits,},                                           \
 271        .name = #_type "_" #_cname "_" #_iname,                                 \
 272};                                                                              \
 273static inline u8 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf)     \
 274{                                                                               \
 275        return __mlxsw_item_get8(buf, &__ITEM_NAME(_type, _cname, _iname), 0);  \
 276}                                                                               \
 277static 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)                 \
 284static 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};                                                                              \
 293static inline u8                                                                \
 294mlxsw_##_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}                                                                               \
 299static inline void                                                              \
 300mlxsw_##_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)         \
 308static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
 309        .offset = _offset,                                                      \
 310        .shift = _shift,                                                        \
 311        .size = {.bits = _sizebits,},                                           \
 312        .name = #_type "_" #_cname "_" #_iname,                                 \
 313};                                                                              \
 314static inline u16 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf)    \
 315{                                                                               \
 316        return __mlxsw_item_get16(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \
 317}                                                                               \
 318static 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)                \
 325static 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};                                                                              \
 334static inline u16                                                               \
 335mlxsw_##_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}                                                                               \
 340static inline void                                                              \
 341mlxsw_##_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)         \
 349static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
 350        .offset = _offset,                                                      \
 351        .shift = _shift,                                                        \
 352        .size = {.bits = _sizebits,},                                           \
 353        .name = #_type "_" #_cname "_" #_iname,                                 \
 354};                                                                              \
 355static inline u32 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf)    \
 356{                                                                               \
 357        return __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \
 358}                                                                               \
 359static 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)                \
 366static 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};                                                                              \
 375static inline u32                                                               \
 376mlxsw_##_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}                                                                               \
 381static inline void                                                              \
 382mlxsw_##_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)         \
 390static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
 391        .offset = _offset,                                                      \
 392        .shift = _shift,                                                        \
 393        .size = {.bits = _sizebits,},                                           \
 394        .name = #_type "_" #_cname "_" #_iname,                                 \
 395};                                                                              \
 396static inline u64 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf)    \
 397{                                                                               \
 398        return __mlxsw_item_get64(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \
 399}                                                                               \
 400static 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)     \
 407static 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};                                                                              \
 416static inline u64                                                               \
 417mlxsw_##_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}                                                                               \
 422static inline void                                                              \
 423mlxsw_##_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)              \
 431static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {                 \
 432        .offset = _offset,                                                      \
 433        .size = {.bytes = _sizebytes,},                                         \
 434        .name = #_type "_" #_cname "_" #_iname,                                 \
 435};                                                                              \
 436static inline void                                                              \
 437mlxsw_##_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}                                                                               \
 442static inline void                                                              \
 443mlxsw_##_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}                                                                               \
 448static inline char *                                                            \
 449mlxsw_##_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)                            \
 456static 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};                                                                              \
 463static inline void                                                              \
 464mlxsw_##_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}                                                                               \
 471static inline void                                                              \
 472mlxsw_##_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}                                                                               \
 479static inline char *                                                            \
 480mlxsw_##_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)                                     \
 488static 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};                                                                              \
 494static inline u8                                                                \
 495mlxsw_##_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}                                                                               \
 501static inline void                                                              \
 502mlxsw_##_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
 510