558 lines · c
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_H5#define _MLXSW_ITEM_H6 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 int26__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 u16205__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 if (WARN_ONCE(index > max_index,222 "name=%s,index=%u,max_index=%u\n", item->name, index,223 max_index))224 index = 0;225 be_index = max_index - index;226 offset = be_index * item->element_size >> 3;227 in_byte_index = index % (BITS_PER_BYTE / item->element_size);228 *shift = in_byte_index * item->element_size;229 230 return item->offset + offset;231}232 233static inline u8 __mlxsw_item_bit_array_get(const char *buf,234 const struct mlxsw_item *item,235 u16 index)236{237 u8 shift, tmp;238 u16 offset = __mlxsw_item_bit_array_offset(item, index, &shift);239 240 tmp = buf[offset];241 tmp >>= shift;242 tmp &= GENMASK(item->element_size - 1, 0);243 return tmp;244}245 246static inline void __mlxsw_item_bit_array_set(char *buf,247 const struct mlxsw_item *item,248 u16 index, u8 val)249{250 u8 shift, tmp;251 u16 offset = __mlxsw_item_bit_array_offset(item, index, &shift);252 u8 mask = GENMASK(item->element_size - 1, 0) << shift;253 254 val <<= shift;255 val &= mask;256 tmp = buf[offset];257 tmp &= ~mask;258 tmp |= val;259 buf[offset] = tmp;260}261 262#define __ITEM_NAME(_type, _cname, _iname) \263 mlxsw_##_type##_##_cname##_##_iname##_item264 265/* _type: cmd_mbox, reg, etc.266 * _cname: containter name (e.g. command name, register name)267 * _iname: item name within the container268 */269 270#define MLXSW_ITEM8(_type, _cname, _iname, _offset, _shift, _sizebits) \271static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \272 .offset = _offset, \273 .shift = _shift, \274 .size = {.bits = _sizebits,}, \275 .name = #_type "_" #_cname "_" #_iname, \276}; \277static inline u8 __maybe_unused \278mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf) \279{ \280 return __mlxsw_item_get8(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \281} \282static inline void __maybe_unused \283mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u8 val) \284{ \285 __mlxsw_item_set8(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val); \286}287 288#define MLXSW_ITEM8_INDEXED(_type, _cname, _iname, _offset, _shift, _sizebits, \289 _step, _instepoffset, _norealshift) \290static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \291 .offset = _offset, \292 .step = _step, \293 .in_step_offset = _instepoffset, \294 .shift = _shift, \295 .no_real_shift = _norealshift, \296 .size = {.bits = _sizebits,}, \297 .name = #_type "_" #_cname "_" #_iname, \298}; \299static inline u8 __maybe_unused \300mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, unsigned short index)\301{ \302 return __mlxsw_item_get8(buf, &__ITEM_NAME(_type, _cname, _iname), \303 index); \304} \305static inline void __maybe_unused \306mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index, \307 u8 val) \308{ \309 __mlxsw_item_set8(buf, &__ITEM_NAME(_type, _cname, _iname), \310 index, val); \311}312 313#define MLXSW_ITEM16(_type, _cname, _iname, _offset, _shift, _sizebits) \314static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \315 .offset = _offset, \316 .shift = _shift, \317 .size = {.bits = _sizebits,}, \318 .name = #_type "_" #_cname "_" #_iname, \319}; \320static inline u16 __maybe_unused \321mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf) \322{ \323 return __mlxsw_item_get16(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \324} \325static inline void __maybe_unused \326mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u16 val) \327{ \328 __mlxsw_item_set16(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val); \329}330 331#define MLXSW_ITEM16_INDEXED(_type, _cname, _iname, _offset, _shift, _sizebits, \332 _step, _instepoffset, _norealshift) \333static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \334 .offset = _offset, \335 .step = _step, \336 .in_step_offset = _instepoffset, \337 .shift = _shift, \338 .no_real_shift = _norealshift, \339 .size = {.bits = _sizebits,}, \340 .name = #_type "_" #_cname "_" #_iname, \341}; \342static inline u16 __maybe_unused \343mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, unsigned short index)\344{ \345 return __mlxsw_item_get16(buf, &__ITEM_NAME(_type, _cname, _iname), \346 index); \347} \348static inline void __maybe_unused \349mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index, \350 u16 val) \351{ \352 __mlxsw_item_set16(buf, &__ITEM_NAME(_type, _cname, _iname), \353 index, val); \354}355 356#define MLXSW_ITEM32(_type, _cname, _iname, _offset, _shift, _sizebits) \357static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \358 .offset = _offset, \359 .shift = _shift, \360 .size = {.bits = _sizebits,}, \361 .name = #_type "_" #_cname "_" #_iname, \362}; \363static inline u32 __maybe_unused \364mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf) \365{ \366 return __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \367} \368static inline void __maybe_unused \369mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u32 val) \370{ \371 __mlxsw_item_set32(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val); \372}373 374#define LOCAL_PORT_LSB_SIZE 8375#define LOCAL_PORT_MSB_SIZE 2376 377#define MLXSW_ITEM32_LP(_type, _cname, _offset1, _shift1, _offset2, _shift2) \378static struct mlxsw_item __ITEM_NAME(_type, _cname, local_port) = { \379 .offset = _offset1, \380 .shift = _shift1, \381 .size = {.bits = LOCAL_PORT_LSB_SIZE,}, \382 .name = #_type "_" #_cname "_local_port", \383}; \384static struct mlxsw_item __ITEM_NAME(_type, _cname, lp_msb) = { \385 .offset = _offset2, \386 .shift = _shift2, \387 .size = {.bits = LOCAL_PORT_MSB_SIZE,}, \388 .name = #_type "_" #_cname "_lp_msb", \389}; \390static inline u32 __maybe_unused \391mlxsw_##_type##_##_cname##_local_port_get(const char *buf) \392{ \393 u32 local_port, lp_msb; \394 \395 local_port = __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, \396 local_port), 0); \397 lp_msb = __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, lp_msb), \398 0); \399 return (lp_msb << LOCAL_PORT_LSB_SIZE) + local_port; \400} \401static inline void __maybe_unused \402mlxsw_##_type##_##_cname##_local_port_set(char *buf, u32 val) \403{ \404 __mlxsw_item_set32(buf, &__ITEM_NAME(_type, _cname, local_port), 0, \405 val & ((1 << LOCAL_PORT_LSB_SIZE) - 1)); \406 __mlxsw_item_set32(buf, &__ITEM_NAME(_type, _cname, lp_msb), 0, \407 val >> LOCAL_PORT_LSB_SIZE); \408}409 410#define MLXSW_ITEM32_INDEXED(_type, _cname, _iname, _offset, _shift, _sizebits, \411 _step, _instepoffset, _norealshift) \412static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \413 .offset = _offset, \414 .step = _step, \415 .in_step_offset = _instepoffset, \416 .shift = _shift, \417 .no_real_shift = _norealshift, \418 .size = {.bits = _sizebits,}, \419 .name = #_type "_" #_cname "_" #_iname, \420}; \421static inline u32 __maybe_unused \422mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, unsigned short index)\423{ \424 return __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, _iname), \425 index); \426} \427static inline void __maybe_unused \428mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index, \429 u32 val) \430{ \431 __mlxsw_item_set32(buf, &__ITEM_NAME(_type, _cname, _iname), \432 index, val); \433}434 435#define MLXSW_ITEM64(_type, _cname, _iname, _offset, _shift, _sizebits) \436static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \437 .offset = _offset, \438 .shift = _shift, \439 .size = {.bits = _sizebits,}, \440 .name = #_type "_" #_cname "_" #_iname, \441}; \442static inline u64 __maybe_unused \443mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf) \444{ \445 return __mlxsw_item_get64(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \446} \447static inline void __maybe_unused \448mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u64 val) \449{ \450 __mlxsw_item_set64(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val); \451}452 453#define MLXSW_ITEM64_INDEXED(_type, _cname, _iname, _offset, _shift, \454 _sizebits, _step, _instepoffset, _norealshift) \455static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \456 .offset = _offset, \457 .step = _step, \458 .in_step_offset = _instepoffset, \459 .shift = _shift, \460 .no_real_shift = _norealshift, \461 .size = {.bits = _sizebits,}, \462 .name = #_type "_" #_cname "_" #_iname, \463}; \464static inline u64 __maybe_unused \465mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, unsigned short index)\466{ \467 return __mlxsw_item_get64(buf, &__ITEM_NAME(_type, _cname, _iname), \468 index); \469} \470static inline void __maybe_unused \471mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index, \472 u64 val) \473{ \474 __mlxsw_item_set64(buf, &__ITEM_NAME(_type, _cname, _iname), \475 index, val); \476}477 478#define MLXSW_ITEM_BUF(_type, _cname, _iname, _offset, _sizebytes) \479static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \480 .offset = _offset, \481 .size = {.bytes = _sizebytes,}, \482 .name = #_type "_" #_cname "_" #_iname, \483}; \484static inline void __maybe_unused \485mlxsw_##_type##_##_cname##_##_iname##_memcpy_from(const char *buf, char *dst) \486{ \487 __mlxsw_item_memcpy_from(buf, dst, \488 &__ITEM_NAME(_type, _cname, _iname), 0); \489} \490static inline void __maybe_unused \491mlxsw_##_type##_##_cname##_##_iname##_memcpy_to(char *buf, const char *src) \492{ \493 __mlxsw_item_memcpy_to(buf, src, \494 &__ITEM_NAME(_type, _cname, _iname), 0); \495} \496static inline char * __maybe_unused \497mlxsw_##_type##_##_cname##_##_iname##_data(char *buf) \498{ \499 return __mlxsw_item_data(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \500}501 502#define MLXSW_ITEM_BUF_INDEXED(_type, _cname, _iname, _offset, _sizebytes, \503 _step, _instepoffset) \504static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \505 .offset = _offset, \506 .step = _step, \507 .in_step_offset = _instepoffset, \508 .size = {.bytes = _sizebytes,}, \509 .name = #_type "_" #_cname "_" #_iname, \510}; \511static inline void __maybe_unused \512mlxsw_##_type##_##_cname##_##_iname##_memcpy_from(const char *buf, \513 unsigned short index, \514 char *dst) \515{ \516 __mlxsw_item_memcpy_from(buf, dst, \517 &__ITEM_NAME(_type, _cname, _iname), index); \518} \519static inline void __maybe_unused \520mlxsw_##_type##_##_cname##_##_iname##_memcpy_to(char *buf, \521 unsigned short index, \522 const char *src) \523{ \524 __mlxsw_item_memcpy_to(buf, src, \525 &__ITEM_NAME(_type, _cname, _iname), index); \526} \527static inline char * __maybe_unused \528mlxsw_##_type##_##_cname##_##_iname##_data(char *buf, unsigned short index) \529{ \530 return __mlxsw_item_data(buf, \531 &__ITEM_NAME(_type, _cname, _iname), index); \532}533 534#define MLXSW_ITEM_BIT_ARRAY(_type, _cname, _iname, _offset, _sizebytes, \535 _element_size) \536static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \537 .offset = _offset, \538 .element_size = _element_size, \539 .size = {.bytes = _sizebytes,}, \540 .name = #_type "_" #_cname "_" #_iname, \541}; \542static inline u8 __maybe_unused \543mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, u16 index) \544{ \545 return __mlxsw_item_bit_array_get(buf, \546 &__ITEM_NAME(_type, _cname, _iname), \547 index); \548} \549static inline void __maybe_unused \550mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u16 index, u8 val) \551{ \552 return __mlxsw_item_bit_array_set(buf, \553 &__ITEM_NAME(_type, _cname, _iname), \554 index, val); \555} \556 557#endif558