0001
0002
0003
0004 #ifndef _MLXSW_ITEM_H
0005 #define _MLXSW_ITEM_H
0006
0007 #include <linux/types.h>
0008 #include <linux/string.h>
0009 #include <linux/bitops.h>
0010
0011 struct mlxsw_item {
0012 unsigned short offset;
0013 short step;
0014 unsigned short in_step_offset;
0015 unsigned char shift;
0016 unsigned char element_size;
0017 bool no_real_shift;
0018 union {
0019 unsigned char bits;
0020 unsigned short bytes;
0021 } size;
0022 const char *name;
0023 };
0024
0025 static inline unsigned int
0026 __mlxsw_item_offset(const struct mlxsw_item *item, unsigned short index,
0027 size_t typesize)
0028 {
0029 BUG_ON(index && !item->step);
0030 if (item->offset % typesize != 0 ||
0031 item->step % typesize != 0 ||
0032 item->in_step_offset % typesize != 0) {
0033 pr_err("mlxsw: item bug (name=%s,offset=%x,step=%x,in_step_offset=%x,typesize=%zx)\n",
0034 item->name, item->offset, item->step,
0035 item->in_step_offset, typesize);
0036 BUG();
0037 }
0038
0039 return ((item->offset + item->step * index + item->in_step_offset) /
0040 typesize);
0041 }
0042
0043 static inline u8 __mlxsw_item_get8(const char *buf,
0044 const struct mlxsw_item *item,
0045 unsigned short index)
0046 {
0047 unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u8));
0048 u8 *b = (u8 *) buf;
0049 u8 tmp;
0050
0051 tmp = b[offset];
0052 tmp >>= item->shift;
0053 tmp &= GENMASK(item->size.bits - 1, 0);
0054 if (item->no_real_shift)
0055 tmp <<= item->shift;
0056 return tmp;
0057 }
0058
0059 static inline void __mlxsw_item_set8(char *buf, const struct mlxsw_item *item,
0060 unsigned short index, u8 val)
0061 {
0062 unsigned int offset = __mlxsw_item_offset(item, index,
0063 sizeof(u8));
0064 u8 *b = (u8 *) buf;
0065 u8 mask = GENMASK(item->size.bits - 1, 0) << item->shift;
0066 u8 tmp;
0067
0068 if (!item->no_real_shift)
0069 val <<= item->shift;
0070 val &= mask;
0071 tmp = b[offset];
0072 tmp &= ~mask;
0073 tmp |= val;
0074 b[offset] = tmp;
0075 }
0076
0077 static inline u16 __mlxsw_item_get16(const char *buf,
0078 const struct mlxsw_item *item,
0079 unsigned short index)
0080 {
0081 unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u16));
0082 __be16 *b = (__be16 *) buf;
0083 u16 tmp;
0084
0085 tmp = be16_to_cpu(b[offset]);
0086 tmp >>= item->shift;
0087 tmp &= GENMASK(item->size.bits - 1, 0);
0088 if (item->no_real_shift)
0089 tmp <<= item->shift;
0090 return tmp;
0091 }
0092
0093 static inline void __mlxsw_item_set16(char *buf, const struct mlxsw_item *item,
0094 unsigned short index, u16 val)
0095 {
0096 unsigned int offset = __mlxsw_item_offset(item, index,
0097 sizeof(u16));
0098 __be16 *b = (__be16 *) buf;
0099 u16 mask = GENMASK(item->size.bits - 1, 0) << item->shift;
0100 u16 tmp;
0101
0102 if (!item->no_real_shift)
0103 val <<= item->shift;
0104 val &= mask;
0105 tmp = be16_to_cpu(b[offset]);
0106 tmp &= ~mask;
0107 tmp |= val;
0108 b[offset] = cpu_to_be16(tmp);
0109 }
0110
0111 static inline u32 __mlxsw_item_get32(const char *buf,
0112 const struct mlxsw_item *item,
0113 unsigned short index)
0114 {
0115 unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u32));
0116 __be32 *b = (__be32 *) buf;
0117 u32 tmp;
0118
0119 tmp = be32_to_cpu(b[offset]);
0120 tmp >>= item->shift;
0121 tmp &= GENMASK(item->size.bits - 1, 0);
0122 if (item->no_real_shift)
0123 tmp <<= item->shift;
0124 return tmp;
0125 }
0126
0127 static inline void __mlxsw_item_set32(char *buf, const struct mlxsw_item *item,
0128 unsigned short index, u32 val)
0129 {
0130 unsigned int offset = __mlxsw_item_offset(item, index,
0131 sizeof(u32));
0132 __be32 *b = (__be32 *) buf;
0133 u32 mask = GENMASK(item->size.bits - 1, 0) << item->shift;
0134 u32 tmp;
0135
0136 if (!item->no_real_shift)
0137 val <<= item->shift;
0138 val &= mask;
0139 tmp = be32_to_cpu(b[offset]);
0140 tmp &= ~mask;
0141 tmp |= val;
0142 b[offset] = cpu_to_be32(tmp);
0143 }
0144
0145 static inline u64 __mlxsw_item_get64(const char *buf,
0146 const struct mlxsw_item *item,
0147 unsigned short index)
0148 {
0149 unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u64));
0150 __be64 *b = (__be64 *) buf;
0151 u64 tmp;
0152
0153 tmp = be64_to_cpu(b[offset]);
0154 tmp >>= item->shift;
0155 tmp &= GENMASK_ULL(item->size.bits - 1, 0);
0156 if (item->no_real_shift)
0157 tmp <<= item->shift;
0158 return tmp;
0159 }
0160
0161 static inline void __mlxsw_item_set64(char *buf, const struct mlxsw_item *item,
0162 unsigned short index, u64 val)
0163 {
0164 unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u64));
0165 __be64 *b = (__be64 *) buf;
0166 u64 mask = GENMASK_ULL(item->size.bits - 1, 0) << item->shift;
0167 u64 tmp;
0168
0169 if (!item->no_real_shift)
0170 val <<= item->shift;
0171 val &= mask;
0172 tmp = be64_to_cpu(b[offset]);
0173 tmp &= ~mask;
0174 tmp |= val;
0175 b[offset] = cpu_to_be64(tmp);
0176 }
0177
0178 static inline void __mlxsw_item_memcpy_from(const char *buf, char *dst,
0179 const struct mlxsw_item *item,
0180 unsigned short index)
0181 {
0182 unsigned int offset = __mlxsw_item_offset(item, index, sizeof(char));
0183
0184 memcpy(dst, &buf[offset], item->size.bytes);
0185 }
0186
0187 static inline void __mlxsw_item_memcpy_to(char *buf, const char *src,
0188 const struct mlxsw_item *item,
0189 unsigned short index)
0190 {
0191 unsigned int offset = __mlxsw_item_offset(item, index, sizeof(char));
0192
0193 memcpy(&buf[offset], src, item->size.bytes);
0194 }
0195
0196 static inline char *__mlxsw_item_data(char *buf, const struct mlxsw_item *item,
0197 unsigned short index)
0198 {
0199 unsigned int offset = __mlxsw_item_offset(item, index, sizeof(char));
0200
0201 return &buf[offset];
0202 }
0203
0204 static inline u16
0205 __mlxsw_item_bit_array_offset(const struct mlxsw_item *item,
0206 u16 index, u8 *shift)
0207 {
0208 u16 max_index, be_index;
0209 u16 offset;
0210 u8 in_byte_index;
0211
0212 BUG_ON(index && !item->element_size);
0213 if (item->offset % sizeof(u32) != 0 ||
0214 BITS_PER_BYTE % item->element_size != 0) {
0215 pr_err("mlxsw: item bug (name=%s,offset=%x,element_size=%x)\n",
0216 item->name, item->offset, item->element_size);
0217 BUG();
0218 }
0219
0220 max_index = (item->size.bytes << 3) / item->element_size - 1;
0221 be_index = max_index - index;
0222 offset = be_index * item->element_size >> 3;
0223 in_byte_index = index % (BITS_PER_BYTE / item->element_size);
0224 *shift = in_byte_index * item->element_size;
0225
0226 return item->offset + offset;
0227 }
0228
0229 static inline u8 __mlxsw_item_bit_array_get(const char *buf,
0230 const struct mlxsw_item *item,
0231 u16 index)
0232 {
0233 u8 shift, tmp;
0234 u16 offset = __mlxsw_item_bit_array_offset(item, index, &shift);
0235
0236 tmp = buf[offset];
0237 tmp >>= shift;
0238 tmp &= GENMASK(item->element_size - 1, 0);
0239 return tmp;
0240 }
0241
0242 static inline void __mlxsw_item_bit_array_set(char *buf,
0243 const struct mlxsw_item *item,
0244 u16 index, u8 val)
0245 {
0246 u8 shift, tmp;
0247 u16 offset = __mlxsw_item_bit_array_offset(item, index, &shift);
0248 u8 mask = GENMASK(item->element_size - 1, 0) << shift;
0249
0250 val <<= shift;
0251 val &= mask;
0252 tmp = buf[offset];
0253 tmp &= ~mask;
0254 tmp |= val;
0255 buf[offset] = tmp;
0256 }
0257
0258 #define __ITEM_NAME(_type, _cname, _iname) \
0259 mlxsw_##_type##_##_cname##_##_iname##_item
0260
0261
0262
0263
0264
0265
0266 #define MLXSW_ITEM8(_type, _cname, _iname, _offset, _shift, _sizebits) \
0267 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \
0268 .offset = _offset, \
0269 .shift = _shift, \
0270 .size = {.bits = _sizebits,}, \
0271 .name = #_type "_" #_cname "_" #_iname, \
0272 }; \
0273 static inline u8 __maybe_unused \
0274 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf) \
0275 { \
0276 return __mlxsw_item_get8(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \
0277 } \
0278 static inline void __maybe_unused \
0279 mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u8 val) \
0280 { \
0281 __mlxsw_item_set8(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val); \
0282 }
0283
0284 #define MLXSW_ITEM8_INDEXED(_type, _cname, _iname, _offset, _shift, _sizebits, \
0285 _step, _instepoffset, _norealshift) \
0286 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \
0287 .offset = _offset, \
0288 .step = _step, \
0289 .in_step_offset = _instepoffset, \
0290 .shift = _shift, \
0291 .no_real_shift = _norealshift, \
0292 .size = {.bits = _sizebits,}, \
0293 .name = #_type "_" #_cname "_" #_iname, \
0294 }; \
0295 static inline u8 __maybe_unused \
0296 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, unsigned short index)\
0297 { \
0298 return __mlxsw_item_get8(buf, &__ITEM_NAME(_type, _cname, _iname), \
0299 index); \
0300 } \
0301 static inline void __maybe_unused \
0302 mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index, \
0303 u8 val) \
0304 { \
0305 __mlxsw_item_set8(buf, &__ITEM_NAME(_type, _cname, _iname), \
0306 index, val); \
0307 }
0308
0309 #define MLXSW_ITEM16(_type, _cname, _iname, _offset, _shift, _sizebits) \
0310 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \
0311 .offset = _offset, \
0312 .shift = _shift, \
0313 .size = {.bits = _sizebits,}, \
0314 .name = #_type "_" #_cname "_" #_iname, \
0315 }; \
0316 static inline u16 __maybe_unused \
0317 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf) \
0318 { \
0319 return __mlxsw_item_get16(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \
0320 } \
0321 static inline void __maybe_unused \
0322 mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u16 val) \
0323 { \
0324 __mlxsw_item_set16(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val); \
0325 }
0326
0327 #define MLXSW_ITEM16_INDEXED(_type, _cname, _iname, _offset, _shift, _sizebits, \
0328 _step, _instepoffset, _norealshift) \
0329 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \
0330 .offset = _offset, \
0331 .step = _step, \
0332 .in_step_offset = _instepoffset, \
0333 .shift = _shift, \
0334 .no_real_shift = _norealshift, \
0335 .size = {.bits = _sizebits,}, \
0336 .name = #_type "_" #_cname "_" #_iname, \
0337 }; \
0338 static inline u16 __maybe_unused \
0339 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, unsigned short index)\
0340 { \
0341 return __mlxsw_item_get16(buf, &__ITEM_NAME(_type, _cname, _iname), \
0342 index); \
0343 } \
0344 static inline void __maybe_unused \
0345 mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index, \
0346 u16 val) \
0347 { \
0348 __mlxsw_item_set16(buf, &__ITEM_NAME(_type, _cname, _iname), \
0349 index, val); \
0350 }
0351
0352 #define MLXSW_ITEM32(_type, _cname, _iname, _offset, _shift, _sizebits) \
0353 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \
0354 .offset = _offset, \
0355 .shift = _shift, \
0356 .size = {.bits = _sizebits,}, \
0357 .name = #_type "_" #_cname "_" #_iname, \
0358 }; \
0359 static inline u32 __maybe_unused \
0360 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf) \
0361 { \
0362 return __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \
0363 } \
0364 static inline void __maybe_unused \
0365 mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u32 val) \
0366 { \
0367 __mlxsw_item_set32(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val); \
0368 }
0369
0370 #define LOCAL_PORT_LSB_SIZE 8
0371 #define LOCAL_PORT_MSB_SIZE 2
0372
0373 #define MLXSW_ITEM32_LP(_type, _cname, _offset1, _shift1, _offset2, _shift2) \
0374 static struct mlxsw_item __ITEM_NAME(_type, _cname, local_port) = { \
0375 .offset = _offset1, \
0376 .shift = _shift1, \
0377 .size = {.bits = LOCAL_PORT_LSB_SIZE,}, \
0378 .name = #_type "_" #_cname "_local_port", \
0379 }; \
0380 static struct mlxsw_item __ITEM_NAME(_type, _cname, lp_msb) = { \
0381 .offset = _offset2, \
0382 .shift = _shift2, \
0383 .size = {.bits = LOCAL_PORT_MSB_SIZE,}, \
0384 .name = #_type "_" #_cname "_lp_msb", \
0385 }; \
0386 static inline u32 __maybe_unused \
0387 mlxsw_##_type##_##_cname##_local_port_get(const char *buf) \
0388 { \
0389 u32 local_port, lp_msb; \
0390 \
0391 local_port = __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, \
0392 local_port), 0); \
0393 lp_msb = __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, lp_msb), \
0394 0); \
0395 return (lp_msb << LOCAL_PORT_LSB_SIZE) + local_port; \
0396 } \
0397 static inline void __maybe_unused \
0398 mlxsw_##_type##_##_cname##_local_port_set(char *buf, u32 val) \
0399 { \
0400 __mlxsw_item_set32(buf, &__ITEM_NAME(_type, _cname, local_port), 0, \
0401 val & ((1 << LOCAL_PORT_LSB_SIZE) - 1)); \
0402 __mlxsw_item_set32(buf, &__ITEM_NAME(_type, _cname, lp_msb), 0, \
0403 val >> LOCAL_PORT_LSB_SIZE); \
0404 }
0405
0406 #define MLXSW_ITEM32_INDEXED(_type, _cname, _iname, _offset, _shift, _sizebits, \
0407 _step, _instepoffset, _norealshift) \
0408 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \
0409 .offset = _offset, \
0410 .step = _step, \
0411 .in_step_offset = _instepoffset, \
0412 .shift = _shift, \
0413 .no_real_shift = _norealshift, \
0414 .size = {.bits = _sizebits,}, \
0415 .name = #_type "_" #_cname "_" #_iname, \
0416 }; \
0417 static inline u32 __maybe_unused \
0418 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, unsigned short index)\
0419 { \
0420 return __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, _iname), \
0421 index); \
0422 } \
0423 static inline void __maybe_unused \
0424 mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index, \
0425 u32 val) \
0426 { \
0427 __mlxsw_item_set32(buf, &__ITEM_NAME(_type, _cname, _iname), \
0428 index, val); \
0429 }
0430
0431 #define MLXSW_ITEM64(_type, _cname, _iname, _offset, _shift, _sizebits) \
0432 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \
0433 .offset = _offset, \
0434 .shift = _shift, \
0435 .size = {.bits = _sizebits,}, \
0436 .name = #_type "_" #_cname "_" #_iname, \
0437 }; \
0438 static inline u64 __maybe_unused \
0439 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf) \
0440 { \
0441 return __mlxsw_item_get64(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \
0442 } \
0443 static inline void __maybe_unused \
0444 mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u64 val) \
0445 { \
0446 __mlxsw_item_set64(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val); \
0447 }
0448
0449 #define MLXSW_ITEM64_INDEXED(_type, _cname, _iname, _offset, _shift, \
0450 _sizebits, _step, _instepoffset, _norealshift) \
0451 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \
0452 .offset = _offset, \
0453 .step = _step, \
0454 .in_step_offset = _instepoffset, \
0455 .shift = _shift, \
0456 .no_real_shift = _norealshift, \
0457 .size = {.bits = _sizebits,}, \
0458 .name = #_type "_" #_cname "_" #_iname, \
0459 }; \
0460 static inline u64 __maybe_unused \
0461 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, unsigned short index)\
0462 { \
0463 return __mlxsw_item_get64(buf, &__ITEM_NAME(_type, _cname, _iname), \
0464 index); \
0465 } \
0466 static inline void __maybe_unused \
0467 mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index, \
0468 u64 val) \
0469 { \
0470 __mlxsw_item_set64(buf, &__ITEM_NAME(_type, _cname, _iname), \
0471 index, val); \
0472 }
0473
0474 #define MLXSW_ITEM_BUF(_type, _cname, _iname, _offset, _sizebytes) \
0475 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \
0476 .offset = _offset, \
0477 .size = {.bytes = _sizebytes,}, \
0478 .name = #_type "_" #_cname "_" #_iname, \
0479 }; \
0480 static inline void __maybe_unused \
0481 mlxsw_##_type##_##_cname##_##_iname##_memcpy_from(const char *buf, char *dst) \
0482 { \
0483 __mlxsw_item_memcpy_from(buf, dst, \
0484 &__ITEM_NAME(_type, _cname, _iname), 0); \
0485 } \
0486 static inline void __maybe_unused \
0487 mlxsw_##_type##_##_cname##_##_iname##_memcpy_to(char *buf, const char *src) \
0488 { \
0489 __mlxsw_item_memcpy_to(buf, src, \
0490 &__ITEM_NAME(_type, _cname, _iname), 0); \
0491 } \
0492 static inline char * __maybe_unused \
0493 mlxsw_##_type##_##_cname##_##_iname##_data(char *buf) \
0494 { \
0495 return __mlxsw_item_data(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \
0496 }
0497
0498 #define MLXSW_ITEM_BUF_INDEXED(_type, _cname, _iname, _offset, _sizebytes, \
0499 _step, _instepoffset) \
0500 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \
0501 .offset = _offset, \
0502 .step = _step, \
0503 .in_step_offset = _instepoffset, \
0504 .size = {.bytes = _sizebytes,}, \
0505 .name = #_type "_" #_cname "_" #_iname, \
0506 }; \
0507 static inline void __maybe_unused \
0508 mlxsw_##_type##_##_cname##_##_iname##_memcpy_from(const char *buf, \
0509 unsigned short index, \
0510 char *dst) \
0511 { \
0512 __mlxsw_item_memcpy_from(buf, dst, \
0513 &__ITEM_NAME(_type, _cname, _iname), index); \
0514 } \
0515 static inline void __maybe_unused \
0516 mlxsw_##_type##_##_cname##_##_iname##_memcpy_to(char *buf, \
0517 unsigned short index, \
0518 const char *src) \
0519 { \
0520 __mlxsw_item_memcpy_to(buf, src, \
0521 &__ITEM_NAME(_type, _cname, _iname), index); \
0522 } \
0523 static inline char * __maybe_unused \
0524 mlxsw_##_type##_##_cname##_##_iname##_data(char *buf, unsigned short index) \
0525 { \
0526 return __mlxsw_item_data(buf, \
0527 &__ITEM_NAME(_type, _cname, _iname), index); \
0528 }
0529
0530 #define MLXSW_ITEM_BIT_ARRAY(_type, _cname, _iname, _offset, _sizebytes, \
0531 _element_size) \
0532 static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \
0533 .offset = _offset, \
0534 .element_size = _element_size, \
0535 .size = {.bytes = _sizebytes,}, \
0536 .name = #_type "_" #_cname "_" #_iname, \
0537 }; \
0538 static inline u8 __maybe_unused \
0539 mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, u16 index) \
0540 { \
0541 return __mlxsw_item_bit_array_get(buf, \
0542 &__ITEM_NAME(_type, _cname, _iname), \
0543 index); \
0544 } \
0545 static inline void __maybe_unused \
0546 mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u16 index, u8 val) \
0547 { \
0548 return __mlxsw_item_bit_array_set(buf, \
0549 &__ITEM_NAME(_type, _cname, _iname), \
0550 index, val); \
0551 } \
0552
0553 #endif