item.h (17818B)
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 __maybe_unused \ 274mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf) \ 275{ \ 276 return __mlxsw_item_get8(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \ 277} \ 278static inline void __maybe_unused \ 279mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u8 val) \ 280{ \ 281 __mlxsw_item_set8(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val); \ 282} 283 284#define MLXSW_ITEM8_INDEXED(_type, _cname, _iname, _offset, _shift, _sizebits, \ 285 _step, _instepoffset, _norealshift) \ 286static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ 287 .offset = _offset, \ 288 .step = _step, \ 289 .in_step_offset = _instepoffset, \ 290 .shift = _shift, \ 291 .no_real_shift = _norealshift, \ 292 .size = {.bits = _sizebits,}, \ 293 .name = #_type "_" #_cname "_" #_iname, \ 294}; \ 295static inline u8 __maybe_unused \ 296mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, unsigned short index)\ 297{ \ 298 return __mlxsw_item_get8(buf, &__ITEM_NAME(_type, _cname, _iname), \ 299 index); \ 300} \ 301static inline void __maybe_unused \ 302mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index, \ 303 u8 val) \ 304{ \ 305 __mlxsw_item_set8(buf, &__ITEM_NAME(_type, _cname, _iname), \ 306 index, val); \ 307} 308 309#define MLXSW_ITEM16(_type, _cname, _iname, _offset, _shift, _sizebits) \ 310static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ 311 .offset = _offset, \ 312 .shift = _shift, \ 313 .size = {.bits = _sizebits,}, \ 314 .name = #_type "_" #_cname "_" #_iname, \ 315}; \ 316static inline u16 __maybe_unused \ 317mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf) \ 318{ \ 319 return __mlxsw_item_get16(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \ 320} \ 321static inline void __maybe_unused \ 322mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u16 val) \ 323{ \ 324 __mlxsw_item_set16(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val); \ 325} 326 327#define MLXSW_ITEM16_INDEXED(_type, _cname, _iname, _offset, _shift, _sizebits, \ 328 _step, _instepoffset, _norealshift) \ 329static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ 330 .offset = _offset, \ 331 .step = _step, \ 332 .in_step_offset = _instepoffset, \ 333 .shift = _shift, \ 334 .no_real_shift = _norealshift, \ 335 .size = {.bits = _sizebits,}, \ 336 .name = #_type "_" #_cname "_" #_iname, \ 337}; \ 338static inline u16 __maybe_unused \ 339mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, unsigned short index)\ 340{ \ 341 return __mlxsw_item_get16(buf, &__ITEM_NAME(_type, _cname, _iname), \ 342 index); \ 343} \ 344static inline void __maybe_unused \ 345mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index, \ 346 u16 val) \ 347{ \ 348 __mlxsw_item_set16(buf, &__ITEM_NAME(_type, _cname, _iname), \ 349 index, val); \ 350} 351 352#define MLXSW_ITEM32(_type, _cname, _iname, _offset, _shift, _sizebits) \ 353static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ 354 .offset = _offset, \ 355 .shift = _shift, \ 356 .size = {.bits = _sizebits,}, \ 357 .name = #_type "_" #_cname "_" #_iname, \ 358}; \ 359static inline u32 __maybe_unused \ 360mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf) \ 361{ \ 362 return __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \ 363} \ 364static inline void __maybe_unused \ 365mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u32 val) \ 366{ \ 367 __mlxsw_item_set32(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val); \ 368} 369 370#define LOCAL_PORT_LSB_SIZE 8 371#define LOCAL_PORT_MSB_SIZE 2 372 373#define MLXSW_ITEM32_LP(_type, _cname, _offset1, _shift1, _offset2, _shift2) \ 374static struct mlxsw_item __ITEM_NAME(_type, _cname, local_port) = { \ 375 .offset = _offset1, \ 376 .shift = _shift1, \ 377 .size = {.bits = LOCAL_PORT_LSB_SIZE,}, \ 378 .name = #_type "_" #_cname "_local_port", \ 379}; \ 380static struct mlxsw_item __ITEM_NAME(_type, _cname, lp_msb) = { \ 381 .offset = _offset2, \ 382 .shift = _shift2, \ 383 .size = {.bits = LOCAL_PORT_MSB_SIZE,}, \ 384 .name = #_type "_" #_cname "_lp_msb", \ 385}; \ 386static inline u32 __maybe_unused \ 387mlxsw_##_type##_##_cname##_local_port_get(const char *buf) \ 388{ \ 389 u32 local_port, lp_msb; \ 390 \ 391 local_port = __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, \ 392 local_port), 0); \ 393 lp_msb = __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, lp_msb), \ 394 0); \ 395 return (lp_msb << LOCAL_PORT_LSB_SIZE) + local_port; \ 396} \ 397static inline void __maybe_unused \ 398mlxsw_##_type##_##_cname##_local_port_set(char *buf, u32 val) \ 399{ \ 400 __mlxsw_item_set32(buf, &__ITEM_NAME(_type, _cname, local_port), 0, \ 401 val & ((1 << LOCAL_PORT_LSB_SIZE) - 1)); \ 402 __mlxsw_item_set32(buf, &__ITEM_NAME(_type, _cname, lp_msb), 0, \ 403 val >> LOCAL_PORT_LSB_SIZE); \ 404} 405 406#define MLXSW_ITEM32_INDEXED(_type, _cname, _iname, _offset, _shift, _sizebits, \ 407 _step, _instepoffset, _norealshift) \ 408static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ 409 .offset = _offset, \ 410 .step = _step, \ 411 .in_step_offset = _instepoffset, \ 412 .shift = _shift, \ 413 .no_real_shift = _norealshift, \ 414 .size = {.bits = _sizebits,}, \ 415 .name = #_type "_" #_cname "_" #_iname, \ 416}; \ 417static inline u32 __maybe_unused \ 418mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, unsigned short index)\ 419{ \ 420 return __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, _iname), \ 421 index); \ 422} \ 423static inline void __maybe_unused \ 424mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index, \ 425 u32 val) \ 426{ \ 427 __mlxsw_item_set32(buf, &__ITEM_NAME(_type, _cname, _iname), \ 428 index, val); \ 429} 430 431#define MLXSW_ITEM64(_type, _cname, _iname, _offset, _shift, _sizebits) \ 432static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ 433 .offset = _offset, \ 434 .shift = _shift, \ 435 .size = {.bits = _sizebits,}, \ 436 .name = #_type "_" #_cname "_" #_iname, \ 437}; \ 438static inline u64 __maybe_unused \ 439mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf) \ 440{ \ 441 return __mlxsw_item_get64(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \ 442} \ 443static inline void __maybe_unused \ 444mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u64 val) \ 445{ \ 446 __mlxsw_item_set64(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val); \ 447} 448 449#define MLXSW_ITEM64_INDEXED(_type, _cname, _iname, _offset, _shift, \ 450 _sizebits, _step, _instepoffset, _norealshift) \ 451static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ 452 .offset = _offset, \ 453 .step = _step, \ 454 .in_step_offset = _instepoffset, \ 455 .shift = _shift, \ 456 .no_real_shift = _norealshift, \ 457 .size = {.bits = _sizebits,}, \ 458 .name = #_type "_" #_cname "_" #_iname, \ 459}; \ 460static inline u64 __maybe_unused \ 461mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, unsigned short index)\ 462{ \ 463 return __mlxsw_item_get64(buf, &__ITEM_NAME(_type, _cname, _iname), \ 464 index); \ 465} \ 466static inline void __maybe_unused \ 467mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index, \ 468 u64 val) \ 469{ \ 470 __mlxsw_item_set64(buf, &__ITEM_NAME(_type, _cname, _iname), \ 471 index, val); \ 472} 473 474#define MLXSW_ITEM_BUF(_type, _cname, _iname, _offset, _sizebytes) \ 475static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ 476 .offset = _offset, \ 477 .size = {.bytes = _sizebytes,}, \ 478 .name = #_type "_" #_cname "_" #_iname, \ 479}; \ 480static inline void __maybe_unused \ 481mlxsw_##_type##_##_cname##_##_iname##_memcpy_from(const char *buf, char *dst) \ 482{ \ 483 __mlxsw_item_memcpy_from(buf, dst, \ 484 &__ITEM_NAME(_type, _cname, _iname), 0); \ 485} \ 486static inline void __maybe_unused \ 487mlxsw_##_type##_##_cname##_##_iname##_memcpy_to(char *buf, const char *src) \ 488{ \ 489 __mlxsw_item_memcpy_to(buf, src, \ 490 &__ITEM_NAME(_type, _cname, _iname), 0); \ 491} \ 492static inline char * __maybe_unused \ 493mlxsw_##_type##_##_cname##_##_iname##_data(char *buf) \ 494{ \ 495 return __mlxsw_item_data(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \ 496} 497 498#define MLXSW_ITEM_BUF_INDEXED(_type, _cname, _iname, _offset, _sizebytes, \ 499 _step, _instepoffset) \ 500static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ 501 .offset = _offset, \ 502 .step = _step, \ 503 .in_step_offset = _instepoffset, \ 504 .size = {.bytes = _sizebytes,}, \ 505 .name = #_type "_" #_cname "_" #_iname, \ 506}; \ 507static inline void __maybe_unused \ 508mlxsw_##_type##_##_cname##_##_iname##_memcpy_from(const char *buf, \ 509 unsigned short index, \ 510 char *dst) \ 511{ \ 512 __mlxsw_item_memcpy_from(buf, dst, \ 513 &__ITEM_NAME(_type, _cname, _iname), index); \ 514} \ 515static inline void __maybe_unused \ 516mlxsw_##_type##_##_cname##_##_iname##_memcpy_to(char *buf, \ 517 unsigned short index, \ 518 const char *src) \ 519{ \ 520 __mlxsw_item_memcpy_to(buf, src, \ 521 &__ITEM_NAME(_type, _cname, _iname), index); \ 522} \ 523static inline char * __maybe_unused \ 524mlxsw_##_type##_##_cname##_##_iname##_data(char *buf, unsigned short index) \ 525{ \ 526 return __mlxsw_item_data(buf, \ 527 &__ITEM_NAME(_type, _cname, _iname), index); \ 528} 529 530#define MLXSW_ITEM_BIT_ARRAY(_type, _cname, _iname, _offset, _sizebytes, \ 531 _element_size) \ 532static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ 533 .offset = _offset, \ 534 .element_size = _element_size, \ 535 .size = {.bytes = _sizebytes,}, \ 536 .name = #_type "_" #_cname "_" #_iname, \ 537}; \ 538static inline u8 __maybe_unused \ 539mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, u16 index) \ 540{ \ 541 return __mlxsw_item_bit_array_get(buf, \ 542 &__ITEM_NAME(_type, _cname, _iname), \ 543 index); \ 544} \ 545static inline void __maybe_unused \ 546mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u16 index, u8 val) \ 547{ \ 548 return __mlxsw_item_bit_array_set(buf, \ 549 &__ITEM_NAME(_type, _cname, _iname), \ 550 index, val); \ 551} \ 552 553#endif