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