162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright(c) 2013 - 2019 Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include "fm10k_tlv.h" 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci/** 762306a36Sopenharmony_ci * fm10k_tlv_msg_init - Initialize message block for TLV data storage 862306a36Sopenharmony_ci * @msg: Pointer to message block 962306a36Sopenharmony_ci * @msg_id: Message ID indicating message type 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * This function return success if provided with a valid message pointer 1262306a36Sopenharmony_ci **/ 1362306a36Sopenharmony_cis32 fm10k_tlv_msg_init(u32 *msg, u16 msg_id) 1462306a36Sopenharmony_ci{ 1562306a36Sopenharmony_ci /* verify pointer is not NULL */ 1662306a36Sopenharmony_ci if (!msg) 1762306a36Sopenharmony_ci return FM10K_ERR_PARAM; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci *msg = (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT) | msg_id; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci return 0; 2262306a36Sopenharmony_ci} 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/** 2562306a36Sopenharmony_ci * fm10k_tlv_attr_put_null_string - Place null terminated string on message 2662306a36Sopenharmony_ci * @msg: Pointer to message block 2762306a36Sopenharmony_ci * @attr_id: Attribute ID 2862306a36Sopenharmony_ci * @string: Pointer to string to be stored in attribute 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * This function will reorder a string to be CPU endian and store it in 3162306a36Sopenharmony_ci * the attribute buffer. It will return success if provided with a valid 3262306a36Sopenharmony_ci * pointers. 3362306a36Sopenharmony_ci **/ 3462306a36Sopenharmony_cistatic s32 fm10k_tlv_attr_put_null_string(u32 *msg, u16 attr_id, 3562306a36Sopenharmony_ci const unsigned char *string) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci u32 attr_data = 0, len = 0; 3862306a36Sopenharmony_ci u32 *attr; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci /* verify pointers are not NULL */ 4162306a36Sopenharmony_ci if (!string || !msg) 4262306a36Sopenharmony_ci return FM10K_ERR_PARAM; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci attr = &msg[FM10K_TLV_DWORD_LEN(*msg)]; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci /* copy string into local variable and then write to msg */ 4762306a36Sopenharmony_ci do { 4862306a36Sopenharmony_ci /* write data to message */ 4962306a36Sopenharmony_ci if (len && !(len % 4)) { 5062306a36Sopenharmony_ci attr[len / 4] = attr_data; 5162306a36Sopenharmony_ci attr_data = 0; 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci /* record character to offset location */ 5562306a36Sopenharmony_ci attr_data |= (u32)(*string) << (8 * (len % 4)); 5662306a36Sopenharmony_ci len++; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci /* test for NULL and then increment */ 5962306a36Sopenharmony_ci } while (*(string++)); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci /* write last piece of data to message */ 6262306a36Sopenharmony_ci attr[(len + 3) / 4] = attr_data; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci /* record attribute header, update message length */ 6562306a36Sopenharmony_ci len <<= FM10K_TLV_LEN_SHIFT; 6662306a36Sopenharmony_ci attr[0] = len | attr_id; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci /* add header length to length */ 6962306a36Sopenharmony_ci len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT; 7062306a36Sopenharmony_ci *msg += FM10K_TLV_LEN_ALIGN(len); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci return 0; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/** 7662306a36Sopenharmony_ci * fm10k_tlv_attr_get_null_string - Get null terminated string from attribute 7762306a36Sopenharmony_ci * @attr: Pointer to attribute 7862306a36Sopenharmony_ci * @string: Pointer to location of destination string 7962306a36Sopenharmony_ci * 8062306a36Sopenharmony_ci * This function pulls the string back out of the attribute and will place 8162306a36Sopenharmony_ci * it in the array pointed by string. It will return success if provided 8262306a36Sopenharmony_ci * with a valid pointers. 8362306a36Sopenharmony_ci **/ 8462306a36Sopenharmony_cistatic s32 fm10k_tlv_attr_get_null_string(u32 *attr, unsigned char *string) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci u32 len; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* verify pointers are not NULL */ 8962306a36Sopenharmony_ci if (!string || !attr) 9062306a36Sopenharmony_ci return FM10K_ERR_PARAM; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci len = *attr >> FM10K_TLV_LEN_SHIFT; 9362306a36Sopenharmony_ci attr++; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci while (len--) 9662306a36Sopenharmony_ci string[len] = (u8)(attr[len / 4] >> (8 * (len % 4))); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci return 0; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci/** 10262306a36Sopenharmony_ci * fm10k_tlv_attr_put_mac_vlan - Store MAC/VLAN attribute in message 10362306a36Sopenharmony_ci * @msg: Pointer to message block 10462306a36Sopenharmony_ci * @attr_id: Attribute ID 10562306a36Sopenharmony_ci * @mac_addr: MAC address to be stored 10662306a36Sopenharmony_ci * @vlan: VLAN to be stored 10762306a36Sopenharmony_ci * 10862306a36Sopenharmony_ci * This function will reorder a MAC address to be CPU endian and store it 10962306a36Sopenharmony_ci * in the attribute buffer. It will return success if provided with a 11062306a36Sopenharmony_ci * valid pointers. 11162306a36Sopenharmony_ci **/ 11262306a36Sopenharmony_cis32 fm10k_tlv_attr_put_mac_vlan(u32 *msg, u16 attr_id, 11362306a36Sopenharmony_ci const u8 *mac_addr, u16 vlan) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci u32 len = ETH_ALEN << FM10K_TLV_LEN_SHIFT; 11662306a36Sopenharmony_ci u32 *attr; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci /* verify pointers are not NULL */ 11962306a36Sopenharmony_ci if (!msg || !mac_addr) 12062306a36Sopenharmony_ci return FM10K_ERR_PARAM; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci attr = &msg[FM10K_TLV_DWORD_LEN(*msg)]; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* record attribute header, update message length */ 12562306a36Sopenharmony_ci attr[0] = len | attr_id; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* copy value into local variable and then write to msg */ 12862306a36Sopenharmony_ci attr[1] = le32_to_cpu(*(const __le32 *)&mac_addr[0]); 12962306a36Sopenharmony_ci attr[2] = le16_to_cpu(*(const __le16 *)&mac_addr[4]); 13062306a36Sopenharmony_ci attr[2] |= (u32)vlan << 16; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* add header length to length */ 13362306a36Sopenharmony_ci len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT; 13462306a36Sopenharmony_ci *msg += FM10K_TLV_LEN_ALIGN(len); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci return 0; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/** 14062306a36Sopenharmony_ci * fm10k_tlv_attr_get_mac_vlan - Get MAC/VLAN stored in attribute 14162306a36Sopenharmony_ci * @attr: Pointer to attribute 14262306a36Sopenharmony_ci * @mac_addr: location of buffer to store MAC address 14362306a36Sopenharmony_ci * @vlan: location of buffer to store VLAN 14462306a36Sopenharmony_ci * 14562306a36Sopenharmony_ci * This function pulls the MAC address back out of the attribute and will 14662306a36Sopenharmony_ci * place it in the array pointed by mac_addr. It will return success 14762306a36Sopenharmony_ci * if provided with a valid pointers. 14862306a36Sopenharmony_ci **/ 14962306a36Sopenharmony_cis32 fm10k_tlv_attr_get_mac_vlan(u32 *attr, u8 *mac_addr, u16 *vlan) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci /* verify pointers are not NULL */ 15262306a36Sopenharmony_ci if (!mac_addr || !attr) 15362306a36Sopenharmony_ci return FM10K_ERR_PARAM; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci *(__le32 *)&mac_addr[0] = cpu_to_le32(attr[1]); 15662306a36Sopenharmony_ci *(__le16 *)&mac_addr[4] = cpu_to_le16((u16)(attr[2])); 15762306a36Sopenharmony_ci *vlan = (u16)(attr[2] >> 16); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci return 0; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci/** 16362306a36Sopenharmony_ci * fm10k_tlv_attr_put_bool - Add header indicating value "true" 16462306a36Sopenharmony_ci * @msg: Pointer to message block 16562306a36Sopenharmony_ci * @attr_id: Attribute ID 16662306a36Sopenharmony_ci * 16762306a36Sopenharmony_ci * This function will simply add an attribute header, the fact 16862306a36Sopenharmony_ci * that the header is here means the attribute value is true, else 16962306a36Sopenharmony_ci * it is false. The function will return success if provided with a 17062306a36Sopenharmony_ci * valid pointers. 17162306a36Sopenharmony_ci **/ 17262306a36Sopenharmony_cis32 fm10k_tlv_attr_put_bool(u32 *msg, u16 attr_id) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci /* verify pointers are not NULL */ 17562306a36Sopenharmony_ci if (!msg) 17662306a36Sopenharmony_ci return FM10K_ERR_PARAM; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* record attribute header */ 17962306a36Sopenharmony_ci msg[FM10K_TLV_DWORD_LEN(*msg)] = attr_id; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci /* add header length to length */ 18262306a36Sopenharmony_ci *msg += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci return 0; 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci/** 18862306a36Sopenharmony_ci * fm10k_tlv_attr_put_value - Store integer value attribute in message 18962306a36Sopenharmony_ci * @msg: Pointer to message block 19062306a36Sopenharmony_ci * @attr_id: Attribute ID 19162306a36Sopenharmony_ci * @value: Value to be written 19262306a36Sopenharmony_ci * @len: Size of value 19362306a36Sopenharmony_ci * 19462306a36Sopenharmony_ci * This function will place an integer value of up to 8 bytes in size 19562306a36Sopenharmony_ci * in a message attribute. The function will return success provided 19662306a36Sopenharmony_ci * that msg is a valid pointer, and len is 1, 2, 4, or 8. 19762306a36Sopenharmony_ci **/ 19862306a36Sopenharmony_cis32 fm10k_tlv_attr_put_value(u32 *msg, u16 attr_id, s64 value, u32 len) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci u32 *attr; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* verify non-null msg and len is 1, 2, 4, or 8 */ 20362306a36Sopenharmony_ci if (!msg || !len || len > 8 || (len & (len - 1))) 20462306a36Sopenharmony_ci return FM10K_ERR_PARAM; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci attr = &msg[FM10K_TLV_DWORD_LEN(*msg)]; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (len < 4) { 20962306a36Sopenharmony_ci attr[1] = (u32)value & (BIT(8 * len) - 1); 21062306a36Sopenharmony_ci } else { 21162306a36Sopenharmony_ci attr[1] = (u32)value; 21262306a36Sopenharmony_ci if (len > 4) 21362306a36Sopenharmony_ci attr[2] = (u32)(value >> 32); 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* record attribute header, update message length */ 21762306a36Sopenharmony_ci len <<= FM10K_TLV_LEN_SHIFT; 21862306a36Sopenharmony_ci attr[0] = len | attr_id; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci /* add header length to length */ 22162306a36Sopenharmony_ci len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT; 22262306a36Sopenharmony_ci *msg += FM10K_TLV_LEN_ALIGN(len); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci return 0; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci/** 22862306a36Sopenharmony_ci * fm10k_tlv_attr_get_value - Get integer value stored in attribute 22962306a36Sopenharmony_ci * @attr: Pointer to attribute 23062306a36Sopenharmony_ci * @value: Pointer to destination buffer 23162306a36Sopenharmony_ci * @len: Size of value 23262306a36Sopenharmony_ci * 23362306a36Sopenharmony_ci * This function will place an integer value of up to 8 bytes in size 23462306a36Sopenharmony_ci * in the offset pointed to by value. The function will return success 23562306a36Sopenharmony_ci * provided that pointers are valid and the len value matches the 23662306a36Sopenharmony_ci * attribute length. 23762306a36Sopenharmony_ci **/ 23862306a36Sopenharmony_cis32 fm10k_tlv_attr_get_value(u32 *attr, void *value, u32 len) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci /* verify pointers are not NULL */ 24162306a36Sopenharmony_ci if (!attr || !value) 24262306a36Sopenharmony_ci return FM10K_ERR_PARAM; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci if ((*attr >> FM10K_TLV_LEN_SHIFT) != len) 24562306a36Sopenharmony_ci return FM10K_ERR_PARAM; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (len == 8) 24862306a36Sopenharmony_ci *(u64 *)value = ((u64)attr[2] << 32) | attr[1]; 24962306a36Sopenharmony_ci else if (len == 4) 25062306a36Sopenharmony_ci *(u32 *)value = attr[1]; 25162306a36Sopenharmony_ci else if (len == 2) 25262306a36Sopenharmony_ci *(u16 *)value = (u16)attr[1]; 25362306a36Sopenharmony_ci else 25462306a36Sopenharmony_ci *(u8 *)value = (u8)attr[1]; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci return 0; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci/** 26062306a36Sopenharmony_ci * fm10k_tlv_attr_put_le_struct - Store little endian structure in message 26162306a36Sopenharmony_ci * @msg: Pointer to message block 26262306a36Sopenharmony_ci * @attr_id: Attribute ID 26362306a36Sopenharmony_ci * @le_struct: Pointer to structure to be written 26462306a36Sopenharmony_ci * @len: Size of le_struct 26562306a36Sopenharmony_ci * 26662306a36Sopenharmony_ci * This function will place a little endian structure value in a message 26762306a36Sopenharmony_ci * attribute. The function will return success provided that all pointers 26862306a36Sopenharmony_ci * are valid and length is a non-zero multiple of 4. 26962306a36Sopenharmony_ci **/ 27062306a36Sopenharmony_cis32 fm10k_tlv_attr_put_le_struct(u32 *msg, u16 attr_id, 27162306a36Sopenharmony_ci const void *le_struct, u32 len) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci const __le32 *le32_ptr = (const __le32 *)le_struct; 27462306a36Sopenharmony_ci u32 *attr; 27562306a36Sopenharmony_ci u32 i; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci /* verify non-null msg and len is in 32 bit words */ 27862306a36Sopenharmony_ci if (!msg || !len || (len % 4)) 27962306a36Sopenharmony_ci return FM10K_ERR_PARAM; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci attr = &msg[FM10K_TLV_DWORD_LEN(*msg)]; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci /* copy le32 structure into host byte order at 32b boundaries */ 28462306a36Sopenharmony_ci for (i = 0; i < (len / 4); i++) 28562306a36Sopenharmony_ci attr[i + 1] = le32_to_cpu(le32_ptr[i]); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci /* record attribute header, update message length */ 28862306a36Sopenharmony_ci len <<= FM10K_TLV_LEN_SHIFT; 28962306a36Sopenharmony_ci attr[0] = len | attr_id; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci /* add header length to length */ 29262306a36Sopenharmony_ci len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT; 29362306a36Sopenharmony_ci *msg += FM10K_TLV_LEN_ALIGN(len); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci return 0; 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci/** 29962306a36Sopenharmony_ci * fm10k_tlv_attr_get_le_struct - Get little endian struct form attribute 30062306a36Sopenharmony_ci * @attr: Pointer to attribute 30162306a36Sopenharmony_ci * @le_struct: Pointer to structure to be written 30262306a36Sopenharmony_ci * @len: Size of structure 30362306a36Sopenharmony_ci * 30462306a36Sopenharmony_ci * This function will place a little endian structure in the buffer 30562306a36Sopenharmony_ci * pointed to by le_struct. The function will return success 30662306a36Sopenharmony_ci * provided that pointers are valid and the len value matches the 30762306a36Sopenharmony_ci * attribute length. 30862306a36Sopenharmony_ci **/ 30962306a36Sopenharmony_cis32 fm10k_tlv_attr_get_le_struct(u32 *attr, void *le_struct, u32 len) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci __le32 *le32_ptr = (__le32 *)le_struct; 31262306a36Sopenharmony_ci u32 i; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci /* verify pointers are not NULL */ 31562306a36Sopenharmony_ci if (!le_struct || !attr) 31662306a36Sopenharmony_ci return FM10K_ERR_PARAM; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if ((*attr >> FM10K_TLV_LEN_SHIFT) != len) 31962306a36Sopenharmony_ci return FM10K_ERR_PARAM; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci attr++; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci for (i = 0; len; i++, len -= 4) 32462306a36Sopenharmony_ci le32_ptr[i] = cpu_to_le32(attr[i]); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci return 0; 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci/** 33062306a36Sopenharmony_ci * fm10k_tlv_attr_nest_start - Start a set of nested attributes 33162306a36Sopenharmony_ci * @msg: Pointer to message block 33262306a36Sopenharmony_ci * @attr_id: Attribute ID 33362306a36Sopenharmony_ci * 33462306a36Sopenharmony_ci * This function will mark off a new nested region for encapsulating 33562306a36Sopenharmony_ci * a given set of attributes. The idea is if you wish to place a secondary 33662306a36Sopenharmony_ci * structure within the message this mechanism allows for that. The 33762306a36Sopenharmony_ci * function will return NULL on failure, and a pointer to the start 33862306a36Sopenharmony_ci * of the nested attributes on success. 33962306a36Sopenharmony_ci **/ 34062306a36Sopenharmony_cistatic u32 *fm10k_tlv_attr_nest_start(u32 *msg, u16 attr_id) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci u32 *attr; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* verify pointer is not NULL */ 34562306a36Sopenharmony_ci if (!msg) 34662306a36Sopenharmony_ci return NULL; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci attr = &msg[FM10K_TLV_DWORD_LEN(*msg)]; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci attr[0] = attr_id; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* return pointer to nest header */ 35362306a36Sopenharmony_ci return attr; 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci/** 35762306a36Sopenharmony_ci * fm10k_tlv_attr_nest_stop - Stop a set of nested attributes 35862306a36Sopenharmony_ci * @msg: Pointer to message block 35962306a36Sopenharmony_ci * 36062306a36Sopenharmony_ci * This function closes off an existing set of nested attributes. The 36162306a36Sopenharmony_ci * message pointer should be pointing to the parent of the nest. So in 36262306a36Sopenharmony_ci * the case of a nest within the nest this would be the outer nest pointer. 36362306a36Sopenharmony_ci * This function will return success provided all pointers are valid. 36462306a36Sopenharmony_ci **/ 36562306a36Sopenharmony_cistatic s32 fm10k_tlv_attr_nest_stop(u32 *msg) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci u32 *attr; 36862306a36Sopenharmony_ci u32 len; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci /* verify pointer is not NULL */ 37162306a36Sopenharmony_ci if (!msg) 37262306a36Sopenharmony_ci return FM10K_ERR_PARAM; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci /* locate the nested header and retrieve its length */ 37562306a36Sopenharmony_ci attr = &msg[FM10K_TLV_DWORD_LEN(*msg)]; 37662306a36Sopenharmony_ci len = (attr[0] >> FM10K_TLV_LEN_SHIFT) << FM10K_TLV_LEN_SHIFT; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* only include nest if data was added to it */ 37962306a36Sopenharmony_ci if (len) { 38062306a36Sopenharmony_ci len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT; 38162306a36Sopenharmony_ci *msg += len; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci return 0; 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci/** 38862306a36Sopenharmony_ci * fm10k_tlv_attr_validate - Validate attribute metadata 38962306a36Sopenharmony_ci * @attr: Pointer to attribute 39062306a36Sopenharmony_ci * @tlv_attr: Type and length info for attribute 39162306a36Sopenharmony_ci * 39262306a36Sopenharmony_ci * This function does some basic validation of the input TLV. It 39362306a36Sopenharmony_ci * verifies the length, and in the case of null terminated strings 39462306a36Sopenharmony_ci * it verifies that the last byte is null. The function will 39562306a36Sopenharmony_ci * return FM10K_ERR_PARAM if any attribute is malformed, otherwise 39662306a36Sopenharmony_ci * it returns 0. 39762306a36Sopenharmony_ci **/ 39862306a36Sopenharmony_cistatic s32 fm10k_tlv_attr_validate(u32 *attr, 39962306a36Sopenharmony_ci const struct fm10k_tlv_attr *tlv_attr) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci u32 attr_id = *attr & FM10K_TLV_ID_MASK; 40262306a36Sopenharmony_ci u16 len = *attr >> FM10K_TLV_LEN_SHIFT; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci /* verify this is an attribute and not a message */ 40562306a36Sopenharmony_ci if (*attr & (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT)) 40662306a36Sopenharmony_ci return FM10K_ERR_PARAM; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci /* search through the list of attributes to find a matching ID */ 40962306a36Sopenharmony_ci while (tlv_attr->id < attr_id) 41062306a36Sopenharmony_ci tlv_attr++; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci /* if didn't find a match then we should exit */ 41362306a36Sopenharmony_ci if (tlv_attr->id != attr_id) 41462306a36Sopenharmony_ci return FM10K_NOT_IMPLEMENTED; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci /* move to start of attribute data */ 41762306a36Sopenharmony_ci attr++; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci switch (tlv_attr->type) { 42062306a36Sopenharmony_ci case FM10K_TLV_NULL_STRING: 42162306a36Sopenharmony_ci if (!len || 42262306a36Sopenharmony_ci (attr[(len - 1) / 4] & (0xFF << (8 * ((len - 1) % 4))))) 42362306a36Sopenharmony_ci return FM10K_ERR_PARAM; 42462306a36Sopenharmony_ci if (len > tlv_attr->len) 42562306a36Sopenharmony_ci return FM10K_ERR_PARAM; 42662306a36Sopenharmony_ci break; 42762306a36Sopenharmony_ci case FM10K_TLV_MAC_ADDR: 42862306a36Sopenharmony_ci if (len != ETH_ALEN) 42962306a36Sopenharmony_ci return FM10K_ERR_PARAM; 43062306a36Sopenharmony_ci break; 43162306a36Sopenharmony_ci case FM10K_TLV_BOOL: 43262306a36Sopenharmony_ci if (len) 43362306a36Sopenharmony_ci return FM10K_ERR_PARAM; 43462306a36Sopenharmony_ci break; 43562306a36Sopenharmony_ci case FM10K_TLV_UNSIGNED: 43662306a36Sopenharmony_ci case FM10K_TLV_SIGNED: 43762306a36Sopenharmony_ci if (len != tlv_attr->len) 43862306a36Sopenharmony_ci return FM10K_ERR_PARAM; 43962306a36Sopenharmony_ci break; 44062306a36Sopenharmony_ci case FM10K_TLV_LE_STRUCT: 44162306a36Sopenharmony_ci /* struct must be 4 byte aligned */ 44262306a36Sopenharmony_ci if ((len % 4) || len != tlv_attr->len) 44362306a36Sopenharmony_ci return FM10K_ERR_PARAM; 44462306a36Sopenharmony_ci break; 44562306a36Sopenharmony_ci case FM10K_TLV_NESTED: 44662306a36Sopenharmony_ci /* nested attributes must be 4 byte aligned */ 44762306a36Sopenharmony_ci if (len % 4) 44862306a36Sopenharmony_ci return FM10K_ERR_PARAM; 44962306a36Sopenharmony_ci break; 45062306a36Sopenharmony_ci default: 45162306a36Sopenharmony_ci /* attribute id is mapped to bad value */ 45262306a36Sopenharmony_ci return FM10K_ERR_PARAM; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci return 0; 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci/** 45962306a36Sopenharmony_ci * fm10k_tlv_attr_parse - Parses stream of attribute data 46062306a36Sopenharmony_ci * @attr: Pointer to attribute list 46162306a36Sopenharmony_ci * @results: Pointer array to store pointers to attributes 46262306a36Sopenharmony_ci * @tlv_attr: Type and length info for attributes 46362306a36Sopenharmony_ci * 46462306a36Sopenharmony_ci * This function validates a stream of attributes and parses them 46562306a36Sopenharmony_ci * up into an array of pointers stored in results. The function will 46662306a36Sopenharmony_ci * return FM10K_ERR_PARAM on any input or message error, 46762306a36Sopenharmony_ci * FM10K_NOT_IMPLEMENTED for any attribute that is outside of the array 46862306a36Sopenharmony_ci * and 0 on success. Any attributes not found in tlv_attr will be silently 46962306a36Sopenharmony_ci * ignored. 47062306a36Sopenharmony_ci **/ 47162306a36Sopenharmony_cistatic s32 fm10k_tlv_attr_parse(u32 *attr, u32 **results, 47262306a36Sopenharmony_ci const struct fm10k_tlv_attr *tlv_attr) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci u32 i, attr_id, offset = 0; 47562306a36Sopenharmony_ci s32 err; 47662306a36Sopenharmony_ci u16 len; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci /* verify pointers are not NULL */ 47962306a36Sopenharmony_ci if (!attr || !results) 48062306a36Sopenharmony_ci return FM10K_ERR_PARAM; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* initialize results to NULL */ 48362306a36Sopenharmony_ci for (i = 0; i < FM10K_TLV_RESULTS_MAX; i++) 48462306a36Sopenharmony_ci results[i] = NULL; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci /* pull length from the message header */ 48762306a36Sopenharmony_ci len = *attr >> FM10K_TLV_LEN_SHIFT; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci /* no attributes to parse if there is no length */ 49062306a36Sopenharmony_ci if (!len) 49162306a36Sopenharmony_ci return 0; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci /* no attributes to parse, just raw data, message becomes attribute */ 49462306a36Sopenharmony_ci if (!tlv_attr) { 49562306a36Sopenharmony_ci results[0] = attr; 49662306a36Sopenharmony_ci return 0; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci /* move to start of attribute data */ 50062306a36Sopenharmony_ci attr++; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci /* run through list parsing all attributes */ 50362306a36Sopenharmony_ci while (offset < len) { 50462306a36Sopenharmony_ci attr_id = *attr & FM10K_TLV_ID_MASK; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci if (attr_id >= FM10K_TLV_RESULTS_MAX) 50762306a36Sopenharmony_ci return FM10K_NOT_IMPLEMENTED; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci err = fm10k_tlv_attr_validate(attr, tlv_attr); 51062306a36Sopenharmony_ci if (err == FM10K_NOT_IMPLEMENTED) 51162306a36Sopenharmony_ci ; /* silently ignore non-implemented attributes */ 51262306a36Sopenharmony_ci else if (err) 51362306a36Sopenharmony_ci return err; 51462306a36Sopenharmony_ci else 51562306a36Sopenharmony_ci results[attr_id] = attr; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci /* update offset */ 51862306a36Sopenharmony_ci offset += FM10K_TLV_DWORD_LEN(*attr) * 4; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* move to next attribute */ 52162306a36Sopenharmony_ci attr = &attr[FM10K_TLV_DWORD_LEN(*attr)]; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci /* we should find ourselves at the end of the list */ 52562306a36Sopenharmony_ci if (offset != len) 52662306a36Sopenharmony_ci return FM10K_ERR_PARAM; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci return 0; 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci/** 53262306a36Sopenharmony_ci * fm10k_tlv_msg_parse - Parses message header and calls function handler 53362306a36Sopenharmony_ci * @hw: Pointer to hardware structure 53462306a36Sopenharmony_ci * @msg: Pointer to message 53562306a36Sopenharmony_ci * @mbx: Pointer to mailbox information structure 53662306a36Sopenharmony_ci * @data: Pointer to message handler data structure 53762306a36Sopenharmony_ci * 53862306a36Sopenharmony_ci * This function should be the first function called upon receiving a 53962306a36Sopenharmony_ci * message. The handler will identify the message type and call the correct 54062306a36Sopenharmony_ci * handler for the given message. It will return the value from the function 54162306a36Sopenharmony_ci * call on a recognized message type, otherwise it will return 54262306a36Sopenharmony_ci * FM10K_NOT_IMPLEMENTED on an unrecognized type. 54362306a36Sopenharmony_ci **/ 54462306a36Sopenharmony_cis32 fm10k_tlv_msg_parse(struct fm10k_hw *hw, u32 *msg, 54562306a36Sopenharmony_ci struct fm10k_mbx_info *mbx, 54662306a36Sopenharmony_ci const struct fm10k_msg_data *data) 54762306a36Sopenharmony_ci{ 54862306a36Sopenharmony_ci u32 *results[FM10K_TLV_RESULTS_MAX]; 54962306a36Sopenharmony_ci u32 msg_id; 55062306a36Sopenharmony_ci s32 err; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci /* verify pointer is not NULL */ 55362306a36Sopenharmony_ci if (!msg || !data) 55462306a36Sopenharmony_ci return FM10K_ERR_PARAM; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci /* verify this is a message and not an attribute */ 55762306a36Sopenharmony_ci if (!(*msg & (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT))) 55862306a36Sopenharmony_ci return FM10K_ERR_PARAM; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci /* grab message ID */ 56162306a36Sopenharmony_ci msg_id = *msg & FM10K_TLV_ID_MASK; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci while (data->id < msg_id) 56462306a36Sopenharmony_ci data++; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci /* if we didn't find it then pass it up as an error */ 56762306a36Sopenharmony_ci if (data->id != msg_id) { 56862306a36Sopenharmony_ci while (data->id != FM10K_TLV_ERROR) 56962306a36Sopenharmony_ci data++; 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci /* parse the attributes into the results list */ 57362306a36Sopenharmony_ci err = fm10k_tlv_attr_parse(msg, results, data->attr); 57462306a36Sopenharmony_ci if (err < 0) 57562306a36Sopenharmony_ci return err; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci return data->func(hw, results, mbx); 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci/** 58162306a36Sopenharmony_ci * fm10k_tlv_msg_error - Default handler for unrecognized TLV message IDs 58262306a36Sopenharmony_ci * @hw: Pointer to hardware structure 58362306a36Sopenharmony_ci * @results: Pointer array to message, results[0] is pointer to message 58462306a36Sopenharmony_ci * @mbx: Unused mailbox pointer 58562306a36Sopenharmony_ci * 58662306a36Sopenharmony_ci * This function is a default handler for unrecognized messages. At a 58762306a36Sopenharmony_ci * minimum it just indicates that the message requested was 58862306a36Sopenharmony_ci * unimplemented. 58962306a36Sopenharmony_ci **/ 59062306a36Sopenharmony_cis32 fm10k_tlv_msg_error(struct fm10k_hw __always_unused *hw, 59162306a36Sopenharmony_ci u32 __always_unused **results, 59262306a36Sopenharmony_ci struct fm10k_mbx_info __always_unused *mbx) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci return FM10K_NOT_IMPLEMENTED; 59562306a36Sopenharmony_ci} 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_cistatic const unsigned char test_str[] = "fm10k"; 59862306a36Sopenharmony_cistatic const unsigned char test_mac[ETH_ALEN] = { 0x12, 0x34, 0x56, 59962306a36Sopenharmony_ci 0x78, 0x9a, 0xbc }; 60062306a36Sopenharmony_cistatic const u16 test_vlan = 0x0FED; 60162306a36Sopenharmony_cistatic const u64 test_u64 = 0xfedcba9876543210ull; 60262306a36Sopenharmony_cistatic const u32 test_u32 = 0x87654321; 60362306a36Sopenharmony_cistatic const u16 test_u16 = 0x8765; 60462306a36Sopenharmony_cistatic const u8 test_u8 = 0x87; 60562306a36Sopenharmony_cistatic const s64 test_s64 = -0x123456789abcdef0ll; 60662306a36Sopenharmony_cistatic const s32 test_s32 = -0x1235678; 60762306a36Sopenharmony_cistatic const s16 test_s16 = -0x1234; 60862306a36Sopenharmony_cistatic const s8 test_s8 = -0x12; 60962306a36Sopenharmony_cistatic const __le32 test_le[2] = { cpu_to_le32(0x12345678), 61062306a36Sopenharmony_ci cpu_to_le32(0x9abcdef0)}; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci/* The message below is meant to be used as a test message to demonstrate 61362306a36Sopenharmony_ci * how to use the TLV interface and to test the types. Normally this code 61462306a36Sopenharmony_ci * be compiled out by stripping the code wrapped in FM10K_TLV_TEST_MSG 61562306a36Sopenharmony_ci */ 61662306a36Sopenharmony_ciconst struct fm10k_tlv_attr fm10k_tlv_msg_test_attr[] = { 61762306a36Sopenharmony_ci FM10K_TLV_ATTR_NULL_STRING(FM10K_TEST_MSG_STRING, 80), 61862306a36Sopenharmony_ci FM10K_TLV_ATTR_MAC_ADDR(FM10K_TEST_MSG_MAC_ADDR), 61962306a36Sopenharmony_ci FM10K_TLV_ATTR_U8(FM10K_TEST_MSG_U8), 62062306a36Sopenharmony_ci FM10K_TLV_ATTR_U16(FM10K_TEST_MSG_U16), 62162306a36Sopenharmony_ci FM10K_TLV_ATTR_U32(FM10K_TEST_MSG_U32), 62262306a36Sopenharmony_ci FM10K_TLV_ATTR_U64(FM10K_TEST_MSG_U64), 62362306a36Sopenharmony_ci FM10K_TLV_ATTR_S8(FM10K_TEST_MSG_S8), 62462306a36Sopenharmony_ci FM10K_TLV_ATTR_S16(FM10K_TEST_MSG_S16), 62562306a36Sopenharmony_ci FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_S32), 62662306a36Sopenharmony_ci FM10K_TLV_ATTR_S64(FM10K_TEST_MSG_S64), 62762306a36Sopenharmony_ci FM10K_TLV_ATTR_LE_STRUCT(FM10K_TEST_MSG_LE_STRUCT, 8), 62862306a36Sopenharmony_ci FM10K_TLV_ATTR_NESTED(FM10K_TEST_MSG_NESTED), 62962306a36Sopenharmony_ci FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_RESULT), 63062306a36Sopenharmony_ci FM10K_TLV_ATTR_LAST 63162306a36Sopenharmony_ci}; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci/** 63462306a36Sopenharmony_ci * fm10k_tlv_msg_test_generate_data - Stuff message with data 63562306a36Sopenharmony_ci * @msg: Pointer to message 63662306a36Sopenharmony_ci * @attr_flags: List of flags indicating what attributes to add 63762306a36Sopenharmony_ci * 63862306a36Sopenharmony_ci * This function is meant to load a message buffer with attribute data 63962306a36Sopenharmony_ci **/ 64062306a36Sopenharmony_cistatic void fm10k_tlv_msg_test_generate_data(u32 *msg, u32 attr_flags) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci if (attr_flags & BIT(FM10K_TEST_MSG_STRING)) 64362306a36Sopenharmony_ci fm10k_tlv_attr_put_null_string(msg, FM10K_TEST_MSG_STRING, 64462306a36Sopenharmony_ci test_str); 64562306a36Sopenharmony_ci if (attr_flags & BIT(FM10K_TEST_MSG_MAC_ADDR)) 64662306a36Sopenharmony_ci fm10k_tlv_attr_put_mac_vlan(msg, FM10K_TEST_MSG_MAC_ADDR, 64762306a36Sopenharmony_ci test_mac, test_vlan); 64862306a36Sopenharmony_ci if (attr_flags & BIT(FM10K_TEST_MSG_U8)) 64962306a36Sopenharmony_ci fm10k_tlv_attr_put_u8(msg, FM10K_TEST_MSG_U8, test_u8); 65062306a36Sopenharmony_ci if (attr_flags & BIT(FM10K_TEST_MSG_U16)) 65162306a36Sopenharmony_ci fm10k_tlv_attr_put_u16(msg, FM10K_TEST_MSG_U16, test_u16); 65262306a36Sopenharmony_ci if (attr_flags & BIT(FM10K_TEST_MSG_U32)) 65362306a36Sopenharmony_ci fm10k_tlv_attr_put_u32(msg, FM10K_TEST_MSG_U32, test_u32); 65462306a36Sopenharmony_ci if (attr_flags & BIT(FM10K_TEST_MSG_U64)) 65562306a36Sopenharmony_ci fm10k_tlv_attr_put_u64(msg, FM10K_TEST_MSG_U64, test_u64); 65662306a36Sopenharmony_ci if (attr_flags & BIT(FM10K_TEST_MSG_S8)) 65762306a36Sopenharmony_ci fm10k_tlv_attr_put_s8(msg, FM10K_TEST_MSG_S8, test_s8); 65862306a36Sopenharmony_ci if (attr_flags & BIT(FM10K_TEST_MSG_S16)) 65962306a36Sopenharmony_ci fm10k_tlv_attr_put_s16(msg, FM10K_TEST_MSG_S16, test_s16); 66062306a36Sopenharmony_ci if (attr_flags & BIT(FM10K_TEST_MSG_S32)) 66162306a36Sopenharmony_ci fm10k_tlv_attr_put_s32(msg, FM10K_TEST_MSG_S32, test_s32); 66262306a36Sopenharmony_ci if (attr_flags & BIT(FM10K_TEST_MSG_S64)) 66362306a36Sopenharmony_ci fm10k_tlv_attr_put_s64(msg, FM10K_TEST_MSG_S64, test_s64); 66462306a36Sopenharmony_ci if (attr_flags & BIT(FM10K_TEST_MSG_LE_STRUCT)) 66562306a36Sopenharmony_ci fm10k_tlv_attr_put_le_struct(msg, FM10K_TEST_MSG_LE_STRUCT, 66662306a36Sopenharmony_ci test_le, 8); 66762306a36Sopenharmony_ci} 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci/** 67062306a36Sopenharmony_ci * fm10k_tlv_msg_test_create - Create a test message testing all attributes 67162306a36Sopenharmony_ci * @msg: Pointer to message 67262306a36Sopenharmony_ci * @attr_flags: List of flags indicating what attributes to add 67362306a36Sopenharmony_ci * 67462306a36Sopenharmony_ci * This function is meant to load a message buffer with all attribute types 67562306a36Sopenharmony_ci * including a nested attribute. 67662306a36Sopenharmony_ci **/ 67762306a36Sopenharmony_civoid fm10k_tlv_msg_test_create(u32 *msg, u32 attr_flags) 67862306a36Sopenharmony_ci{ 67962306a36Sopenharmony_ci u32 *nest = NULL; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci fm10k_tlv_msg_init(msg, FM10K_TLV_MSG_ID_TEST); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci fm10k_tlv_msg_test_generate_data(msg, attr_flags); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci /* check for nested attributes */ 68662306a36Sopenharmony_ci attr_flags >>= FM10K_TEST_MSG_NESTED; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci if (attr_flags) { 68962306a36Sopenharmony_ci nest = fm10k_tlv_attr_nest_start(msg, FM10K_TEST_MSG_NESTED); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci fm10k_tlv_msg_test_generate_data(nest, attr_flags); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci fm10k_tlv_attr_nest_stop(msg); 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci} 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci/** 69862306a36Sopenharmony_ci * fm10k_tlv_msg_test - Validate all results on test message receive 69962306a36Sopenharmony_ci * @hw: Pointer to hardware structure 70062306a36Sopenharmony_ci * @results: Pointer array to attributes in the message 70162306a36Sopenharmony_ci * @mbx: Pointer to mailbox information structure 70262306a36Sopenharmony_ci * 70362306a36Sopenharmony_ci * This function does a check to verify all attributes match what the test 70462306a36Sopenharmony_ci * message placed in the message buffer. It is the default handler 70562306a36Sopenharmony_ci * for TLV test messages. 70662306a36Sopenharmony_ci **/ 70762306a36Sopenharmony_cis32 fm10k_tlv_msg_test(struct fm10k_hw *hw, u32 **results, 70862306a36Sopenharmony_ci struct fm10k_mbx_info *mbx) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci u32 *nest_results[FM10K_TLV_RESULTS_MAX]; 71162306a36Sopenharmony_ci unsigned char result_str[80]; 71262306a36Sopenharmony_ci unsigned char result_mac[ETH_ALEN]; 71362306a36Sopenharmony_ci s32 err = 0; 71462306a36Sopenharmony_ci __le32 result_le[2]; 71562306a36Sopenharmony_ci u16 result_vlan; 71662306a36Sopenharmony_ci u64 result_u64; 71762306a36Sopenharmony_ci u32 result_u32; 71862306a36Sopenharmony_ci u16 result_u16; 71962306a36Sopenharmony_ci u8 result_u8; 72062306a36Sopenharmony_ci s64 result_s64; 72162306a36Sopenharmony_ci s32 result_s32; 72262306a36Sopenharmony_ci s16 result_s16; 72362306a36Sopenharmony_ci s8 result_s8; 72462306a36Sopenharmony_ci u32 reply[3]; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci /* retrieve results of a previous test */ 72762306a36Sopenharmony_ci if (!!results[FM10K_TEST_MSG_RESULT]) 72862306a36Sopenharmony_ci return fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_RESULT], 72962306a36Sopenharmony_ci &mbx->test_result); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ciparse_nested: 73262306a36Sopenharmony_ci if (!!results[FM10K_TEST_MSG_STRING]) { 73362306a36Sopenharmony_ci err = fm10k_tlv_attr_get_null_string( 73462306a36Sopenharmony_ci results[FM10K_TEST_MSG_STRING], 73562306a36Sopenharmony_ci result_str); 73662306a36Sopenharmony_ci if (!err && memcmp(test_str, result_str, sizeof(test_str))) 73762306a36Sopenharmony_ci err = FM10K_ERR_INVALID_VALUE; 73862306a36Sopenharmony_ci if (err) 73962306a36Sopenharmony_ci goto report_result; 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci if (!!results[FM10K_TEST_MSG_MAC_ADDR]) { 74262306a36Sopenharmony_ci err = fm10k_tlv_attr_get_mac_vlan( 74362306a36Sopenharmony_ci results[FM10K_TEST_MSG_MAC_ADDR], 74462306a36Sopenharmony_ci result_mac, &result_vlan); 74562306a36Sopenharmony_ci if (!err && !ether_addr_equal(test_mac, result_mac)) 74662306a36Sopenharmony_ci err = FM10K_ERR_INVALID_VALUE; 74762306a36Sopenharmony_ci if (!err && test_vlan != result_vlan) 74862306a36Sopenharmony_ci err = FM10K_ERR_INVALID_VALUE; 74962306a36Sopenharmony_ci if (err) 75062306a36Sopenharmony_ci goto report_result; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci if (!!results[FM10K_TEST_MSG_U8]) { 75362306a36Sopenharmony_ci err = fm10k_tlv_attr_get_u8(results[FM10K_TEST_MSG_U8], 75462306a36Sopenharmony_ci &result_u8); 75562306a36Sopenharmony_ci if (!err && test_u8 != result_u8) 75662306a36Sopenharmony_ci err = FM10K_ERR_INVALID_VALUE; 75762306a36Sopenharmony_ci if (err) 75862306a36Sopenharmony_ci goto report_result; 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci if (!!results[FM10K_TEST_MSG_U16]) { 76162306a36Sopenharmony_ci err = fm10k_tlv_attr_get_u16(results[FM10K_TEST_MSG_U16], 76262306a36Sopenharmony_ci &result_u16); 76362306a36Sopenharmony_ci if (!err && test_u16 != result_u16) 76462306a36Sopenharmony_ci err = FM10K_ERR_INVALID_VALUE; 76562306a36Sopenharmony_ci if (err) 76662306a36Sopenharmony_ci goto report_result; 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci if (!!results[FM10K_TEST_MSG_U32]) { 76962306a36Sopenharmony_ci err = fm10k_tlv_attr_get_u32(results[FM10K_TEST_MSG_U32], 77062306a36Sopenharmony_ci &result_u32); 77162306a36Sopenharmony_ci if (!err && test_u32 != result_u32) 77262306a36Sopenharmony_ci err = FM10K_ERR_INVALID_VALUE; 77362306a36Sopenharmony_ci if (err) 77462306a36Sopenharmony_ci goto report_result; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci if (!!results[FM10K_TEST_MSG_U64]) { 77762306a36Sopenharmony_ci err = fm10k_tlv_attr_get_u64(results[FM10K_TEST_MSG_U64], 77862306a36Sopenharmony_ci &result_u64); 77962306a36Sopenharmony_ci if (!err && test_u64 != result_u64) 78062306a36Sopenharmony_ci err = FM10K_ERR_INVALID_VALUE; 78162306a36Sopenharmony_ci if (err) 78262306a36Sopenharmony_ci goto report_result; 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci if (!!results[FM10K_TEST_MSG_S8]) { 78562306a36Sopenharmony_ci err = fm10k_tlv_attr_get_s8(results[FM10K_TEST_MSG_S8], 78662306a36Sopenharmony_ci &result_s8); 78762306a36Sopenharmony_ci if (!err && test_s8 != result_s8) 78862306a36Sopenharmony_ci err = FM10K_ERR_INVALID_VALUE; 78962306a36Sopenharmony_ci if (err) 79062306a36Sopenharmony_ci goto report_result; 79162306a36Sopenharmony_ci } 79262306a36Sopenharmony_ci if (!!results[FM10K_TEST_MSG_S16]) { 79362306a36Sopenharmony_ci err = fm10k_tlv_attr_get_s16(results[FM10K_TEST_MSG_S16], 79462306a36Sopenharmony_ci &result_s16); 79562306a36Sopenharmony_ci if (!err && test_s16 != result_s16) 79662306a36Sopenharmony_ci err = FM10K_ERR_INVALID_VALUE; 79762306a36Sopenharmony_ci if (err) 79862306a36Sopenharmony_ci goto report_result; 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci if (!!results[FM10K_TEST_MSG_S32]) { 80162306a36Sopenharmony_ci err = fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_S32], 80262306a36Sopenharmony_ci &result_s32); 80362306a36Sopenharmony_ci if (!err && test_s32 != result_s32) 80462306a36Sopenharmony_ci err = FM10K_ERR_INVALID_VALUE; 80562306a36Sopenharmony_ci if (err) 80662306a36Sopenharmony_ci goto report_result; 80762306a36Sopenharmony_ci } 80862306a36Sopenharmony_ci if (!!results[FM10K_TEST_MSG_S64]) { 80962306a36Sopenharmony_ci err = fm10k_tlv_attr_get_s64(results[FM10K_TEST_MSG_S64], 81062306a36Sopenharmony_ci &result_s64); 81162306a36Sopenharmony_ci if (!err && test_s64 != result_s64) 81262306a36Sopenharmony_ci err = FM10K_ERR_INVALID_VALUE; 81362306a36Sopenharmony_ci if (err) 81462306a36Sopenharmony_ci goto report_result; 81562306a36Sopenharmony_ci } 81662306a36Sopenharmony_ci if (!!results[FM10K_TEST_MSG_LE_STRUCT]) { 81762306a36Sopenharmony_ci err = fm10k_tlv_attr_get_le_struct( 81862306a36Sopenharmony_ci results[FM10K_TEST_MSG_LE_STRUCT], 81962306a36Sopenharmony_ci result_le, 82062306a36Sopenharmony_ci sizeof(result_le)); 82162306a36Sopenharmony_ci if (!err && memcmp(test_le, result_le, sizeof(test_le))) 82262306a36Sopenharmony_ci err = FM10K_ERR_INVALID_VALUE; 82362306a36Sopenharmony_ci if (err) 82462306a36Sopenharmony_ci goto report_result; 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci if (!!results[FM10K_TEST_MSG_NESTED]) { 82862306a36Sopenharmony_ci /* clear any pointers */ 82962306a36Sopenharmony_ci memset(nest_results, 0, sizeof(nest_results)); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci /* parse the nested attributes into the nest results list */ 83262306a36Sopenharmony_ci err = fm10k_tlv_attr_parse(results[FM10K_TEST_MSG_NESTED], 83362306a36Sopenharmony_ci nest_results, 83462306a36Sopenharmony_ci fm10k_tlv_msg_test_attr); 83562306a36Sopenharmony_ci if (err) 83662306a36Sopenharmony_ci goto report_result; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci /* loop back through to the start */ 83962306a36Sopenharmony_ci results = nest_results; 84062306a36Sopenharmony_ci goto parse_nested; 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_cireport_result: 84462306a36Sopenharmony_ci /* generate reply with test result */ 84562306a36Sopenharmony_ci fm10k_tlv_msg_init(reply, FM10K_TLV_MSG_ID_TEST); 84662306a36Sopenharmony_ci fm10k_tlv_attr_put_s32(reply, FM10K_TEST_MSG_RESULT, err); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci /* load onto outgoing mailbox */ 84962306a36Sopenharmony_ci return mbx->ops.enqueue_tx(hw, mbx, reply); 85062306a36Sopenharmony_ci} 851