1  // SPDX-License-Identifier: GPL-2.0
2  /* Copyright(c) 2013 - 2019 Intel Corporation. */
3  
4  #include "fm10k_tlv.h"
5  
6  /**
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
10   *
11   *  This function return success if provided with a valid message pointer
12   **/
fm10k_tlv_msg_init(u32 * msg,u16 msg_id)13  s32 fm10k_tlv_msg_init(u32 *msg, u16 msg_id)
14  {
15  	/* verify pointer is not NULL */
16  	if (!msg)
17  		return FM10K_ERR_PARAM;
18  
19  	*msg = (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT) | msg_id;
20  
21  	return 0;
22  }
23  
24  /**
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
29   *
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
32   *  pointers.
33   **/
fm10k_tlv_attr_put_null_string(u32 * msg,u16 attr_id,const unsigned char * string)34  static s32 fm10k_tlv_attr_put_null_string(u32 *msg, u16 attr_id,
35  					  const unsigned char *string)
36  {
37  	u32 attr_data = 0, len = 0;
38  	u32 *attr;
39  
40  	/* verify pointers are not NULL */
41  	if (!string || !msg)
42  		return FM10K_ERR_PARAM;
43  
44  	attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
45  
46  	/* copy string into local variable and then write to msg */
47  	do {
48  		/* write data to message */
49  		if (len && !(len % 4)) {
50  			attr[len / 4] = attr_data;
51  			attr_data = 0;
52  		}
53  
54  		/* record character to offset location */
55  		attr_data |= (u32)(*string) << (8 * (len % 4));
56  		len++;
57  
58  		/* test for NULL and then increment */
59  	} while (*(string++));
60  
61  	/* write last piece of data to message */
62  	attr[(len + 3) / 4] = attr_data;
63  
64  	/* record attribute header, update message length */
65  	len <<= FM10K_TLV_LEN_SHIFT;
66  	attr[0] = len | attr_id;
67  
68  	/* add header length to length */
69  	len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
70  	*msg += FM10K_TLV_LEN_ALIGN(len);
71  
72  	return 0;
73  }
74  
75  /**
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
79   *
80   *  This function pulls the string back out of the attribute and will place
81   *  it in the array pointed by string.  It will return success if provided
82   *  with a valid pointers.
83   **/
fm10k_tlv_attr_get_null_string(u32 * attr,unsigned char * string)84  static s32 fm10k_tlv_attr_get_null_string(u32 *attr, unsigned char *string)
85  {
86  	u32 len;
87  
88  	/* verify pointers are not NULL */
89  	if (!string || !attr)
90  		return FM10K_ERR_PARAM;
91  
92  	len = *attr >> FM10K_TLV_LEN_SHIFT;
93  	attr++;
94  
95  	while (len--)
96  		string[len] = (u8)(attr[len / 4] >> (8 * (len % 4)));
97  
98  	return 0;
99  }
100  
101  /**
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
107   *
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
110   *  valid pointers.
111   **/
fm10k_tlv_attr_put_mac_vlan(u32 * msg,u16 attr_id,const u8 * mac_addr,u16 vlan)112  s32 fm10k_tlv_attr_put_mac_vlan(u32 *msg, u16 attr_id,
113  				const u8 *mac_addr, u16 vlan)
114  {
115  	u32 len = ETH_ALEN << FM10K_TLV_LEN_SHIFT;
116  	u32 *attr;
117  
118  	/* verify pointers are not NULL */
119  	if (!msg || !mac_addr)
120  		return FM10K_ERR_PARAM;
121  
122  	attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
123  
124  	/* record attribute header, update message length */
125  	attr[0] = len | attr_id;
126  
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;
131  
132  	/* add header length to length */
133  	len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
134  	*msg += FM10K_TLV_LEN_ALIGN(len);
135  
136  	return 0;
137  }
138  
139  /**
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
144   *
145   *  This function pulls the MAC address back out of the attribute and will
146   *  place it in the array pointed by mac_addr.  It will return success
147   *  if provided with a valid pointers.
148   **/
fm10k_tlv_attr_get_mac_vlan(u32 * attr,u8 * mac_addr,u16 * vlan)149  s32 fm10k_tlv_attr_get_mac_vlan(u32 *attr, u8 *mac_addr, u16 *vlan)
150  {
151  	/* verify pointers are not NULL */
152  	if (!mac_addr || !attr)
153  		return FM10K_ERR_PARAM;
154  
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);
158  
159  	return 0;
160  }
161  
162  /**
163   *  fm10k_tlv_attr_put_bool - Add header indicating value "true"
164   *  @msg: Pointer to message block
165   *  @attr_id: Attribute ID
166   *
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
170   *  valid pointers.
171   **/
fm10k_tlv_attr_put_bool(u32 * msg,u16 attr_id)172  s32 fm10k_tlv_attr_put_bool(u32 *msg, u16 attr_id)
173  {
174  	/* verify pointers are not NULL */
175  	if (!msg)
176  		return FM10K_ERR_PARAM;
177  
178  	/* record attribute header */
179  	msg[FM10K_TLV_DWORD_LEN(*msg)] = attr_id;
180  
181  	/* add header length to length */
182  	*msg += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
183  
184  	return 0;
185  }
186  
187  /**
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
193   *
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.
197   **/
fm10k_tlv_attr_put_value(u32 * msg,u16 attr_id,s64 value,u32 len)198  s32 fm10k_tlv_attr_put_value(u32 *msg, u16 attr_id, s64 value, u32 len)
199  {
200  	u32 *attr;
201  
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;
205  
206  	attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
207  
208  	if (len < 4) {
209  		attr[1] = (u32)value & (BIT(8 * len) - 1);
210  	} else {
211  		attr[1] = (u32)value;
212  		if (len > 4)
213  			attr[2] = (u32)(value >> 32);
214  	}
215  
216  	/* record attribute header, update message length */
217  	len <<= FM10K_TLV_LEN_SHIFT;
218  	attr[0] = len | attr_id;
219  
220  	/* add header length to length */
221  	len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
222  	*msg += FM10K_TLV_LEN_ALIGN(len);
223  
224  	return 0;
225  }
226  
227  /**
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
232   *
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
236   *  attribute length.
237   **/
fm10k_tlv_attr_get_value(u32 * attr,void * value,u32 len)238  s32 fm10k_tlv_attr_get_value(u32 *attr, void *value, u32 len)
239  {
240  	/* verify pointers are not NULL */
241  	if (!attr || !value)
242  		return FM10K_ERR_PARAM;
243  
244  	if ((*attr >> FM10K_TLV_LEN_SHIFT) != len)
245  		return FM10K_ERR_PARAM;
246  
247  	if (len == 8)
248  		*(u64 *)value = ((u64)attr[2] << 32) | attr[1];
249  	else if (len == 4)
250  		*(u32 *)value = attr[1];
251  	else if (len == 2)
252  		*(u16 *)value = (u16)attr[1];
253  	else
254  		*(u8 *)value = (u8)attr[1];
255  
256  	return 0;
257  }
258  
259  /**
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
265   *
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.
269   **/
fm10k_tlv_attr_put_le_struct(u32 * msg,u16 attr_id,const void * le_struct,u32 len)270  s32 fm10k_tlv_attr_put_le_struct(u32 *msg, u16 attr_id,
271  				 const void *le_struct, u32 len)
272  {
273  	const __le32 *le32_ptr = (const __le32 *)le_struct;
274  	u32 *attr;
275  	u32 i;
276  
277  	/* verify non-null msg and len is in 32 bit words */
278  	if (!msg || !len || (len % 4))
279  		return FM10K_ERR_PARAM;
280  
281  	attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
282  
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]);
286  
287  	/* record attribute header, update message length */
288  	len <<= FM10K_TLV_LEN_SHIFT;
289  	attr[0] = len | attr_id;
290  
291  	/* add header length to length */
292  	len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
293  	*msg += FM10K_TLV_LEN_ALIGN(len);
294  
295  	return 0;
296  }
297  
298  /**
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
303   *
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
307   *  attribute length.
308   **/
fm10k_tlv_attr_get_le_struct(u32 * attr,void * le_struct,u32 len)309  s32 fm10k_tlv_attr_get_le_struct(u32 *attr, void *le_struct, u32 len)
310  {
311  	__le32 *le32_ptr = (__le32 *)le_struct;
312  	u32 i;
313  
314  	/* verify pointers are not NULL */
315  	if (!le_struct || !attr)
316  		return FM10K_ERR_PARAM;
317  
318  	if ((*attr >> FM10K_TLV_LEN_SHIFT) != len)
319  		return FM10K_ERR_PARAM;
320  
321  	attr++;
322  
323  	for (i = 0; len; i++, len -= 4)
324  		le32_ptr[i] = cpu_to_le32(attr[i]);
325  
326  	return 0;
327  }
328  
329  /**
330   *  fm10k_tlv_attr_nest_start - Start a set of nested attributes
331   *  @msg: Pointer to message block
332   *  @attr_id: Attribute ID
333   *
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.
339   **/
fm10k_tlv_attr_nest_start(u32 * msg,u16 attr_id)340  static u32 *fm10k_tlv_attr_nest_start(u32 *msg, u16 attr_id)
341  {
342  	u32 *attr;
343  
344  	/* verify pointer is not NULL */
345  	if (!msg)
346  		return NULL;
347  
348  	attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
349  
350  	attr[0] = attr_id;
351  
352  	/* return pointer to nest header */
353  	return attr;
354  }
355  
356  /**
357   *  fm10k_tlv_attr_nest_stop - Stop a set of nested attributes
358   *  @msg: Pointer to message block
359   *
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.
364   **/
fm10k_tlv_attr_nest_stop(u32 * msg)365  static s32 fm10k_tlv_attr_nest_stop(u32 *msg)
366  {
367  	u32 *attr;
368  	u32 len;
369  
370  	/* verify pointer is not NULL */
371  	if (!msg)
372  		return FM10K_ERR_PARAM;
373  
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;
377  
378  	/* only include nest if data was added to it */
379  	if (len) {
380  		len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
381  		*msg += len;
382  	}
383  
384  	return 0;
385  }
386  
387  /**
388   *  fm10k_tlv_attr_validate - Validate attribute metadata
389   *  @attr: Pointer to attribute
390   *  @tlv_attr: Type and length info for attribute
391   *
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
396   *  it returns 0.
397   **/
fm10k_tlv_attr_validate(u32 * attr,const struct fm10k_tlv_attr * tlv_attr)398  static s32 fm10k_tlv_attr_validate(u32 *attr,
399  				   const struct fm10k_tlv_attr *tlv_attr)
400  {
401  	u32 attr_id = *attr & FM10K_TLV_ID_MASK;
402  	u16 len = *attr >> FM10K_TLV_LEN_SHIFT;
403  
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;
407  
408  	/* search through the list of attributes to find a matching ID */
409  	while (tlv_attr->id < attr_id)
410  		tlv_attr++;
411  
412  	/* if didn't find a match then we should exit */
413  	if (tlv_attr->id != attr_id)
414  		return FM10K_NOT_IMPLEMENTED;
415  
416  	/* move to start of attribute data */
417  	attr++;
418  
419  	switch (tlv_attr->type) {
420  	case FM10K_TLV_NULL_STRING:
421  		if (!len ||
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;
426  		break;
427  	case FM10K_TLV_MAC_ADDR:
428  		if (len != ETH_ALEN)
429  			return FM10K_ERR_PARAM;
430  		break;
431  	case FM10K_TLV_BOOL:
432  		if (len)
433  			return FM10K_ERR_PARAM;
434  		break;
435  	case FM10K_TLV_UNSIGNED:
436  	case FM10K_TLV_SIGNED:
437  		if (len != tlv_attr->len)
438  			return FM10K_ERR_PARAM;
439  		break;
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;
444  		break;
445  	case FM10K_TLV_NESTED:
446  		/* nested attributes must be 4 byte aligned */
447  		if (len % 4)
448  			return FM10K_ERR_PARAM;
449  		break;
450  	default:
451  		/* attribute id is mapped to bad value */
452  		return FM10K_ERR_PARAM;
453  	}
454  
455  	return 0;
456  }
457  
458  /**
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
463   *
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
469   *  ignored.
470   **/
fm10k_tlv_attr_parse(u32 * attr,u32 ** results,const struct fm10k_tlv_attr * tlv_attr)471  static s32 fm10k_tlv_attr_parse(u32 *attr, u32 **results,
472  				const struct fm10k_tlv_attr *tlv_attr)
473  {
474  	u32 i, attr_id, offset = 0;
475  	s32 err;
476  	u16 len;
477  
478  	/* verify pointers are not NULL */
479  	if (!attr || !results)
480  		return FM10K_ERR_PARAM;
481  
482  	/* initialize results to NULL */
483  	for (i = 0; i < FM10K_TLV_RESULTS_MAX; i++)
484  		results[i] = NULL;
485  
486  	/* pull length from the message header */
487  	len = *attr >> FM10K_TLV_LEN_SHIFT;
488  
489  	/* no attributes to parse if there is no length */
490  	if (!len)
491  		return 0;
492  
493  	/* no attributes to parse, just raw data, message becomes attribute */
494  	if (!tlv_attr) {
495  		results[0] = attr;
496  		return 0;
497  	}
498  
499  	/* move to start of attribute data */
500  	attr++;
501  
502  	/* run through list parsing all attributes */
503  	while (offset < len) {
504  		attr_id = *attr & FM10K_TLV_ID_MASK;
505  
506  		if (attr_id >= FM10K_TLV_RESULTS_MAX)
507  			return FM10K_NOT_IMPLEMENTED;
508  
509  		err = fm10k_tlv_attr_validate(attr, tlv_attr);
510  		if (err == FM10K_NOT_IMPLEMENTED)
511  			; /* silently ignore non-implemented attributes */
512  		else if (err)
513  			return err;
514  		else
515  			results[attr_id] = attr;
516  
517  		/* update offset */
518  		offset += FM10K_TLV_DWORD_LEN(*attr) * 4;
519  
520  		/* move to next attribute */
521  		attr = &attr[FM10K_TLV_DWORD_LEN(*attr)];
522  	}
523  
524  	/* we should find ourselves at the end of the list */
525  	if (offset != len)
526  		return FM10K_ERR_PARAM;
527  
528  	return 0;
529  }
530  
531  /**
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
537   *
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.
543   **/
fm10k_tlv_msg_parse(struct fm10k_hw * hw,u32 * msg,struct fm10k_mbx_info * mbx,const struct fm10k_msg_data * data)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)
547  {
548  	u32 *results[FM10K_TLV_RESULTS_MAX];
549  	u32 msg_id;
550  	s32 err;
551  
552  	/* verify pointer is not NULL */
553  	if (!msg || !data)
554  		return FM10K_ERR_PARAM;
555  
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;
559  
560  	/* grab message ID */
561  	msg_id = *msg & FM10K_TLV_ID_MASK;
562  
563  	while (data->id < msg_id)
564  		data++;
565  
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)
569  			data++;
570  	}
571  
572  	/* parse the attributes into the results list */
573  	err = fm10k_tlv_attr_parse(msg, results, data->attr);
574  	if (err < 0)
575  		return err;
576  
577  	return data->func(hw, results, mbx);
578  }
579  
580  /**
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
585   *
586   *  This function is a default handler for unrecognized messages.  At a
587   *  minimum it just indicates that the message requested was
588   *  unimplemented.
589   **/
fm10k_tlv_msg_error(struct fm10k_hw __always_unused * hw,u32 __always_unused ** results,struct fm10k_mbx_info __always_unused * mbx)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)
593  {
594  	return FM10K_NOT_IMPLEMENTED;
595  }
596  
597  static const unsigned char test_str[] =	"fm10k";
598  static const unsigned char test_mac[ETH_ALEN] = { 0x12, 0x34, 0x56,
599  						  0x78, 0x9a, 0xbc };
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)};
611  
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
615   */
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),
630  	FM10K_TLV_ATTR_LAST
631  };
632  
633  /**
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
637   *
638   *  This function is meant to load a message buffer with attribute data
639   **/
fm10k_tlv_msg_test_generate_data(u32 * msg,u32 attr_flags)640  static void fm10k_tlv_msg_test_generate_data(u32 *msg, u32 attr_flags)
641  {
642  	if (attr_flags & BIT(FM10K_TEST_MSG_STRING))
643  		fm10k_tlv_attr_put_null_string(msg, FM10K_TEST_MSG_STRING,
644  					       test_str);
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,
666  					     test_le, 8);
667  }
668  
669  /**
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
673   *
674   *  This function is meant to load a message buffer with all attribute types
675   *  including a nested attribute.
676   **/
fm10k_tlv_msg_test_create(u32 * msg,u32 attr_flags)677  void fm10k_tlv_msg_test_create(u32 *msg, u32 attr_flags)
678  {
679  	u32 *nest = NULL;
680  
681  	fm10k_tlv_msg_init(msg, FM10K_TLV_MSG_ID_TEST);
682  
683  	fm10k_tlv_msg_test_generate_data(msg, attr_flags);
684  
685  	/* check for nested attributes */
686  	attr_flags >>= FM10K_TEST_MSG_NESTED;
687  
688  	if (attr_flags) {
689  		nest = fm10k_tlv_attr_nest_start(msg, FM10K_TEST_MSG_NESTED);
690  
691  		fm10k_tlv_msg_test_generate_data(nest, attr_flags);
692  
693  		fm10k_tlv_attr_nest_stop(msg);
694  	}
695  }
696  
697  /**
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
702   *
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.
706   **/
fm10k_tlv_msg_test(struct fm10k_hw * hw,u32 ** results,struct fm10k_mbx_info * mbx)707  s32 fm10k_tlv_msg_test(struct fm10k_hw *hw, u32 **results,
708  		       struct fm10k_mbx_info *mbx)
709  {
710  	u32 *nest_results[FM10K_TLV_RESULTS_MAX];
711  	unsigned char result_str[80];
712  	unsigned char result_mac[ETH_ALEN];
713  	s32 err = 0;
714  	__le32 result_le[2];
715  	u16 result_vlan;
716  	u64 result_u64;
717  	u32 result_u32;
718  	u16 result_u16;
719  	u8  result_u8;
720  	s64 result_s64;
721  	s32 result_s32;
722  	s16 result_s16;
723  	s8  result_s8;
724  	u32 reply[3];
725  
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],
729  					      &mbx->test_result);
730  
731  parse_nested:
732  	if (!!results[FM10K_TEST_MSG_STRING]) {
733  		err = fm10k_tlv_attr_get_null_string(
734  					results[FM10K_TEST_MSG_STRING],
735  					result_str);
736  		if (!err && memcmp(test_str, result_str, sizeof(test_str)))
737  			err = FM10K_ERR_INVALID_VALUE;
738  		if (err)
739  			goto report_result;
740  	}
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;
749  		if (err)
750  			goto report_result;
751  	}
752  	if (!!results[FM10K_TEST_MSG_U8]) {
753  		err = fm10k_tlv_attr_get_u8(results[FM10K_TEST_MSG_U8],
754  					    &result_u8);
755  		if (!err && test_u8 != result_u8)
756  			err = FM10K_ERR_INVALID_VALUE;
757  		if (err)
758  			goto report_result;
759  	}
760  	if (!!results[FM10K_TEST_MSG_U16]) {
761  		err = fm10k_tlv_attr_get_u16(results[FM10K_TEST_MSG_U16],
762  					     &result_u16);
763  		if (!err && test_u16 != result_u16)
764  			err = FM10K_ERR_INVALID_VALUE;
765  		if (err)
766  			goto report_result;
767  	}
768  	if (!!results[FM10K_TEST_MSG_U32]) {
769  		err = fm10k_tlv_attr_get_u32(results[FM10K_TEST_MSG_U32],
770  					     &result_u32);
771  		if (!err && test_u32 != result_u32)
772  			err = FM10K_ERR_INVALID_VALUE;
773  		if (err)
774  			goto report_result;
775  	}
776  	if (!!results[FM10K_TEST_MSG_U64]) {
777  		err = fm10k_tlv_attr_get_u64(results[FM10K_TEST_MSG_U64],
778  					     &result_u64);
779  		if (!err && test_u64 != result_u64)
780  			err = FM10K_ERR_INVALID_VALUE;
781  		if (err)
782  			goto report_result;
783  	}
784  	if (!!results[FM10K_TEST_MSG_S8]) {
785  		err = fm10k_tlv_attr_get_s8(results[FM10K_TEST_MSG_S8],
786  					    &result_s8);
787  		if (!err && test_s8 != result_s8)
788  			err = FM10K_ERR_INVALID_VALUE;
789  		if (err)
790  			goto report_result;
791  	}
792  	if (!!results[FM10K_TEST_MSG_S16]) {
793  		err = fm10k_tlv_attr_get_s16(results[FM10K_TEST_MSG_S16],
794  					     &result_s16);
795  		if (!err && test_s16 != result_s16)
796  			err = FM10K_ERR_INVALID_VALUE;
797  		if (err)
798  			goto report_result;
799  	}
800  	if (!!results[FM10K_TEST_MSG_S32]) {
801  		err = fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_S32],
802  					     &result_s32);
803  		if (!err && test_s32 != result_s32)
804  			err = FM10K_ERR_INVALID_VALUE;
805  		if (err)
806  			goto report_result;
807  	}
808  	if (!!results[FM10K_TEST_MSG_S64]) {
809  		err = fm10k_tlv_attr_get_s64(results[FM10K_TEST_MSG_S64],
810  					     &result_s64);
811  		if (!err && test_s64 != result_s64)
812  			err = FM10K_ERR_INVALID_VALUE;
813  		if (err)
814  			goto report_result;
815  	}
816  	if (!!results[FM10K_TEST_MSG_LE_STRUCT]) {
817  		err = fm10k_tlv_attr_get_le_struct(
818  					results[FM10K_TEST_MSG_LE_STRUCT],
819  					result_le,
820  					sizeof(result_le));
821  		if (!err && memcmp(test_le, result_le, sizeof(test_le)))
822  			err = FM10K_ERR_INVALID_VALUE;
823  		if (err)
824  			goto report_result;
825  	}
826  
827  	if (!!results[FM10K_TEST_MSG_NESTED]) {
828  		/* clear any pointers */
829  		memset(nest_results, 0, sizeof(nest_results));
830  
831  		/* parse the nested attributes into the nest results list */
832  		err = fm10k_tlv_attr_parse(results[FM10K_TEST_MSG_NESTED],
833  					   nest_results,
834  					   fm10k_tlv_msg_test_attr);
835  		if (err)
836  			goto report_result;
837  
838  		/* loop back through to the start */
839  		results = nest_results;
840  		goto parse_nested;
841  	}
842  
843  report_result:
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);
847  
848  	/* load onto outgoing mailbox */
849  	return mbx->ops.enqueue_tx(hw, mbx, reply);
850  }
851