1/* Intel Ethernet Switch Host Interface Driver 2 * Copyright(c) 2013 - 2014 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 **/ 30s32 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 **/ 51s32 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 **/ 101s32 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 **/ 128s32 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 **/ 165s32 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 **/ 188s32 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 **/ 214s32 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 & ((0x1ul << (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 **/ 254s32 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 **/ 286s32 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 **/ 325s32 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 **/ 356u32 *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_start - Start 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 **/ 381s32 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 **/ 414static 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. 485 **/ 486s32 fm10k_tlv_attr_parse(u32 *attr, u32 **results, 487 const struct fm10k_tlv_attr *tlv_attr) 488{ 489 u32 i, attr_id, offset = 0; 490 s32 err = 0; 491 u16 len; 492 493 /* verify pointers are not NULL */ 494 if (!attr || !results) 495 return FM10K_ERR_PARAM; 496 497 /* initialize results to NULL */ 498 for (i = 0; i < FM10K_TLV_RESULTS_MAX; i++) 499 results[i] = NULL; 500 501 /* pull length from the message header */ 502 len = *attr >> FM10K_TLV_LEN_SHIFT; 503 504 /* no attributes to parse if there is no length */ 505 if (!len) 506 return 0; 507 508 /* no attributes to parse, just raw data, message becomes attribute */ 509 if (!tlv_attr) { 510 results[0] = attr; 511 return 0; 512 } 513 514 /* move to start of attribute data */ 515 attr++; 516 517 /* run through list parsing all attributes */ 518 while (offset < len) { 519 attr_id = *attr & FM10K_TLV_ID_MASK; 520 521 if (attr_id < FM10K_TLV_RESULTS_MAX) 522 err = fm10k_tlv_attr_validate(attr, tlv_attr); 523 else 524 err = FM10K_NOT_IMPLEMENTED; 525 526 if (err < 0) 527 return err; 528 if (!err) 529 results[attr_id] = attr; 530 531 /* update offset */ 532 offset += FM10K_TLV_DWORD_LEN(*attr) * 4; 533 534 /* move to next attribute */ 535 attr = &attr[FM10K_TLV_DWORD_LEN(*attr)]; 536 } 537 538 /* we should find ourselves at the end of the list */ 539 if (offset != len) 540 return FM10K_ERR_PARAM; 541 542 return 0; 543} 544 545/** 546 * fm10k_tlv_msg_parse - Parses message header and calls function handler 547 * @hw: Pointer to hardware structure 548 * @msg: Pointer to message 549 * @mbx: Pointer to mailbox information structure 550 * @func: Function array containing list of message handling functions 551 * 552 * This function should be the first function called upon receiving a 553 * message. The handler will identify the message type and call the correct 554 * handler for the given message. It will return the value from the function 555 * call on a recognized message type, otherwise it will return 556 * FM10K_NOT_IMPLEMENTED on an unrecognized type. 557 **/ 558s32 fm10k_tlv_msg_parse(struct fm10k_hw *hw, u32 *msg, 559 struct fm10k_mbx_info *mbx, 560 const struct fm10k_msg_data *data) 561{ 562 u32 *results[FM10K_TLV_RESULTS_MAX]; 563 u32 msg_id; 564 s32 err; 565 566 /* verify pointer is not NULL */ 567 if (!msg || !data) 568 return FM10K_ERR_PARAM; 569 570 /* verify this is a message and not an attribute */ 571 if (!(*msg & (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT))) 572 return FM10K_ERR_PARAM; 573 574 /* grab message ID */ 575 msg_id = *msg & FM10K_TLV_ID_MASK; 576 577 while (data->id < msg_id) 578 data++; 579 580 /* if we didn't find it then pass it up as an error */ 581 if (data->id != msg_id) { 582 while (data->id != FM10K_TLV_ERROR) 583 data++; 584 } 585 586 /* parse the attributes into the results list */ 587 err = fm10k_tlv_attr_parse(msg, results, data->attr); 588 if (err < 0) 589 return err; 590 591 return data->func(hw, results, mbx); 592} 593 594/** 595 * fm10k_tlv_msg_error - Default handler for unrecognized TLV message IDs 596 * @hw: Pointer to hardware structure 597 * @results: Pointer array to message, results[0] is pointer to message 598 * @mbx: Unused mailbox pointer 599 * 600 * This function is a default handler for unrecognized messages. At a 601 * a minimum it just indicates that the message requested was 602 * unimplemented. 603 **/ 604s32 fm10k_tlv_msg_error(struct fm10k_hw *hw, u32 **results, 605 struct fm10k_mbx_info *mbx) 606{ 607 return FM10K_NOT_IMPLEMENTED; 608} 609 610static const unsigned char test_str[] = "fm10k"; 611static const unsigned char test_mac[ETH_ALEN] = { 0x12, 0x34, 0x56, 612 0x78, 0x9a, 0xbc }; 613static const u16 test_vlan = 0x0FED; 614static const u64 test_u64 = 0xfedcba9876543210ull; 615static const u32 test_u32 = 0x87654321; 616static const u16 test_u16 = 0x8765; 617static const u8 test_u8 = 0x87; 618static const s64 test_s64 = -0x123456789abcdef0ll; 619static const s32 test_s32 = -0x1235678; 620static const s16 test_s16 = -0x1234; 621static const s8 test_s8 = -0x12; 622static const __le32 test_le[2] = { cpu_to_le32(0x12345678), 623 cpu_to_le32(0x9abcdef0)}; 624 625/* The message below is meant to be used as a test message to demonstrate 626 * how to use the TLV interface and to test the types. Normally this code 627 * be compiled out by stripping the code wrapped in FM10K_TLV_TEST_MSG 628 */ 629const struct fm10k_tlv_attr fm10k_tlv_msg_test_attr[] = { 630 FM10K_TLV_ATTR_NULL_STRING(FM10K_TEST_MSG_STRING, 80), 631 FM10K_TLV_ATTR_MAC_ADDR(FM10K_TEST_MSG_MAC_ADDR), 632 FM10K_TLV_ATTR_U8(FM10K_TEST_MSG_U8), 633 FM10K_TLV_ATTR_U16(FM10K_TEST_MSG_U16), 634 FM10K_TLV_ATTR_U32(FM10K_TEST_MSG_U32), 635 FM10K_TLV_ATTR_U64(FM10K_TEST_MSG_U64), 636 FM10K_TLV_ATTR_S8(FM10K_TEST_MSG_S8), 637 FM10K_TLV_ATTR_S16(FM10K_TEST_MSG_S16), 638 FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_S32), 639 FM10K_TLV_ATTR_S64(FM10K_TEST_MSG_S64), 640 FM10K_TLV_ATTR_LE_STRUCT(FM10K_TEST_MSG_LE_STRUCT, 8), 641 FM10K_TLV_ATTR_NESTED(FM10K_TEST_MSG_NESTED), 642 FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_RESULT), 643 FM10K_TLV_ATTR_LAST 644}; 645 646/** 647 * fm10k_tlv_msg_test_generate_data - Stuff message with data 648 * @msg: Pointer to message 649 * @attr_flags: List of flags indicating what attributes to add 650 * 651 * This function is meant to load a message buffer with attribute data 652 **/ 653static void fm10k_tlv_msg_test_generate_data(u32 *msg, u32 attr_flags) 654{ 655 if (attr_flags & (1 << FM10K_TEST_MSG_STRING)) 656 fm10k_tlv_attr_put_null_string(msg, FM10K_TEST_MSG_STRING, 657 test_str); 658 if (attr_flags & (1 << FM10K_TEST_MSG_MAC_ADDR)) 659 fm10k_tlv_attr_put_mac_vlan(msg, FM10K_TEST_MSG_MAC_ADDR, 660 test_mac, test_vlan); 661 if (attr_flags & (1 << FM10K_TEST_MSG_U8)) 662 fm10k_tlv_attr_put_u8(msg, FM10K_TEST_MSG_U8, test_u8); 663 if (attr_flags & (1 << FM10K_TEST_MSG_U16)) 664 fm10k_tlv_attr_put_u16(msg, FM10K_TEST_MSG_U16, test_u16); 665 if (attr_flags & (1 << FM10K_TEST_MSG_U32)) 666 fm10k_tlv_attr_put_u32(msg, FM10K_TEST_MSG_U32, test_u32); 667 if (attr_flags & (1 << FM10K_TEST_MSG_U64)) 668 fm10k_tlv_attr_put_u64(msg, FM10K_TEST_MSG_U64, test_u64); 669 if (attr_flags & (1 << FM10K_TEST_MSG_S8)) 670 fm10k_tlv_attr_put_s8(msg, FM10K_TEST_MSG_S8, test_s8); 671 if (attr_flags & (1 << FM10K_TEST_MSG_S16)) 672 fm10k_tlv_attr_put_s16(msg, FM10K_TEST_MSG_S16, test_s16); 673 if (attr_flags & (1 << FM10K_TEST_MSG_S32)) 674 fm10k_tlv_attr_put_s32(msg, FM10K_TEST_MSG_S32, test_s32); 675 if (attr_flags & (1 << FM10K_TEST_MSG_S64)) 676 fm10k_tlv_attr_put_s64(msg, FM10K_TEST_MSG_S64, test_s64); 677 if (attr_flags & (1 << FM10K_TEST_MSG_LE_STRUCT)) 678 fm10k_tlv_attr_put_le_struct(msg, FM10K_TEST_MSG_LE_STRUCT, 679 test_le, 8); 680} 681 682/** 683 * fm10k_tlv_msg_test_create - Create a test message testing all attributes 684 * @msg: Pointer to message 685 * @attr_flags: List of flags indicating what attributes to add 686 * 687 * This function is meant to load a message buffer with all attribute types 688 * including a nested attribute. 689 **/ 690void fm10k_tlv_msg_test_create(u32 *msg, u32 attr_flags) 691{ 692 u32 *nest = NULL; 693 694 fm10k_tlv_msg_init(msg, FM10K_TLV_MSG_ID_TEST); 695 696 fm10k_tlv_msg_test_generate_data(msg, attr_flags); 697 698 /* check for nested attributes */ 699 attr_flags >>= FM10K_TEST_MSG_NESTED; 700 701 if (attr_flags) { 702 nest = fm10k_tlv_attr_nest_start(msg, FM10K_TEST_MSG_NESTED); 703 704 fm10k_tlv_msg_test_generate_data(nest, attr_flags); 705 706 fm10k_tlv_attr_nest_stop(msg); 707 } 708} 709 710/** 711 * fm10k_tlv_msg_test - Validate all results on test message receive 712 * @hw: Pointer to hardware structure 713 * @results: Pointer array to attributes in the message 714 * @mbx: Pointer to mailbox information structure 715 * 716 * This function does a check to verify all attributes match what the test 717 * message placed in the message buffer. It is the default handler 718 * for TLV test messages. 719 **/ 720s32 fm10k_tlv_msg_test(struct fm10k_hw *hw, u32 **results, 721 struct fm10k_mbx_info *mbx) 722{ 723 u32 *nest_results[FM10K_TLV_RESULTS_MAX]; 724 unsigned char result_str[80]; 725 unsigned char result_mac[ETH_ALEN]; 726 s32 err = 0; 727 __le32 result_le[2]; 728 u16 result_vlan; 729 u64 result_u64; 730 u32 result_u32; 731 u16 result_u16; 732 u8 result_u8; 733 s64 result_s64; 734 s32 result_s32; 735 s16 result_s16; 736 s8 result_s8; 737 u32 reply[3]; 738 739 /* retrieve results of a previous test */ 740 if (!!results[FM10K_TEST_MSG_RESULT]) 741 return fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_RESULT], 742 &mbx->test_result); 743 744parse_nested: 745 if (!!results[FM10K_TEST_MSG_STRING]) { 746 err = fm10k_tlv_attr_get_null_string( 747 results[FM10K_TEST_MSG_STRING], 748 result_str); 749 if (!err && memcmp(test_str, result_str, sizeof(test_str))) 750 err = FM10K_ERR_INVALID_VALUE; 751 if (err) 752 goto report_result; 753 } 754 if (!!results[FM10K_TEST_MSG_MAC_ADDR]) { 755 err = fm10k_tlv_attr_get_mac_vlan( 756 results[FM10K_TEST_MSG_MAC_ADDR], 757 result_mac, &result_vlan); 758 if (!err && memcmp(test_mac, result_mac, ETH_ALEN)) 759 err = FM10K_ERR_INVALID_VALUE; 760 if (!err && test_vlan != result_vlan) 761 err = FM10K_ERR_INVALID_VALUE; 762 if (err) 763 goto report_result; 764 } 765 if (!!results[FM10K_TEST_MSG_U8]) { 766 err = fm10k_tlv_attr_get_u8(results[FM10K_TEST_MSG_U8], 767 &result_u8); 768 if (!err && test_u8 != result_u8) 769 err = FM10K_ERR_INVALID_VALUE; 770 if (err) 771 goto report_result; 772 } 773 if (!!results[FM10K_TEST_MSG_U16]) { 774 err = fm10k_tlv_attr_get_u16(results[FM10K_TEST_MSG_U16], 775 &result_u16); 776 if (!err && test_u16 != result_u16) 777 err = FM10K_ERR_INVALID_VALUE; 778 if (err) 779 goto report_result; 780 } 781 if (!!results[FM10K_TEST_MSG_U32]) { 782 err = fm10k_tlv_attr_get_u32(results[FM10K_TEST_MSG_U32], 783 &result_u32); 784 if (!err && test_u32 != result_u32) 785 err = FM10K_ERR_INVALID_VALUE; 786 if (err) 787 goto report_result; 788 } 789 if (!!results[FM10K_TEST_MSG_U64]) { 790 err = fm10k_tlv_attr_get_u64(results[FM10K_TEST_MSG_U64], 791 &result_u64); 792 if (!err && test_u64 != result_u64) 793 err = FM10K_ERR_INVALID_VALUE; 794 if (err) 795 goto report_result; 796 } 797 if (!!results[FM10K_TEST_MSG_S8]) { 798 err = fm10k_tlv_attr_get_s8(results[FM10K_TEST_MSG_S8], 799 &result_s8); 800 if (!err && test_s8 != result_s8) 801 err = FM10K_ERR_INVALID_VALUE; 802 if (err) 803 goto report_result; 804 } 805 if (!!results[FM10K_TEST_MSG_S16]) { 806 err = fm10k_tlv_attr_get_s16(results[FM10K_TEST_MSG_S16], 807 &result_s16); 808 if (!err && test_s16 != result_s16) 809 err = FM10K_ERR_INVALID_VALUE; 810 if (err) 811 goto report_result; 812 } 813 if (!!results[FM10K_TEST_MSG_S32]) { 814 err = fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_S32], 815 &result_s32); 816 if (!err && test_s32 != result_s32) 817 err = FM10K_ERR_INVALID_VALUE; 818 if (err) 819 goto report_result; 820 } 821 if (!!results[FM10K_TEST_MSG_S64]) { 822 err = fm10k_tlv_attr_get_s64(results[FM10K_TEST_MSG_S64], 823 &result_s64); 824 if (!err && test_s64 != result_s64) 825 err = FM10K_ERR_INVALID_VALUE; 826 if (err) 827 goto report_result; 828 } 829 if (!!results[FM10K_TEST_MSG_LE_STRUCT]) { 830 err = fm10k_tlv_attr_get_le_struct( 831 results[FM10K_TEST_MSG_LE_STRUCT], 832 result_le, 833 sizeof(result_le)); 834 if (!err && memcmp(test_le, result_le, sizeof(test_le))) 835 err = FM10K_ERR_INVALID_VALUE; 836 if (err) 837 goto report_result; 838 } 839 840 if (!!results[FM10K_TEST_MSG_NESTED]) { 841 /* clear any pointers */ 842 memset(nest_results, 0, sizeof(nest_results)); 843 844 /* parse the nested attributes into the nest results list */ 845 err = fm10k_tlv_attr_parse(results[FM10K_TEST_MSG_NESTED], 846 nest_results, 847 fm10k_tlv_msg_test_attr); 848 if (err) 849 goto report_result; 850 851 /* loop back through to the start */ 852 results = nest_results; 853 goto parse_nested; 854 } 855 856report_result: 857 /* generate reply with test result */ 858 fm10k_tlv_msg_init(reply, FM10K_TLV_MSG_ID_TEST); 859 fm10k_tlv_attr_put_s32(reply, FM10K_TEST_MSG_RESULT, err); 860 861 /* load onto outgoing mailbox */ 862 return mbx->ops.enqueue_tx(hw, mbx, reply); 863} 864