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_start - Start 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
525 static s32 fm10k_tlv_attr_parse(u32 *attr, u32 **results,
526 const struct fm10k_tlv_attr *tlv_attr)
528 u32 i, attr_id, offset = 0;
532 DEBUGFUNC("fm10k_tlv_attr_parse");
534 /* verify pointers are not NULL */
535 if (!attr || !results)
536 return FM10K_ERR_PARAM;
538 /* initialize results to NULL */
539 for (i = 0; i < FM10K_TLV_RESULTS_MAX; i++)
542 /* pull length from the message header */
543 len = *attr >> FM10K_TLV_LEN_SHIFT;
545 /* no attributes to parse if there is no length */
547 return FM10K_SUCCESS;
549 /* no attributes to parse, just raw data, message becomes attribute */
552 return FM10K_SUCCESS;
555 /* move to start of attribute data */
558 /* run through list parsing all attributes */
559 while (offset < len) {
560 attr_id = *attr & FM10K_TLV_ID_MASK;
562 if (attr_id < FM10K_TLV_RESULTS_MAX)
563 err = fm10k_tlv_attr_validate(attr, tlv_attr);
565 err = FM10K_NOT_IMPLEMENTED;
570 results[attr_id] = attr;
573 offset += FM10K_TLV_DWORD_LEN(*attr) * 4;
575 /* move to next attribute */
576 attr = &attr[FM10K_TLV_DWORD_LEN(*attr)];
579 /* we should find ourselves at the end of the list */
581 return FM10K_ERR_PARAM;
583 return FM10K_SUCCESS;
587 * fm10k_tlv_msg_parse - Parses message header and calls function handler
588 * @hw: Pointer to hardware structure
589 * @msg: Pointer to message
590 * @mbx: Pointer to mailbox information structure
591 * @func: Function array containing list of message handling functions
593 * This function should be the first function called upon receiving a
594 * message. The handler will identify the message type and call the correct
595 * handler for the given message. It will return the value from the function
596 * call on a recognized message type, otherwise it will return
597 * FM10K_NOT_IMPLEMENTED on an unrecognized type.
599 s32 fm10k_tlv_msg_parse(struct fm10k_hw *hw, u32 *msg,
600 struct fm10k_mbx_info *mbx,
601 const struct fm10k_msg_data *data)
603 u32 *results[FM10K_TLV_RESULTS_MAX];
607 DEBUGFUNC("fm10k_tlv_msg_parse");
609 /* verify pointer is not NULL */
611 return FM10K_ERR_PARAM;
613 /* verify this is a message and not an attribute */
614 if (!(*msg & (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT)))
615 return FM10K_ERR_PARAM;
617 /* grab message ID */
618 msg_id = *msg & FM10K_TLV_ID_MASK;
620 while (data->id < msg_id)
623 /* if we didn't find it then pass it up as an error */
624 if (data->id != msg_id) {
625 while (data->id != FM10K_TLV_ERROR)
629 /* parse the attributes into the results list */
630 err = fm10k_tlv_attr_parse(msg, results, data->attr);
634 return data->func(hw, results, mbx);
638 * fm10k_tlv_msg_error - Default handler for unrecognized TLV message IDs
639 * @hw: Pointer to hardware structure
640 * @results: Pointer array to message, results[0] is pointer to message
641 * @mbx: Unused mailbox pointer
643 * This function is a default handler for unrecognized messages. At a
644 * a minimum it just indicates that the message requested was
647 s32 fm10k_tlv_msg_error(struct fm10k_hw *hw, u32 **results,
648 struct fm10k_mbx_info *mbx)
650 UNREFERENCED_3PARAMETER(hw, results, mbx);
651 DEBUGOUT1("Unknown message ID %u\n", **results & FM10K_TLV_ID_MASK);
652 return FM10K_NOT_IMPLEMENTED;
655 STATIC const unsigned char test_str[] = "fm10k";
656 STATIC const unsigned char test_mac[ETH_ALEN] = { 0x12, 0x34, 0x56,
658 STATIC const u16 test_vlan = 0x0FED;
659 STATIC const u64 test_u64 = 0xfedcba9876543210ull;
660 STATIC const u32 test_u32 = 0x87654321;
661 STATIC const u16 test_u16 = 0x8765;
662 STATIC const u8 test_u8 = 0x87;
663 STATIC const s64 test_s64 = -0x123456789abcdef0ll;
664 STATIC const s32 test_s32 = -0x1235678;
665 STATIC const s16 test_s16 = -0x1234;
666 STATIC const s8 test_s8 = -0x12;
667 STATIC const __le32 test_le[2] = { FM10K_CPU_TO_LE32(0x12345678),
668 FM10K_CPU_TO_LE32(0x9abcdef0)};
670 /* The message below is meant to be used as a test message to demonstrate
671 * how to use the TLV interface and to test the types. Normally this code
672 * be compiled out by stripping the code wrapped in FM10K_TLV_TEST_MSG
674 const struct fm10k_tlv_attr fm10k_tlv_msg_test_attr[] = {
675 FM10K_TLV_ATTR_NULL_STRING(FM10K_TEST_MSG_STRING, 80),
676 FM10K_TLV_ATTR_MAC_ADDR(FM10K_TEST_MSG_MAC_ADDR),
677 FM10K_TLV_ATTR_U8(FM10K_TEST_MSG_U8),
678 FM10K_TLV_ATTR_U16(FM10K_TEST_MSG_U16),
679 FM10K_TLV_ATTR_U32(FM10K_TEST_MSG_U32),
680 FM10K_TLV_ATTR_U64(FM10K_TEST_MSG_U64),
681 FM10K_TLV_ATTR_S8(FM10K_TEST_MSG_S8),
682 FM10K_TLV_ATTR_S16(FM10K_TEST_MSG_S16),
683 FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_S32),
684 FM10K_TLV_ATTR_S64(FM10K_TEST_MSG_S64),
685 FM10K_TLV_ATTR_LE_STRUCT(FM10K_TEST_MSG_LE_STRUCT, 8),
686 FM10K_TLV_ATTR_NESTED(FM10K_TEST_MSG_NESTED),
687 FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_RESULT),
692 * fm10k_tlv_msg_test_generate_data - Stuff message with data
693 * @msg: Pointer to message
694 * @attr_flags: List of flags indicating what attributes to add
696 * This function is meant to load a message buffer with attribute data
698 STATIC void fm10k_tlv_msg_test_generate_data(u32 *msg, u32 attr_flags)
700 DEBUGFUNC("fm10k_tlv_msg_test_generate_data");
702 if (attr_flags & BIT(FM10K_TEST_MSG_STRING))
703 fm10k_tlv_attr_put_null_string(msg, FM10K_TEST_MSG_STRING,
705 if (attr_flags & BIT(FM10K_TEST_MSG_MAC_ADDR))
706 fm10k_tlv_attr_put_mac_vlan(msg, FM10K_TEST_MSG_MAC_ADDR,
707 test_mac, test_vlan);
708 if (attr_flags & BIT(FM10K_TEST_MSG_U8))
709 fm10k_tlv_attr_put_u8(msg, FM10K_TEST_MSG_U8, test_u8);
710 if (attr_flags & BIT(FM10K_TEST_MSG_U16))
711 fm10k_tlv_attr_put_u16(msg, FM10K_TEST_MSG_U16, test_u16);
712 if (attr_flags & BIT(FM10K_TEST_MSG_U32))
713 fm10k_tlv_attr_put_u32(msg, FM10K_TEST_MSG_U32, test_u32);
714 if (attr_flags & BIT(FM10K_TEST_MSG_U64))
715 fm10k_tlv_attr_put_u64(msg, FM10K_TEST_MSG_U64, test_u64);
716 if (attr_flags & BIT(FM10K_TEST_MSG_S8))
717 fm10k_tlv_attr_put_s8(msg, FM10K_TEST_MSG_S8, test_s8);
718 if (attr_flags & BIT(FM10K_TEST_MSG_S16))
719 fm10k_tlv_attr_put_s16(msg, FM10K_TEST_MSG_S16, test_s16);
720 if (attr_flags & BIT(FM10K_TEST_MSG_S32))
721 fm10k_tlv_attr_put_s32(msg, FM10K_TEST_MSG_S32, test_s32);
722 if (attr_flags & BIT(FM10K_TEST_MSG_S64))
723 fm10k_tlv_attr_put_s64(msg, FM10K_TEST_MSG_S64, test_s64);
724 if (attr_flags & BIT(FM10K_TEST_MSG_LE_STRUCT))
725 fm10k_tlv_attr_put_le_struct(msg, FM10K_TEST_MSG_LE_STRUCT,
730 * fm10k_tlv_msg_test_create - Create a test message testing all attributes
731 * @msg: Pointer to message
732 * @attr_flags: List of flags indicating what attributes to add
734 * This function is meant to load a message buffer with all attribute types
735 * including a nested attribute.
737 void fm10k_tlv_msg_test_create(u32 *msg, u32 attr_flags)
741 DEBUGFUNC("fm10k_tlv_msg_test_create");
743 fm10k_tlv_msg_init(msg, FM10K_TLV_MSG_ID_TEST);
745 fm10k_tlv_msg_test_generate_data(msg, attr_flags);
747 /* check for nested attributes */
748 attr_flags >>= FM10K_TEST_MSG_NESTED;
751 nest = fm10k_tlv_attr_nest_start(msg, FM10K_TEST_MSG_NESTED);
753 fm10k_tlv_msg_test_generate_data(nest, attr_flags);
755 fm10k_tlv_attr_nest_stop(msg);
760 * fm10k_tlv_msg_test - Validate all results on test message receive
761 * @hw: Pointer to hardware structure
762 * @results: Pointer array to attributes in the message
763 * @mbx: Pointer to mailbox information structure
765 * This function does a check to verify all attributes match what the test
766 * message placed in the message buffer. It is the default handler
767 * for TLV test messages.
769 s32 fm10k_tlv_msg_test(struct fm10k_hw *hw, u32 **results,
770 struct fm10k_mbx_info *mbx)
772 u32 *nest_results[FM10K_TLV_RESULTS_MAX];
773 unsigned char result_str[80];
774 unsigned char result_mac[ETH_ALEN];
775 s32 err = FM10K_SUCCESS;
788 DEBUGFUNC("fm10k_tlv_msg_test");
790 /* retrieve results of a previous test */
791 if (!!results[FM10K_TEST_MSG_RESULT])
792 return fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_RESULT],
796 if (!!results[FM10K_TEST_MSG_STRING]) {
797 err = fm10k_tlv_attr_get_null_string(
798 results[FM10K_TEST_MSG_STRING],
800 if (!err && memcmp(test_str, result_str, sizeof(test_str)))
801 err = FM10K_ERR_INVALID_VALUE;
805 if (!!results[FM10K_TEST_MSG_MAC_ADDR]) {
806 err = fm10k_tlv_attr_get_mac_vlan(
807 results[FM10K_TEST_MSG_MAC_ADDR],
808 result_mac, &result_vlan);
809 if (!err && memcmp(test_mac, result_mac, ETH_ALEN))
810 err = FM10K_ERR_INVALID_VALUE;
811 if (!err && test_vlan != result_vlan)
812 err = FM10K_ERR_INVALID_VALUE;
816 if (!!results[FM10K_TEST_MSG_U8]) {
817 err = fm10k_tlv_attr_get_u8(results[FM10K_TEST_MSG_U8],
819 if (!err && test_u8 != result_u8)
820 err = FM10K_ERR_INVALID_VALUE;
824 if (!!results[FM10K_TEST_MSG_U16]) {
825 err = fm10k_tlv_attr_get_u16(results[FM10K_TEST_MSG_U16],
827 if (!err && test_u16 != result_u16)
828 err = FM10K_ERR_INVALID_VALUE;
832 if (!!results[FM10K_TEST_MSG_U32]) {
833 err = fm10k_tlv_attr_get_u32(results[FM10K_TEST_MSG_U32],
835 if (!err && test_u32 != result_u32)
836 err = FM10K_ERR_INVALID_VALUE;
840 if (!!results[FM10K_TEST_MSG_U64]) {
841 err = fm10k_tlv_attr_get_u64(results[FM10K_TEST_MSG_U64],
843 if (!err && test_u64 != result_u64)
844 err = FM10K_ERR_INVALID_VALUE;
848 if (!!results[FM10K_TEST_MSG_S8]) {
849 err = fm10k_tlv_attr_get_s8(results[FM10K_TEST_MSG_S8],
851 if (!err && test_s8 != result_s8)
852 err = FM10K_ERR_INVALID_VALUE;
856 if (!!results[FM10K_TEST_MSG_S16]) {
857 err = fm10k_tlv_attr_get_s16(results[FM10K_TEST_MSG_S16],
859 if (!err && test_s16 != result_s16)
860 err = FM10K_ERR_INVALID_VALUE;
864 if (!!results[FM10K_TEST_MSG_S32]) {
865 err = fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_S32],
867 if (!err && test_s32 != result_s32)
868 err = FM10K_ERR_INVALID_VALUE;
872 if (!!results[FM10K_TEST_MSG_S64]) {
873 err = fm10k_tlv_attr_get_s64(results[FM10K_TEST_MSG_S64],
875 if (!err && test_s64 != result_s64)
876 err = FM10K_ERR_INVALID_VALUE;
880 if (!!results[FM10K_TEST_MSG_LE_STRUCT]) {
881 err = fm10k_tlv_attr_get_le_struct(
882 results[FM10K_TEST_MSG_LE_STRUCT],
885 if (!err && memcmp(test_le, result_le, sizeof(test_le)))
886 err = FM10K_ERR_INVALID_VALUE;
891 if (!!results[FM10K_TEST_MSG_NESTED]) {
892 /* clear any pointers */
893 memset(nest_results, 0, sizeof(nest_results));
895 /* parse the nested attributes into the nest results list */
896 err = fm10k_tlv_attr_parse(results[FM10K_TEST_MSG_NESTED],
898 fm10k_tlv_msg_test_attr);
902 /* loop back through to the start */
903 results = nest_results;
908 /* generate reply with test result */
909 fm10k_tlv_msg_init(reply, FM10K_TLV_MSG_ID_TEST);
910 fm10k_tlv_attr_put_s32(reply, FM10K_TEST_MSG_RESULT, err);
912 /* load onto outgoing mailbox */
913 return mbx->ops.enqueue_tx(hw, mbx, reply);