1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright(c) 2013 - 2018 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 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 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 = 0; 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 * a minimum it just indicates that the message requested was 588 * unimplemented. 589 **/ 590 s32 fm10k_tlv_msg_error(struct fm10k_hw *hw, u32 **results, 591 struct fm10k_mbx_info *mbx) 592 { 593 return FM10K_NOT_IMPLEMENTED; 594 } 595 596 static const unsigned char test_str[] = "fm10k"; 597 static const unsigned char test_mac[ETH_ALEN] = { 0x12, 0x34, 0x56, 598 0x78, 0x9a, 0xbc }; 599 static const u16 test_vlan = 0x0FED; 600 static const u64 test_u64 = 0xfedcba9876543210ull; 601 static const u32 test_u32 = 0x87654321; 602 static const u16 test_u16 = 0x8765; 603 static const u8 test_u8 = 0x87; 604 static const s64 test_s64 = -0x123456789abcdef0ll; 605 static const s32 test_s32 = -0x1235678; 606 static const s16 test_s16 = -0x1234; 607 static const s8 test_s8 = -0x12; 608 static const __le32 test_le[2] = { cpu_to_le32(0x12345678), 609 cpu_to_le32(0x9abcdef0)}; 610 611 /* The message below is meant to be used as a test message to demonstrate 612 * how to use the TLV interface and to test the types. Normally this code 613 * be compiled out by stripping the code wrapped in FM10K_TLV_TEST_MSG 614 */ 615 const struct fm10k_tlv_attr fm10k_tlv_msg_test_attr[] = { 616 FM10K_TLV_ATTR_NULL_STRING(FM10K_TEST_MSG_STRING, 80), 617 FM10K_TLV_ATTR_MAC_ADDR(FM10K_TEST_MSG_MAC_ADDR), 618 FM10K_TLV_ATTR_U8(FM10K_TEST_MSG_U8), 619 FM10K_TLV_ATTR_U16(FM10K_TEST_MSG_U16), 620 FM10K_TLV_ATTR_U32(FM10K_TEST_MSG_U32), 621 FM10K_TLV_ATTR_U64(FM10K_TEST_MSG_U64), 622 FM10K_TLV_ATTR_S8(FM10K_TEST_MSG_S8), 623 FM10K_TLV_ATTR_S16(FM10K_TEST_MSG_S16), 624 FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_S32), 625 FM10K_TLV_ATTR_S64(FM10K_TEST_MSG_S64), 626 FM10K_TLV_ATTR_LE_STRUCT(FM10K_TEST_MSG_LE_STRUCT, 8), 627 FM10K_TLV_ATTR_NESTED(FM10K_TEST_MSG_NESTED), 628 FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_RESULT), 629 FM10K_TLV_ATTR_LAST 630 }; 631 632 /** 633 * fm10k_tlv_msg_test_generate_data - Stuff message with data 634 * @msg: Pointer to message 635 * @attr_flags: List of flags indicating what attributes to add 636 * 637 * This function is meant to load a message buffer with attribute data 638 **/ 639 static void fm10k_tlv_msg_test_generate_data(u32 *msg, u32 attr_flags) 640 { 641 if (attr_flags & BIT(FM10K_TEST_MSG_STRING)) 642 fm10k_tlv_attr_put_null_string(msg, FM10K_TEST_MSG_STRING, 643 test_str); 644 if (attr_flags & BIT(FM10K_TEST_MSG_MAC_ADDR)) 645 fm10k_tlv_attr_put_mac_vlan(msg, FM10K_TEST_MSG_MAC_ADDR, 646 test_mac, test_vlan); 647 if (attr_flags & BIT(FM10K_TEST_MSG_U8)) 648 fm10k_tlv_attr_put_u8(msg, FM10K_TEST_MSG_U8, test_u8); 649 if (attr_flags & BIT(FM10K_TEST_MSG_U16)) 650 fm10k_tlv_attr_put_u16(msg, FM10K_TEST_MSG_U16, test_u16); 651 if (attr_flags & BIT(FM10K_TEST_MSG_U32)) 652 fm10k_tlv_attr_put_u32(msg, FM10K_TEST_MSG_U32, test_u32); 653 if (attr_flags & BIT(FM10K_TEST_MSG_U64)) 654 fm10k_tlv_attr_put_u64(msg, FM10K_TEST_MSG_U64, test_u64); 655 if (attr_flags & BIT(FM10K_TEST_MSG_S8)) 656 fm10k_tlv_attr_put_s8(msg, FM10K_TEST_MSG_S8, test_s8); 657 if (attr_flags & BIT(FM10K_TEST_MSG_S16)) 658 fm10k_tlv_attr_put_s16(msg, FM10K_TEST_MSG_S16, test_s16); 659 if (attr_flags & BIT(FM10K_TEST_MSG_S32)) 660 fm10k_tlv_attr_put_s32(msg, FM10K_TEST_MSG_S32, test_s32); 661 if (attr_flags & BIT(FM10K_TEST_MSG_S64)) 662 fm10k_tlv_attr_put_s64(msg, FM10K_TEST_MSG_S64, test_s64); 663 if (attr_flags & BIT(FM10K_TEST_MSG_LE_STRUCT)) 664 fm10k_tlv_attr_put_le_struct(msg, FM10K_TEST_MSG_LE_STRUCT, 665 test_le, 8); 666 } 667 668 /** 669 * fm10k_tlv_msg_test_create - Create a test message testing all attributes 670 * @msg: Pointer to message 671 * @attr_flags: List of flags indicating what attributes to add 672 * 673 * This function is meant to load a message buffer with all attribute types 674 * including a nested attribute. 675 **/ 676 void fm10k_tlv_msg_test_create(u32 *msg, u32 attr_flags) 677 { 678 u32 *nest = NULL; 679 680 fm10k_tlv_msg_init(msg, FM10K_TLV_MSG_ID_TEST); 681 682 fm10k_tlv_msg_test_generate_data(msg, attr_flags); 683 684 /* check for nested attributes */ 685 attr_flags >>= FM10K_TEST_MSG_NESTED; 686 687 if (attr_flags) { 688 nest = fm10k_tlv_attr_nest_start(msg, FM10K_TEST_MSG_NESTED); 689 690 fm10k_tlv_msg_test_generate_data(nest, attr_flags); 691 692 fm10k_tlv_attr_nest_stop(msg); 693 } 694 } 695 696 /** 697 * fm10k_tlv_msg_test - Validate all results on test message receive 698 * @hw: Pointer to hardware structure 699 * @results: Pointer array to attributes in the message 700 * @mbx: Pointer to mailbox information structure 701 * 702 * This function does a check to verify all attributes match what the test 703 * message placed in the message buffer. It is the default handler 704 * for TLV test messages. 705 **/ 706 s32 fm10k_tlv_msg_test(struct fm10k_hw *hw, u32 **results, 707 struct fm10k_mbx_info *mbx) 708 { 709 u32 *nest_results[FM10K_TLV_RESULTS_MAX]; 710 unsigned char result_str[80]; 711 unsigned char result_mac[ETH_ALEN]; 712 s32 err = 0; 713 __le32 result_le[2]; 714 u16 result_vlan; 715 u64 result_u64; 716 u32 result_u32; 717 u16 result_u16; 718 u8 result_u8; 719 s64 result_s64; 720 s32 result_s32; 721 s16 result_s16; 722 s8 result_s8; 723 u32 reply[3]; 724 725 /* retrieve results of a previous test */ 726 if (!!results[FM10K_TEST_MSG_RESULT]) 727 return fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_RESULT], 728 &mbx->test_result); 729 730 parse_nested: 731 if (!!results[FM10K_TEST_MSG_STRING]) { 732 err = fm10k_tlv_attr_get_null_string( 733 results[FM10K_TEST_MSG_STRING], 734 result_str); 735 if (!err && memcmp(test_str, result_str, sizeof(test_str))) 736 err = FM10K_ERR_INVALID_VALUE; 737 if (err) 738 goto report_result; 739 } 740 if (!!results[FM10K_TEST_MSG_MAC_ADDR]) { 741 err = fm10k_tlv_attr_get_mac_vlan( 742 results[FM10K_TEST_MSG_MAC_ADDR], 743 result_mac, &result_vlan); 744 if (!err && !ether_addr_equal(test_mac, result_mac)) 745 err = FM10K_ERR_INVALID_VALUE; 746 if (!err && test_vlan != result_vlan) 747 err = FM10K_ERR_INVALID_VALUE; 748 if (err) 749 goto report_result; 750 } 751 if (!!results[FM10K_TEST_MSG_U8]) { 752 err = fm10k_tlv_attr_get_u8(results[FM10K_TEST_MSG_U8], 753 &result_u8); 754 if (!err && test_u8 != result_u8) 755 err = FM10K_ERR_INVALID_VALUE; 756 if (err) 757 goto report_result; 758 } 759 if (!!results[FM10K_TEST_MSG_U16]) { 760 err = fm10k_tlv_attr_get_u16(results[FM10K_TEST_MSG_U16], 761 &result_u16); 762 if (!err && test_u16 != result_u16) 763 err = FM10K_ERR_INVALID_VALUE; 764 if (err) 765 goto report_result; 766 } 767 if (!!results[FM10K_TEST_MSG_U32]) { 768 err = fm10k_tlv_attr_get_u32(results[FM10K_TEST_MSG_U32], 769 &result_u32); 770 if (!err && test_u32 != result_u32) 771 err = FM10K_ERR_INVALID_VALUE; 772 if (err) 773 goto report_result; 774 } 775 if (!!results[FM10K_TEST_MSG_U64]) { 776 err = fm10k_tlv_attr_get_u64(results[FM10K_TEST_MSG_U64], 777 &result_u64); 778 if (!err && test_u64 != result_u64) 779 err = FM10K_ERR_INVALID_VALUE; 780 if (err) 781 goto report_result; 782 } 783 if (!!results[FM10K_TEST_MSG_S8]) { 784 err = fm10k_tlv_attr_get_s8(results[FM10K_TEST_MSG_S8], 785 &result_s8); 786 if (!err && test_s8 != result_s8) 787 err = FM10K_ERR_INVALID_VALUE; 788 if (err) 789 goto report_result; 790 } 791 if (!!results[FM10K_TEST_MSG_S16]) { 792 err = fm10k_tlv_attr_get_s16(results[FM10K_TEST_MSG_S16], 793 &result_s16); 794 if (!err && test_s16 != result_s16) 795 err = FM10K_ERR_INVALID_VALUE; 796 if (err) 797 goto report_result; 798 } 799 if (!!results[FM10K_TEST_MSG_S32]) { 800 err = fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_S32], 801 &result_s32); 802 if (!err && test_s32 != result_s32) 803 err = FM10K_ERR_INVALID_VALUE; 804 if (err) 805 goto report_result; 806 } 807 if (!!results[FM10K_TEST_MSG_S64]) { 808 err = fm10k_tlv_attr_get_s64(results[FM10K_TEST_MSG_S64], 809 &result_s64); 810 if (!err && test_s64 != result_s64) 811 err = FM10K_ERR_INVALID_VALUE; 812 if (err) 813 goto report_result; 814 } 815 if (!!results[FM10K_TEST_MSG_LE_STRUCT]) { 816 err = fm10k_tlv_attr_get_le_struct( 817 results[FM10K_TEST_MSG_LE_STRUCT], 818 result_le, 819 sizeof(result_le)); 820 if (!err && memcmp(test_le, result_le, sizeof(test_le))) 821 err = FM10K_ERR_INVALID_VALUE; 822 if (err) 823 goto report_result; 824 } 825 826 if (!!results[FM10K_TEST_MSG_NESTED]) { 827 /* clear any pointers */ 828 memset(nest_results, 0, sizeof(nest_results)); 829 830 /* parse the nested attributes into the nest results list */ 831 err = fm10k_tlv_attr_parse(results[FM10K_TEST_MSG_NESTED], 832 nest_results, 833 fm10k_tlv_msg_test_attr); 834 if (err) 835 goto report_result; 836 837 /* loop back through to the start */ 838 results = nest_results; 839 goto parse_nested; 840 } 841 842 report_result: 843 /* generate reply with test result */ 844 fm10k_tlv_msg_init(reply, FM10K_TLV_MSG_ID_TEST); 845 fm10k_tlv_attr_put_s32(reply, FM10K_TEST_MSG_RESULT, err); 846 847 /* load onto outgoing mailbox */ 848 return mbx->ops.enqueue_tx(hw, mbx, reply); 849 } 850