1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) 2013 - 2019 Intel Corporation. */
7 * fm10k_tlv_msg_init - Initialize message block for TLV data storage
8 * @msg: Pointer to message block
9 * @msg_id: Message ID indicating message type
11 * This function return success if provided with a valid message pointer
13 s32
fm10k_tlv_msg_init(u32
*msg
, u16 msg_id
)
15 /* verify pointer is not NULL */
17 return FM10K_ERR_PARAM
;
19 *msg
= (FM10K_TLV_FLAGS_MSG
<< FM10K_TLV_FLAGS_SHIFT
) | msg_id
;
25 * fm10k_tlv_attr_put_null_string - Place null terminated string on message
26 * @msg: Pointer to message block
27 * @attr_id: Attribute ID
28 * @string: Pointer to string to be stored in attribute
30 * This function will reorder a string to be CPU endian and store it in
31 * the attribute buffer. It will return success if provided with a valid
34 static s32
fm10k_tlv_attr_put_null_string(u32
*msg
, u16 attr_id
,
35 const unsigned char *string
)
37 u32 attr_data
= 0, len
= 0;
40 /* verify pointers are not NULL */
42 return FM10K_ERR_PARAM
;
44 attr
= &msg
[FM10K_TLV_DWORD_LEN(*msg
)];
46 /* copy string into local variable and then write to msg */
48 /* write data to message */
49 if (len
&& !(len
% 4)) {
50 attr
[len
/ 4] = attr_data
;
54 /* record character to offset location */
55 attr_data
|= (u32
)(*string
) << (8 * (len
% 4));
58 /* test for NULL and then increment */
59 } while (*(string
++));
61 /* write last piece of data to message */
62 attr
[(len
+ 3) / 4] = attr_data
;
64 /* record attribute header, update message length */
65 len
<<= FM10K_TLV_LEN_SHIFT
;
66 attr
[0] = len
| attr_id
;
68 /* add header length to length */
69 len
+= FM10K_TLV_HDR_LEN
<< FM10K_TLV_LEN_SHIFT
;
70 *msg
+= FM10K_TLV_LEN_ALIGN(len
);
76 * fm10k_tlv_attr_get_null_string - Get null terminated string from attribute
77 * @attr: Pointer to attribute
78 * @string: Pointer to location of destination string
80 * This function pulls the string back out of the attribute and will place
81 * it in the array pointed by by string. It will return success if provided
82 * with a valid pointers.
84 static s32
fm10k_tlv_attr_get_null_string(u32
*attr
, unsigned char *string
)
88 /* verify pointers are not NULL */
90 return FM10K_ERR_PARAM
;
92 len
= *attr
>> FM10K_TLV_LEN_SHIFT
;
96 string
[len
] = (u8
)(attr
[len
/ 4] >> (8 * (len
% 4)));
102 * fm10k_tlv_attr_put_mac_vlan - Store MAC/VLAN attribute in message
103 * @msg: Pointer to message block
104 * @attr_id: Attribute ID
105 * @mac_addr: MAC address to be stored
106 * @vlan: VLAN to be stored
108 * This function will reorder a MAC address to be CPU endian and store it
109 * in the attribute buffer. It will return success if provided with a
112 s32
fm10k_tlv_attr_put_mac_vlan(u32
*msg
, u16 attr_id
,
113 const u8
*mac_addr
, u16 vlan
)
115 u32 len
= ETH_ALEN
<< FM10K_TLV_LEN_SHIFT
;
118 /* verify pointers are not NULL */
119 if (!msg
|| !mac_addr
)
120 return FM10K_ERR_PARAM
;
122 attr
= &msg
[FM10K_TLV_DWORD_LEN(*msg
)];
124 /* record attribute header, update message length */
125 attr
[0] = len
| attr_id
;
127 /* copy value into local variable and then write to msg */
128 attr
[1] = le32_to_cpu(*(const __le32
*)&mac_addr
[0]);
129 attr
[2] = le16_to_cpu(*(const __le16
*)&mac_addr
[4]);
130 attr
[2] |= (u32
)vlan
<< 16;
132 /* add header length to length */
133 len
+= FM10K_TLV_HDR_LEN
<< FM10K_TLV_LEN_SHIFT
;
134 *msg
+= FM10K_TLV_LEN_ALIGN(len
);
140 * fm10k_tlv_attr_get_mac_vlan - Get MAC/VLAN stored in attribute
141 * @attr: Pointer to attribute
142 * @mac_addr: location of buffer to store MAC address
143 * @vlan: location of buffer to store VLAN
145 * This function pulls the MAC address back out of the attribute and will
146 * place it in the array pointed by by mac_addr. It will return success
147 * if provided with a valid pointers.
149 s32
fm10k_tlv_attr_get_mac_vlan(u32
*attr
, u8
*mac_addr
, u16
*vlan
)
151 /* verify pointers are not NULL */
152 if (!mac_addr
|| !attr
)
153 return FM10K_ERR_PARAM
;
155 *(__le32
*)&mac_addr
[0] = cpu_to_le32(attr
[1]);
156 *(__le16
*)&mac_addr
[4] = cpu_to_le16((u16
)(attr
[2]));
157 *vlan
= (u16
)(attr
[2] >> 16);
163 * fm10k_tlv_attr_put_bool - Add header indicating value "true"
164 * @msg: Pointer to message block
165 * @attr_id: Attribute ID
167 * This function will simply add an attribute header, the fact
168 * that the header is here means the attribute value is true, else
169 * it is false. The function will return success if provided with a
172 s32
fm10k_tlv_attr_put_bool(u32
*msg
, u16 attr_id
)
174 /* verify pointers are not NULL */
176 return FM10K_ERR_PARAM
;
178 /* record attribute header */
179 msg
[FM10K_TLV_DWORD_LEN(*msg
)] = attr_id
;
181 /* add header length to length */
182 *msg
+= FM10K_TLV_HDR_LEN
<< FM10K_TLV_LEN_SHIFT
;
188 * fm10k_tlv_attr_put_value - Store integer value attribute in message
189 * @msg: Pointer to message block
190 * @attr_id: Attribute ID
191 * @value: Value to be written
192 * @len: Size of value
194 * This function will place an integer value of up to 8 bytes in size
195 * in a message attribute. The function will return success provided
196 * that msg is a valid pointer, and len is 1, 2, 4, or 8.
198 s32
fm10k_tlv_attr_put_value(u32
*msg
, u16 attr_id
, s64 value
, u32 len
)
202 /* verify non-null msg and len is 1, 2, 4, or 8 */
203 if (!msg
|| !len
|| len
> 8 || (len
& (len
- 1)))
204 return FM10K_ERR_PARAM
;
206 attr
= &msg
[FM10K_TLV_DWORD_LEN(*msg
)];
209 attr
[1] = (u32
)value
& (BIT(8 * len
) - 1);
211 attr
[1] = (u32
)value
;
213 attr
[2] = (u32
)(value
>> 32);
216 /* record attribute header, update message length */
217 len
<<= FM10K_TLV_LEN_SHIFT
;
218 attr
[0] = len
| attr_id
;
220 /* add header length to length */
221 len
+= FM10K_TLV_HDR_LEN
<< FM10K_TLV_LEN_SHIFT
;
222 *msg
+= FM10K_TLV_LEN_ALIGN(len
);
228 * fm10k_tlv_attr_get_value - Get integer value stored in attribute
229 * @attr: Pointer to attribute
230 * @value: Pointer to destination buffer
231 * @len: Size of value
233 * This function will place an integer value of up to 8 bytes in size
234 * in the offset pointed to by value. The function will return success
235 * provided that pointers are valid and the len value matches the
238 s32
fm10k_tlv_attr_get_value(u32
*attr
, void *value
, u32 len
)
240 /* verify pointers are not NULL */
242 return FM10K_ERR_PARAM
;
244 if ((*attr
>> FM10K_TLV_LEN_SHIFT
) != len
)
245 return FM10K_ERR_PARAM
;
248 *(u64
*)value
= ((u64
)attr
[2] << 32) | attr
[1];
250 *(u32
*)value
= attr
[1];
252 *(u16
*)value
= (u16
)attr
[1];
254 *(u8
*)value
= (u8
)attr
[1];
260 * fm10k_tlv_attr_put_le_struct - Store little endian structure in message
261 * @msg: Pointer to message block
262 * @attr_id: Attribute ID
263 * @le_struct: Pointer to structure to be written
264 * @len: Size of le_struct
266 * This function will place a little endian structure value in a message
267 * attribute. The function will return success provided that all pointers
268 * are valid and length is a non-zero multiple of 4.
270 s32
fm10k_tlv_attr_put_le_struct(u32
*msg
, u16 attr_id
,
271 const void *le_struct
, u32 len
)
273 const __le32
*le32_ptr
= (const __le32
*)le_struct
;
277 /* verify non-null msg and len is in 32 bit words */
278 if (!msg
|| !len
|| (len
% 4))
279 return FM10K_ERR_PARAM
;
281 attr
= &msg
[FM10K_TLV_DWORD_LEN(*msg
)];
283 /* copy le32 structure into host byte order at 32b boundaries */
284 for (i
= 0; i
< (len
/ 4); i
++)
285 attr
[i
+ 1] = le32_to_cpu(le32_ptr
[i
]);
287 /* record attribute header, update message length */
288 len
<<= FM10K_TLV_LEN_SHIFT
;
289 attr
[0] = len
| attr_id
;
291 /* add header length to length */
292 len
+= FM10K_TLV_HDR_LEN
<< FM10K_TLV_LEN_SHIFT
;
293 *msg
+= FM10K_TLV_LEN_ALIGN(len
);
299 * fm10k_tlv_attr_get_le_struct - Get little endian struct form attribute
300 * @attr: Pointer to attribute
301 * @le_struct: Pointer to structure to be written
302 * @len: Size of structure
304 * This function will place a little endian structure in the buffer
305 * pointed to by le_struct. The function will return success
306 * provided that pointers are valid and the len value matches the
309 s32
fm10k_tlv_attr_get_le_struct(u32
*attr
, void *le_struct
, u32 len
)
311 __le32
*le32_ptr
= (__le32
*)le_struct
;
314 /* verify pointers are not NULL */
315 if (!le_struct
|| !attr
)
316 return FM10K_ERR_PARAM
;
318 if ((*attr
>> FM10K_TLV_LEN_SHIFT
) != len
)
319 return FM10K_ERR_PARAM
;
323 for (i
= 0; len
; i
++, len
-= 4)
324 le32_ptr
[i
] = cpu_to_le32(attr
[i
]);
330 * fm10k_tlv_attr_nest_start - Start a set of nested attributes
331 * @msg: Pointer to message block
332 * @attr_id: Attribute ID
334 * This function will mark off a new nested region for encapsulating
335 * a given set of attributes. The idea is if you wish to place a secondary
336 * structure within the message this mechanism allows for that. The
337 * function will return NULL on failure, and a pointer to the start
338 * of the nested attributes on success.
340 static u32
*fm10k_tlv_attr_nest_start(u32
*msg
, u16 attr_id
)
344 /* verify pointer is not NULL */
348 attr
= &msg
[FM10K_TLV_DWORD_LEN(*msg
)];
352 /* return pointer to nest header */
357 * fm10k_tlv_attr_nest_stop - Stop a set of nested attributes
358 * @msg: Pointer to message block
360 * This function closes off an existing set of nested attributes. The
361 * message pointer should be pointing to the parent of the nest. So in
362 * the case of a nest within the nest this would be the outer nest pointer.
363 * This function will return success provided all pointers are valid.
365 static s32
fm10k_tlv_attr_nest_stop(u32
*msg
)
370 /* verify pointer is not NULL */
372 return FM10K_ERR_PARAM
;
374 /* locate the nested header and retrieve its length */
375 attr
= &msg
[FM10K_TLV_DWORD_LEN(*msg
)];
376 len
= (attr
[0] >> FM10K_TLV_LEN_SHIFT
) << FM10K_TLV_LEN_SHIFT
;
378 /* only include nest if data was added to it */
380 len
+= FM10K_TLV_HDR_LEN
<< FM10K_TLV_LEN_SHIFT
;
388 * fm10k_tlv_attr_validate - Validate attribute metadata
389 * @attr: Pointer to attribute
390 * @tlv_attr: Type and length info for attribute
392 * This function does some basic validation of the input TLV. It
393 * verifies the length, and in the case of null terminated strings
394 * it verifies that the last byte is null. The function will
395 * return FM10K_ERR_PARAM if any attribute is malformed, otherwise
398 static s32
fm10k_tlv_attr_validate(u32
*attr
,
399 const struct fm10k_tlv_attr
*tlv_attr
)
401 u32 attr_id
= *attr
& FM10K_TLV_ID_MASK
;
402 u16 len
= *attr
>> FM10K_TLV_LEN_SHIFT
;
404 /* verify this is an attribute and not a message */
405 if (*attr
& (FM10K_TLV_FLAGS_MSG
<< FM10K_TLV_FLAGS_SHIFT
))
406 return FM10K_ERR_PARAM
;
408 /* search through the list of attributes to find a matching ID */
409 while (tlv_attr
->id
< attr_id
)
412 /* if didn't find a match then we should exit */
413 if (tlv_attr
->id
!= attr_id
)
414 return FM10K_NOT_IMPLEMENTED
;
416 /* move to start of attribute data */
419 switch (tlv_attr
->type
) {
420 case FM10K_TLV_NULL_STRING
:
422 (attr
[(len
- 1) / 4] & (0xFF << (8 * ((len
- 1) % 4)))))
423 return FM10K_ERR_PARAM
;
424 if (len
> tlv_attr
->len
)
425 return FM10K_ERR_PARAM
;
427 case FM10K_TLV_MAC_ADDR
:
429 return FM10K_ERR_PARAM
;
433 return FM10K_ERR_PARAM
;
435 case FM10K_TLV_UNSIGNED
:
436 case FM10K_TLV_SIGNED
:
437 if (len
!= tlv_attr
->len
)
438 return FM10K_ERR_PARAM
;
440 case FM10K_TLV_LE_STRUCT
:
441 /* struct must be 4 byte aligned */
442 if ((len
% 4) || len
!= tlv_attr
->len
)
443 return FM10K_ERR_PARAM
;
445 case FM10K_TLV_NESTED
:
446 /* nested attributes must be 4 byte aligned */
448 return FM10K_ERR_PARAM
;
451 /* attribute id is mapped to bad value */
452 return FM10K_ERR_PARAM
;
459 * fm10k_tlv_attr_parse - Parses stream of attribute data
460 * @attr: Pointer to attribute list
461 * @results: Pointer array to store pointers to attributes
462 * @tlv_attr: Type and length info for attributes
464 * This function validates a stream of attributes and parses them
465 * up into an array of pointers stored in results. The function will
466 * return FM10K_ERR_PARAM on any input or message error,
467 * FM10K_NOT_IMPLEMENTED for any attribute that is outside of the array
468 * and 0 on success. Any attributes not found in tlv_attr will be silently
471 static s32
fm10k_tlv_attr_parse(u32
*attr
, u32
**results
,
472 const struct fm10k_tlv_attr
*tlv_attr
)
474 u32 i
, attr_id
, offset
= 0;
478 /* verify pointers are not NULL */
479 if (!attr
|| !results
)
480 return FM10K_ERR_PARAM
;
482 /* initialize results to NULL */
483 for (i
= 0; i
< FM10K_TLV_RESULTS_MAX
; i
++)
486 /* pull length from the message header */
487 len
= *attr
>> FM10K_TLV_LEN_SHIFT
;
489 /* no attributes to parse if there is no length */
493 /* no attributes to parse, just raw data, message becomes attribute */
499 /* move to start of attribute data */
502 /* run through list parsing all attributes */
503 while (offset
< len
) {
504 attr_id
= *attr
& FM10K_TLV_ID_MASK
;
506 if (attr_id
>= FM10K_TLV_RESULTS_MAX
)
507 return FM10K_NOT_IMPLEMENTED
;
509 err
= fm10k_tlv_attr_validate(attr
, tlv_attr
);
510 if (err
== FM10K_NOT_IMPLEMENTED
)
511 ; /* silently ignore non-implemented attributes */
515 results
[attr_id
] = attr
;
518 offset
+= FM10K_TLV_DWORD_LEN(*attr
) * 4;
520 /* move to next attribute */
521 attr
= &attr
[FM10K_TLV_DWORD_LEN(*attr
)];
524 /* we should find ourselves at the end of the list */
526 return FM10K_ERR_PARAM
;
532 * fm10k_tlv_msg_parse - Parses message header and calls function handler
533 * @hw: Pointer to hardware structure
534 * @msg: Pointer to message
535 * @mbx: Pointer to mailbox information structure
536 * @data: Pointer to message handler data structure
538 * This function should be the first function called upon receiving a
539 * message. The handler will identify the message type and call the correct
540 * handler for the given message. It will return the value from the function
541 * call on a recognized message type, otherwise it will return
542 * FM10K_NOT_IMPLEMENTED on an unrecognized type.
544 s32
fm10k_tlv_msg_parse(struct fm10k_hw
*hw
, u32
*msg
,
545 struct fm10k_mbx_info
*mbx
,
546 const struct fm10k_msg_data
*data
)
548 u32
*results
[FM10K_TLV_RESULTS_MAX
];
552 /* verify pointer is not NULL */
554 return FM10K_ERR_PARAM
;
556 /* verify this is a message and not an attribute */
557 if (!(*msg
& (FM10K_TLV_FLAGS_MSG
<< FM10K_TLV_FLAGS_SHIFT
)))
558 return FM10K_ERR_PARAM
;
560 /* grab message ID */
561 msg_id
= *msg
& FM10K_TLV_ID_MASK
;
563 while (data
->id
< msg_id
)
566 /* if we didn't find it then pass it up as an error */
567 if (data
->id
!= msg_id
) {
568 while (data
->id
!= FM10K_TLV_ERROR
)
572 /* parse the attributes into the results list */
573 err
= fm10k_tlv_attr_parse(msg
, results
, data
->attr
);
577 return data
->func(hw
, results
, mbx
);
581 * fm10k_tlv_msg_error - Default handler for unrecognized TLV message IDs
582 * @hw: Pointer to hardware structure
583 * @results: Pointer array to message, results[0] is pointer to message
584 * @mbx: Unused mailbox pointer
586 * This function is a default handler for unrecognized messages. At a
587 * a minimum it just indicates that the message requested was
590 s32
fm10k_tlv_msg_error(struct fm10k_hw __always_unused
*hw
,
591 u32 __always_unused
**results
,
592 struct fm10k_mbx_info __always_unused
*mbx
)
594 return FM10K_NOT_IMPLEMENTED
;
597 static const unsigned char test_str
[] = "fm10k";
598 static const unsigned char test_mac
[ETH_ALEN
] = { 0x12, 0x34, 0x56,
600 static const u16 test_vlan
= 0x0FED;
601 static const u64 test_u64
= 0xfedcba9876543210ull
;
602 static const u32 test_u32
= 0x87654321;
603 static const u16 test_u16
= 0x8765;
604 static const u8 test_u8
= 0x87;
605 static const s64 test_s64
= -0x123456789abcdef0ll
;
606 static const s32 test_s32
= -0x1235678;
607 static const s16 test_s16
= -0x1234;
608 static const s8 test_s8
= -0x12;
609 static const __le32 test_le
[2] = { cpu_to_le32(0x12345678),
610 cpu_to_le32(0x9abcdef0)};
612 /* The message below is meant to be used as a test message to demonstrate
613 * how to use the TLV interface and to test the types. Normally this code
614 * be compiled out by stripping the code wrapped in FM10K_TLV_TEST_MSG
616 const struct fm10k_tlv_attr fm10k_tlv_msg_test_attr
[] = {
617 FM10K_TLV_ATTR_NULL_STRING(FM10K_TEST_MSG_STRING
, 80),
618 FM10K_TLV_ATTR_MAC_ADDR(FM10K_TEST_MSG_MAC_ADDR
),
619 FM10K_TLV_ATTR_U8(FM10K_TEST_MSG_U8
),
620 FM10K_TLV_ATTR_U16(FM10K_TEST_MSG_U16
),
621 FM10K_TLV_ATTR_U32(FM10K_TEST_MSG_U32
),
622 FM10K_TLV_ATTR_U64(FM10K_TEST_MSG_U64
),
623 FM10K_TLV_ATTR_S8(FM10K_TEST_MSG_S8
),
624 FM10K_TLV_ATTR_S16(FM10K_TEST_MSG_S16
),
625 FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_S32
),
626 FM10K_TLV_ATTR_S64(FM10K_TEST_MSG_S64
),
627 FM10K_TLV_ATTR_LE_STRUCT(FM10K_TEST_MSG_LE_STRUCT
, 8),
628 FM10K_TLV_ATTR_NESTED(FM10K_TEST_MSG_NESTED
),
629 FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_RESULT
),
634 * fm10k_tlv_msg_test_generate_data - Stuff message with data
635 * @msg: Pointer to message
636 * @attr_flags: List of flags indicating what attributes to add
638 * This function is meant to load a message buffer with attribute data
640 static void fm10k_tlv_msg_test_generate_data(u32
*msg
, u32 attr_flags
)
642 if (attr_flags
& BIT(FM10K_TEST_MSG_STRING
))
643 fm10k_tlv_attr_put_null_string(msg
, FM10K_TEST_MSG_STRING
,
645 if (attr_flags
& BIT(FM10K_TEST_MSG_MAC_ADDR
))
646 fm10k_tlv_attr_put_mac_vlan(msg
, FM10K_TEST_MSG_MAC_ADDR
,
647 test_mac
, test_vlan
);
648 if (attr_flags
& BIT(FM10K_TEST_MSG_U8
))
649 fm10k_tlv_attr_put_u8(msg
, FM10K_TEST_MSG_U8
, test_u8
);
650 if (attr_flags
& BIT(FM10K_TEST_MSG_U16
))
651 fm10k_tlv_attr_put_u16(msg
, FM10K_TEST_MSG_U16
, test_u16
);
652 if (attr_flags
& BIT(FM10K_TEST_MSG_U32
))
653 fm10k_tlv_attr_put_u32(msg
, FM10K_TEST_MSG_U32
, test_u32
);
654 if (attr_flags
& BIT(FM10K_TEST_MSG_U64
))
655 fm10k_tlv_attr_put_u64(msg
, FM10K_TEST_MSG_U64
, test_u64
);
656 if (attr_flags
& BIT(FM10K_TEST_MSG_S8
))
657 fm10k_tlv_attr_put_s8(msg
, FM10K_TEST_MSG_S8
, test_s8
);
658 if (attr_flags
& BIT(FM10K_TEST_MSG_S16
))
659 fm10k_tlv_attr_put_s16(msg
, FM10K_TEST_MSG_S16
, test_s16
);
660 if (attr_flags
& BIT(FM10K_TEST_MSG_S32
))
661 fm10k_tlv_attr_put_s32(msg
, FM10K_TEST_MSG_S32
, test_s32
);
662 if (attr_flags
& BIT(FM10K_TEST_MSG_S64
))
663 fm10k_tlv_attr_put_s64(msg
, FM10K_TEST_MSG_S64
, test_s64
);
664 if (attr_flags
& BIT(FM10K_TEST_MSG_LE_STRUCT
))
665 fm10k_tlv_attr_put_le_struct(msg
, FM10K_TEST_MSG_LE_STRUCT
,
670 * fm10k_tlv_msg_test_create - Create a test message testing all attributes
671 * @msg: Pointer to message
672 * @attr_flags: List of flags indicating what attributes to add
674 * This function is meant to load a message buffer with all attribute types
675 * including a nested attribute.
677 void fm10k_tlv_msg_test_create(u32
*msg
, u32 attr_flags
)
681 fm10k_tlv_msg_init(msg
, FM10K_TLV_MSG_ID_TEST
);
683 fm10k_tlv_msg_test_generate_data(msg
, attr_flags
);
685 /* check for nested attributes */
686 attr_flags
>>= FM10K_TEST_MSG_NESTED
;
689 nest
= fm10k_tlv_attr_nest_start(msg
, FM10K_TEST_MSG_NESTED
);
691 fm10k_tlv_msg_test_generate_data(nest
, attr_flags
);
693 fm10k_tlv_attr_nest_stop(msg
);
698 * fm10k_tlv_msg_test - Validate all results on test message receive
699 * @hw: Pointer to hardware structure
700 * @results: Pointer array to attributes in the message
701 * @mbx: Pointer to mailbox information structure
703 * This function does a check to verify all attributes match what the test
704 * message placed in the message buffer. It is the default handler
705 * for TLV test messages.
707 s32
fm10k_tlv_msg_test(struct fm10k_hw
*hw
, u32
**results
,
708 struct fm10k_mbx_info
*mbx
)
710 u32
*nest_results
[FM10K_TLV_RESULTS_MAX
];
711 unsigned char result_str
[80];
712 unsigned char result_mac
[ETH_ALEN
];
726 /* retrieve results of a previous test */
727 if (!!results
[FM10K_TEST_MSG_RESULT
])
728 return fm10k_tlv_attr_get_s32(results
[FM10K_TEST_MSG_RESULT
],
732 if (!!results
[FM10K_TEST_MSG_STRING
]) {
733 err
= fm10k_tlv_attr_get_null_string(
734 results
[FM10K_TEST_MSG_STRING
],
736 if (!err
&& memcmp(test_str
, result_str
, sizeof(test_str
)))
737 err
= FM10K_ERR_INVALID_VALUE
;
741 if (!!results
[FM10K_TEST_MSG_MAC_ADDR
]) {
742 err
= fm10k_tlv_attr_get_mac_vlan(
743 results
[FM10K_TEST_MSG_MAC_ADDR
],
744 result_mac
, &result_vlan
);
745 if (!err
&& !ether_addr_equal(test_mac
, result_mac
))
746 err
= FM10K_ERR_INVALID_VALUE
;
747 if (!err
&& test_vlan
!= result_vlan
)
748 err
= FM10K_ERR_INVALID_VALUE
;
752 if (!!results
[FM10K_TEST_MSG_U8
]) {
753 err
= fm10k_tlv_attr_get_u8(results
[FM10K_TEST_MSG_U8
],
755 if (!err
&& test_u8
!= result_u8
)
756 err
= FM10K_ERR_INVALID_VALUE
;
760 if (!!results
[FM10K_TEST_MSG_U16
]) {
761 err
= fm10k_tlv_attr_get_u16(results
[FM10K_TEST_MSG_U16
],
763 if (!err
&& test_u16
!= result_u16
)
764 err
= FM10K_ERR_INVALID_VALUE
;
768 if (!!results
[FM10K_TEST_MSG_U32
]) {
769 err
= fm10k_tlv_attr_get_u32(results
[FM10K_TEST_MSG_U32
],
771 if (!err
&& test_u32
!= result_u32
)
772 err
= FM10K_ERR_INVALID_VALUE
;
776 if (!!results
[FM10K_TEST_MSG_U64
]) {
777 err
= fm10k_tlv_attr_get_u64(results
[FM10K_TEST_MSG_U64
],
779 if (!err
&& test_u64
!= result_u64
)
780 err
= FM10K_ERR_INVALID_VALUE
;
784 if (!!results
[FM10K_TEST_MSG_S8
]) {
785 err
= fm10k_tlv_attr_get_s8(results
[FM10K_TEST_MSG_S8
],
787 if (!err
&& test_s8
!= result_s8
)
788 err
= FM10K_ERR_INVALID_VALUE
;
792 if (!!results
[FM10K_TEST_MSG_S16
]) {
793 err
= fm10k_tlv_attr_get_s16(results
[FM10K_TEST_MSG_S16
],
795 if (!err
&& test_s16
!= result_s16
)
796 err
= FM10K_ERR_INVALID_VALUE
;
800 if (!!results
[FM10K_TEST_MSG_S32
]) {
801 err
= fm10k_tlv_attr_get_s32(results
[FM10K_TEST_MSG_S32
],
803 if (!err
&& test_s32
!= result_s32
)
804 err
= FM10K_ERR_INVALID_VALUE
;
808 if (!!results
[FM10K_TEST_MSG_S64
]) {
809 err
= fm10k_tlv_attr_get_s64(results
[FM10K_TEST_MSG_S64
],
811 if (!err
&& test_s64
!= result_s64
)
812 err
= FM10K_ERR_INVALID_VALUE
;
816 if (!!results
[FM10K_TEST_MSG_LE_STRUCT
]) {
817 err
= fm10k_tlv_attr_get_le_struct(
818 results
[FM10K_TEST_MSG_LE_STRUCT
],
821 if (!err
&& memcmp(test_le
, result_le
, sizeof(test_le
)))
822 err
= FM10K_ERR_INVALID_VALUE
;
827 if (!!results
[FM10K_TEST_MSG_NESTED
]) {
828 /* clear any pointers */
829 memset(nest_results
, 0, sizeof(nest_results
));
831 /* parse the nested attributes into the nest results list */
832 err
= fm10k_tlv_attr_parse(results
[FM10K_TEST_MSG_NESTED
],
834 fm10k_tlv_msg_test_attr
);
838 /* loop back through to the start */
839 results
= nest_results
;
844 /* generate reply with test result */
845 fm10k_tlv_msg_init(reply
, FM10K_TLV_MSG_ID_TEST
);
846 fm10k_tlv_attr_put_s32(reply
, FM10K_TEST_MSG_RESULT
, err
);
848 /* load onto outgoing mailbox */
849 return mbx
->ops
.enqueue_tx(hw
, mbx
, reply
);