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