1 /*******************************************************************************
3 Copyright (c) 2013 - 2015, Intel Corporation
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
9 1. Redistributions of source code must retain the above copyright notice,
10 this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
16 3. Neither the name of the Intel Corporation nor the names of its
17 contributors may be used to endorse or promote products derived from
18 this software without specific prior written permission.
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 POSSIBILITY OF SUCH DAMAGE.
32 ***************************************************************************/
34 #include "fm10k_tlv.h"
37 * fm10k_tlv_msg_init - Initialize message block for TLV data storage
38 * @msg: Pointer to message block
39 * @msg_id: Message ID indicating message type
41 * This function return success if provided with a valid message pointer
43 s32 fm10k_tlv_msg_init(u32 *msg, u16 msg_id)
45 DEBUGFUNC("fm10k_tlv_msg_init");
47 /* verify pointer is not NULL */
49 return FM10K_ERR_PARAM;
51 *msg = (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT) | msg_id;
57 * fm10k_tlv_attr_put_null_string - Place null terminated string on message
58 * @msg: Pointer to message block
59 * @attr_id: Attribute ID
60 * @string: Pointer to string to be stored in attribute
62 * This function will reorder a string to be CPU endian and store it in
63 * the attribute buffer. It will return success if provided with a valid
66 static s32 fm10k_tlv_attr_put_null_string(u32 *msg, u16 attr_id,
67 const unsigned char *string)
69 u32 attr_data = 0, len = 0;
72 DEBUGFUNC("fm10k_tlv_attr_put_null_string");
74 /* verify pointers are not NULL */
76 return FM10K_ERR_PARAM;
78 attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
80 /* copy string into local variable and then write to msg */
82 /* write data to message */
83 if (len && !(len % 4)) {
84 attr[len / 4] = attr_data;
88 /* record character to offset location */
89 attr_data |= (u32)(*string) << (8 * (len % 4));
92 /* test for NULL and then increment */
93 } while (*(string++));
95 /* write last piece of data to message */
96 attr[(len + 3) / 4] = attr_data;
98 /* record attribute header, update message length */
99 len <<= FM10K_TLV_LEN_SHIFT;
100 attr[0] = len | attr_id;
102 /* add header length to length */
103 len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
104 *msg += FM10K_TLV_LEN_ALIGN(len);
106 return FM10K_SUCCESS;
110 * fm10k_tlv_attr_get_null_string - Get null terminated string from attribute
111 * @attr: Pointer to attribute
112 * @string: Pointer to location of destination string
114 * This function pulls the string back out of the attribute and will place
115 * it in the array pointed by by string. It will return success if provided
116 * with a valid pointers.
118 static s32 fm10k_tlv_attr_get_null_string(u32 *attr, unsigned char *string)
122 DEBUGFUNC("fm10k_tlv_attr_get_null_string");
124 /* verify pointers are not NULL */
125 if (!string || !attr)
126 return FM10K_ERR_PARAM;
128 len = *attr >> FM10K_TLV_LEN_SHIFT;
132 string[len] = (u8)(attr[len / 4] >> (8 * (len % 4)));
134 return FM10K_SUCCESS;
138 * fm10k_tlv_attr_put_mac_vlan - Store MAC/VLAN attribute in message
139 * @msg: Pointer to message block
140 * @attr_id: Attribute ID
141 * @mac_addr: MAC address to be stored
143 * This function will reorder a MAC address to be CPU endian and store it
144 * in the attribute buffer. It will return success if provided with a
147 s32 fm10k_tlv_attr_put_mac_vlan(u32 *msg, u16 attr_id,
148 const u8 *mac_addr, u16 vlan)
150 u32 len = ETH_ALEN << FM10K_TLV_LEN_SHIFT;
153 DEBUGFUNC("fm10k_tlv_attr_put_mac_vlan");
155 /* verify pointers are not NULL */
156 if (!msg || !mac_addr)
157 return FM10K_ERR_PARAM;
159 attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
161 /* record attribute header, update message length */
162 attr[0] = len | attr_id;
164 /* copy value into local variable and then write to msg */
165 attr[1] = FM10K_LE32_TO_CPU(*(const __le32 *)&mac_addr[0]);
166 attr[2] = FM10K_LE16_TO_CPU(*(const __le16 *)&mac_addr[4]);
167 attr[2] |= (u32)vlan << 16;
169 /* add header length to length */
170 len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
171 *msg += FM10K_TLV_LEN_ALIGN(len);
173 return FM10K_SUCCESS;
177 * fm10k_tlv_attr_get_mac_vlan - Get MAC/VLAN stored in attribute
178 * @attr: Pointer to attribute
179 * @attr_id: Attribute ID
180 * @mac_addr: location of buffer to store MAC address
182 * This function pulls the MAC address back out of the attribute and will
183 * place it in the array pointed by by mac_addr. It will return success
184 * if provided with a valid pointers.
186 s32 fm10k_tlv_attr_get_mac_vlan(u32 *attr, u8 *mac_addr, u16 *vlan)
188 DEBUGFUNC("fm10k_tlv_attr_get_mac_vlan");
190 /* verify pointers are not NULL */
191 if (!mac_addr || !attr)
192 return FM10K_ERR_PARAM;
194 *(__le32 *)&mac_addr[0] = FM10K_CPU_TO_LE32(attr[1]);
195 *(__le16 *)&mac_addr[4] = FM10K_CPU_TO_LE16((u16)(attr[2]));
196 *vlan = (u16)(attr[2] >> 16);
198 return FM10K_SUCCESS;
202 * fm10k_tlv_attr_put_bool - Add header indicating value "true"
203 * @msg: Pointer to message block
204 * @attr_id: Attribute ID
206 * This function will simply add an attribute header, the fact
207 * that the header is here means the attribute value is true, else
208 * it is false. The function will return success if provided with a
211 s32 fm10k_tlv_attr_put_bool(u32 *msg, u16 attr_id)
213 DEBUGFUNC("fm10k_tlv_attr_put_bool");
215 /* verify pointers are not NULL */
217 return FM10K_ERR_PARAM;
219 /* record attribute header */
220 msg[FM10K_TLV_DWORD_LEN(*msg)] = attr_id;
222 /* add header length to length */
223 *msg += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
225 return FM10K_SUCCESS;
229 * fm10k_tlv_attr_put_value - Store integer value attribute in message
230 * @msg: Pointer to message block
231 * @attr_id: Attribute ID
232 * @value: Value to be written
233 * @len: Size of value
235 * This function will place an integer value of up to 8 bytes in size
236 * in a message attribute. The function will return success provided
237 * that msg is a valid pointer, and len is 1, 2, 4, or 8.
239 s32 fm10k_tlv_attr_put_value(u32 *msg, u16 attr_id, s64 value, u32 len)
243 DEBUGFUNC("fm10k_tlv_attr_put_value");
245 /* verify non-null msg and len is 1, 2, 4, or 8 */
246 if (!msg || !len || len > 8 || (len & (len - 1)))
247 return FM10K_ERR_PARAM;
249 attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
252 attr[1] = (u32)value & (BIT(8 * len) - 1);
254 attr[1] = (u32)value;
256 attr[2] = (u32)(value >> 32);
259 /* record attribute header, update message length */
260 len <<= FM10K_TLV_LEN_SHIFT;
261 attr[0] = len | attr_id;
263 /* add header length to length */
264 len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
265 *msg += FM10K_TLV_LEN_ALIGN(len);
267 return FM10K_SUCCESS;
271 * fm10k_tlv_attr_get_value - Get integer value stored in attribute
272 * @attr: Pointer to attribute
273 * @value: Pointer to destination buffer
274 * @len: Size of value
276 * This function will place an integer value of up to 8 bytes in size
277 * in the offset pointed to by value. The function will return success
278 * provided that pointers are valid and the len value matches the
281 s32 fm10k_tlv_attr_get_value(u32 *attr, void *value, u32 len)
283 DEBUGFUNC("fm10k_tlv_attr_get_value");
285 /* verify pointers are not NULL */
287 return FM10K_ERR_PARAM;
289 if ((*attr >> FM10K_TLV_LEN_SHIFT) != len)
290 return FM10K_ERR_PARAM;
293 *(u64 *)value = ((u64)attr[2] << 32) | attr[1];
295 *(u32 *)value = attr[1];
297 *(u16 *)value = (u16)attr[1];
299 *(u8 *)value = (u8)attr[1];
301 return FM10K_SUCCESS;
305 * fm10k_tlv_attr_put_le_struct - Store little endian structure in message
306 * @msg: Pointer to message block
307 * @attr_id: Attribute ID
308 * @le_struct: Pointer to structure to be written
309 * @len: Size of le_struct
311 * This function will place a little endian structure value in a message
312 * attribute. The function will return success provided that all pointers
313 * are valid and length is a non-zero multiple of 4.
315 s32 fm10k_tlv_attr_put_le_struct(u32 *msg, u16 attr_id,
316 const void *le_struct, u32 len)
318 const __le32 *le32_ptr = (const __le32 *)le_struct;
322 DEBUGFUNC("fm10k_tlv_attr_put_le_struct");
324 /* verify non-null msg and len is in 32 bit words */
325 if (!msg || !len || (len % 4))
326 return FM10K_ERR_PARAM;
328 attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
330 /* copy le32 structure into host byte order at 32b boundaries */
331 for (i = 0; i < (len / 4); i++)
332 attr[i + 1] = FM10K_LE32_TO_CPU(le32_ptr[i]);
334 /* record attribute header, update message length */
335 len <<= FM10K_TLV_LEN_SHIFT;
336 attr[0] = len | attr_id;
338 /* add header length to length */
339 len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
340 *msg += FM10K_TLV_LEN_ALIGN(len);
342 return FM10K_SUCCESS;
346 * fm10k_tlv_attr_get_le_struct - Get little endian struct form attribute
347 * @attr: Pointer to attribute
348 * @le_struct: Pointer to structure to be written
349 * @len: Size of structure
351 * This function will place a little endian structure in the buffer
352 * pointed to by le_struct. The function will return success
353 * provided that pointers are valid and the len value matches the
356 s32 fm10k_tlv_attr_get_le_struct(u32 *attr, void *le_struct, u32 len)
358 __le32 *le32_ptr = (__le32 *)le_struct;
361 DEBUGFUNC("fm10k_tlv_attr_get_le_struct");
363 /* verify pointers are not NULL */
364 if (!le_struct || !attr)
365 return FM10K_ERR_PARAM;
367 if ((*attr >> FM10K_TLV_LEN_SHIFT) != len)
368 return FM10K_ERR_PARAM;
372 for (i = 0; len; i++, len -= 4)
373 le32_ptr[i] = FM10K_CPU_TO_LE32(attr[i]);
375 return FM10K_SUCCESS;
379 * fm10k_tlv_attr_nest_start - Start a set of nested attributes
380 * @msg: Pointer to message block
381 * @attr_id: Attribute ID
383 * This function will mark off a new nested region for encapsulating
384 * a given set of attributes. The idea is if you wish to place a secondary
385 * structure within the message this mechanism allows for that. The
386 * function will return NULL on failure, and a pointer to the start
387 * of the nested attributes on success.
389 static u32 *fm10k_tlv_attr_nest_start(u32 *msg, u16 attr_id)
393 DEBUGFUNC("fm10k_tlv_attr_nest_start");
395 /* verify pointer is not NULL */
399 attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
403 /* return pointer to nest header */
408 * fm10k_tlv_attr_nest_stop - Stop a set of nested attributes
409 * @msg: Pointer to message block
411 * This function closes off an existing set of nested attributes. The
412 * message pointer should be pointing to the parent of the nest. So in
413 * the case of a nest within the nest this would be the outer nest pointer.
414 * This function will return success provided all pointers are valid.
416 static s32 fm10k_tlv_attr_nest_stop(u32 *msg)
421 DEBUGFUNC("fm10k_tlv_attr_nest_stop");
423 /* verify pointer is not NULL */
425 return FM10K_ERR_PARAM;
427 /* locate the nested header and retrieve its length */
428 attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
429 len = (attr[0] >> FM10K_TLV_LEN_SHIFT) << FM10K_TLV_LEN_SHIFT;
431 /* only include nest if data was added to it */
433 len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
437 return FM10K_SUCCESS;
441 * fm10k_tlv_attr_validate - Validate attribute metadata
442 * @attr: Pointer to attribute
443 * @tlv_attr: Type and length info for attribute
445 * This function does some basic validation of the input TLV. It
446 * verifies the length, and in the case of null terminated strings
447 * it verifies that the last byte is null. The function will
448 * return FM10K_ERR_PARAM if any attribute is malformed, otherwise
451 STATIC s32 fm10k_tlv_attr_validate(u32 *attr,
452 const struct fm10k_tlv_attr *tlv_attr)
454 u32 attr_id = *attr & FM10K_TLV_ID_MASK;
455 u16 len = *attr >> FM10K_TLV_LEN_SHIFT;
457 DEBUGFUNC("fm10k_tlv_attr_validate");
459 /* verify this is an attribute and not a message */
460 if (*attr & (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT))
461 return FM10K_ERR_PARAM;
463 /* search through the list of attributes to find a matching ID */
464 while (tlv_attr->id < attr_id)
467 /* if didn't find a match then we should exit */
468 if (tlv_attr->id != attr_id)
469 return FM10K_NOT_IMPLEMENTED;
471 /* move to start of attribute data */
474 switch (tlv_attr->type) {
475 case FM10K_TLV_NULL_STRING:
477 (attr[(len - 1) / 4] & (0xFF << (8 * ((len - 1) % 4)))))
478 return FM10K_ERR_PARAM;
479 if (len > tlv_attr->len)
480 return FM10K_ERR_PARAM;
482 case FM10K_TLV_MAC_ADDR:
484 return FM10K_ERR_PARAM;
488 return FM10K_ERR_PARAM;
490 case FM10K_TLV_UNSIGNED:
491 case FM10K_TLV_SIGNED:
492 if (len != tlv_attr->len)
493 return FM10K_ERR_PARAM;
495 case FM10K_TLV_LE_STRUCT:
496 /* struct must be 4 byte aligned */
497 if ((len % 4) || len != tlv_attr->len)
498 return FM10K_ERR_PARAM;
500 case FM10K_TLV_NESTED:
501 /* nested attributes must be 4 byte aligned */
503 return FM10K_ERR_PARAM;
506 /* attribute id is mapped to bad value */
507 return FM10K_ERR_PARAM;
510 return FM10K_SUCCESS;
514 * fm10k_tlv_attr_parse - Parses stream of attribute data
515 * @attr: Pointer to attribute list
516 * @results: Pointer array to store pointers to attributes
517 * @tlv_attr: Type and length info for attributes
519 * This function validates a stream of attributes and parses them
520 * up into an array of pointers stored in results. The function will
521 * return FM10K_ERR_PARAM on any input or message error,
522 * FM10K_NOT_IMPLEMENTED for any attribute that is outside of the array
523 * and 0 on success. Any attributes not found in tlv_attr will be silently
526 static s32 fm10k_tlv_attr_parse(u32 *attr, u32 **results,
527 const struct fm10k_tlv_attr *tlv_attr)
529 u32 i, attr_id, offset = 0;
533 DEBUGFUNC("fm10k_tlv_attr_parse");
535 /* verify pointers are not NULL */
536 if (!attr || !results)
537 return FM10K_ERR_PARAM;
539 /* initialize results to NULL */
540 for (i = 0; i < FM10K_TLV_RESULTS_MAX; i++)
543 /* pull length from the message header */
544 len = *attr >> FM10K_TLV_LEN_SHIFT;
546 /* no attributes to parse if there is no length */
548 return FM10K_SUCCESS;
550 /* no attributes to parse, just raw data, message becomes attribute */
553 return FM10K_SUCCESS;
556 /* move to start of attribute data */
559 /* run through list parsing all attributes */
560 while (offset < len) {
561 attr_id = *attr & FM10K_TLV_ID_MASK;
563 if (attr_id >= FM10K_TLV_RESULTS_MAX)
564 return FM10K_NOT_IMPLEMENTED;
566 err = fm10k_tlv_attr_validate(attr, tlv_attr);
567 if (err == FM10K_NOT_IMPLEMENTED)
568 ; /* silently ignore non-implemented attributes */
572 results[attr_id] = attr;
575 offset += FM10K_TLV_DWORD_LEN(*attr) * 4;
577 /* move to next attribute */
578 attr = &attr[FM10K_TLV_DWORD_LEN(*attr)];
581 /* we should find ourselves at the end of the list */
583 return FM10K_ERR_PARAM;
585 return FM10K_SUCCESS;
589 * fm10k_tlv_msg_parse - Parses message header and calls function handler
590 * @hw: Pointer to hardware structure
591 * @msg: Pointer to message
592 * @mbx: Pointer to mailbox information structure
593 * @func: Function array containing list of message handling functions
595 * This function should be the first function called upon receiving a
596 * message. The handler will identify the message type and call the correct
597 * handler for the given message. It will return the value from the function
598 * call on a recognized message type, otherwise it will return
599 * FM10K_NOT_IMPLEMENTED on an unrecognized type.
601 s32 fm10k_tlv_msg_parse(struct fm10k_hw *hw, u32 *msg,
602 struct fm10k_mbx_info *mbx,
603 const struct fm10k_msg_data *data)
605 u32 *results[FM10K_TLV_RESULTS_MAX];
609 DEBUGFUNC("fm10k_tlv_msg_parse");
611 /* verify pointer is not NULL */
613 return FM10K_ERR_PARAM;
615 /* verify this is a message and not an attribute */
616 if (!(*msg & (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT)))
617 return FM10K_ERR_PARAM;
619 /* grab message ID */
620 msg_id = *msg & FM10K_TLV_ID_MASK;
622 while (data->id < msg_id)
625 /* if we didn't find it then pass it up as an error */
626 if (data->id != msg_id) {
627 while (data->id != FM10K_TLV_ERROR)
631 /* parse the attributes into the results list */
632 err = fm10k_tlv_attr_parse(msg, results, data->attr);
636 return data->func(hw, results, mbx);
640 * fm10k_tlv_msg_error - Default handler for unrecognized TLV message IDs
641 * @hw: Pointer to hardware structure
642 * @results: Pointer array to message, results[0] is pointer to message
643 * @mbx: Unused mailbox pointer
645 * This function is a default handler for unrecognized messages. At a
646 * a minimum it just indicates that the message requested was
649 s32 fm10k_tlv_msg_error(struct fm10k_hw *hw, u32 **results,
650 struct fm10k_mbx_info *mbx)
652 UNREFERENCED_3PARAMETER(hw, results, mbx);
653 DEBUGOUT1("Unknown message ID %u\n", **results & FM10K_TLV_ID_MASK);
654 return FM10K_NOT_IMPLEMENTED;
657 STATIC const unsigned char test_str[] = "fm10k";
658 STATIC const unsigned char test_mac[ETH_ALEN] = { 0x12, 0x34, 0x56,
660 STATIC const u16 test_vlan = 0x0FED;
661 STATIC const u64 test_u64 = 0xfedcba9876543210ull;
662 STATIC const u32 test_u32 = 0x87654321;
663 STATIC const u16 test_u16 = 0x8765;
664 STATIC const u8 test_u8 = 0x87;
665 STATIC const s64 test_s64 = -0x123456789abcdef0ll;
666 STATIC const s32 test_s32 = -0x1235678;
667 STATIC const s16 test_s16 = -0x1234;
668 STATIC const s8 test_s8 = -0x12;
669 STATIC const __le32 test_le[2] = { FM10K_CPU_TO_LE32(0x12345678),
670 FM10K_CPU_TO_LE32(0x9abcdef0)};
672 /* The message below is meant to be used as a test message to demonstrate
673 * how to use the TLV interface and to test the types. Normally this code
674 * be compiled out by stripping the code wrapped in FM10K_TLV_TEST_MSG
676 const struct fm10k_tlv_attr fm10k_tlv_msg_test_attr[] = {
677 FM10K_TLV_ATTR_NULL_STRING(FM10K_TEST_MSG_STRING, 80),
678 FM10K_TLV_ATTR_MAC_ADDR(FM10K_TEST_MSG_MAC_ADDR),
679 FM10K_TLV_ATTR_U8(FM10K_TEST_MSG_U8),
680 FM10K_TLV_ATTR_U16(FM10K_TEST_MSG_U16),
681 FM10K_TLV_ATTR_U32(FM10K_TEST_MSG_U32),
682 FM10K_TLV_ATTR_U64(FM10K_TEST_MSG_U64),
683 FM10K_TLV_ATTR_S8(FM10K_TEST_MSG_S8),
684 FM10K_TLV_ATTR_S16(FM10K_TEST_MSG_S16),
685 FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_S32),
686 FM10K_TLV_ATTR_S64(FM10K_TEST_MSG_S64),
687 FM10K_TLV_ATTR_LE_STRUCT(FM10K_TEST_MSG_LE_STRUCT, 8),
688 FM10K_TLV_ATTR_NESTED(FM10K_TEST_MSG_NESTED),
689 FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_RESULT),
694 * fm10k_tlv_msg_test_generate_data - Stuff message with data
695 * @msg: Pointer to message
696 * @attr_flags: List of flags indicating what attributes to add
698 * This function is meant to load a message buffer with attribute data
700 STATIC void fm10k_tlv_msg_test_generate_data(u32 *msg, u32 attr_flags)
702 DEBUGFUNC("fm10k_tlv_msg_test_generate_data");
704 if (attr_flags & BIT(FM10K_TEST_MSG_STRING))
705 fm10k_tlv_attr_put_null_string(msg, FM10K_TEST_MSG_STRING,
707 if (attr_flags & BIT(FM10K_TEST_MSG_MAC_ADDR))
708 fm10k_tlv_attr_put_mac_vlan(msg, FM10K_TEST_MSG_MAC_ADDR,
709 test_mac, test_vlan);
710 if (attr_flags & BIT(FM10K_TEST_MSG_U8))
711 fm10k_tlv_attr_put_u8(msg, FM10K_TEST_MSG_U8, test_u8);
712 if (attr_flags & BIT(FM10K_TEST_MSG_U16))
713 fm10k_tlv_attr_put_u16(msg, FM10K_TEST_MSG_U16, test_u16);
714 if (attr_flags & BIT(FM10K_TEST_MSG_U32))
715 fm10k_tlv_attr_put_u32(msg, FM10K_TEST_MSG_U32, test_u32);
716 if (attr_flags & BIT(FM10K_TEST_MSG_U64))
717 fm10k_tlv_attr_put_u64(msg, FM10K_TEST_MSG_U64, test_u64);
718 if (attr_flags & BIT(FM10K_TEST_MSG_S8))
719 fm10k_tlv_attr_put_s8(msg, FM10K_TEST_MSG_S8, test_s8);
720 if (attr_flags & BIT(FM10K_TEST_MSG_S16))
721 fm10k_tlv_attr_put_s16(msg, FM10K_TEST_MSG_S16, test_s16);
722 if (attr_flags & BIT(FM10K_TEST_MSG_S32))
723 fm10k_tlv_attr_put_s32(msg, FM10K_TEST_MSG_S32, test_s32);
724 if (attr_flags & BIT(FM10K_TEST_MSG_S64))
725 fm10k_tlv_attr_put_s64(msg, FM10K_TEST_MSG_S64, test_s64);
726 if (attr_flags & BIT(FM10K_TEST_MSG_LE_STRUCT))
727 fm10k_tlv_attr_put_le_struct(msg, FM10K_TEST_MSG_LE_STRUCT,
732 * fm10k_tlv_msg_test_create - Create a test message testing all attributes
733 * @msg: Pointer to message
734 * @attr_flags: List of flags indicating what attributes to add
736 * This function is meant to load a message buffer with all attribute types
737 * including a nested attribute.
739 void fm10k_tlv_msg_test_create(u32 *msg, u32 attr_flags)
743 DEBUGFUNC("fm10k_tlv_msg_test_create");
745 fm10k_tlv_msg_init(msg, FM10K_TLV_MSG_ID_TEST);
747 fm10k_tlv_msg_test_generate_data(msg, attr_flags);
749 /* check for nested attributes */
750 attr_flags >>= FM10K_TEST_MSG_NESTED;
753 nest = fm10k_tlv_attr_nest_start(msg, FM10K_TEST_MSG_NESTED);
755 fm10k_tlv_msg_test_generate_data(nest, attr_flags);
757 fm10k_tlv_attr_nest_stop(msg);
762 * fm10k_tlv_msg_test - Validate all results on test message receive
763 * @hw: Pointer to hardware structure
764 * @results: Pointer array to attributes in the message
765 * @mbx: Pointer to mailbox information structure
767 * This function does a check to verify all attributes match what the test
768 * message placed in the message buffer. It is the default handler
769 * for TLV test messages.
771 s32 fm10k_tlv_msg_test(struct fm10k_hw *hw, u32 **results,
772 struct fm10k_mbx_info *mbx)
774 u32 *nest_results[FM10K_TLV_RESULTS_MAX];
775 unsigned char result_str[80];
776 unsigned char result_mac[ETH_ALEN];
777 s32 err = FM10K_SUCCESS;
790 DEBUGFUNC("fm10k_tlv_msg_test");
792 /* retrieve results of a previous test */
793 if (!!results[FM10K_TEST_MSG_RESULT])
794 return fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_RESULT],
798 if (!!results[FM10K_TEST_MSG_STRING]) {
799 err = fm10k_tlv_attr_get_null_string(
800 results[FM10K_TEST_MSG_STRING],
802 if (!err && memcmp(test_str, result_str, sizeof(test_str)))
803 err = FM10K_ERR_INVALID_VALUE;
807 if (!!results[FM10K_TEST_MSG_MAC_ADDR]) {
808 err = fm10k_tlv_attr_get_mac_vlan(
809 results[FM10K_TEST_MSG_MAC_ADDR],
810 result_mac, &result_vlan);
811 if (!err && memcmp(test_mac, result_mac, ETH_ALEN))
812 err = FM10K_ERR_INVALID_VALUE;
813 if (!err && test_vlan != result_vlan)
814 err = FM10K_ERR_INVALID_VALUE;
818 if (!!results[FM10K_TEST_MSG_U8]) {
819 err = fm10k_tlv_attr_get_u8(results[FM10K_TEST_MSG_U8],
821 if (!err && test_u8 != result_u8)
822 err = FM10K_ERR_INVALID_VALUE;
826 if (!!results[FM10K_TEST_MSG_U16]) {
827 err = fm10k_tlv_attr_get_u16(results[FM10K_TEST_MSG_U16],
829 if (!err && test_u16 != result_u16)
830 err = FM10K_ERR_INVALID_VALUE;
834 if (!!results[FM10K_TEST_MSG_U32]) {
835 err = fm10k_tlv_attr_get_u32(results[FM10K_TEST_MSG_U32],
837 if (!err && test_u32 != result_u32)
838 err = FM10K_ERR_INVALID_VALUE;
842 if (!!results[FM10K_TEST_MSG_U64]) {
843 err = fm10k_tlv_attr_get_u64(results[FM10K_TEST_MSG_U64],
845 if (!err && test_u64 != result_u64)
846 err = FM10K_ERR_INVALID_VALUE;
850 if (!!results[FM10K_TEST_MSG_S8]) {
851 err = fm10k_tlv_attr_get_s8(results[FM10K_TEST_MSG_S8],
853 if (!err && test_s8 != result_s8)
854 err = FM10K_ERR_INVALID_VALUE;
858 if (!!results[FM10K_TEST_MSG_S16]) {
859 err = fm10k_tlv_attr_get_s16(results[FM10K_TEST_MSG_S16],
861 if (!err && test_s16 != result_s16)
862 err = FM10K_ERR_INVALID_VALUE;
866 if (!!results[FM10K_TEST_MSG_S32]) {
867 err = fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_S32],
869 if (!err && test_s32 != result_s32)
870 err = FM10K_ERR_INVALID_VALUE;
874 if (!!results[FM10K_TEST_MSG_S64]) {
875 err = fm10k_tlv_attr_get_s64(results[FM10K_TEST_MSG_S64],
877 if (!err && test_s64 != result_s64)
878 err = FM10K_ERR_INVALID_VALUE;
882 if (!!results[FM10K_TEST_MSG_LE_STRUCT]) {
883 err = fm10k_tlv_attr_get_le_struct(
884 results[FM10K_TEST_MSG_LE_STRUCT],
887 if (!err && memcmp(test_le, result_le, sizeof(test_le)))
888 err = FM10K_ERR_INVALID_VALUE;
893 if (!!results[FM10K_TEST_MSG_NESTED]) {
894 /* clear any pointers */
895 memset(nest_results, 0, sizeof(nest_results));
897 /* parse the nested attributes into the nest results list */
898 err = fm10k_tlv_attr_parse(results[FM10K_TEST_MSG_NESTED],
900 fm10k_tlv_msg_test_attr);
904 /* loop back through to the start */
905 results = nest_results;
910 /* generate reply with test result */
911 fm10k_tlv_msg_init(reply, FM10K_TLV_MSG_ID_TEST);
912 fm10k_tlv_attr_put_s32(reply, FM10K_TEST_MSG_RESULT, err);
914 /* load onto outgoing mailbox */
915 return mbx->ops.enqueue_tx(hw, mbx, reply);