]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/dpdk/drivers/net/fm10k/base/fm10k_tlv.c
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / seastar / dpdk / 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 }