net/fm10k/base: clean up the logic
[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. Any attributes not found in tlv_attr will be silently
524  *  ignored.
525  **/
526 static s32 fm10k_tlv_attr_parse(u32 *attr, u32 **results,
527                                 const struct fm10k_tlv_attr *tlv_attr)
528 {
529         u32 i, attr_id, offset = 0;
530         s32 err = 0;
531         u16 len;
532
533         DEBUGFUNC("fm10k_tlv_attr_parse");
534
535         /* verify pointers are not NULL */
536         if (!attr || !results)
537                 return FM10K_ERR_PARAM;
538
539         /* initialize results to NULL */
540         for (i = 0; i < FM10K_TLV_RESULTS_MAX; i++)
541                 results[i] = NULL;
542
543         /* pull length from the message header */
544         len = *attr >> FM10K_TLV_LEN_SHIFT;
545
546         /* no attributes to parse if there is no length */
547         if (!len)
548                 return FM10K_SUCCESS;
549
550         /* no attributes to parse, just raw data, message becomes attribute */
551         if (!tlv_attr) {
552                 results[0] = attr;
553                 return FM10K_SUCCESS;
554         }
555
556         /* move to start of attribute data */
557         attr++;
558
559         /* run through list parsing all attributes */
560         while (offset < len) {
561                 attr_id = *attr & FM10K_TLV_ID_MASK;
562
563                 if (attr_id >= FM10K_TLV_RESULTS_MAX)
564                         return FM10K_NOT_IMPLEMENTED;
565
566                 err = fm10k_tlv_attr_validate(attr, tlv_attr);
567                 if (err == FM10K_NOT_IMPLEMENTED)
568                         ; /* silently ignore non-implemented attributes */
569                 else if (err)
570                         return err;
571                 else
572                         results[attr_id] = attr;
573
574                 /* update offset */
575                 offset += FM10K_TLV_DWORD_LEN(*attr) * 4;
576
577                 /* move to next attribute */
578                 attr = &attr[FM10K_TLV_DWORD_LEN(*attr)];
579         }
580
581         /* we should find ourselves at the end of the list */
582         if (offset != len)
583                 return FM10K_ERR_PARAM;
584
585         return FM10K_SUCCESS;
586 }
587
588 /**
589  *  fm10k_tlv_msg_parse - Parses message header and calls function handler
590  *  @hw: Pointer to hardware structure
591  *  @msg: Pointer to message
592  *  @mbx: Pointer to mailbox information structure
593  *  @func: Function array containing list of message handling functions
594  *
595  *  This function should be the first function called upon receiving a
596  *  message.  The handler will identify the message type and call the correct
597  *  handler for the given message.  It will return the value from the function
598  *  call on a recognized message type, otherwise it will return
599  *  FM10K_NOT_IMPLEMENTED on an unrecognized type.
600  **/
601 s32 fm10k_tlv_msg_parse(struct fm10k_hw *hw, u32 *msg,
602                         struct fm10k_mbx_info *mbx,
603                         const struct fm10k_msg_data *data)
604 {
605         u32 *results[FM10K_TLV_RESULTS_MAX];
606         u32 msg_id;
607         s32 err;
608
609         DEBUGFUNC("fm10k_tlv_msg_parse");
610
611         /* verify pointer is not NULL */
612         if (!msg || !data)
613                 return FM10K_ERR_PARAM;
614
615         /* verify this is a message and not an attribute */
616         if (!(*msg & (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT)))
617                 return FM10K_ERR_PARAM;
618
619         /* grab message ID */
620         msg_id = *msg & FM10K_TLV_ID_MASK;
621
622         while (data->id < msg_id)
623                 data++;
624
625         /* if we didn't find it then pass it up as an error */
626         if (data->id != msg_id) {
627                 while (data->id != FM10K_TLV_ERROR)
628                         data++;
629         }
630
631         /* parse the attributes into the results list */
632         err = fm10k_tlv_attr_parse(msg, results, data->attr);
633         if (err < 0)
634                 return err;
635
636         return data->func(hw, results, mbx);
637 }
638
639 /**
640  *  fm10k_tlv_msg_error - Default handler for unrecognized TLV message IDs
641  *  @hw: Pointer to hardware structure
642  *  @results: Pointer array to message, results[0] is pointer to message
643  *  @mbx: Unused mailbox pointer
644  *
645  *  This function is a default handler for unrecognized messages.  At a
646  *  a minimum it just indicates that the message requested was
647  *  unimplemented.
648  **/
649 s32 fm10k_tlv_msg_error(struct fm10k_hw *hw, u32 **results,
650                         struct fm10k_mbx_info *mbx)
651 {
652         UNREFERENCED_3PARAMETER(hw, results, mbx);
653         DEBUGOUT1("Unknown message ID %u\n", **results & FM10K_TLV_ID_MASK);
654         return FM10K_NOT_IMPLEMENTED;
655 }
656
657 STATIC const unsigned char test_str[] = "fm10k";
658 STATIC const unsigned char test_mac[ETH_ALEN] = { 0x12, 0x34, 0x56,
659                                                   0x78, 0x9a, 0xbc };
660 STATIC const u16 test_vlan = 0x0FED;
661 STATIC const u64 test_u64 = 0xfedcba9876543210ull;
662 STATIC const u32 test_u32 = 0x87654321;
663 STATIC const u16 test_u16 = 0x8765;
664 STATIC const u8  test_u8  = 0x87;
665 STATIC const s64 test_s64 = -0x123456789abcdef0ll;
666 STATIC const s32 test_s32 = -0x1235678;
667 STATIC const s16 test_s16 = -0x1234;
668 STATIC const s8  test_s8  = -0x12;
669 STATIC const __le32 test_le[2] = { FM10K_CPU_TO_LE32(0x12345678),
670                                    FM10K_CPU_TO_LE32(0x9abcdef0)};
671
672 /* The message below is meant to be used as a test message to demonstrate
673  * how to use the TLV interface and to test the types.  Normally this code
674  * be compiled out by stripping the code wrapped in FM10K_TLV_TEST_MSG
675  */
676 const struct fm10k_tlv_attr fm10k_tlv_msg_test_attr[] = {
677         FM10K_TLV_ATTR_NULL_STRING(FM10K_TEST_MSG_STRING, 80),
678         FM10K_TLV_ATTR_MAC_ADDR(FM10K_TEST_MSG_MAC_ADDR),
679         FM10K_TLV_ATTR_U8(FM10K_TEST_MSG_U8),
680         FM10K_TLV_ATTR_U16(FM10K_TEST_MSG_U16),
681         FM10K_TLV_ATTR_U32(FM10K_TEST_MSG_U32),
682         FM10K_TLV_ATTR_U64(FM10K_TEST_MSG_U64),
683         FM10K_TLV_ATTR_S8(FM10K_TEST_MSG_S8),
684         FM10K_TLV_ATTR_S16(FM10K_TEST_MSG_S16),
685         FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_S32),
686         FM10K_TLV_ATTR_S64(FM10K_TEST_MSG_S64),
687         FM10K_TLV_ATTR_LE_STRUCT(FM10K_TEST_MSG_LE_STRUCT, 8),
688         FM10K_TLV_ATTR_NESTED(FM10K_TEST_MSG_NESTED),
689         FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_RESULT),
690         FM10K_TLV_ATTR_LAST
691 };
692
693 /**
694  *  fm10k_tlv_msg_test_generate_data - Stuff message with data
695  *  @msg: Pointer to message
696  *  @attr_flags: List of flags indicating what attributes to add
697  *
698  *  This function is meant to load a message buffer with attribute data
699  **/
700 STATIC void fm10k_tlv_msg_test_generate_data(u32 *msg, u32 attr_flags)
701 {
702         DEBUGFUNC("fm10k_tlv_msg_test_generate_data");
703
704         if (attr_flags & BIT(FM10K_TEST_MSG_STRING))
705                 fm10k_tlv_attr_put_null_string(msg, FM10K_TEST_MSG_STRING,
706                                                test_str);
707         if (attr_flags & BIT(FM10K_TEST_MSG_MAC_ADDR))
708                 fm10k_tlv_attr_put_mac_vlan(msg, FM10K_TEST_MSG_MAC_ADDR,
709                                             test_mac, test_vlan);
710         if (attr_flags & BIT(FM10K_TEST_MSG_U8))
711                 fm10k_tlv_attr_put_u8(msg, FM10K_TEST_MSG_U8,  test_u8);
712         if (attr_flags & BIT(FM10K_TEST_MSG_U16))
713                 fm10k_tlv_attr_put_u16(msg, FM10K_TEST_MSG_U16, test_u16);
714         if (attr_flags & BIT(FM10K_TEST_MSG_U32))
715                 fm10k_tlv_attr_put_u32(msg, FM10K_TEST_MSG_U32, test_u32);
716         if (attr_flags & BIT(FM10K_TEST_MSG_U64))
717                 fm10k_tlv_attr_put_u64(msg, FM10K_TEST_MSG_U64, test_u64);
718         if (attr_flags & BIT(FM10K_TEST_MSG_S8))
719                 fm10k_tlv_attr_put_s8(msg, FM10K_TEST_MSG_S8,  test_s8);
720         if (attr_flags & BIT(FM10K_TEST_MSG_S16))
721                 fm10k_tlv_attr_put_s16(msg, FM10K_TEST_MSG_S16, test_s16);
722         if (attr_flags & BIT(FM10K_TEST_MSG_S32))
723                 fm10k_tlv_attr_put_s32(msg, FM10K_TEST_MSG_S32, test_s32);
724         if (attr_flags & BIT(FM10K_TEST_MSG_S64))
725                 fm10k_tlv_attr_put_s64(msg, FM10K_TEST_MSG_S64, test_s64);
726         if (attr_flags & BIT(FM10K_TEST_MSG_LE_STRUCT))
727                 fm10k_tlv_attr_put_le_struct(msg, FM10K_TEST_MSG_LE_STRUCT,
728                                              test_le, 8);
729 }
730
731 /**
732  *  fm10k_tlv_msg_test_create - Create a test message testing all attributes
733  *  @msg: Pointer to message
734  *  @attr_flags: List of flags indicating what attributes to add
735  *
736  *  This function is meant to load a message buffer with all attribute types
737  *  including a nested attribute.
738  **/
739 void fm10k_tlv_msg_test_create(u32 *msg, u32 attr_flags)
740 {
741         u32 *nest = NULL;
742
743         DEBUGFUNC("fm10k_tlv_msg_test_create");
744
745         fm10k_tlv_msg_init(msg, FM10K_TLV_MSG_ID_TEST);
746
747         fm10k_tlv_msg_test_generate_data(msg, attr_flags);
748
749         /* check for nested attributes */
750         attr_flags >>= FM10K_TEST_MSG_NESTED;
751
752         if (attr_flags) {
753                 nest = fm10k_tlv_attr_nest_start(msg, FM10K_TEST_MSG_NESTED);
754
755                 fm10k_tlv_msg_test_generate_data(nest, attr_flags);
756
757                 fm10k_tlv_attr_nest_stop(msg);
758         }
759 }
760
761 /**
762  *  fm10k_tlv_msg_test - Validate all results on test message receive
763  *  @hw: Pointer to hardware structure
764  *  @results: Pointer array to attributes in the message
765  *  @mbx: Pointer to mailbox information structure
766  *
767  *  This function does a check to verify all attributes match what the test
768  *  message placed in the message buffer.  It is the default handler
769  *  for TLV test messages.
770  **/
771 s32 fm10k_tlv_msg_test(struct fm10k_hw *hw, u32 **results,
772                        struct fm10k_mbx_info *mbx)
773 {
774         u32 *nest_results[FM10K_TLV_RESULTS_MAX];
775         unsigned char result_str[80];
776         unsigned char result_mac[ETH_ALEN];
777         s32 err = FM10K_SUCCESS;
778         __le32 result_le[2];
779         u16 result_vlan;
780         u64 result_u64;
781         u32 result_u32;
782         u16 result_u16;
783         u8  result_u8;
784         s64 result_s64;
785         s32 result_s32;
786         s16 result_s16;
787         s8  result_s8;
788         u32 reply[3];
789
790         DEBUGFUNC("fm10k_tlv_msg_test");
791
792         /* retrieve results of a previous test */
793         if (!!results[FM10K_TEST_MSG_RESULT])
794                 return fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_RESULT],
795                                               &mbx->test_result);
796
797 parse_nested:
798         if (!!results[FM10K_TEST_MSG_STRING]) {
799                 err = fm10k_tlv_attr_get_null_string(
800                                         results[FM10K_TEST_MSG_STRING],
801                                         result_str);
802                 if (!err && memcmp(test_str, result_str, sizeof(test_str)))
803                         err = FM10K_ERR_INVALID_VALUE;
804                 if (err)
805                         goto report_result;
806         }
807         if (!!results[FM10K_TEST_MSG_MAC_ADDR]) {
808                 err = fm10k_tlv_attr_get_mac_vlan(
809                                         results[FM10K_TEST_MSG_MAC_ADDR],
810                                         result_mac, &result_vlan);
811                 if (!err && memcmp(test_mac, result_mac, ETH_ALEN))
812                         err = FM10K_ERR_INVALID_VALUE;
813                 if (!err && test_vlan != result_vlan)
814                         err = FM10K_ERR_INVALID_VALUE;
815                 if (err)
816                         goto report_result;
817         }
818         if (!!results[FM10K_TEST_MSG_U8]) {
819                 err = fm10k_tlv_attr_get_u8(results[FM10K_TEST_MSG_U8],
820                                             &result_u8);
821                 if (!err && test_u8 != result_u8)
822                         err = FM10K_ERR_INVALID_VALUE;
823                 if (err)
824                         goto report_result;
825         }
826         if (!!results[FM10K_TEST_MSG_U16]) {
827                 err = fm10k_tlv_attr_get_u16(results[FM10K_TEST_MSG_U16],
828                                              &result_u16);
829                 if (!err && test_u16 != result_u16)
830                         err = FM10K_ERR_INVALID_VALUE;
831                 if (err)
832                         goto report_result;
833         }
834         if (!!results[FM10K_TEST_MSG_U32]) {
835                 err = fm10k_tlv_attr_get_u32(results[FM10K_TEST_MSG_U32],
836                                              &result_u32);
837                 if (!err && test_u32 != result_u32)
838                         err = FM10K_ERR_INVALID_VALUE;
839                 if (err)
840                         goto report_result;
841         }
842         if (!!results[FM10K_TEST_MSG_U64]) {
843                 err = fm10k_tlv_attr_get_u64(results[FM10K_TEST_MSG_U64],
844                                              &result_u64);
845                 if (!err && test_u64 != result_u64)
846                         err = FM10K_ERR_INVALID_VALUE;
847                 if (err)
848                         goto report_result;
849         }
850         if (!!results[FM10K_TEST_MSG_S8]) {
851                 err = fm10k_tlv_attr_get_s8(results[FM10K_TEST_MSG_S8],
852                                             &result_s8);
853                 if (!err && test_s8 != result_s8)
854                         err = FM10K_ERR_INVALID_VALUE;
855                 if (err)
856                         goto report_result;
857         }
858         if (!!results[FM10K_TEST_MSG_S16]) {
859                 err = fm10k_tlv_attr_get_s16(results[FM10K_TEST_MSG_S16],
860                                              &result_s16);
861                 if (!err && test_s16 != result_s16)
862                         err = FM10K_ERR_INVALID_VALUE;
863                 if (err)
864                         goto report_result;
865         }
866         if (!!results[FM10K_TEST_MSG_S32]) {
867                 err = fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_S32],
868                                              &result_s32);
869                 if (!err && test_s32 != result_s32)
870                         err = FM10K_ERR_INVALID_VALUE;
871                 if (err)
872                         goto report_result;
873         }
874         if (!!results[FM10K_TEST_MSG_S64]) {
875                 err = fm10k_tlv_attr_get_s64(results[FM10K_TEST_MSG_S64],
876                                              &result_s64);
877                 if (!err && test_s64 != result_s64)
878                         err = FM10K_ERR_INVALID_VALUE;
879                 if (err)
880                         goto report_result;
881         }
882         if (!!results[FM10K_TEST_MSG_LE_STRUCT]) {
883                 err = fm10k_tlv_attr_get_le_struct(
884                                         results[FM10K_TEST_MSG_LE_STRUCT],
885                                         result_le,
886                                         sizeof(result_le));
887                 if (!err && memcmp(test_le, result_le, sizeof(test_le)))
888                         err = FM10K_ERR_INVALID_VALUE;
889                 if (err)
890                         goto report_result;
891         }
892
893         if (!!results[FM10K_TEST_MSG_NESTED]) {
894                 /* clear any pointers */
895                 memset(nest_results, 0, sizeof(nest_results));
896
897                 /* parse the nested attributes into the nest results list */
898                 err = fm10k_tlv_attr_parse(results[FM10K_TEST_MSG_NESTED],
899                                            nest_results,
900                                            fm10k_tlv_msg_test_attr);
901                 if (err)
902                         goto report_result;
903
904                 /* loop back through to the start */
905                 results = nest_results;
906                 goto parse_nested;
907         }
908
909 report_result:
910         /* generate reply with test result */
911         fm10k_tlv_msg_init(reply, FM10K_TLV_MSG_ID_TEST);
912         fm10k_tlv_attr_put_s32(reply, FM10K_TEST_MSG_RESULT, err);
913
914         /* load onto outgoing mailbox */
915         return mbx->ops.enqueue_tx(hw, mbx, reply);
916 }