Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright(c) 2013 - 2019 Intel Corporation. */
0003 
0004 #include "fm10k_tlv.h"
0005 
0006 /**
0007  *  fm10k_tlv_msg_init - Initialize message block for TLV data storage
0008  *  @msg: Pointer to message block
0009  *  @msg_id: Message ID indicating message type
0010  *
0011  *  This function return success if provided with a valid message pointer
0012  **/
0013 s32 fm10k_tlv_msg_init(u32 *msg, u16 msg_id)
0014 {
0015     /* verify pointer is not NULL */
0016     if (!msg)
0017         return FM10K_ERR_PARAM;
0018 
0019     *msg = (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT) | msg_id;
0020 
0021     return 0;
0022 }
0023 
0024 /**
0025  *  fm10k_tlv_attr_put_null_string - Place null terminated string on message
0026  *  @msg: Pointer to message block
0027  *  @attr_id: Attribute ID
0028  *  @string: Pointer to string to be stored in attribute
0029  *
0030  *  This function will reorder a string to be CPU endian and store it in
0031  *  the attribute buffer.  It will return success if provided with a valid
0032  *  pointers.
0033  **/
0034 static s32 fm10k_tlv_attr_put_null_string(u32 *msg, u16 attr_id,
0035                       const unsigned char *string)
0036 {
0037     u32 attr_data = 0, len = 0;
0038     u32 *attr;
0039 
0040     /* verify pointers are not NULL */
0041     if (!string || !msg)
0042         return FM10K_ERR_PARAM;
0043 
0044     attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
0045 
0046     /* copy string into local variable and then write to msg */
0047     do {
0048         /* write data to message */
0049         if (len && !(len % 4)) {
0050             attr[len / 4] = attr_data;
0051             attr_data = 0;
0052         }
0053 
0054         /* record character to offset location */
0055         attr_data |= (u32)(*string) << (8 * (len % 4));
0056         len++;
0057 
0058         /* test for NULL and then increment */
0059     } while (*(string++));
0060 
0061     /* write last piece of data to message */
0062     attr[(len + 3) / 4] = attr_data;
0063 
0064     /* record attribute header, update message length */
0065     len <<= FM10K_TLV_LEN_SHIFT;
0066     attr[0] = len | attr_id;
0067 
0068     /* add header length to length */
0069     len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
0070     *msg += FM10K_TLV_LEN_ALIGN(len);
0071 
0072     return 0;
0073 }
0074 
0075 /**
0076  *  fm10k_tlv_attr_get_null_string - Get null terminated string from attribute
0077  *  @attr: Pointer to attribute
0078  *  @string: Pointer to location of destination string
0079  *
0080  *  This function pulls the string back out of the attribute and will place
0081  *  it in the array pointed by string.  It will return success if provided
0082  *  with a valid pointers.
0083  **/
0084 static s32 fm10k_tlv_attr_get_null_string(u32 *attr, unsigned char *string)
0085 {
0086     u32 len;
0087 
0088     /* verify pointers are not NULL */
0089     if (!string || !attr)
0090         return FM10K_ERR_PARAM;
0091 
0092     len = *attr >> FM10K_TLV_LEN_SHIFT;
0093     attr++;
0094 
0095     while (len--)
0096         string[len] = (u8)(attr[len / 4] >> (8 * (len % 4)));
0097 
0098     return 0;
0099 }
0100 
0101 /**
0102  *  fm10k_tlv_attr_put_mac_vlan - Store MAC/VLAN attribute in message
0103  *  @msg: Pointer to message block
0104  *  @attr_id: Attribute ID
0105  *  @mac_addr: MAC address to be stored
0106  *  @vlan: VLAN to be stored
0107  *
0108  *  This function will reorder a MAC address to be CPU endian and store it
0109  *  in the attribute buffer.  It will return success if provided with a
0110  *  valid pointers.
0111  **/
0112 s32 fm10k_tlv_attr_put_mac_vlan(u32 *msg, u16 attr_id,
0113                 const u8 *mac_addr, u16 vlan)
0114 {
0115     u32 len = ETH_ALEN << FM10K_TLV_LEN_SHIFT;
0116     u32 *attr;
0117 
0118     /* verify pointers are not NULL */
0119     if (!msg || !mac_addr)
0120         return FM10K_ERR_PARAM;
0121 
0122     attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
0123 
0124     /* record attribute header, update message length */
0125     attr[0] = len | attr_id;
0126 
0127     /* copy value into local variable and then write to msg */
0128     attr[1] = le32_to_cpu(*(const __le32 *)&mac_addr[0]);
0129     attr[2] = le16_to_cpu(*(const __le16 *)&mac_addr[4]);
0130     attr[2] |= (u32)vlan << 16;
0131 
0132     /* add header length to length */
0133     len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
0134     *msg += FM10K_TLV_LEN_ALIGN(len);
0135 
0136     return 0;
0137 }
0138 
0139 /**
0140  *  fm10k_tlv_attr_get_mac_vlan - Get MAC/VLAN stored in attribute
0141  *  @attr: Pointer to attribute
0142  *  @mac_addr: location of buffer to store MAC address
0143  *  @vlan: location of buffer to store VLAN
0144  *
0145  *  This function pulls the MAC address back out of the attribute and will
0146  *  place it in the array pointed by mac_addr.  It will return success
0147  *  if provided with a valid pointers.
0148  **/
0149 s32 fm10k_tlv_attr_get_mac_vlan(u32 *attr, u8 *mac_addr, u16 *vlan)
0150 {
0151     /* verify pointers are not NULL */
0152     if (!mac_addr || !attr)
0153         return FM10K_ERR_PARAM;
0154 
0155     *(__le32 *)&mac_addr[0] = cpu_to_le32(attr[1]);
0156     *(__le16 *)&mac_addr[4] = cpu_to_le16((u16)(attr[2]));
0157     *vlan = (u16)(attr[2] >> 16);
0158 
0159     return 0;
0160 }
0161 
0162 /**
0163  *  fm10k_tlv_attr_put_bool - Add header indicating value "true"
0164  *  @msg: Pointer to message block
0165  *  @attr_id: Attribute ID
0166  *
0167  *  This function will simply add an attribute header, the fact
0168  *  that the header is here means the attribute value is true, else
0169  *  it is false.  The function will return success if provided with a
0170  *  valid pointers.
0171  **/
0172 s32 fm10k_tlv_attr_put_bool(u32 *msg, u16 attr_id)
0173 {
0174     /* verify pointers are not NULL */
0175     if (!msg)
0176         return FM10K_ERR_PARAM;
0177 
0178     /* record attribute header */
0179     msg[FM10K_TLV_DWORD_LEN(*msg)] = attr_id;
0180 
0181     /* add header length to length */
0182     *msg += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
0183 
0184     return 0;
0185 }
0186 
0187 /**
0188  *  fm10k_tlv_attr_put_value - Store integer value attribute in message
0189  *  @msg: Pointer to message block
0190  *  @attr_id: Attribute ID
0191  *  @value: Value to be written
0192  *  @len: Size of value
0193  *
0194  *  This function will place an integer value of up to 8 bytes in size
0195  *  in a message attribute.  The function will return success provided
0196  *  that msg is a valid pointer, and len is 1, 2, 4, or 8.
0197  **/
0198 s32 fm10k_tlv_attr_put_value(u32 *msg, u16 attr_id, s64 value, u32 len)
0199 {
0200     u32 *attr;
0201 
0202     /* verify non-null msg and len is 1, 2, 4, or 8 */
0203     if (!msg || !len || len > 8 || (len & (len - 1)))
0204         return FM10K_ERR_PARAM;
0205 
0206     attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
0207 
0208     if (len < 4) {
0209         attr[1] = (u32)value & (BIT(8 * len) - 1);
0210     } else {
0211         attr[1] = (u32)value;
0212         if (len > 4)
0213             attr[2] = (u32)(value >> 32);
0214     }
0215 
0216     /* record attribute header, update message length */
0217     len <<= FM10K_TLV_LEN_SHIFT;
0218     attr[0] = len | attr_id;
0219 
0220     /* add header length to length */
0221     len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
0222     *msg += FM10K_TLV_LEN_ALIGN(len);
0223 
0224     return 0;
0225 }
0226 
0227 /**
0228  *  fm10k_tlv_attr_get_value - Get integer value stored in attribute
0229  *  @attr: Pointer to attribute
0230  *  @value: Pointer to destination buffer
0231  *  @len: Size of value
0232  *
0233  *  This function will place an integer value of up to 8 bytes in size
0234  *  in the offset pointed to by value.  The function will return success
0235  *  provided that pointers are valid and the len value matches the
0236  *  attribute length.
0237  **/
0238 s32 fm10k_tlv_attr_get_value(u32 *attr, void *value, u32 len)
0239 {
0240     /* verify pointers are not NULL */
0241     if (!attr || !value)
0242         return FM10K_ERR_PARAM;
0243 
0244     if ((*attr >> FM10K_TLV_LEN_SHIFT) != len)
0245         return FM10K_ERR_PARAM;
0246 
0247     if (len == 8)
0248         *(u64 *)value = ((u64)attr[2] << 32) | attr[1];
0249     else if (len == 4)
0250         *(u32 *)value = attr[1];
0251     else if (len == 2)
0252         *(u16 *)value = (u16)attr[1];
0253     else
0254         *(u8 *)value = (u8)attr[1];
0255 
0256     return 0;
0257 }
0258 
0259 /**
0260  *  fm10k_tlv_attr_put_le_struct - Store little endian structure in message
0261  *  @msg: Pointer to message block
0262  *  @attr_id: Attribute ID
0263  *  @le_struct: Pointer to structure to be written
0264  *  @len: Size of le_struct
0265  *
0266  *  This function will place a little endian structure value in a message
0267  *  attribute.  The function will return success provided that all pointers
0268  *  are valid and length is a non-zero multiple of 4.
0269  **/
0270 s32 fm10k_tlv_attr_put_le_struct(u32 *msg, u16 attr_id,
0271                  const void *le_struct, u32 len)
0272 {
0273     const __le32 *le32_ptr = (const __le32 *)le_struct;
0274     u32 *attr;
0275     u32 i;
0276 
0277     /* verify non-null msg and len is in 32 bit words */
0278     if (!msg || !len || (len % 4))
0279         return FM10K_ERR_PARAM;
0280 
0281     attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
0282 
0283     /* copy le32 structure into host byte order at 32b boundaries */
0284     for (i = 0; i < (len / 4); i++)
0285         attr[i + 1] = le32_to_cpu(le32_ptr[i]);
0286 
0287     /* record attribute header, update message length */
0288     len <<= FM10K_TLV_LEN_SHIFT;
0289     attr[0] = len | attr_id;
0290 
0291     /* add header length to length */
0292     len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
0293     *msg += FM10K_TLV_LEN_ALIGN(len);
0294 
0295     return 0;
0296 }
0297 
0298 /**
0299  *  fm10k_tlv_attr_get_le_struct - Get little endian struct form attribute
0300  *  @attr: Pointer to attribute
0301  *  @le_struct: Pointer to structure to be written
0302  *  @len: Size of structure
0303  *
0304  *  This function will place a little endian structure in the buffer
0305  *  pointed to by le_struct.  The function will return success
0306  *  provided that pointers are valid and the len value matches the
0307  *  attribute length.
0308  **/
0309 s32 fm10k_tlv_attr_get_le_struct(u32 *attr, void *le_struct, u32 len)
0310 {
0311     __le32 *le32_ptr = (__le32 *)le_struct;
0312     u32 i;
0313 
0314     /* verify pointers are not NULL */
0315     if (!le_struct || !attr)
0316         return FM10K_ERR_PARAM;
0317 
0318     if ((*attr >> FM10K_TLV_LEN_SHIFT) != len)
0319         return FM10K_ERR_PARAM;
0320 
0321     attr++;
0322 
0323     for (i = 0; len; i++, len -= 4)
0324         le32_ptr[i] = cpu_to_le32(attr[i]);
0325 
0326     return 0;
0327 }
0328 
0329 /**
0330  *  fm10k_tlv_attr_nest_start - Start a set of nested attributes
0331  *  @msg: Pointer to message block
0332  *  @attr_id: Attribute ID
0333  *
0334  *  This function will mark off a new nested region for encapsulating
0335  *  a given set of attributes.  The idea is if you wish to place a secondary
0336  *  structure within the message this mechanism allows for that.  The
0337  *  function will return NULL on failure, and a pointer to the start
0338  *  of the nested attributes on success.
0339  **/
0340 static u32 *fm10k_tlv_attr_nest_start(u32 *msg, u16 attr_id)
0341 {
0342     u32 *attr;
0343 
0344     /* verify pointer is not NULL */
0345     if (!msg)
0346         return NULL;
0347 
0348     attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
0349 
0350     attr[0] = attr_id;
0351 
0352     /* return pointer to nest header */
0353     return attr;
0354 }
0355 
0356 /**
0357  *  fm10k_tlv_attr_nest_stop - Stop a set of nested attributes
0358  *  @msg: Pointer to message block
0359  *
0360  *  This function closes off an existing set of nested attributes.  The
0361  *  message pointer should be pointing to the parent of the nest.  So in
0362  *  the case of a nest within the nest this would be the outer nest pointer.
0363  *  This function will return success provided all pointers are valid.
0364  **/
0365 static s32 fm10k_tlv_attr_nest_stop(u32 *msg)
0366 {
0367     u32 *attr;
0368     u32 len;
0369 
0370     /* verify pointer is not NULL */
0371     if (!msg)
0372         return FM10K_ERR_PARAM;
0373 
0374     /* locate the nested header and retrieve its length */
0375     attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
0376     len = (attr[0] >> FM10K_TLV_LEN_SHIFT) << FM10K_TLV_LEN_SHIFT;
0377 
0378     /* only include nest if data was added to it */
0379     if (len) {
0380         len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
0381         *msg += len;
0382     }
0383 
0384     return 0;
0385 }
0386 
0387 /**
0388  *  fm10k_tlv_attr_validate - Validate attribute metadata
0389  *  @attr: Pointer to attribute
0390  *  @tlv_attr: Type and length info for attribute
0391  *
0392  *  This function does some basic validation of the input TLV.  It
0393  *  verifies the length, and in the case of null terminated strings
0394  *  it verifies that the last byte is null.  The function will
0395  *  return FM10K_ERR_PARAM if any attribute is malformed, otherwise
0396  *  it returns 0.
0397  **/
0398 static s32 fm10k_tlv_attr_validate(u32 *attr,
0399                    const struct fm10k_tlv_attr *tlv_attr)
0400 {
0401     u32 attr_id = *attr & FM10K_TLV_ID_MASK;
0402     u16 len = *attr >> FM10K_TLV_LEN_SHIFT;
0403 
0404     /* verify this is an attribute and not a message */
0405     if (*attr & (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT))
0406         return FM10K_ERR_PARAM;
0407 
0408     /* search through the list of attributes to find a matching ID */
0409     while (tlv_attr->id < attr_id)
0410         tlv_attr++;
0411 
0412     /* if didn't find a match then we should exit */
0413     if (tlv_attr->id != attr_id)
0414         return FM10K_NOT_IMPLEMENTED;
0415 
0416     /* move to start of attribute data */
0417     attr++;
0418 
0419     switch (tlv_attr->type) {
0420     case FM10K_TLV_NULL_STRING:
0421         if (!len ||
0422             (attr[(len - 1) / 4] & (0xFF << (8 * ((len - 1) % 4)))))
0423             return FM10K_ERR_PARAM;
0424         if (len > tlv_attr->len)
0425             return FM10K_ERR_PARAM;
0426         break;
0427     case FM10K_TLV_MAC_ADDR:
0428         if (len != ETH_ALEN)
0429             return FM10K_ERR_PARAM;
0430         break;
0431     case FM10K_TLV_BOOL:
0432         if (len)
0433             return FM10K_ERR_PARAM;
0434         break;
0435     case FM10K_TLV_UNSIGNED:
0436     case FM10K_TLV_SIGNED:
0437         if (len != tlv_attr->len)
0438             return FM10K_ERR_PARAM;
0439         break;
0440     case FM10K_TLV_LE_STRUCT:
0441         /* struct must be 4 byte aligned */
0442         if ((len % 4) || len != tlv_attr->len)
0443             return FM10K_ERR_PARAM;
0444         break;
0445     case FM10K_TLV_NESTED:
0446         /* nested attributes must be 4 byte aligned */
0447         if (len % 4)
0448             return FM10K_ERR_PARAM;
0449         break;
0450     default:
0451         /* attribute id is mapped to bad value */
0452         return FM10K_ERR_PARAM;
0453     }
0454 
0455     return 0;
0456 }
0457 
0458 /**
0459  *  fm10k_tlv_attr_parse - Parses stream of attribute data
0460  *  @attr: Pointer to attribute list
0461  *  @results: Pointer array to store pointers to attributes
0462  *  @tlv_attr: Type and length info for attributes
0463  *
0464  *  This function validates a stream of attributes and parses them
0465  *  up into an array of pointers stored in results.  The function will
0466  *  return FM10K_ERR_PARAM on any input or message error,
0467  *  FM10K_NOT_IMPLEMENTED for any attribute that is outside of the array
0468  *  and 0 on success. Any attributes not found in tlv_attr will be silently
0469  *  ignored.
0470  **/
0471 static s32 fm10k_tlv_attr_parse(u32 *attr, u32 **results,
0472                 const struct fm10k_tlv_attr *tlv_attr)
0473 {
0474     u32 i, attr_id, offset = 0;
0475     s32 err;
0476     u16 len;
0477 
0478     /* verify pointers are not NULL */
0479     if (!attr || !results)
0480         return FM10K_ERR_PARAM;
0481 
0482     /* initialize results to NULL */
0483     for (i = 0; i < FM10K_TLV_RESULTS_MAX; i++)
0484         results[i] = NULL;
0485 
0486     /* pull length from the message header */
0487     len = *attr >> FM10K_TLV_LEN_SHIFT;
0488 
0489     /* no attributes to parse if there is no length */
0490     if (!len)
0491         return 0;
0492 
0493     /* no attributes to parse, just raw data, message becomes attribute */
0494     if (!tlv_attr) {
0495         results[0] = attr;
0496         return 0;
0497     }
0498 
0499     /* move to start of attribute data */
0500     attr++;
0501 
0502     /* run through list parsing all attributes */
0503     while (offset < len) {
0504         attr_id = *attr & FM10K_TLV_ID_MASK;
0505 
0506         if (attr_id >= FM10K_TLV_RESULTS_MAX)
0507             return FM10K_NOT_IMPLEMENTED;
0508 
0509         err = fm10k_tlv_attr_validate(attr, tlv_attr);
0510         if (err == FM10K_NOT_IMPLEMENTED)
0511             ; /* silently ignore non-implemented attributes */
0512         else if (err)
0513             return err;
0514         else
0515             results[attr_id] = attr;
0516 
0517         /* update offset */
0518         offset += FM10K_TLV_DWORD_LEN(*attr) * 4;
0519 
0520         /* move to next attribute */
0521         attr = &attr[FM10K_TLV_DWORD_LEN(*attr)];
0522     }
0523 
0524     /* we should find ourselves at the end of the list */
0525     if (offset != len)
0526         return FM10K_ERR_PARAM;
0527 
0528     return 0;
0529 }
0530 
0531 /**
0532  *  fm10k_tlv_msg_parse - Parses message header and calls function handler
0533  *  @hw: Pointer to hardware structure
0534  *  @msg: Pointer to message
0535  *  @mbx: Pointer to mailbox information structure
0536  *  @data: Pointer to message handler data structure
0537  *
0538  *  This function should be the first function called upon receiving a
0539  *  message.  The handler will identify the message type and call the correct
0540  *  handler for the given message.  It will return the value from the function
0541  *  call on a recognized message type, otherwise it will return
0542  *  FM10K_NOT_IMPLEMENTED on an unrecognized type.
0543  **/
0544 s32 fm10k_tlv_msg_parse(struct fm10k_hw *hw, u32 *msg,
0545             struct fm10k_mbx_info *mbx,
0546             const struct fm10k_msg_data *data)
0547 {
0548     u32 *results[FM10K_TLV_RESULTS_MAX];
0549     u32 msg_id;
0550     s32 err;
0551 
0552     /* verify pointer is not NULL */
0553     if (!msg || !data)
0554         return FM10K_ERR_PARAM;
0555 
0556     /* verify this is a message and not an attribute */
0557     if (!(*msg & (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT)))
0558         return FM10K_ERR_PARAM;
0559 
0560     /* grab message ID */
0561     msg_id = *msg & FM10K_TLV_ID_MASK;
0562 
0563     while (data->id < msg_id)
0564         data++;
0565 
0566     /* if we didn't find it then pass it up as an error */
0567     if (data->id != msg_id) {
0568         while (data->id != FM10K_TLV_ERROR)
0569             data++;
0570     }
0571 
0572     /* parse the attributes into the results list */
0573     err = fm10k_tlv_attr_parse(msg, results, data->attr);
0574     if (err < 0)
0575         return err;
0576 
0577     return data->func(hw, results, mbx);
0578 }
0579 
0580 /**
0581  *  fm10k_tlv_msg_error - Default handler for unrecognized TLV message IDs
0582  *  @hw: Pointer to hardware structure
0583  *  @results: Pointer array to message, results[0] is pointer to message
0584  *  @mbx: Unused mailbox pointer
0585  *
0586  *  This function is a default handler for unrecognized messages.  At a
0587  *  minimum it just indicates that the message requested was
0588  *  unimplemented.
0589  **/
0590 s32 fm10k_tlv_msg_error(struct fm10k_hw __always_unused *hw,
0591             u32 __always_unused **results,
0592             struct fm10k_mbx_info __always_unused *mbx)
0593 {
0594     return FM10K_NOT_IMPLEMENTED;
0595 }
0596 
0597 static const unsigned char test_str[] = "fm10k";
0598 static const unsigned char test_mac[ETH_ALEN] = { 0x12, 0x34, 0x56,
0599                           0x78, 0x9a, 0xbc };
0600 static const u16 test_vlan = 0x0FED;
0601 static const u64 test_u64 = 0xfedcba9876543210ull;
0602 static const u32 test_u32 = 0x87654321;
0603 static const u16 test_u16 = 0x8765;
0604 static const u8  test_u8  = 0x87;
0605 static const s64 test_s64 = -0x123456789abcdef0ll;
0606 static const s32 test_s32 = -0x1235678;
0607 static const s16 test_s16 = -0x1234;
0608 static const s8  test_s8  = -0x12;
0609 static const __le32 test_le[2] = { cpu_to_le32(0x12345678),
0610                    cpu_to_le32(0x9abcdef0)};
0611 
0612 /* The message below is meant to be used as a test message to demonstrate
0613  * how to use the TLV interface and to test the types.  Normally this code
0614  * be compiled out by stripping the code wrapped in FM10K_TLV_TEST_MSG
0615  */
0616 const struct fm10k_tlv_attr fm10k_tlv_msg_test_attr[] = {
0617     FM10K_TLV_ATTR_NULL_STRING(FM10K_TEST_MSG_STRING, 80),
0618     FM10K_TLV_ATTR_MAC_ADDR(FM10K_TEST_MSG_MAC_ADDR),
0619     FM10K_TLV_ATTR_U8(FM10K_TEST_MSG_U8),
0620     FM10K_TLV_ATTR_U16(FM10K_TEST_MSG_U16),
0621     FM10K_TLV_ATTR_U32(FM10K_TEST_MSG_U32),
0622     FM10K_TLV_ATTR_U64(FM10K_TEST_MSG_U64),
0623     FM10K_TLV_ATTR_S8(FM10K_TEST_MSG_S8),
0624     FM10K_TLV_ATTR_S16(FM10K_TEST_MSG_S16),
0625     FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_S32),
0626     FM10K_TLV_ATTR_S64(FM10K_TEST_MSG_S64),
0627     FM10K_TLV_ATTR_LE_STRUCT(FM10K_TEST_MSG_LE_STRUCT, 8),
0628     FM10K_TLV_ATTR_NESTED(FM10K_TEST_MSG_NESTED),
0629     FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_RESULT),
0630     FM10K_TLV_ATTR_LAST
0631 };
0632 
0633 /**
0634  *  fm10k_tlv_msg_test_generate_data - Stuff message with data
0635  *  @msg: Pointer to message
0636  *  @attr_flags: List of flags indicating what attributes to add
0637  *
0638  *  This function is meant to load a message buffer with attribute data
0639  **/
0640 static void fm10k_tlv_msg_test_generate_data(u32 *msg, u32 attr_flags)
0641 {
0642     if (attr_flags & BIT(FM10K_TEST_MSG_STRING))
0643         fm10k_tlv_attr_put_null_string(msg, FM10K_TEST_MSG_STRING,
0644                            test_str);
0645     if (attr_flags & BIT(FM10K_TEST_MSG_MAC_ADDR))
0646         fm10k_tlv_attr_put_mac_vlan(msg, FM10K_TEST_MSG_MAC_ADDR,
0647                         test_mac, test_vlan);
0648     if (attr_flags & BIT(FM10K_TEST_MSG_U8))
0649         fm10k_tlv_attr_put_u8(msg, FM10K_TEST_MSG_U8,  test_u8);
0650     if (attr_flags & BIT(FM10K_TEST_MSG_U16))
0651         fm10k_tlv_attr_put_u16(msg, FM10K_TEST_MSG_U16, test_u16);
0652     if (attr_flags & BIT(FM10K_TEST_MSG_U32))
0653         fm10k_tlv_attr_put_u32(msg, FM10K_TEST_MSG_U32, test_u32);
0654     if (attr_flags & BIT(FM10K_TEST_MSG_U64))
0655         fm10k_tlv_attr_put_u64(msg, FM10K_TEST_MSG_U64, test_u64);
0656     if (attr_flags & BIT(FM10K_TEST_MSG_S8))
0657         fm10k_tlv_attr_put_s8(msg, FM10K_TEST_MSG_S8,  test_s8);
0658     if (attr_flags & BIT(FM10K_TEST_MSG_S16))
0659         fm10k_tlv_attr_put_s16(msg, FM10K_TEST_MSG_S16, test_s16);
0660     if (attr_flags & BIT(FM10K_TEST_MSG_S32))
0661         fm10k_tlv_attr_put_s32(msg, FM10K_TEST_MSG_S32, test_s32);
0662     if (attr_flags & BIT(FM10K_TEST_MSG_S64))
0663         fm10k_tlv_attr_put_s64(msg, FM10K_TEST_MSG_S64, test_s64);
0664     if (attr_flags & BIT(FM10K_TEST_MSG_LE_STRUCT))
0665         fm10k_tlv_attr_put_le_struct(msg, FM10K_TEST_MSG_LE_STRUCT,
0666                          test_le, 8);
0667 }
0668 
0669 /**
0670  *  fm10k_tlv_msg_test_create - Create a test message testing all attributes
0671  *  @msg: Pointer to message
0672  *  @attr_flags: List of flags indicating what attributes to add
0673  *
0674  *  This function is meant to load a message buffer with all attribute types
0675  *  including a nested attribute.
0676  **/
0677 void fm10k_tlv_msg_test_create(u32 *msg, u32 attr_flags)
0678 {
0679     u32 *nest = NULL;
0680 
0681     fm10k_tlv_msg_init(msg, FM10K_TLV_MSG_ID_TEST);
0682 
0683     fm10k_tlv_msg_test_generate_data(msg, attr_flags);
0684 
0685     /* check for nested attributes */
0686     attr_flags >>= FM10K_TEST_MSG_NESTED;
0687 
0688     if (attr_flags) {
0689         nest = fm10k_tlv_attr_nest_start(msg, FM10K_TEST_MSG_NESTED);
0690 
0691         fm10k_tlv_msg_test_generate_data(nest, attr_flags);
0692 
0693         fm10k_tlv_attr_nest_stop(msg);
0694     }
0695 }
0696 
0697 /**
0698  *  fm10k_tlv_msg_test - Validate all results on test message receive
0699  *  @hw: Pointer to hardware structure
0700  *  @results: Pointer array to attributes in the message
0701  *  @mbx: Pointer to mailbox information structure
0702  *
0703  *  This function does a check to verify all attributes match what the test
0704  *  message placed in the message buffer.  It is the default handler
0705  *  for TLV test messages.
0706  **/
0707 s32 fm10k_tlv_msg_test(struct fm10k_hw *hw, u32 **results,
0708                struct fm10k_mbx_info *mbx)
0709 {
0710     u32 *nest_results[FM10K_TLV_RESULTS_MAX];
0711     unsigned char result_str[80];
0712     unsigned char result_mac[ETH_ALEN];
0713     s32 err = 0;
0714     __le32 result_le[2];
0715     u16 result_vlan;
0716     u64 result_u64;
0717     u32 result_u32;
0718     u16 result_u16;
0719     u8  result_u8;
0720     s64 result_s64;
0721     s32 result_s32;
0722     s16 result_s16;
0723     s8  result_s8;
0724     u32 reply[3];
0725 
0726     /* retrieve results of a previous test */
0727     if (!!results[FM10K_TEST_MSG_RESULT])
0728         return fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_RESULT],
0729                           &mbx->test_result);
0730 
0731 parse_nested:
0732     if (!!results[FM10K_TEST_MSG_STRING]) {
0733         err = fm10k_tlv_attr_get_null_string(
0734                     results[FM10K_TEST_MSG_STRING],
0735                     result_str);
0736         if (!err && memcmp(test_str, result_str, sizeof(test_str)))
0737             err = FM10K_ERR_INVALID_VALUE;
0738         if (err)
0739             goto report_result;
0740     }
0741     if (!!results[FM10K_TEST_MSG_MAC_ADDR]) {
0742         err = fm10k_tlv_attr_get_mac_vlan(
0743                     results[FM10K_TEST_MSG_MAC_ADDR],
0744                     result_mac, &result_vlan);
0745         if (!err && !ether_addr_equal(test_mac, result_mac))
0746             err = FM10K_ERR_INVALID_VALUE;
0747         if (!err && test_vlan != result_vlan)
0748             err = FM10K_ERR_INVALID_VALUE;
0749         if (err)
0750             goto report_result;
0751     }
0752     if (!!results[FM10K_TEST_MSG_U8]) {
0753         err = fm10k_tlv_attr_get_u8(results[FM10K_TEST_MSG_U8],
0754                         &result_u8);
0755         if (!err && test_u8 != result_u8)
0756             err = FM10K_ERR_INVALID_VALUE;
0757         if (err)
0758             goto report_result;
0759     }
0760     if (!!results[FM10K_TEST_MSG_U16]) {
0761         err = fm10k_tlv_attr_get_u16(results[FM10K_TEST_MSG_U16],
0762                          &result_u16);
0763         if (!err && test_u16 != result_u16)
0764             err = FM10K_ERR_INVALID_VALUE;
0765         if (err)
0766             goto report_result;
0767     }
0768     if (!!results[FM10K_TEST_MSG_U32]) {
0769         err = fm10k_tlv_attr_get_u32(results[FM10K_TEST_MSG_U32],
0770                          &result_u32);
0771         if (!err && test_u32 != result_u32)
0772             err = FM10K_ERR_INVALID_VALUE;
0773         if (err)
0774             goto report_result;
0775     }
0776     if (!!results[FM10K_TEST_MSG_U64]) {
0777         err = fm10k_tlv_attr_get_u64(results[FM10K_TEST_MSG_U64],
0778                          &result_u64);
0779         if (!err && test_u64 != result_u64)
0780             err = FM10K_ERR_INVALID_VALUE;
0781         if (err)
0782             goto report_result;
0783     }
0784     if (!!results[FM10K_TEST_MSG_S8]) {
0785         err = fm10k_tlv_attr_get_s8(results[FM10K_TEST_MSG_S8],
0786                         &result_s8);
0787         if (!err && test_s8 != result_s8)
0788             err = FM10K_ERR_INVALID_VALUE;
0789         if (err)
0790             goto report_result;
0791     }
0792     if (!!results[FM10K_TEST_MSG_S16]) {
0793         err = fm10k_tlv_attr_get_s16(results[FM10K_TEST_MSG_S16],
0794                          &result_s16);
0795         if (!err && test_s16 != result_s16)
0796             err = FM10K_ERR_INVALID_VALUE;
0797         if (err)
0798             goto report_result;
0799     }
0800     if (!!results[FM10K_TEST_MSG_S32]) {
0801         err = fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_S32],
0802                          &result_s32);
0803         if (!err && test_s32 != result_s32)
0804             err = FM10K_ERR_INVALID_VALUE;
0805         if (err)
0806             goto report_result;
0807     }
0808     if (!!results[FM10K_TEST_MSG_S64]) {
0809         err = fm10k_tlv_attr_get_s64(results[FM10K_TEST_MSG_S64],
0810                          &result_s64);
0811         if (!err && test_s64 != result_s64)
0812             err = FM10K_ERR_INVALID_VALUE;
0813         if (err)
0814             goto report_result;
0815     }
0816     if (!!results[FM10K_TEST_MSG_LE_STRUCT]) {
0817         err = fm10k_tlv_attr_get_le_struct(
0818                     results[FM10K_TEST_MSG_LE_STRUCT],
0819                     result_le,
0820                     sizeof(result_le));
0821         if (!err && memcmp(test_le, result_le, sizeof(test_le)))
0822             err = FM10K_ERR_INVALID_VALUE;
0823         if (err)
0824             goto report_result;
0825     }
0826 
0827     if (!!results[FM10K_TEST_MSG_NESTED]) {
0828         /* clear any pointers */
0829         memset(nest_results, 0, sizeof(nest_results));
0830 
0831         /* parse the nested attributes into the nest results list */
0832         err = fm10k_tlv_attr_parse(results[FM10K_TEST_MSG_NESTED],
0833                        nest_results,
0834                        fm10k_tlv_msg_test_attr);
0835         if (err)
0836             goto report_result;
0837 
0838         /* loop back through to the start */
0839         results = nest_results;
0840         goto parse_nested;
0841     }
0842 
0843 report_result:
0844     /* generate reply with test result */
0845     fm10k_tlv_msg_init(reply, FM10K_TLV_MSG_ID_TEST);
0846     fm10k_tlv_attr_put_s32(reply, FM10K_TEST_MSG_RESULT, err);
0847 
0848     /* load onto outgoing mailbox */
0849     return mbx->ops.enqueue_tx(hw, mbx, reply);
0850 }