Imported Upstream version 16.04
[deb_dpdk.git] / drivers / net / fm10k / base / fm10k_tlv.c
1 /*******************************************************************************
2
3 Copyright (c) 2013 - 2015, Intel Corporation
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8
9  1. Redistributions of source code must retain the above copyright notice,
10     this list of conditions and the following disclaimer.
11
12  2. Redistributions in binary form must reproduce the above copyright
13     notice, this list of conditions and the following disclaimer in the
14     documentation and/or other materials provided with the distribution.
15
16  3. Neither the name of the Intel Corporation nor the names of its
17     contributors may be used to endorse or promote products derived from
18     this software without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 POSSIBILITY OF SUCH DAMAGE.
31
32 ***************************************************************************/
33
34 #include "fm10k_tlv.h"
35
36 /**
37  *  fm10k_tlv_msg_init - Initialize message block for TLV data storage
38  *  @msg: Pointer to message block
39  *  @msg_id: Message ID indicating message type
40  *
41  *  This function return success if provided with a valid message pointer
42  **/
43 s32 fm10k_tlv_msg_init(u32 *msg, u16 msg_id)
44 {
45         DEBUGFUNC("fm10k_tlv_msg_init");
46
47         /* verify pointer is not NULL */
48         if (!msg)
49                 return FM10K_ERR_PARAM;
50
51         *msg = (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT) | msg_id;
52
53         return FM10K_SUCCESS;
54 }
55
56 /**
57  *  fm10k_tlv_attr_put_null_string - Place null terminated string on message
58  *  @msg: Pointer to message block
59  *  @attr_id: Attribute ID
60  *  @string: Pointer to string to be stored in attribute
61  *
62  *  This function will reorder a string to be CPU endian and store it in
63  *  the attribute buffer.  It will return success if provided with a valid
64  *  pointers.
65  **/
66 static s32 fm10k_tlv_attr_put_null_string(u32 *msg, u16 attr_id,
67                                           const unsigned char *string)
68 {
69         u32 attr_data = 0, len = 0;
70         u32 *attr;
71
72         DEBUGFUNC("fm10k_tlv_attr_put_null_string");
73
74         /* verify pointers are not NULL */
75         if (!string || !msg)
76                 return FM10K_ERR_PARAM;
77
78         attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
79
80         /* copy string into local variable and then write to msg */
81         do {
82                 /* write data to message */
83                 if (len && !(len % 4)) {
84                         attr[len / 4] = attr_data;
85                         attr_data = 0;
86                 }
87
88                 /* record character to offset location */
89                 attr_data |= (u32)(*string) << (8 * (len % 4));
90                 len++;
91
92                 /* test for NULL and then increment */
93         } while (*(string++));
94
95         /* write last piece of data to message */
96         attr[(len + 3) / 4] = attr_data;
97
98         /* record attribute header, update message length */
99         len <<= FM10K_TLV_LEN_SHIFT;
100         attr[0] = len | attr_id;
101
102         /* add header length to length */
103         len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
104         *msg += FM10K_TLV_LEN_ALIGN(len);
105
106         return FM10K_SUCCESS;
107 }
108
109 /**
110  *  fm10k_tlv_attr_get_null_string - Get null terminated string from attribute
111  *  @attr: Pointer to attribute
112  *  @string: Pointer to location of destination string
113  *
114  *  This function pulls the string back out of the attribute and will place
115  *  it in the array pointed by by string.  It will return success if provided
116  *  with a valid pointers.
117  **/
118 static s32 fm10k_tlv_attr_get_null_string(u32 *attr, unsigned char *string)
119 {
120         u32 len;
121
122         DEBUGFUNC("fm10k_tlv_attr_get_null_string");
123
124         /* verify pointers are not NULL */
125         if (!string || !attr)
126                 return FM10K_ERR_PARAM;
127
128         len = *attr >> FM10K_TLV_LEN_SHIFT;
129         attr++;
130
131         while (len--)
132                 string[len] = (u8)(attr[len / 4] >> (8 * (len % 4)));
133
134         return FM10K_SUCCESS;
135 }
136
137 /**
138  *  fm10k_tlv_attr_put_mac_vlan - Store MAC/VLAN attribute in message
139  *  @msg: Pointer to message block
140  *  @attr_id: Attribute ID
141  *  @mac_addr: MAC address to be stored
142  *
143  *  This function will reorder a MAC address to be CPU endian and store it
144  *  in the attribute buffer.  It will return success if provided with a
145  *  valid pointers.
146  **/
147 s32 fm10k_tlv_attr_put_mac_vlan(u32 *msg, u16 attr_id,
148                                 const u8 *mac_addr, u16 vlan)
149 {
150         u32 len = ETH_ALEN << FM10K_TLV_LEN_SHIFT;
151         u32 *attr;
152
153         DEBUGFUNC("fm10k_tlv_attr_put_mac_vlan");
154
155         /* verify pointers are not NULL */
156         if (!msg || !mac_addr)
157                 return FM10K_ERR_PARAM;
158
159         attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
160
161         /* record attribute header, update message length */
162         attr[0] = len | attr_id;
163
164         /* copy value into local variable and then write to msg */
165         attr[1] = FM10K_LE32_TO_CPU(*(const __le32 *)&mac_addr[0]);
166         attr[2] = FM10K_LE16_TO_CPU(*(const __le16 *)&mac_addr[4]);
167         attr[2] |= (u32)vlan << 16;
168
169         /* add header length to length */
170         len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
171         *msg += FM10K_TLV_LEN_ALIGN(len);
172
173         return FM10K_SUCCESS;
174 }
175
176 /**
177  *  fm10k_tlv_attr_get_mac_vlan - Get MAC/VLAN stored in attribute
178  *  @attr: Pointer to attribute
179  *  @attr_id: Attribute ID
180  *  @mac_addr: location of buffer to store MAC address
181  *
182  *  This function pulls the MAC address back out of the attribute and will
183  *  place it in the array pointed by by mac_addr.  It will return success
184  *  if provided with a valid pointers.
185  **/
186 s32 fm10k_tlv_attr_get_mac_vlan(u32 *attr, u8 *mac_addr, u16 *vlan)
187 {
188         DEBUGFUNC("fm10k_tlv_attr_get_mac_vlan");
189
190         /* verify pointers are not NULL */
191         if (!mac_addr || !attr)
192                 return FM10K_ERR_PARAM;
193
194         *(__le32 *)&mac_addr[0] = FM10K_CPU_TO_LE32(attr[1]);
195         *(__le16 *)&mac_addr[4] = FM10K_CPU_TO_LE16((u16)(attr[2]));
196         *vlan = (u16)(attr[2] >> 16);
197
198         return FM10K_SUCCESS;
199 }
200
201 /**
202  *  fm10k_tlv_attr_put_bool - Add header indicating value "true"
203  *  @msg: Pointer to message block
204  *  @attr_id: Attribute ID
205  *
206  *  This function will simply add an attribute header, the fact
207  *  that the header is here means the attribute value is true, else
208  *  it is false.  The function will return success if provided with a
209  *  valid pointers.
210  **/
211 s32 fm10k_tlv_attr_put_bool(u32 *msg, u16 attr_id)
212 {
213         DEBUGFUNC("fm10k_tlv_attr_put_bool");
214
215         /* verify pointers are not NULL */
216         if (!msg)
217                 return FM10K_ERR_PARAM;
218
219         /* record attribute header */
220         msg[FM10K_TLV_DWORD_LEN(*msg)] = attr_id;
221
222         /* add header length to length */
223         *msg += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
224
225         return FM10K_SUCCESS;
226 }
227
228 /**
229  *  fm10k_tlv_attr_put_value - Store integer value attribute in message
230  *  @msg: Pointer to message block
231  *  @attr_id: Attribute ID
232  *  @value: Value to be written
233  *  @len: Size of value
234  *
235  *  This function will place an integer value of up to 8 bytes in size
236  *  in a message attribute.  The function will return success provided
237  *  that msg is a valid pointer, and len is 1, 2, 4, or 8.
238  **/
239 s32 fm10k_tlv_attr_put_value(u32 *msg, u16 attr_id, s64 value, u32 len)
240 {
241         u32 *attr;
242
243         DEBUGFUNC("fm10k_tlv_attr_put_value");
244
245         /* verify non-null msg and len is 1, 2, 4, or 8 */
246         if (!msg || !len || len > 8 || (len & (len - 1)))
247                 return FM10K_ERR_PARAM;
248
249         attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
250
251         if (len < 4) {
252                 attr[1] = (u32)value & (BIT(8 * len) - 1);
253         } else {
254                 attr[1] = (u32)value;
255                 if (len > 4)
256                         attr[2] = (u32)(value >> 32);
257         }
258
259         /* record attribute header, update message length */
260         len <<= FM10K_TLV_LEN_SHIFT;
261         attr[0] = len | attr_id;
262
263         /* add header length to length */
264         len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
265         *msg += FM10K_TLV_LEN_ALIGN(len);
266
267         return FM10K_SUCCESS;
268 }
269
270 /**
271  *  fm10k_tlv_attr_get_value - Get integer value stored in attribute
272  *  @attr: Pointer to attribute
273  *  @value: Pointer to destination buffer
274  *  @len: Size of value
275  *
276  *  This function will place an integer value of up to 8 bytes in size
277  *  in the offset pointed to by value.  The function will return success
278  *  provided that pointers are valid and the len value matches the
279  *  attribute length.
280  **/
281 s32 fm10k_tlv_attr_get_value(u32 *attr, void *value, u32 len)
282 {
283         DEBUGFUNC("fm10k_tlv_attr_get_value");
284
285         /* verify pointers are not NULL */
286         if (!attr || !value)
287                 return FM10K_ERR_PARAM;
288
289         if ((*attr >> FM10K_TLV_LEN_SHIFT) != len)
290                 return FM10K_ERR_PARAM;
291
292         if (len == 8)
293                 *(u64 *)value = ((u64)attr[2] << 32) | attr[1];
294         else if (len == 4)
295                 *(u32 *)value = attr[1];
296         else if (len == 2)
297                 *(u16 *)value = (u16)attr[1];
298         else
299                 *(u8 *)value = (u8)attr[1];
300
301         return FM10K_SUCCESS;
302 }
303
304 /**
305  *  fm10k_tlv_attr_put_le_struct - Store little endian structure in message
306  *  @msg: Pointer to message block
307  *  @attr_id: Attribute ID
308  *  @le_struct: Pointer to structure to be written
309  *  @len: Size of le_struct
310  *
311  *  This function will place a little endian structure value in a message
312  *  attribute.  The function will return success provided that all pointers
313  *  are valid and length is a non-zero multiple of 4.
314  **/
315 s32 fm10k_tlv_attr_put_le_struct(u32 *msg, u16 attr_id,
316                                  const void *le_struct, u32 len)
317 {
318         const __le32 *le32_ptr = (const __le32 *)le_struct;
319         u32 *attr;
320         u32 i;
321
322         DEBUGFUNC("fm10k_tlv_attr_put_le_struct");
323
324         /* verify non-null msg and len is in 32 bit words */
325         if (!msg || !len || (len % 4))
326                 return FM10K_ERR_PARAM;
327
328         attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
329
330         /* copy le32 structure into host byte order at 32b boundaries */
331         for (i = 0; i < (len / 4); i++)
332                 attr[i + 1] = FM10K_LE32_TO_CPU(le32_ptr[i]);
333
334         /* record attribute header, update message length */
335         len <<= FM10K_TLV_LEN_SHIFT;
336         attr[0] = len | attr_id;
337
338         /* add header length to length */
339         len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
340         *msg += FM10K_TLV_LEN_ALIGN(len);
341
342         return FM10K_SUCCESS;
343 }
344
345 /**
346  *  fm10k_tlv_attr_get_le_struct - Get little endian struct form attribute
347  *  @attr: Pointer to attribute
348  *  @le_struct: Pointer to structure to be written
349  *  @len: Size of structure
350  *
351  *  This function will place a little endian structure in the buffer
352  *  pointed to by le_struct.  The function will return success
353  *  provided that pointers are valid and the len value matches the
354  *  attribute length.
355  **/
356 s32 fm10k_tlv_attr_get_le_struct(u32 *attr, void *le_struct, u32 len)
357 {
358         __le32 *le32_ptr = (__le32 *)le_struct;
359         u32 i;
360
361         DEBUGFUNC("fm10k_tlv_attr_get_le_struct");
362
363         /* verify pointers are not NULL */
364         if (!le_struct || !attr)
365                 return FM10K_ERR_PARAM;
366
367         if ((*attr >> FM10K_TLV_LEN_SHIFT) != len)
368                 return FM10K_ERR_PARAM;
369
370         attr++;
371
372         for (i = 0; len; i++, len -= 4)
373                 le32_ptr[i] = FM10K_CPU_TO_LE32(attr[i]);
374
375         return FM10K_SUCCESS;
376 }
377
378 /**
379  *  fm10k_tlv_attr_nest_start - Start a set of nested attributes
380  *  @msg: Pointer to message block
381  *  @attr_id: Attribute ID
382  *
383  *  This function will mark off a new nested region for encapsulating
384  *  a given set of attributes.  The idea is if you wish to place a secondary
385  *  structure within the message this mechanism allows for that.  The
386  *  function will return NULL on failure, and a pointer to the start
387  *  of the nested attributes on success.
388  **/
389 static u32 *fm10k_tlv_attr_nest_start(u32 *msg, u16 attr_id)
390 {
391         u32 *attr;
392
393         DEBUGFUNC("fm10k_tlv_attr_nest_start");
394
395         /* verify pointer is not NULL */
396         if (!msg)
397                 return NULL;
398
399         attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
400
401         attr[0] = attr_id;
402
403         /* return pointer to nest header */
404         return attr;
405 }
406
407 /**
408  *  fm10k_tlv_attr_nest_stop - Stop a set of nested attributes
409  *  @msg: Pointer to message block
410  *
411  *  This function closes off an existing set of nested attributes.  The
412  *  message pointer should be pointing to the parent of the nest.  So in
413  *  the case of a nest within the nest this would be the outer nest pointer.
414  *  This function will return success provided all pointers are valid.
415  **/
416 static s32 fm10k_tlv_attr_nest_stop(u32 *msg)
417 {
418         u32 *attr;
419         u32 len;
420
421         DEBUGFUNC("fm10k_tlv_attr_nest_stop");
422
423         /* verify pointer is not NULL */
424         if (!msg)
425                 return FM10K_ERR_PARAM;
426
427         /* locate the nested header and retrieve its length */
428         attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
429         len = (attr[0] >> FM10K_TLV_LEN_SHIFT) << FM10K_TLV_LEN_SHIFT;
430
431         /* only include nest if data was added to it */
432         if (len) {
433                 len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
434                 *msg += len;
435         }
436
437         return FM10K_SUCCESS;
438 }
439
440 /**
441  *  fm10k_tlv_attr_validate - Validate attribute metadata
442  *  @attr: Pointer to attribute
443  *  @tlv_attr: Type and length info for attribute
444  *
445  *  This function does some basic validation of the input TLV.  It
446  *  verifies the length, and in the case of null terminated strings
447  *  it verifies that the last byte is null.  The function will
448  *  return FM10K_ERR_PARAM if any attribute is malformed, otherwise
449  *  it returns 0.
450  **/
451 STATIC s32 fm10k_tlv_attr_validate(u32 *attr,
452                                    const struct fm10k_tlv_attr *tlv_attr)
453 {
454         u32 attr_id = *attr & FM10K_TLV_ID_MASK;
455         u16 len = *attr >> FM10K_TLV_LEN_SHIFT;
456
457         DEBUGFUNC("fm10k_tlv_attr_validate");
458
459         /* verify this is an attribute and not a message */
460         if (*attr & (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT))
461                 return FM10K_ERR_PARAM;
462
463         /* search through the list of attributes to find a matching ID */
464         while (tlv_attr->id < attr_id)
465                 tlv_attr++;
466
467         /* if didn't find a match then we should exit */
468         if (tlv_attr->id != attr_id)
469                 return FM10K_NOT_IMPLEMENTED;
470
471         /* move to start of attribute data */
472         attr++;
473
474         switch (tlv_attr->type) {
475         case FM10K_TLV_NULL_STRING:
476                 if (!len ||
477                     (attr[(len - 1) / 4] & (0xFF << (8 * ((len - 1) % 4)))))
478                         return FM10K_ERR_PARAM;
479                 if (len > tlv_attr->len)
480                         return FM10K_ERR_PARAM;
481                 break;
482         case FM10K_TLV_MAC_ADDR:
483                 if (len != ETH_ALEN)
484                         return FM10K_ERR_PARAM;
485                 break;
486         case FM10K_TLV_BOOL:
487                 if (len)
488                         return FM10K_ERR_PARAM;
489                 break;
490         case FM10K_TLV_UNSIGNED:
491         case FM10K_TLV_SIGNED:
492                 if (len != tlv_attr->len)
493                         return FM10K_ERR_PARAM;
494                 break;
495         case FM10K_TLV_LE_STRUCT:
496                 /* struct must be 4 byte aligned */
497                 if ((len % 4) || len != tlv_attr->len)
498                         return FM10K_ERR_PARAM;
499                 break;
500         case FM10K_TLV_NESTED:
501                 /* nested attributes must be 4 byte aligned */
502                 if (len % 4)
503                         return FM10K_ERR_PARAM;
504                 break;
505         default:
506                 /* attribute id is mapped to bad value */
507                 return FM10K_ERR_PARAM;
508         }
509
510         return FM10K_SUCCESS;
511 }
512
513 /**
514  *  fm10k_tlv_attr_parse - Parses stream of attribute data
515  *  @attr: Pointer to attribute list
516  *  @results: Pointer array to store pointers to attributes
517  *  @tlv_attr: Type and length info for attributes
518  *
519  *  This function validates a stream of attributes and parses them
520  *  up into an array of pointers stored in results.  The function will
521  *  return FM10K_ERR_PARAM on any input or message error,
522  *  FM10K_NOT_IMPLEMENTED for any attribute that is outside of the array
523  *  and 0 on success.
524  **/
525 static s32 fm10k_tlv_attr_parse(u32 *attr, u32 **results,
526                                 const struct fm10k_tlv_attr *tlv_attr)
527 {
528         u32 i, attr_id, offset = 0;
529         s32 err = 0;
530         u16 len;
531
532         DEBUGFUNC("fm10k_tlv_attr_parse");
533
534         /* verify pointers are not NULL */
535         if (!attr || !results)
536                 return FM10K_ERR_PARAM;
537
538         /* initialize results to NULL */
539         for (i = 0; i < FM10K_TLV_RESULTS_MAX; i++)
540                 results[i] = NULL;
541
542         /* pull length from the message header */
543         len = *attr >> FM10K_TLV_LEN_SHIFT;
544
545         /* no attributes to parse if there is no length */
546         if (!len)
547                 return FM10K_SUCCESS;
548
549         /* no attributes to parse, just raw data, message becomes attribute */
550         if (!tlv_attr) {
551                 results[0] = attr;
552                 return FM10K_SUCCESS;
553         }
554
555         /* move to start of attribute data */
556         attr++;
557
558         /* run through list parsing all attributes */
559         while (offset < len) {
560                 attr_id = *attr & FM10K_TLV_ID_MASK;
561
562                 if (attr_id < FM10K_TLV_RESULTS_MAX)
563                         err = fm10k_tlv_attr_validate(attr, tlv_attr);
564                 else
565                         err = FM10K_NOT_IMPLEMENTED;
566
567                 if (err < 0)
568                         return err;
569                 if (!err)
570                         results[attr_id] = attr;
571
572                 /* update offset */
573                 offset += FM10K_TLV_DWORD_LEN(*attr) * 4;
574
575                 /* move to next attribute */
576                 attr = &attr[FM10K_TLV_DWORD_LEN(*attr)];
577         }
578
579         /* we should find ourselves at the end of the list */
580         if (offset != len)
581                 return FM10K_ERR_PARAM;
582
583         return FM10K_SUCCESS;
584 }
585
586 /**
587  *  fm10k_tlv_msg_parse - Parses message header and calls function handler
588  *  @hw: Pointer to hardware structure
589  *  @msg: Pointer to message
590  *  @mbx: Pointer to mailbox information structure
591  *  @func: Function array containing list of message handling functions
592  *
593  *  This function should be the first function called upon receiving a
594  *  message.  The handler will identify the message type and call the correct
595  *  handler for the given message.  It will return the value from the function
596  *  call on a recognized message type, otherwise it will return
597  *  FM10K_NOT_IMPLEMENTED on an unrecognized type.
598  **/
599 s32 fm10k_tlv_msg_parse(struct fm10k_hw *hw, u32 *msg,
600                         struct fm10k_mbx_info *mbx,
601                         const struct fm10k_msg_data *data)
602 {
603         u32 *results[FM10K_TLV_RESULTS_MAX];
604         u32 msg_id;
605         s32 err;
606
607         DEBUGFUNC("fm10k_tlv_msg_parse");
608
609         /* verify pointer is not NULL */
610         if (!msg || !data)
611                 return FM10K_ERR_PARAM;
612
613         /* verify this is a message and not an attribute */
614         if (!(*msg & (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT)))
615                 return FM10K_ERR_PARAM;
616
617         /* grab message ID */
618         msg_id = *msg & FM10K_TLV_ID_MASK;
619
620         while (data->id < msg_id)
621                 data++;
622
623         /* if we didn't find it then pass it up as an error */
624         if (data->id != msg_id) {
625                 while (data->id != FM10K_TLV_ERROR)
626                         data++;
627         }
628
629         /* parse the attributes into the results list */
630         err = fm10k_tlv_attr_parse(msg, results, data->attr);
631         if (err < 0)
632                 return err;
633
634         return data->func(hw, results, mbx);
635 }
636
637 /**
638  *  fm10k_tlv_msg_error - Default handler for unrecognized TLV message IDs
639  *  @hw: Pointer to hardware structure
640  *  @results: Pointer array to message, results[0] is pointer to message
641  *  @mbx: Unused mailbox pointer
642  *
643  *  This function is a default handler for unrecognized messages.  At a
644  *  a minimum it just indicates that the message requested was
645  *  unimplemented.
646  **/
647 s32 fm10k_tlv_msg_error(struct fm10k_hw *hw, u32 **results,
648                         struct fm10k_mbx_info *mbx)
649 {
650         UNREFERENCED_3PARAMETER(hw, results, mbx);
651         DEBUGOUT1("Unknown message ID %u\n", **results & FM10K_TLV_ID_MASK);
652         return FM10K_NOT_IMPLEMENTED;
653 }
654
655 STATIC const unsigned char test_str[] = "fm10k";
656 STATIC const unsigned char test_mac[ETH_ALEN] = { 0x12, 0x34, 0x56,
657                                                   0x78, 0x9a, 0xbc };
658 STATIC const u16 test_vlan = 0x0FED;
659 STATIC const u64 test_u64 = 0xfedcba9876543210ull;
660 STATIC const u32 test_u32 = 0x87654321;
661 STATIC const u16 test_u16 = 0x8765;
662 STATIC const u8  test_u8  = 0x87;
663 STATIC const s64 test_s64 = -0x123456789abcdef0ll;
664 STATIC const s32 test_s32 = -0x1235678;
665 STATIC const s16 test_s16 = -0x1234;
666 STATIC const s8  test_s8  = -0x12;
667 STATIC const __le32 test_le[2] = { FM10K_CPU_TO_LE32(0x12345678),
668                                    FM10K_CPU_TO_LE32(0x9abcdef0)};
669
670 /* The message below is meant to be used as a test message to demonstrate
671  * how to use the TLV interface and to test the types.  Normally this code
672  * be compiled out by stripping the code wrapped in FM10K_TLV_TEST_MSG
673  */
674 const struct fm10k_tlv_attr fm10k_tlv_msg_test_attr[] = {
675         FM10K_TLV_ATTR_NULL_STRING(FM10K_TEST_MSG_STRING, 80),
676         FM10K_TLV_ATTR_MAC_ADDR(FM10K_TEST_MSG_MAC_ADDR),
677         FM10K_TLV_ATTR_U8(FM10K_TEST_MSG_U8),
678         FM10K_TLV_ATTR_U16(FM10K_TEST_MSG_U16),
679         FM10K_TLV_ATTR_U32(FM10K_TEST_MSG_U32),
680         FM10K_TLV_ATTR_U64(FM10K_TEST_MSG_U64),
681         FM10K_TLV_ATTR_S8(FM10K_TEST_MSG_S8),
682         FM10K_TLV_ATTR_S16(FM10K_TEST_MSG_S16),
683         FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_S32),
684         FM10K_TLV_ATTR_S64(FM10K_TEST_MSG_S64),
685         FM10K_TLV_ATTR_LE_STRUCT(FM10K_TEST_MSG_LE_STRUCT, 8),
686         FM10K_TLV_ATTR_NESTED(FM10K_TEST_MSG_NESTED),
687         FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_RESULT),
688         FM10K_TLV_ATTR_LAST
689 };
690
691 /**
692  *  fm10k_tlv_msg_test_generate_data - Stuff message with data
693  *  @msg: Pointer to message
694  *  @attr_flags: List of flags indicating what attributes to add
695  *
696  *  This function is meant to load a message buffer with attribute data
697  **/
698 STATIC void fm10k_tlv_msg_test_generate_data(u32 *msg, u32 attr_flags)
699 {
700         DEBUGFUNC("fm10k_tlv_msg_test_generate_data");
701
702         if (attr_flags & BIT(FM10K_TEST_MSG_STRING))
703                 fm10k_tlv_attr_put_null_string(msg, FM10K_TEST_MSG_STRING,
704                                                test_str);
705         if (attr_flags & BIT(FM10K_TEST_MSG_MAC_ADDR))
706                 fm10k_tlv_attr_put_mac_vlan(msg, FM10K_TEST_MSG_MAC_ADDR,
707                                             test_mac, test_vlan);
708         if (attr_flags & BIT(FM10K_TEST_MSG_U8))
709                 fm10k_tlv_attr_put_u8(msg, FM10K_TEST_MSG_U8,  test_u8);
710         if (attr_flags & BIT(FM10K_TEST_MSG_U16))
711                 fm10k_tlv_attr_put_u16(msg, FM10K_TEST_MSG_U16, test_u16);
712         if (attr_flags & BIT(FM10K_TEST_MSG_U32))
713                 fm10k_tlv_attr_put_u32(msg, FM10K_TEST_MSG_U32, test_u32);
714         if (attr_flags & BIT(FM10K_TEST_MSG_U64))
715                 fm10k_tlv_attr_put_u64(msg, FM10K_TEST_MSG_U64, test_u64);
716         if (attr_flags & BIT(FM10K_TEST_MSG_S8))
717                 fm10k_tlv_attr_put_s8(msg, FM10K_TEST_MSG_S8,  test_s8);
718         if (attr_flags & BIT(FM10K_TEST_MSG_S16))
719                 fm10k_tlv_attr_put_s16(msg, FM10K_TEST_MSG_S16, test_s16);
720         if (attr_flags & BIT(FM10K_TEST_MSG_S32))
721                 fm10k_tlv_attr_put_s32(msg, FM10K_TEST_MSG_S32, test_s32);
722         if (attr_flags & BIT(FM10K_TEST_MSG_S64))
723                 fm10k_tlv_attr_put_s64(msg, FM10K_TEST_MSG_S64, test_s64);
724         if (attr_flags & BIT(FM10K_TEST_MSG_LE_STRUCT))
725                 fm10k_tlv_attr_put_le_struct(msg, FM10K_TEST_MSG_LE_STRUCT,
726                                              test_le, 8);
727 }
728
729 /**
730  *  fm10k_tlv_msg_test_create - Create a test message testing all attributes
731  *  @msg: Pointer to message
732  *  @attr_flags: List of flags indicating what attributes to add
733  *
734  *  This function is meant to load a message buffer with all attribute types
735  *  including a nested attribute.
736  **/
737 void fm10k_tlv_msg_test_create(u32 *msg, u32 attr_flags)
738 {
739         u32 *nest = NULL;
740
741         DEBUGFUNC("fm10k_tlv_msg_test_create");
742
743         fm10k_tlv_msg_init(msg, FM10K_TLV_MSG_ID_TEST);
744
745         fm10k_tlv_msg_test_generate_data(msg, attr_flags);
746
747         /* check for nested attributes */
748         attr_flags >>= FM10K_TEST_MSG_NESTED;
749
750         if (attr_flags) {
751                 nest = fm10k_tlv_attr_nest_start(msg, FM10K_TEST_MSG_NESTED);
752
753                 fm10k_tlv_msg_test_generate_data(nest, attr_flags);
754
755                 fm10k_tlv_attr_nest_stop(msg);
756         }
757 }
758
759 /**
760  *  fm10k_tlv_msg_test - Validate all results on test message receive
761  *  @hw: Pointer to hardware structure
762  *  @results: Pointer array to attributes in the message
763  *  @mbx: Pointer to mailbox information structure
764  *
765  *  This function does a check to verify all attributes match what the test
766  *  message placed in the message buffer.  It is the default handler
767  *  for TLV test messages.
768  **/
769 s32 fm10k_tlv_msg_test(struct fm10k_hw *hw, u32 **results,
770                        struct fm10k_mbx_info *mbx)
771 {
772         u32 *nest_results[FM10K_TLV_RESULTS_MAX];
773         unsigned char result_str[80];
774         unsigned char result_mac[ETH_ALEN];
775         s32 err = FM10K_SUCCESS;
776         __le32 result_le[2];
777         u16 result_vlan;
778         u64 result_u64;
779         u32 result_u32;
780         u16 result_u16;
781         u8  result_u8;
782         s64 result_s64;
783         s32 result_s32;
784         s16 result_s16;
785         s8  result_s8;
786         u32 reply[3];
787
788         DEBUGFUNC("fm10k_tlv_msg_test");
789
790         /* retrieve results of a previous test */
791         if (!!results[FM10K_TEST_MSG_RESULT])
792                 return fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_RESULT],
793                                               &mbx->test_result);
794
795 parse_nested:
796         if (!!results[FM10K_TEST_MSG_STRING]) {
797                 err = fm10k_tlv_attr_get_null_string(
798                                         results[FM10K_TEST_MSG_STRING],
799                                         result_str);
800                 if (!err && memcmp(test_str, result_str, sizeof(test_str)))
801                         err = FM10K_ERR_INVALID_VALUE;
802                 if (err)
803                         goto report_result;
804         }
805         if (!!results[FM10K_TEST_MSG_MAC_ADDR]) {
806                 err = fm10k_tlv_attr_get_mac_vlan(
807                                         results[FM10K_TEST_MSG_MAC_ADDR],
808                                         result_mac, &result_vlan);
809                 if (!err && memcmp(test_mac, result_mac, ETH_ALEN))
810                         err = FM10K_ERR_INVALID_VALUE;
811                 if (!err && test_vlan != result_vlan)
812                         err = FM10K_ERR_INVALID_VALUE;
813                 if (err)
814                         goto report_result;
815         }
816         if (!!results[FM10K_TEST_MSG_U8]) {
817                 err = fm10k_tlv_attr_get_u8(results[FM10K_TEST_MSG_U8],
818                                             &result_u8);
819                 if (!err && test_u8 != result_u8)
820                         err = FM10K_ERR_INVALID_VALUE;
821                 if (err)
822                         goto report_result;
823         }
824         if (!!results[FM10K_TEST_MSG_U16]) {
825                 err = fm10k_tlv_attr_get_u16(results[FM10K_TEST_MSG_U16],
826                                              &result_u16);
827                 if (!err && test_u16 != result_u16)
828                         err = FM10K_ERR_INVALID_VALUE;
829                 if (err)
830                         goto report_result;
831         }
832         if (!!results[FM10K_TEST_MSG_U32]) {
833                 err = fm10k_tlv_attr_get_u32(results[FM10K_TEST_MSG_U32],
834                                              &result_u32);
835                 if (!err && test_u32 != result_u32)
836                         err = FM10K_ERR_INVALID_VALUE;
837                 if (err)
838                         goto report_result;
839         }
840         if (!!results[FM10K_TEST_MSG_U64]) {
841                 err = fm10k_tlv_attr_get_u64(results[FM10K_TEST_MSG_U64],
842                                              &result_u64);
843                 if (!err && test_u64 != result_u64)
844                         err = FM10K_ERR_INVALID_VALUE;
845                 if (err)
846                         goto report_result;
847         }
848         if (!!results[FM10K_TEST_MSG_S8]) {
849                 err = fm10k_tlv_attr_get_s8(results[FM10K_TEST_MSG_S8],
850                                             &result_s8);
851                 if (!err && test_s8 != result_s8)
852                         err = FM10K_ERR_INVALID_VALUE;
853                 if (err)
854                         goto report_result;
855         }
856         if (!!results[FM10K_TEST_MSG_S16]) {
857                 err = fm10k_tlv_attr_get_s16(results[FM10K_TEST_MSG_S16],
858                                              &result_s16);
859                 if (!err && test_s16 != result_s16)
860                         err = FM10K_ERR_INVALID_VALUE;
861                 if (err)
862                         goto report_result;
863         }
864         if (!!results[FM10K_TEST_MSG_S32]) {
865                 err = fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_S32],
866                                              &result_s32);
867                 if (!err && test_s32 != result_s32)
868                         err = FM10K_ERR_INVALID_VALUE;
869                 if (err)
870                         goto report_result;
871         }
872         if (!!results[FM10K_TEST_MSG_S64]) {
873                 err = fm10k_tlv_attr_get_s64(results[FM10K_TEST_MSG_S64],
874                                              &result_s64);
875                 if (!err && test_s64 != result_s64)
876                         err = FM10K_ERR_INVALID_VALUE;
877                 if (err)
878                         goto report_result;
879         }
880         if (!!results[FM10K_TEST_MSG_LE_STRUCT]) {
881                 err = fm10k_tlv_attr_get_le_struct(
882                                         results[FM10K_TEST_MSG_LE_STRUCT],
883                                         result_le,
884                                         sizeof(result_le));
885                 if (!err && memcmp(test_le, result_le, sizeof(test_le)))
886                         err = FM10K_ERR_INVALID_VALUE;
887                 if (err)
888                         goto report_result;
889         }
890
891         if (!!results[FM10K_TEST_MSG_NESTED]) {
892                 /* clear any pointers */
893                 memset(nest_results, 0, sizeof(nest_results));
894
895                 /* parse the nested attributes into the nest results list */
896                 err = fm10k_tlv_attr_parse(results[FM10K_TEST_MSG_NESTED],
897                                            nest_results,
898                                            fm10k_tlv_msg_test_attr);
899                 if (err)
900                         goto report_result;
901
902                 /* loop back through to the start */
903                 results = nest_results;
904                 goto parse_nested;
905         }
906
907 report_result:
908         /* generate reply with test result */
909         fm10k_tlv_msg_init(reply, FM10K_TLV_MSG_ID_TEST);
910         fm10k_tlv_attr_put_s32(reply, FM10K_TEST_MSG_RESULT, err);
911
912         /* load onto outgoing mailbox */
913         return mbx->ops.enqueue_tx(hw, mbx, reply);
914 }