0001
0002
0003
0004 #include "fm10k_tlv.h"
0005
0006
0007
0008
0009
0010
0011
0012
0013 s32 fm10k_tlv_msg_init(u32 *msg, u16 msg_id)
0014 {
0015
0016 if (!msg)
0017 return FM10K_ERR_PARAM;
0018
0019 *msg = (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT) | msg_id;
0020
0021 return 0;
0022 }
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034 static s32 fm10k_tlv_attr_put_null_string(u32 *msg, u16 attr_id,
0035 const unsigned char *string)
0036 {
0037 u32 attr_data = 0, len = 0;
0038 u32 *attr;
0039
0040
0041 if (!string || !msg)
0042 return FM10K_ERR_PARAM;
0043
0044 attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
0045
0046
0047 do {
0048
0049 if (len && !(len % 4)) {
0050 attr[len / 4] = attr_data;
0051 attr_data = 0;
0052 }
0053
0054
0055 attr_data |= (u32)(*string) << (8 * (len % 4));
0056 len++;
0057
0058
0059 } while (*(string++));
0060
0061
0062 attr[(len + 3) / 4] = attr_data;
0063
0064
0065 len <<= FM10K_TLV_LEN_SHIFT;
0066 attr[0] = len | attr_id;
0067
0068
0069 len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
0070 *msg += FM10K_TLV_LEN_ALIGN(len);
0071
0072 return 0;
0073 }
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084 static s32 fm10k_tlv_attr_get_null_string(u32 *attr, unsigned char *string)
0085 {
0086 u32 len;
0087
0088
0089 if (!string || !attr)
0090 return FM10K_ERR_PARAM;
0091
0092 len = *attr >> FM10K_TLV_LEN_SHIFT;
0093 attr++;
0094
0095 while (len--)
0096 string[len] = (u8)(attr[len / 4] >> (8 * (len % 4)));
0097
0098 return 0;
0099 }
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112 s32 fm10k_tlv_attr_put_mac_vlan(u32 *msg, u16 attr_id,
0113 const u8 *mac_addr, u16 vlan)
0114 {
0115 u32 len = ETH_ALEN << FM10K_TLV_LEN_SHIFT;
0116 u32 *attr;
0117
0118
0119 if (!msg || !mac_addr)
0120 return FM10K_ERR_PARAM;
0121
0122 attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
0123
0124
0125 attr[0] = len | attr_id;
0126
0127
0128 attr[1] = le32_to_cpu(*(const __le32 *)&mac_addr[0]);
0129 attr[2] = le16_to_cpu(*(const __le16 *)&mac_addr[4]);
0130 attr[2] |= (u32)vlan << 16;
0131
0132
0133 len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
0134 *msg += FM10K_TLV_LEN_ALIGN(len);
0135
0136 return 0;
0137 }
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149 s32 fm10k_tlv_attr_get_mac_vlan(u32 *attr, u8 *mac_addr, u16 *vlan)
0150 {
0151
0152 if (!mac_addr || !attr)
0153 return FM10K_ERR_PARAM;
0154
0155 *(__le32 *)&mac_addr[0] = cpu_to_le32(attr[1]);
0156 *(__le16 *)&mac_addr[4] = cpu_to_le16((u16)(attr[2]));
0157 *vlan = (u16)(attr[2] >> 16);
0158
0159 return 0;
0160 }
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172 s32 fm10k_tlv_attr_put_bool(u32 *msg, u16 attr_id)
0173 {
0174
0175 if (!msg)
0176 return FM10K_ERR_PARAM;
0177
0178
0179 msg[FM10K_TLV_DWORD_LEN(*msg)] = attr_id;
0180
0181
0182 *msg += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
0183
0184 return 0;
0185 }
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198 s32 fm10k_tlv_attr_put_value(u32 *msg, u16 attr_id, s64 value, u32 len)
0199 {
0200 u32 *attr;
0201
0202
0203 if (!msg || !len || len > 8 || (len & (len - 1)))
0204 return FM10K_ERR_PARAM;
0205
0206 attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
0207
0208 if (len < 4) {
0209 attr[1] = (u32)value & (BIT(8 * len) - 1);
0210 } else {
0211 attr[1] = (u32)value;
0212 if (len > 4)
0213 attr[2] = (u32)(value >> 32);
0214 }
0215
0216
0217 len <<= FM10K_TLV_LEN_SHIFT;
0218 attr[0] = len | attr_id;
0219
0220
0221 len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
0222 *msg += FM10K_TLV_LEN_ALIGN(len);
0223
0224 return 0;
0225 }
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238 s32 fm10k_tlv_attr_get_value(u32 *attr, void *value, u32 len)
0239 {
0240
0241 if (!attr || !value)
0242 return FM10K_ERR_PARAM;
0243
0244 if ((*attr >> FM10K_TLV_LEN_SHIFT) != len)
0245 return FM10K_ERR_PARAM;
0246
0247 if (len == 8)
0248 *(u64 *)value = ((u64)attr[2] << 32) | attr[1];
0249 else if (len == 4)
0250 *(u32 *)value = attr[1];
0251 else if (len == 2)
0252 *(u16 *)value = (u16)attr[1];
0253 else
0254 *(u8 *)value = (u8)attr[1];
0255
0256 return 0;
0257 }
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270 s32 fm10k_tlv_attr_put_le_struct(u32 *msg, u16 attr_id,
0271 const void *le_struct, u32 len)
0272 {
0273 const __le32 *le32_ptr = (const __le32 *)le_struct;
0274 u32 *attr;
0275 u32 i;
0276
0277
0278 if (!msg || !len || (len % 4))
0279 return FM10K_ERR_PARAM;
0280
0281 attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
0282
0283
0284 for (i = 0; i < (len / 4); i++)
0285 attr[i + 1] = le32_to_cpu(le32_ptr[i]);
0286
0287
0288 len <<= FM10K_TLV_LEN_SHIFT;
0289 attr[0] = len | attr_id;
0290
0291
0292 len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
0293 *msg += FM10K_TLV_LEN_ALIGN(len);
0294
0295 return 0;
0296 }
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309 s32 fm10k_tlv_attr_get_le_struct(u32 *attr, void *le_struct, u32 len)
0310 {
0311 __le32 *le32_ptr = (__le32 *)le_struct;
0312 u32 i;
0313
0314
0315 if (!le_struct || !attr)
0316 return FM10K_ERR_PARAM;
0317
0318 if ((*attr >> FM10K_TLV_LEN_SHIFT) != len)
0319 return FM10K_ERR_PARAM;
0320
0321 attr++;
0322
0323 for (i = 0; len; i++, len -= 4)
0324 le32_ptr[i] = cpu_to_le32(attr[i]);
0325
0326 return 0;
0327 }
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340 static u32 *fm10k_tlv_attr_nest_start(u32 *msg, u16 attr_id)
0341 {
0342 u32 *attr;
0343
0344
0345 if (!msg)
0346 return NULL;
0347
0348 attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
0349
0350 attr[0] = attr_id;
0351
0352
0353 return attr;
0354 }
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365 static s32 fm10k_tlv_attr_nest_stop(u32 *msg)
0366 {
0367 u32 *attr;
0368 u32 len;
0369
0370
0371 if (!msg)
0372 return FM10K_ERR_PARAM;
0373
0374
0375 attr = &msg[FM10K_TLV_DWORD_LEN(*msg)];
0376 len = (attr[0] >> FM10K_TLV_LEN_SHIFT) << FM10K_TLV_LEN_SHIFT;
0377
0378
0379 if (len) {
0380 len += FM10K_TLV_HDR_LEN << FM10K_TLV_LEN_SHIFT;
0381 *msg += len;
0382 }
0383
0384 return 0;
0385 }
0386
0387
0388
0389
0390
0391
0392
0393
0394
0395
0396
0397
0398 static s32 fm10k_tlv_attr_validate(u32 *attr,
0399 const struct fm10k_tlv_attr *tlv_attr)
0400 {
0401 u32 attr_id = *attr & FM10K_TLV_ID_MASK;
0402 u16 len = *attr >> FM10K_TLV_LEN_SHIFT;
0403
0404
0405 if (*attr & (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT))
0406 return FM10K_ERR_PARAM;
0407
0408
0409 while (tlv_attr->id < attr_id)
0410 tlv_attr++;
0411
0412
0413 if (tlv_attr->id != attr_id)
0414 return FM10K_NOT_IMPLEMENTED;
0415
0416
0417 attr++;
0418
0419 switch (tlv_attr->type) {
0420 case FM10K_TLV_NULL_STRING:
0421 if (!len ||
0422 (attr[(len - 1) / 4] & (0xFF << (8 * ((len - 1) % 4)))))
0423 return FM10K_ERR_PARAM;
0424 if (len > tlv_attr->len)
0425 return FM10K_ERR_PARAM;
0426 break;
0427 case FM10K_TLV_MAC_ADDR:
0428 if (len != ETH_ALEN)
0429 return FM10K_ERR_PARAM;
0430 break;
0431 case FM10K_TLV_BOOL:
0432 if (len)
0433 return FM10K_ERR_PARAM;
0434 break;
0435 case FM10K_TLV_UNSIGNED:
0436 case FM10K_TLV_SIGNED:
0437 if (len != tlv_attr->len)
0438 return FM10K_ERR_PARAM;
0439 break;
0440 case FM10K_TLV_LE_STRUCT:
0441
0442 if ((len % 4) || len != tlv_attr->len)
0443 return FM10K_ERR_PARAM;
0444 break;
0445 case FM10K_TLV_NESTED:
0446
0447 if (len % 4)
0448 return FM10K_ERR_PARAM;
0449 break;
0450 default:
0451
0452 return FM10K_ERR_PARAM;
0453 }
0454
0455 return 0;
0456 }
0457
0458
0459
0460
0461
0462
0463
0464
0465
0466
0467
0468
0469
0470
0471 static s32 fm10k_tlv_attr_parse(u32 *attr, u32 **results,
0472 const struct fm10k_tlv_attr *tlv_attr)
0473 {
0474 u32 i, attr_id, offset = 0;
0475 s32 err;
0476 u16 len;
0477
0478
0479 if (!attr || !results)
0480 return FM10K_ERR_PARAM;
0481
0482
0483 for (i = 0; i < FM10K_TLV_RESULTS_MAX; i++)
0484 results[i] = NULL;
0485
0486
0487 len = *attr >> FM10K_TLV_LEN_SHIFT;
0488
0489
0490 if (!len)
0491 return 0;
0492
0493
0494 if (!tlv_attr) {
0495 results[0] = attr;
0496 return 0;
0497 }
0498
0499
0500 attr++;
0501
0502
0503 while (offset < len) {
0504 attr_id = *attr & FM10K_TLV_ID_MASK;
0505
0506 if (attr_id >= FM10K_TLV_RESULTS_MAX)
0507 return FM10K_NOT_IMPLEMENTED;
0508
0509 err = fm10k_tlv_attr_validate(attr, tlv_attr);
0510 if (err == FM10K_NOT_IMPLEMENTED)
0511 ;
0512 else if (err)
0513 return err;
0514 else
0515 results[attr_id] = attr;
0516
0517
0518 offset += FM10K_TLV_DWORD_LEN(*attr) * 4;
0519
0520
0521 attr = &attr[FM10K_TLV_DWORD_LEN(*attr)];
0522 }
0523
0524
0525 if (offset != len)
0526 return FM10K_ERR_PARAM;
0527
0528 return 0;
0529 }
0530
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540
0541
0542
0543
0544 s32 fm10k_tlv_msg_parse(struct fm10k_hw *hw, u32 *msg,
0545 struct fm10k_mbx_info *mbx,
0546 const struct fm10k_msg_data *data)
0547 {
0548 u32 *results[FM10K_TLV_RESULTS_MAX];
0549 u32 msg_id;
0550 s32 err;
0551
0552
0553 if (!msg || !data)
0554 return FM10K_ERR_PARAM;
0555
0556
0557 if (!(*msg & (FM10K_TLV_FLAGS_MSG << FM10K_TLV_FLAGS_SHIFT)))
0558 return FM10K_ERR_PARAM;
0559
0560
0561 msg_id = *msg & FM10K_TLV_ID_MASK;
0562
0563 while (data->id < msg_id)
0564 data++;
0565
0566
0567 if (data->id != msg_id) {
0568 while (data->id != FM10K_TLV_ERROR)
0569 data++;
0570 }
0571
0572
0573 err = fm10k_tlv_attr_parse(msg, results, data->attr);
0574 if (err < 0)
0575 return err;
0576
0577 return data->func(hw, results, mbx);
0578 }
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590 s32 fm10k_tlv_msg_error(struct fm10k_hw __always_unused *hw,
0591 u32 __always_unused **results,
0592 struct fm10k_mbx_info __always_unused *mbx)
0593 {
0594 return FM10K_NOT_IMPLEMENTED;
0595 }
0596
0597 static const unsigned char test_str[] = "fm10k";
0598 static const unsigned char test_mac[ETH_ALEN] = { 0x12, 0x34, 0x56,
0599 0x78, 0x9a, 0xbc };
0600 static const u16 test_vlan = 0x0FED;
0601 static const u64 test_u64 = 0xfedcba9876543210ull;
0602 static const u32 test_u32 = 0x87654321;
0603 static const u16 test_u16 = 0x8765;
0604 static const u8 test_u8 = 0x87;
0605 static const s64 test_s64 = -0x123456789abcdef0ll;
0606 static const s32 test_s32 = -0x1235678;
0607 static const s16 test_s16 = -0x1234;
0608 static const s8 test_s8 = -0x12;
0609 static const __le32 test_le[2] = { cpu_to_le32(0x12345678),
0610 cpu_to_le32(0x9abcdef0)};
0611
0612
0613
0614
0615
0616 const struct fm10k_tlv_attr fm10k_tlv_msg_test_attr[] = {
0617 FM10K_TLV_ATTR_NULL_STRING(FM10K_TEST_MSG_STRING, 80),
0618 FM10K_TLV_ATTR_MAC_ADDR(FM10K_TEST_MSG_MAC_ADDR),
0619 FM10K_TLV_ATTR_U8(FM10K_TEST_MSG_U8),
0620 FM10K_TLV_ATTR_U16(FM10K_TEST_MSG_U16),
0621 FM10K_TLV_ATTR_U32(FM10K_TEST_MSG_U32),
0622 FM10K_TLV_ATTR_U64(FM10K_TEST_MSG_U64),
0623 FM10K_TLV_ATTR_S8(FM10K_TEST_MSG_S8),
0624 FM10K_TLV_ATTR_S16(FM10K_TEST_MSG_S16),
0625 FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_S32),
0626 FM10K_TLV_ATTR_S64(FM10K_TEST_MSG_S64),
0627 FM10K_TLV_ATTR_LE_STRUCT(FM10K_TEST_MSG_LE_STRUCT, 8),
0628 FM10K_TLV_ATTR_NESTED(FM10K_TEST_MSG_NESTED),
0629 FM10K_TLV_ATTR_S32(FM10K_TEST_MSG_RESULT),
0630 FM10K_TLV_ATTR_LAST
0631 };
0632
0633
0634
0635
0636
0637
0638
0639
0640 static void fm10k_tlv_msg_test_generate_data(u32 *msg, u32 attr_flags)
0641 {
0642 if (attr_flags & BIT(FM10K_TEST_MSG_STRING))
0643 fm10k_tlv_attr_put_null_string(msg, FM10K_TEST_MSG_STRING,
0644 test_str);
0645 if (attr_flags & BIT(FM10K_TEST_MSG_MAC_ADDR))
0646 fm10k_tlv_attr_put_mac_vlan(msg, FM10K_TEST_MSG_MAC_ADDR,
0647 test_mac, test_vlan);
0648 if (attr_flags & BIT(FM10K_TEST_MSG_U8))
0649 fm10k_tlv_attr_put_u8(msg, FM10K_TEST_MSG_U8, test_u8);
0650 if (attr_flags & BIT(FM10K_TEST_MSG_U16))
0651 fm10k_tlv_attr_put_u16(msg, FM10K_TEST_MSG_U16, test_u16);
0652 if (attr_flags & BIT(FM10K_TEST_MSG_U32))
0653 fm10k_tlv_attr_put_u32(msg, FM10K_TEST_MSG_U32, test_u32);
0654 if (attr_flags & BIT(FM10K_TEST_MSG_U64))
0655 fm10k_tlv_attr_put_u64(msg, FM10K_TEST_MSG_U64, test_u64);
0656 if (attr_flags & BIT(FM10K_TEST_MSG_S8))
0657 fm10k_tlv_attr_put_s8(msg, FM10K_TEST_MSG_S8, test_s8);
0658 if (attr_flags & BIT(FM10K_TEST_MSG_S16))
0659 fm10k_tlv_attr_put_s16(msg, FM10K_TEST_MSG_S16, test_s16);
0660 if (attr_flags & BIT(FM10K_TEST_MSG_S32))
0661 fm10k_tlv_attr_put_s32(msg, FM10K_TEST_MSG_S32, test_s32);
0662 if (attr_flags & BIT(FM10K_TEST_MSG_S64))
0663 fm10k_tlv_attr_put_s64(msg, FM10K_TEST_MSG_S64, test_s64);
0664 if (attr_flags & BIT(FM10K_TEST_MSG_LE_STRUCT))
0665 fm10k_tlv_attr_put_le_struct(msg, FM10K_TEST_MSG_LE_STRUCT,
0666 test_le, 8);
0667 }
0668
0669
0670
0671
0672
0673
0674
0675
0676
0677 void fm10k_tlv_msg_test_create(u32 *msg, u32 attr_flags)
0678 {
0679 u32 *nest = NULL;
0680
0681 fm10k_tlv_msg_init(msg, FM10K_TLV_MSG_ID_TEST);
0682
0683 fm10k_tlv_msg_test_generate_data(msg, attr_flags);
0684
0685
0686 attr_flags >>= FM10K_TEST_MSG_NESTED;
0687
0688 if (attr_flags) {
0689 nest = fm10k_tlv_attr_nest_start(msg, FM10K_TEST_MSG_NESTED);
0690
0691 fm10k_tlv_msg_test_generate_data(nest, attr_flags);
0692
0693 fm10k_tlv_attr_nest_stop(msg);
0694 }
0695 }
0696
0697
0698
0699
0700
0701
0702
0703
0704
0705
0706
0707 s32 fm10k_tlv_msg_test(struct fm10k_hw *hw, u32 **results,
0708 struct fm10k_mbx_info *mbx)
0709 {
0710 u32 *nest_results[FM10K_TLV_RESULTS_MAX];
0711 unsigned char result_str[80];
0712 unsigned char result_mac[ETH_ALEN];
0713 s32 err = 0;
0714 __le32 result_le[2];
0715 u16 result_vlan;
0716 u64 result_u64;
0717 u32 result_u32;
0718 u16 result_u16;
0719 u8 result_u8;
0720 s64 result_s64;
0721 s32 result_s32;
0722 s16 result_s16;
0723 s8 result_s8;
0724 u32 reply[3];
0725
0726
0727 if (!!results[FM10K_TEST_MSG_RESULT])
0728 return fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_RESULT],
0729 &mbx->test_result);
0730
0731 parse_nested:
0732 if (!!results[FM10K_TEST_MSG_STRING]) {
0733 err = fm10k_tlv_attr_get_null_string(
0734 results[FM10K_TEST_MSG_STRING],
0735 result_str);
0736 if (!err && memcmp(test_str, result_str, sizeof(test_str)))
0737 err = FM10K_ERR_INVALID_VALUE;
0738 if (err)
0739 goto report_result;
0740 }
0741 if (!!results[FM10K_TEST_MSG_MAC_ADDR]) {
0742 err = fm10k_tlv_attr_get_mac_vlan(
0743 results[FM10K_TEST_MSG_MAC_ADDR],
0744 result_mac, &result_vlan);
0745 if (!err && !ether_addr_equal(test_mac, result_mac))
0746 err = FM10K_ERR_INVALID_VALUE;
0747 if (!err && test_vlan != result_vlan)
0748 err = FM10K_ERR_INVALID_VALUE;
0749 if (err)
0750 goto report_result;
0751 }
0752 if (!!results[FM10K_TEST_MSG_U8]) {
0753 err = fm10k_tlv_attr_get_u8(results[FM10K_TEST_MSG_U8],
0754 &result_u8);
0755 if (!err && test_u8 != result_u8)
0756 err = FM10K_ERR_INVALID_VALUE;
0757 if (err)
0758 goto report_result;
0759 }
0760 if (!!results[FM10K_TEST_MSG_U16]) {
0761 err = fm10k_tlv_attr_get_u16(results[FM10K_TEST_MSG_U16],
0762 &result_u16);
0763 if (!err && test_u16 != result_u16)
0764 err = FM10K_ERR_INVALID_VALUE;
0765 if (err)
0766 goto report_result;
0767 }
0768 if (!!results[FM10K_TEST_MSG_U32]) {
0769 err = fm10k_tlv_attr_get_u32(results[FM10K_TEST_MSG_U32],
0770 &result_u32);
0771 if (!err && test_u32 != result_u32)
0772 err = FM10K_ERR_INVALID_VALUE;
0773 if (err)
0774 goto report_result;
0775 }
0776 if (!!results[FM10K_TEST_MSG_U64]) {
0777 err = fm10k_tlv_attr_get_u64(results[FM10K_TEST_MSG_U64],
0778 &result_u64);
0779 if (!err && test_u64 != result_u64)
0780 err = FM10K_ERR_INVALID_VALUE;
0781 if (err)
0782 goto report_result;
0783 }
0784 if (!!results[FM10K_TEST_MSG_S8]) {
0785 err = fm10k_tlv_attr_get_s8(results[FM10K_TEST_MSG_S8],
0786 &result_s8);
0787 if (!err && test_s8 != result_s8)
0788 err = FM10K_ERR_INVALID_VALUE;
0789 if (err)
0790 goto report_result;
0791 }
0792 if (!!results[FM10K_TEST_MSG_S16]) {
0793 err = fm10k_tlv_attr_get_s16(results[FM10K_TEST_MSG_S16],
0794 &result_s16);
0795 if (!err && test_s16 != result_s16)
0796 err = FM10K_ERR_INVALID_VALUE;
0797 if (err)
0798 goto report_result;
0799 }
0800 if (!!results[FM10K_TEST_MSG_S32]) {
0801 err = fm10k_tlv_attr_get_s32(results[FM10K_TEST_MSG_S32],
0802 &result_s32);
0803 if (!err && test_s32 != result_s32)
0804 err = FM10K_ERR_INVALID_VALUE;
0805 if (err)
0806 goto report_result;
0807 }
0808 if (!!results[FM10K_TEST_MSG_S64]) {
0809 err = fm10k_tlv_attr_get_s64(results[FM10K_TEST_MSG_S64],
0810 &result_s64);
0811 if (!err && test_s64 != result_s64)
0812 err = FM10K_ERR_INVALID_VALUE;
0813 if (err)
0814 goto report_result;
0815 }
0816 if (!!results[FM10K_TEST_MSG_LE_STRUCT]) {
0817 err = fm10k_tlv_attr_get_le_struct(
0818 results[FM10K_TEST_MSG_LE_STRUCT],
0819 result_le,
0820 sizeof(result_le));
0821 if (!err && memcmp(test_le, result_le, sizeof(test_le)))
0822 err = FM10K_ERR_INVALID_VALUE;
0823 if (err)
0824 goto report_result;
0825 }
0826
0827 if (!!results[FM10K_TEST_MSG_NESTED]) {
0828
0829 memset(nest_results, 0, sizeof(nest_results));
0830
0831
0832 err = fm10k_tlv_attr_parse(results[FM10K_TEST_MSG_NESTED],
0833 nest_results,
0834 fm10k_tlv_msg_test_attr);
0835 if (err)
0836 goto report_result;
0837
0838
0839 results = nest_results;
0840 goto parse_nested;
0841 }
0842
0843 report_result:
0844
0845 fm10k_tlv_msg_init(reply, FM10K_TLV_MSG_ID_TEST);
0846 fm10k_tlv_attr_put_s32(reply, FM10K_TEST_MSG_RESULT, err);
0847
0848
0849 return mbx->ops.enqueue_tx(hw, mbx, reply);
0850 }