1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright(c) 2013 - 2019 Intel Corporation. */ 3 4 #include "fm10k_tlv.h" 5 6 /** 7 * fm10k_tlv_msg_init - Initialize message block for TLV data storage 8 * @msg: Pointer to message block 9 * @msg_id: Message ID indicating message type 10 * 11 * This function return success if provided with a valid message pointer 12 **/ 13 s32 fm10k_tlv_msg_init(u32 *msg, u16 msg_id) 14 { 15 /* verify pointer is not NULL */ 16 if (!msg) 17 return FM10K_ERR_PARAM; 18 19 *msg = (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT) | msg_id; 20 21 return 0; 22 } 23 24 /** 25 * fm10k_tlv_attr_put_null_string - Place null terminated string on message 26 * @msg: Pointer to message block 27 * @attr_id: Attribute ID 28 * @string: Pointer to string to be stored in attribute 29 * 30 * This function will reorder a string to be CPU endian and store it in 31 * the attribute buffer. It will return success if provided with a valid 32 * pointers. 33 **/ 34 static s32 fm10k_tlv_attr_put_null_string(u32 *msg, u16 attr_id, 35 const unsigned char *string) 36 { 37 u32 attr_data = 0, len = 0; 38 u32 *attr; 39 40 /* verify pointers are not NULL */ 41 if (!string || !msg) 42 return FM10K_ERR_PARAM; 43 44 attr = &msg[FM10K_TLV_DWORD_LEN(*msg)]; 45 46 /* copy string into local variable and then write to msg */ 47 do { 48 /* write data to message */ 49 if (len && !(len % 4)) { 50 attr[len / 4] = attr_data; 51 attr_data = 0; 52 } 53 54 /* record character to offset location */ 55 attr_data |= (u32)(*string) << (8 * (len % 4)); 56 len++; 57 58 /* test for NULL and then increment */ 59 } while (*(string++)); 60 61 /* write last piece of data to message */ 62 attr[(len + 3) / 4] = attr_data; 63 64 /* record attribute header, update message length */ 65 len <<= FM10K_TLV_LEN_SHIFT; 66 attr[0] = len | attr_id; 67 68 /* add header length to length */ 69 len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT; 70 *msg += FM10K_TLV_LEN_ALIGN(len); 71 72 return 0; 73 } 74 75 /** 76 * fm10k_tlv_attr_get_null_string - Get null terminated string from attribute 77 * @attr: Pointer to attribute 78 * @string: Pointer to location of destination string 79 * 80 * This function pulls the string back out of the attribute and will place 81 * it in the array pointed by string. It will return success if provided 82 * with a valid pointers. 83 **/ 84 static s32 fm10k_tlv_attr_get_null_string(u32 *attr, unsigned char *string) 85 { 86 u32 len; 87 88 /* verify pointers are not NULL */ 89 if (!string || !attr) 90 return FM10K_ERR_PARAM; 91 92 len = *attr >> FM10K_TLV_LEN_SHIFT; 93 attr++; 94 95 while (len--) 96 string[len] = (u8)(attr[len / 4] >> (8 * (len % 4))); 97 98 return 0; 99 } 100 101 /** 102 * fm10k_tlv_attr_put_mac_vlan - Store MAC/VLAN attribute in message 103 * @msg: Pointer to message block 104 * @attr_id: Attribute ID 105 * @mac_addr: MAC address to be stored 106 * @vlan: VLAN to be stored 107 * 108 * This function will reorder a MAC address to be CPU endian and store it 109 * in the attribute buffer. It will return success if provided with a 110 * valid pointers. 111 **/ 112 s32 fm10k_tlv_attr_put_mac_vlan(u32 *msg, u16 attr_id, 113 const u8 *mac_addr, u16 vlan) 114 { 115 u32 len = ETH_ALEN << FM10K_TLV_LEN_SHIFT; 116 u32 *attr; 117 118 /* verify pointers are not NULL */ 119 if (!msg || !mac_addr) 120 return FM10K_ERR_PARAM; 121 122 attr = &msg[FM10K_TLV_DWORD_LEN(*msg)]; 123 124 /* record attribute header, update message length */ 125 attr[0] = len | attr_id; 126 127 /* copy value into local variable and then write to msg */ 128 attr[1] = le32_to_cpu(*(const __le32 *)&mac_addr[0]); 129 attr[2] = le16_to_cpu(*(const __le16 *)&mac_addr[4]); 130 attr[2] |= (u32)vlan << 16; 131 132 /* add header length to length */ 133 len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT; 134 *msg += FM10K_TLV_LEN_ALIGN(len); 135 136 return 0; 137 } 138 139 /** 140 * fm10k_tlv_attr_get_mac_vlan - Get MAC/VLAN stored in attribute 141 * @attr: Pointer to attribute 142 * @mac_addr: location of buffer to store MAC address 143 * @vlan: location of buffer to store VLAN 144 * 145 * This function pulls the MAC address back out of the attribute and will 146 * place it in the array pointed by mac_addr. It will return success 147 * if provided with a valid pointers. 148 **/ 149 s32 fm10k_tlv_attr_get_mac_vlan(u32 *attr, u8 *mac_addr, u16 *vlan) 150 { 151 /* verify pointers are not NULL */ 152 if (!mac_addr || !attr) 153 return FM10K_ERR_PARAM; 154 155 *(__le32 *)&mac_addr[0] = cpu_to_le32(attr[1]); 156 *(__le16 *)&mac_addr[4] = cpu_to_le16((u16)(attr[2])); 157 *vlan = (u16)(attr[2] >> 16); 158 159 return 0; 160 } 161 162 /** 163 * fm10k_tlv_attr_put_bool - Add header indicating value "true" 164 * @msg: Pointer to message block 165 * @attr_id: Attribute ID 166 * 167 * This function will simply add an attribute header, the fact 168 * that the header is here means the attribute value is true, else 169 * it is false. The function will return success if provided with a 170 * valid pointers. 171 **/ 172 s32 fm10k_tlv_attr_put_bool(u32 *msg, u16 attr_id) 173 { 174 /* verify pointers are not NULL */ 175 if (!msg) 176 return FM10K_ERR_PARAM; 177 178 /* record attribute header */ 179 msg[FM10K_TLV_DWORD_LEN(*msg)] = attr_id; 180 181 /* add header length to length */ 182 *msg += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT; 183 184 return 0; 185 } 186 187 /** 188 * fm10k_tlv_attr_put_value - Store integer value attribute in message 189 * @msg: Pointer to message block 190 * @attr_id: Attribute ID 191 * @value: Value to be written 192 * @len: Size of value 193 * 194 * This function will place an integer value of up to 8 bytes in size 195 * in a message attribute. The function will return success provided 196 * that msg is a valid pointer, and len is 1, 2, 4, or 8. 197 **/ 198 s32 fm10k_tlv_attr_put_value(u32 *msg, u16 attr_id, s64 value, u32 len) 199 { 200 u32 *attr; 201 202 /* verify non-null msg and len is 1, 2, 4, or 8 */ 203 if (!msg || !len || len > 8 || (len & (len - 1))) 204 return FM10K_ERR_PARAM; 205 206 attr = &msg[FM10K_TLV_DWORD_LEN(*msg)]; 207 208 if (len < 4) { 209 attr[1] = (u32)value & (BIT(8 * len) - 1); 210 } else { 211 attr[1] = (u32)value; 212 if (len > 4) 213 attr[2] = (u32)(value >> 32); 214 } 215 216 /* record attribute header, update message length */ 217 len <<= FM10K_TLV_LEN_SHIFT; 218 attr[0] = len | attr_id; 219 220 /* add header length to length */ 221 len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT; 222 *msg += FM10K_TLV_LEN_ALIGN(len); 223 224 return 0; 225 } 226 227 /** 228 * fm10k_tlv_attr_get_value - Get integer value stored in attribute 229 * @attr: Pointer to attribute 230 * @value: Pointer to destination buffer 231 * @len: Size of value 232 * 233 * This function will place an integer value of up to 8 bytes in size 234 * in the offset pointed to by value. The function will return success 235 * provided that pointers are valid and the len value matches the 236 * attribute length. 237 **/ 238 s32 fm10k_tlv_attr_get_value(u32 *attr, void *value, u32 len) 239 { 240 /* verify pointers are not NULL */ 241 if (!attr || !value) 242 return FM10K_ERR_PARAM; 243 244 if ((*attr >> FM10K_TLV_LEN_SHIFT) != len) 245 return FM10K_ERR_PARAM; 246 247 if (len == 8) 248 *(u64 *)value = ((u64)attr[2] << 32) | attr[1]; 249 else if (len == 4) 250 *(u32 *)value = attr[1]; 251 else if (len == 2) 252 *(u16 *)value = (u16)attr[1]; 253 else 254 *(u8 *)value = (u8)attr[1]; 255 256 return 0; 257 } 258 259 /** 260 * fm10k_tlv_attr_put_le_struct - Store little endian structure in message 261 * @msg: Pointer to message block 262 * @attr_id: Attribute ID 263 * @le_struct: Pointer to structure to be written 264 * @len: Size of le_struct 265 * 266 * This function will place a little endian structure value in a message 267 * attribute. The function will return success provided that all pointers 268 * are valid and length is a non-zero multiple of 4. 269 **/ 270 s32 fm10k_tlv_attr_put_le_struct(u32 *msg, u16 attr_id, 271 const void *le_struct, u32 len) 272 { 273 const __le32 *le32_ptr = (const __le32 *)le_struct; 274 u32 *attr; 275 u32 i; 276 277 /* verify non-null msg and len is in 32 bit words */ 278 if (!msg || !len || (len % 4)) 279 return FM10K_ERR_PARAM; 280 281 attr = &msg[FM10K_TLV_DWORD_LEN(*msg)]; 282 283 /* copy le32 structure into host byte order at 32b boundaries */ 284 for (i = 0; i < (len / 4); i++) 285 attr[i + 1] = le32_to_cpu(le32_ptr[i]); 286 287 /* record attribute header, update message length */ 288 len <<= FM10K_TLV_LEN_SHIFT; 289 attr[0] = len | attr_id; 290 291 /* add header length to length */ 292 len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT; 293 *msg += FM10K_TLV_LEN_ALIGN(len); 294 295 return 0; 296 } 297 298 /** 299 * fm10k_tlv_attr_get_le_struct - Get little endian struct form attribute 300 * @attr: Pointer to attribute 301 * @le_struct: Pointer to structure to be written 302 * @len: Size of structure 303 * 304 * This function will place a little endian structure in the buffer 305 * pointed to by le_struct. The function will return success 306 * provided that pointers are valid and the len value matches the 307 * attribute length. 308 **/ 309 s32 fm10k_tlv_attr_get_le_struct(u32 *attr, void *le_struct, u32 len) 310 { 311 __le32 *le32_ptr = (__le32 *)le_struct; 312 u32 i; 313 314 /* verify pointers are not NULL */ 315 if (!le_struct || !attr) 316 return FM10K_ERR_PARAM; 317 318 if ((*attr >> FM10K_TLV_LEN_SHIFT) != len) 319 return FM10K_ERR_PARAM; 320 321 attr++; 322 323 for (i = 0; len; i++, len -= 4) 324 le32_ptr[i] = cpu_to_le32(attr[i]); 325 326 return 0; 327 } 328 329 /** 330 * fm10k_tlv_attr_nest_start - Start a set of nested attributes 331 * @msg: Pointer to message block 332 * @attr_id: Attribute ID 333 * 334 * This function will mark off a new nested region for encapsulating 335 * a given set of attributes. The idea is if you wish to place a secondary 336 * structure within the message this mechanism allows for that. The 337 * function will return NULL on failure, and a pointer to the start 338 * of the nested attributes on success. 339 **/ 340 static u32 *fm10k_tlv_attr_nest_start(u32 *msg, u16 attr_id) 341 { 342 u32 *attr; 343 344 /* verify pointer is not NULL */ 345 if (!msg) 346 return NULL; 347 348 attr = &msg[FM10K_TLV_DWORD_LEN(*msg)]; 349 350 attr[0] = attr_id; 351 352 /* return pointer to nest header */ 353 return attr; 354 } 355 356 /** 357 * fm10k_tlv_attr_nest_stop - Stop a set of nested attributes 358 * @msg: Pointer to message block 359 * 360 * This function closes off an existing set of nested attributes. The 361 * message pointer should be pointing to the parent of the nest. So in 362 * the case of a nest within the nest this would be the outer nest pointer. 363 * This function will return success provided all pointers are valid. 364 **/ 365 static s32 fm10k_tlv_attr_nest_stop(u32 *msg) 366 { 367 u32 *attr; 368 u32 len; 369 370 /* verify pointer is not NULL */ 371 if (!msg) 372 return FM10K_ERR_PARAM; 373 374 /* locate the nested header and retrieve its length */ 375 attr = &msg[FM10K_TLV_DWORD_LEN(*msg)]; 376 len = (attr[0] >> FM10K_TLV_LEN_SHIFT) << FM10K_TLV_LEN_SHIFT; 377 378 /* only include nest if data was added to it */ 379 if (len) { 380 len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT; 381 *msg += len; 382 } 383 384 return 0; 385 } 386 387 /** 388 * fm10k_tlv_attr_validate - Validate attribute metadata 389 * @attr: Pointer to attribute 390 * @tlv_attr: Type and length info for attribute 391 * 392 * This function does some basic validation of the input TLV. It 393 * verifies the length, and in the case of null terminated strings 394 * it verifies that the last byte is null. The function will 395 * return FM10K_ERR_PARAM if any attribute is malformed, otherwise 396 * it returns 0. 397 **/ 398 static s32 fm10k_tlv_attr_validate(u32 *attr, 399 const struct fm10k_tlv_attr *tlv_attr) 400 { 401 u32 attr_id = *attr & FM10K_TLV_ID_MASK; 402 u16 len = *attr >> FM10K_TLV_LEN_SHIFT; 403 404 /* verify this is an attribute and not a message */ 405 if (*attr & (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT)) 406 return FM10K_ERR_PARAM; 407 408 /* search through the list of attributes to find a matching ID */ 409 while (tlv_attr->id < attr_id) 410 tlv_attr++; 411 412 /* if didn't find a match then we should exit */ 413 if (tlv_attr->id != attr_id) 414 return FM10K_NOT_IMPLEMENTED; 415 416 /* move to start of attribute data */ 417 attr++; 418 419 switch (tlv_attr->type) { 420 case FM10K_TLV_NULL_STRING: 421 if (!len || 422 (attr[(len - 1) / 4] & (0xFF << (8 * ((len - 1) % 4))))) 423 return FM10K_ERR_PARAM; 424 if (len > tlv_attr->len) 425 return FM10K_ERR_PARAM; 426 break; 427 case FM10K_TLV_MAC_ADDR: 428 if (len != ETH_ALEN) 429 return FM10K_ERR_PARAM; 430 break; 431 case FM10K_TLV_BOOL: 432 if (len) 433 return FM10K_ERR_PARAM; 434 break; 435 case FM10K_TLV_UNSIGNED: 436 case FM10K_TLV_SIGNED: 437 if (len != tlv_attr->len) 438 return FM10K_ERR_PARAM; 439 break; 440 case FM10K_TLV_LE_STRUCT: 441 /* struct must be 4 byte aligned */ 442 if ((len % 4) || len != tlv_attr->len) 443 return FM10K_ERR_PARAM; 444 break; 445 case FM10K_TLV_NESTED: 446 /* nested attributes must be 4 byte aligned */ 447 if (len % 4) 448 return FM10K_ERR_PARAM; 449 break; 450 default: 451 /* attribute id is mapped to bad value */ 452 return FM10K_ERR_PARAM; 453 } 454 455 return 0; 456 } 457 458 /** 459 * fm10k_tlv_attr_parse - Parses stream of attribute data 460 * @attr: Pointer to attribute list 461 * @results: Pointer array to store pointers to attributes 462 * @tlv_attr: Type and length info for attributes 463 * 464 * This function validates a stream of attributes and parses them 465 * up into an array of pointers stored in results. The function will 466 * return FM10K_ERR_PARAM on any input or message error, 467 * FM10K_NOT_IMPLEMENTED for any attribute that is outside of the array 468 * and 0 on success. Any attributes not found in tlv_attr will be silently 469 * ignored. 470 **/ 471 static s32 fm10k_tlv_attr_parse(u32 *attr, u32 **results, 472 const struct fm10k_tlv_attr *tlv_attr) 473 { 474 u32 i, attr_id, offset = 0; 475 s32 err; 476 u16 len; 477 478 /* verify pointers are not NULL */ 479 if (!attr || !results) 480 return FM10K_ERR_PARAM; 481 482 /* initialize results to NULL */ 483 for (i = 0; i < FM10K_TLV_RESULTS_MAX; i++) 484 results[i] = NULL; 485 486 /* pull length from the message header */ 487 len = *attr >> FM10K_TLV_LEN_SHIFT; 488 489 /* no attributes to parse if there is no length */ 490 if (!len) 491 return 0; 492 493 /* no attributes to parse, just raw data, message becomes attribute */ 494 if (!tlv_attr) { 495 results[0] = attr; 496 return 0; 497 } 498 499 /* move to start of attribute data */ 500 attr++; 501 502 /* run through list parsing all attributes */ 503 while (offset < len) { 504 attr_id = *attr & FM10K_TLV_ID_MASK; 505 506 if (attr_id >= FM10K_TLV_RESULTS_MAX) 507 return FM10K_NOT_IMPLEMENTED; 508 509 err = fm10k_tlv_attr_validate(attr, tlv_attr); 510 if (err == FM10K_NOT_IMPLEMENTED) 511 ; /* silently ignore non-implemented attributes */ 512 else if (err) 513 return err; 514 else 515 results[attr_id] = attr; 516 517 /* update offset */ 518 offset += FM10K_TLV_DWORD_LEN(*attr) * 4; 519 520 /* move to next attribute */ 521 attr = &attr[FM10K_TLV_DWORD_LEN(*attr)]; 522 } 523 524 /* we should find ourselves at the end of the list */ 525 if (offset != len) 526 return FM10K_ERR_PARAM; 527 528 return 0; 529 } 530 531 /** 532 * fm10k_tlv_msg_parse - Parses message header and calls function handler 533 * @hw: Pointer to hardware structure 534 * @msg: Pointer to message 535 * @mbx: Pointer to mailbox information structure 536 * @data: Pointer to message handler data structure 537 * 538 * This function should be the first function called upon receiving a 539 * message. The handler will identify the message type and call the correct 540 * handler for the given message. It will return the value from the function 541 * call on a recognized message type, otherwise it will return 542 * FM10K_NOT_IMPLEMENTED on an unrecognized type. 543 **/ 544 s32 fm10k_tlv_msg_parse(struct fm10k_hw *hw, u32 *msg, 545 struct fm10k_mbx_info *mbx, 546 const struct fm10k_msg_data *data) 547 { 548 u32 *results[FM10K_TLV_RESULTS_MAX]; 549 u32 msg_id; 550 s32 err; 551 552 /* verify pointer is not NULL */ 553 if (!msg || !data) 554 return FM10K_ERR_PARAM; 555 556 /* verify this is a message and not an attribute */ 557 if (!(*msg & (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT))) 558 return FM10K_ERR_PARAM; 559 560 /* grab message ID */ 561 msg_id = *msg & FM10K_TLV_ID_MASK; 562 563 while (data->id < msg_id) 564 data++; 565 566 /* if we didn't find it then pass it up as an error */ 567 if (data->id != msg_id) { 568 while (data->id != FM10K_TLV_ERROR) 569 data++; 570 } 571 572 /* parse the attributes into the results list */ 573 err = fm10k_tlv_attr_parse(msg, results, data->attr); 574 if (err < 0) 575 return err; 576 577 return data->func(hw, results, mbx); 578 } 579 580 /** 581 * fm10k_tlv_msg_error - Default handler for unrecognized TLV message IDs 582 * @hw: Pointer to hardware structure 583 * @results: Pointer array to message, results[0] is pointer to message 584 * @mbx: Unused mailbox pointer 585 * 586 * This function is a default handler for unrecognized messages. At a 587 * minimum it just indicates that the message requested was 588 * unimplemented. 589 **/ 590 s32 fm10k_tlv_msg_error(struct fm10k_hw __always_unused *hw, 591 u32 __always_unused **results, 592 struct fm10k_mbx_info __always_unused *mbx) 593 { 594 return FM10K_NOT_IMPLEMENTED; 595 } 596 597 static const unsigned char test_str[] = "fm10k"; 598 static const unsigned char test_mac[ETH_ALEN] = { 0x12, 0x34, 0x56, 599 0x78, 0x9a, 0xbc }; 600 static const u16 test_vlan = 0x0FED; 601 static const u64 test_u64 = 0xfedcba9876543210ull; 602 static const u32 test_u32 = 0x87654321; 603 static const u16 test_u16 = 0x8765; 604 static const u8 test_u8 = 0x87; 605 static const s64 test_s64 = -0x123456789abcdef0ll; 606 static const s32 test_s32 = -0x1235678; 607 static const s16 test_s16 = -0x1234; 608 static const s8 test_s8 = -0x12; 609 static const __le32 test_le[2] = { cpu_to_le32(0x12345678), 610 cpu_to_le32(0x9abcdef0)}; 611 612 /* The message below is meant to be used as a test message to demonstrate 613 * how to use the TLV interface and to test the types. Normally this code 614 * be compiled out by stripping the code wrapped in FM10K_TLV_TEST_MSG 615 */ 616 const struct fm10k_tlv_attr fm10k_tlv_msg_test_attr[] = { 617 FM10K_TLV_ATTR_NULL_STRING(FM10K_TEST_MSG_STRING, 80), 618 FM10K_TLV_ATTR_MAC_ADDR(FM10K_TEST_MSG_MAC_ADDR), 619 FM10K_TLV_ATTR_U8(FM10K_TEST_MSG_U8), 620 FM10K_TLV_ATTR_U16(FM10K_TEST_MSG_U16), 621 FM10K_TLV_ATTR_U32(FM10K_TEST_MSG_U32), 622 FM10K_TLV_ATTR_U64(FM10K_TEST_MSG_U64), 623 FM10K_TLV_ATTR_S8(FM10K_TEST_MSG_S8), 624 FM10K_TLV_ATTR_S16(FM10K_TEST_MSG_S16), 625 FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_S32), 626 FM10K_TLV_ATTR_S64(FM10K_TEST_MSG_S64), 627 FM10K_TLV_ATTR_LE_STRUCT(FM10K_TEST_MSG_LE_STRUCT, 8), 628 FM10K_TLV_ATTR_NESTED(FM10K_TEST_MSG_NESTED), 629 FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_RESULT), 630 FM10K_TLV_ATTR_LAST 631 }; 632 633 /** 634 * fm10k_tlv_msg_test_generate_data - Stuff message with data 635 * @msg: Pointer to message 636 * @attr_flags: List of flags indicating what attributes to add 637 * 638 * This function is meant to load a message buffer with attribute data 639 **/ 640 static void fm10k_tlv_msg_test_generate_data(u32 *msg, u32 attr_flags) 641 { 642 if (attr_flags & BIT(FM10K_TEST_MSG_STRING)) 643 fm10k_tlv_attr_put_null_string(msg, FM10K_TEST_MSG_STRING, 644 test_str); 645 if (attr_flags & BIT(FM10K_TEST_MSG_MAC_ADDR)) 646 fm10k_tlv_attr_put_mac_vlan(msg, FM10K_TEST_MSG_MAC_ADDR, 647 test_mac, test_vlan); 648 if (attr_flags & BIT(FM10K_TEST_MSG_U8)) 649 fm10k_tlv_attr_put_u8(msg, FM10K_TEST_MSG_U8, test_u8); 650 if (attr_flags & BIT(FM10K_TEST_MSG_U16)) 651 fm10k_tlv_attr_put_u16(msg, FM10K_TEST_MSG_U16, test_u16); 652 if (attr_flags & BIT(FM10K_TEST_MSG_U32)) 653 fm10k_tlv_attr_put_u32(msg, FM10K_TEST_MSG_U32, test_u32); 654 if (attr_flags & BIT(FM10K_TEST_MSG_U64)) 655 fm10k_tlv_attr_put_u64(msg, FM10K_TEST_MSG_U64, test_u64); 656 if (attr_flags & BIT(FM10K_TEST_MSG_S8)) 657 fm10k_tlv_attr_put_s8(msg, FM10K_TEST_MSG_S8, test_s8); 658 if (attr_flags & BIT(FM10K_TEST_MSG_S16)) 659 fm10k_tlv_attr_put_s16(msg, FM10K_TEST_MSG_S16, test_s16); 660 if (attr_flags & BIT(FM10K_TEST_MSG_S32)) 661 fm10k_tlv_attr_put_s32(msg, FM10K_TEST_MSG_S32, test_s32); 662 if (attr_flags & BIT(FM10K_TEST_MSG_S64)) 663 fm10k_tlv_attr_put_s64(msg, FM10K_TEST_MSG_S64, test_s64); 664 if (attr_flags & BIT(FM10K_TEST_MSG_LE_STRUCT)) 665 fm10k_tlv_attr_put_le_struct(msg, FM10K_TEST_MSG_LE_STRUCT, 666 test_le, 8); 667 } 668 669 /** 670 * fm10k_tlv_msg_test_create - Create a test message testing all attributes 671 * @msg: Pointer to message 672 * @attr_flags: List of flags indicating what attributes to add 673 * 674 * This function is meant to load a message buffer with all attribute types 675 * including a nested attribute. 676 **/ 677 void fm10k_tlv_msg_test_create(u32 *msg, u32 attr_flags) 678 { 679 u32 *nest = NULL; 680 681 fm10k_tlv_msg_init(msg, FM10K_TLV_MSG_ID_TEST); 682 683 fm10k_tlv_msg_test_generate_data(msg, attr_flags); 684 685 /* check for nested attributes */ 686 attr_flags >>= FM10K_TEST_MSG_NESTED; 687 688 if (attr_flags) { 689 nest = fm10k_tlv_attr_nest_start(msg, FM10K_TEST_MSG_NESTED); 690 691 fm10k_tlv_msg_test_generate_data(nest, attr_flags); 692 693 fm10k_tlv_attr_nest_stop(msg); 694 } 695 } 696 697 /** 698 * fm10k_tlv_msg_test - Validate all results on test message receive 699 * @hw: Pointer to hardware structure 700 * @results: Pointer array to attributes in the message 701 * @mbx: Pointer to mailbox information structure 702 * 703 * This function does a check to verify all attributes match what the test 704 * message placed in the message buffer. It is the default handler 705 * for TLV test messages. 706 **/ 707 s32 fm10k_tlv_msg_test(struct fm10k_hw *hw, u32 **results, 708 struct fm10k_mbx_info *mbx) 709 { 710 u32 *nest_results[FM10K_TLV_RESULTS_MAX]; 711 unsigned char result_str[80]; 712 unsigned char result_mac[ETH_ALEN]; 713 s32 err = 0; 714 __le32 result_le[2]; 715 u16 result_vlan; 716 u64 result_u64; 717 u32 result_u32; 718 u16 result_u16; 719 u8 result_u8; 720 s64 result_s64; 721 s32 result_s32; 722 s16 result_s16; 723 s8 result_s8; 724 u32 reply[3]; 725 726 /* retrieve results of a previous test */ 727 if (!!results[FM10K_TEST_MSG_RESULT]) 728 return fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_RESULT], 729 &mbx->test_result); 730 731 parse_nested: 732 if (!!results[FM10K_TEST_MSG_STRING]) { 733 err = fm10k_tlv_attr_get_null_string( 734 results[FM10K_TEST_MSG_STRING], 735 result_str); 736 if (!err && memcmp(test_str, result_str, sizeof(test_str))) 737 err = FM10K_ERR_INVALID_VALUE; 738 if (err) 739 goto report_result; 740 } 741 if (!!results[FM10K_TEST_MSG_MAC_ADDR]) { 742 err = fm10k_tlv_attr_get_mac_vlan( 743 results[FM10K_TEST_MSG_MAC_ADDR], 744 result_mac, &result_vlan); 745 if (!err && !ether_addr_equal(test_mac, result_mac)) 746 err = FM10K_ERR_INVALID_VALUE; 747 if (!err && test_vlan != result_vlan) 748 err = FM10K_ERR_INVALID_VALUE; 749 if (err) 750 goto report_result; 751 } 752 if (!!results[FM10K_TEST_MSG_U8]) { 753 err = fm10k_tlv_attr_get_u8(results[FM10K_TEST_MSG_U8], 754 &result_u8); 755 if (!err && test_u8 != result_u8) 756 err = FM10K_ERR_INVALID_VALUE; 757 if (err) 758 goto report_result; 759 } 760 if (!!results[FM10K_TEST_MSG_U16]) { 761 err = fm10k_tlv_attr_get_u16(results[FM10K_TEST_MSG_U16], 762 &result_u16); 763 if (!err && test_u16 != result_u16) 764 err = FM10K_ERR_INVALID_VALUE; 765 if (err) 766 goto report_result; 767 } 768 if (!!results[FM10K_TEST_MSG_U32]) { 769 err = fm10k_tlv_attr_get_u32(results[FM10K_TEST_MSG_U32], 770 &result_u32); 771 if (!err && test_u32 != result_u32) 772 err = FM10K_ERR_INVALID_VALUE; 773 if (err) 774 goto report_result; 775 } 776 if (!!results[FM10K_TEST_MSG_U64]) { 777 err = fm10k_tlv_attr_get_u64(results[FM10K_TEST_MSG_U64], 778 &result_u64); 779 if (!err && test_u64 != result_u64) 780 err = FM10K_ERR_INVALID_VALUE; 781 if (err) 782 goto report_result; 783 } 784 if (!!results[FM10K_TEST_MSG_S8]) { 785 err = fm10k_tlv_attr_get_s8(results[FM10K_TEST_MSG_S8], 786 &result_s8); 787 if (!err && test_s8 != result_s8) 788 err = FM10K_ERR_INVALID_VALUE; 789 if (err) 790 goto report_result; 791 } 792 if (!!results[FM10K_TEST_MSG_S16]) { 793 err = fm10k_tlv_attr_get_s16(results[FM10K_TEST_MSG_S16], 794 &result_s16); 795 if (!err && test_s16 != result_s16) 796 err = FM10K_ERR_INVALID_VALUE; 797 if (err) 798 goto report_result; 799 } 800 if (!!results[FM10K_TEST_MSG_S32]) { 801 err = fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_S32], 802 &result_s32); 803 if (!err && test_s32 != result_s32) 804 err = FM10K_ERR_INVALID_VALUE; 805 if (err) 806 goto report_result; 807 } 808 if (!!results[FM10K_TEST_MSG_S64]) { 809 err = fm10k_tlv_attr_get_s64(results[FM10K_TEST_MSG_S64], 810 &result_s64); 811 if (!err && test_s64 != result_s64) 812 err = FM10K_ERR_INVALID_VALUE; 813 if (err) 814 goto report_result; 815 } 816 if (!!results[FM10K_TEST_MSG_LE_STRUCT]) { 817 err = fm10k_tlv_attr_get_le_struct( 818 results[FM10K_TEST_MSG_LE_STRUCT], 819 result_le, 820 sizeof(result_le)); 821 if (!err && memcmp(test_le, result_le, sizeof(test_le))) 822 err = FM10K_ERR_INVALID_VALUE; 823 if (err) 824 goto report_result; 825 } 826 827 if (!!results[FM10K_TEST_MSG_NESTED]) { 828 /* clear any pointers */ 829 memset(nest_results, 0, sizeof(nest_results)); 830 831 /* parse the nested attributes into the nest results list */ 832 err = fm10k_tlv_attr_parse(results[FM10K_TEST_MSG_NESTED], 833 nest_results, 834 fm10k_tlv_msg_test_attr); 835 if (err) 836 goto report_result; 837 838 /* loop back through to the start */ 839 results = nest_results; 840 goto parse_nested; 841 } 842 843 report_result: 844 /* generate reply with test result */ 845 fm10k_tlv_msg_init(reply, FM10K_TLV_MSG_ID_TEST); 846 fm10k_tlv_attr_put_s32(reply, FM10K_TEST_MSG_RESULT, err); 847 848 /* load onto outgoing mailbox */ 849 return mbx->ops.enqueue_tx(hw, mbx, reply); 850 } 851