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