0001
0002
0003
0004 #include "fm10k_common.h"
0005
0006
0007
0008
0009
0010
0011
0012 static void fm10k_fifo_init(struct fm10k_mbx_fifo *fifo, u32 *buffer, u16 size)
0013 {
0014 fifo->buffer = buffer;
0015 fifo->size = size;
0016 fifo->head = 0;
0017 fifo->tail = 0;
0018 }
0019
0020
0021
0022
0023
0024
0025
0026 static u16 fm10k_fifo_used(struct fm10k_mbx_fifo *fifo)
0027 {
0028 return fifo->tail - fifo->head;
0029 }
0030
0031
0032
0033
0034
0035
0036
0037 static u16 fm10k_fifo_unused(struct fm10k_mbx_fifo *fifo)
0038 {
0039 return fifo->size + fifo->head - fifo->tail;
0040 }
0041
0042
0043
0044
0045
0046
0047
0048 static bool fm10k_fifo_empty(struct fm10k_mbx_fifo *fifo)
0049 {
0050 return fifo->head == fifo->tail;
0051 }
0052
0053
0054
0055
0056
0057
0058
0059
0060 static u16 fm10k_fifo_head_offset(struct fm10k_mbx_fifo *fifo, u16 offset)
0061 {
0062 return (fifo->head + offset) & (fifo->size - 1);
0063 }
0064
0065
0066
0067
0068
0069
0070
0071
0072 static u16 fm10k_fifo_tail_offset(struct fm10k_mbx_fifo *fifo, u16 offset)
0073 {
0074 return (fifo->tail + offset) & (fifo->size - 1);
0075 }
0076
0077
0078
0079
0080
0081
0082
0083 static u16 fm10k_fifo_head_len(struct fm10k_mbx_fifo *fifo)
0084 {
0085 u32 *head = fifo->buffer + fm10k_fifo_head_offset(fifo, 0);
0086
0087
0088 if (fm10k_fifo_empty(fifo))
0089 return 0;
0090
0091
0092 return FM10K_TLV_DWORD_LEN(*head);
0093 }
0094
0095
0096
0097
0098
0099
0100
0101 static u16 fm10k_fifo_head_drop(struct fm10k_mbx_fifo *fifo)
0102 {
0103 u16 len = fm10k_fifo_head_len(fifo);
0104
0105
0106 fifo->head += len;
0107
0108 return len;
0109 }
0110
0111
0112
0113
0114
0115
0116
0117
0118 static void fm10k_fifo_drop_all(struct fm10k_mbx_fifo *fifo)
0119 {
0120 fifo->head = fifo->tail;
0121 }
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132 static u16 fm10k_mbx_index_len(struct fm10k_mbx_info *mbx, u16 head, u16 tail)
0133 {
0134 u16 len = tail - head;
0135
0136
0137 if (len > tail)
0138 len -= 2;
0139
0140 return len & ((mbx->mbmem_len << 1) - 1);
0141 }
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151 static u16 fm10k_mbx_tail_add(struct fm10k_mbx_info *mbx, u16 offset)
0152 {
0153 u16 tail = (mbx->tail + offset + 1) & ((mbx->mbmem_len << 1) - 1);
0154
0155
0156 return (tail > mbx->tail) ? --tail : ++tail;
0157 }
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167 static u16 fm10k_mbx_tail_sub(struct fm10k_mbx_info *mbx, u16 offset)
0168 {
0169 u16 tail = (mbx->tail - offset - 1) & ((mbx->mbmem_len << 1) - 1);
0170
0171
0172 return (tail < mbx->tail) ? ++tail : --tail;
0173 }
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183 static u16 fm10k_mbx_head_add(struct fm10k_mbx_info *mbx, u16 offset)
0184 {
0185 u16 head = (mbx->head + offset + 1) & ((mbx->mbmem_len << 1) - 1);
0186
0187
0188 return (head > mbx->head) ? --head : ++head;
0189 }
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199 static u16 fm10k_mbx_head_sub(struct fm10k_mbx_info *mbx, u16 offset)
0200 {
0201 u16 head = (mbx->head - offset - 1) & ((mbx->mbmem_len << 1) - 1);
0202
0203
0204 return (head < mbx->head) ? ++head : --head;
0205 }
0206
0207
0208
0209
0210
0211
0212
0213
0214 static u16 fm10k_mbx_pushed_tail_len(struct fm10k_mbx_info *mbx)
0215 {
0216 u32 *tail = mbx->rx.buffer + fm10k_fifo_tail_offset(&mbx->rx, 0);
0217
0218
0219 if (!mbx->pushed)
0220 return 0;
0221
0222 return FM10K_TLV_DWORD_LEN(*tail);
0223 }
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236 static void fm10k_fifo_write_copy(struct fm10k_mbx_fifo *fifo,
0237 const u32 *msg, u16 tail_offset, u16 len)
0238 {
0239 u16 end = fm10k_fifo_tail_offset(fifo, tail_offset);
0240 u32 *tail = fifo->buffer + end;
0241
0242
0243 end = fifo->size - end;
0244
0245
0246 if (end < len)
0247 memcpy(fifo->buffer, msg + end, (len - end) << 2);
0248 else
0249 end = len;
0250
0251
0252 memcpy(tail, msg, end << 2);
0253 }
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264 static s32 fm10k_fifo_enqueue(struct fm10k_mbx_fifo *fifo, const u32 *msg)
0265 {
0266 u16 len = FM10K_TLV_DWORD_LEN(*msg);
0267
0268
0269 if (len > fifo->size)
0270 return FM10K_MBX_ERR_SIZE;
0271
0272
0273 if (len > fm10k_fifo_unused(fifo))
0274 return FM10K_MBX_ERR_NO_SPACE;
0275
0276
0277 fm10k_fifo_write_copy(fifo, msg, 0, len);
0278
0279
0280 wmb();
0281
0282
0283 fifo->tail += len;
0284
0285 return 0;
0286 }
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296 static u16 fm10k_mbx_validate_msg_size(struct fm10k_mbx_info *mbx, u16 len)
0297 {
0298 struct fm10k_mbx_fifo *fifo = &mbx->rx;
0299 u16 total_len = 0, msg_len;
0300
0301
0302 len += mbx->pushed;
0303
0304
0305 do {
0306 u32 *msg;
0307
0308 msg = fifo->buffer + fm10k_fifo_tail_offset(fifo, total_len);
0309 msg_len = FM10K_TLV_DWORD_LEN(*msg);
0310 total_len += msg_len;
0311 } while (total_len < len);
0312
0313
0314 if ((len < total_len) && (msg_len <= mbx->max_size))
0315 return 0;
0316
0317
0318 return (len < total_len) ? len : (len - total_len);
0319 }
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330 static void fm10k_mbx_write_copy(struct fm10k_hw *hw,
0331 struct fm10k_mbx_info *mbx)
0332 {
0333 struct fm10k_mbx_fifo *fifo = &mbx->tx;
0334 u32 mbmem = mbx->mbmem_reg;
0335 u32 *head = fifo->buffer;
0336 u16 end, len, tail, mask;
0337
0338 if (!mbx->tail_len)
0339 return;
0340
0341
0342 mask = mbx->mbmem_len - 1;
0343 len = mbx->tail_len;
0344 tail = fm10k_mbx_tail_sub(mbx, len);
0345 if (tail > mask)
0346 tail++;
0347
0348
0349 end = fm10k_fifo_head_offset(fifo, mbx->pulled);
0350 head += end;
0351
0352
0353 rmb();
0354
0355
0356 for (end = fifo->size - end; len; head = fifo->buffer) {
0357 do {
0358
0359 tail &= mask;
0360 if (!tail)
0361 tail++;
0362
0363 mbx->tx_mbmem_pulled++;
0364
0365
0366 fm10k_write_reg(hw, mbmem + tail++, *(head++));
0367 } while (--len && --end);
0368 }
0369 }
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382 static void fm10k_mbx_pull_head(struct fm10k_hw *hw,
0383 struct fm10k_mbx_info *mbx, u16 head)
0384 {
0385 u16 mbmem_len, len, ack = fm10k_mbx_index_len(mbx, head, mbx->tail);
0386 struct fm10k_mbx_fifo *fifo = &mbx->tx;
0387
0388
0389 mbx->pulled += mbx->tail_len - ack;
0390
0391
0392 mbmem_len = mbx->mbmem_len - 1;
0393 len = fm10k_fifo_used(fifo) - mbx->pulled;
0394 if (len > mbmem_len)
0395 len = mbmem_len;
0396
0397
0398 mbx->tail = fm10k_mbx_tail_add(mbx, len - ack);
0399 mbx->tail_len = len;
0400
0401
0402 for (len = fm10k_fifo_head_len(fifo);
0403 len && (mbx->pulled >= len);
0404 len = fm10k_fifo_head_len(fifo)) {
0405 mbx->pulled -= fm10k_fifo_head_drop(fifo);
0406 mbx->tx_messages++;
0407 mbx->tx_dwords += len;
0408 }
0409
0410
0411 fm10k_mbx_write_copy(hw, mbx);
0412 }
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423 static void fm10k_mbx_read_copy(struct fm10k_hw *hw,
0424 struct fm10k_mbx_info *mbx)
0425 {
0426 struct fm10k_mbx_fifo *fifo = &mbx->rx;
0427 u32 mbmem = mbx->mbmem_reg ^ mbx->mbmem_len;
0428 u32 *tail = fifo->buffer;
0429 u16 end, len, head;
0430
0431
0432 len = mbx->head_len;
0433 head = fm10k_mbx_head_sub(mbx, len);
0434 if (head >= mbx->mbmem_len)
0435 head++;
0436
0437
0438 end = fm10k_fifo_tail_offset(fifo, mbx->pushed);
0439 tail += end;
0440
0441
0442 for (end = fifo->size - end; len; tail = fifo->buffer) {
0443 do {
0444
0445 head &= mbx->mbmem_len - 1;
0446 if (!head)
0447 head++;
0448
0449 mbx->rx_mbmem_pushed++;
0450
0451
0452 *(tail++) = fm10k_read_reg(hw, mbmem + head++);
0453 } while (--len && --end);
0454 }
0455
0456
0457 wmb();
0458 }
0459
0460
0461
0462
0463
0464
0465
0466
0467
0468
0469
0470
0471 static s32 fm10k_mbx_push_tail(struct fm10k_hw *hw,
0472 struct fm10k_mbx_info *mbx,
0473 u16 tail)
0474 {
0475 struct fm10k_mbx_fifo *fifo = &mbx->rx;
0476 u16 len, seq = fm10k_mbx_index_len(mbx, mbx->head, tail);
0477
0478
0479 len = fm10k_fifo_unused(fifo) - mbx->pushed;
0480 if (len > seq)
0481 len = seq;
0482
0483
0484 mbx->head = fm10k_mbx_head_add(mbx, len);
0485 mbx->head_len = len;
0486
0487
0488 if (!len)
0489 return 0;
0490
0491
0492 fm10k_mbx_read_copy(hw, mbx);
0493
0494
0495 if (fm10k_mbx_validate_msg_size(mbx, len))
0496 return FM10K_MBX_ERR_SIZE;
0497
0498
0499 mbx->pushed += len;
0500
0501
0502 for (len = fm10k_mbx_pushed_tail_len(mbx);
0503 len && (mbx->pushed >= len);
0504 len = fm10k_mbx_pushed_tail_len(mbx)) {
0505 fifo->tail += len;
0506 mbx->pushed -= len;
0507 mbx->rx_messages++;
0508 mbx->rx_dwords += len;
0509 }
0510
0511 return 0;
0512 }
0513
0514
0515 static const u16 fm10k_crc_16b_table[256] = {
0516 0x0000, 0x7956, 0xF2AC, 0x8BFA, 0xBC6D, 0xC53B, 0x4EC1, 0x3797,
0517 0x21EF, 0x58B9, 0xD343, 0xAA15, 0x9D82, 0xE4D4, 0x6F2E, 0x1678,
0518 0x43DE, 0x3A88, 0xB172, 0xC824, 0xFFB3, 0x86E5, 0x0D1F, 0x7449,
0519 0x6231, 0x1B67, 0x909D, 0xE9CB, 0xDE5C, 0xA70A, 0x2CF0, 0x55A6,
0520 0x87BC, 0xFEEA, 0x7510, 0x0C46, 0x3BD1, 0x4287, 0xC97D, 0xB02B,
0521 0xA653, 0xDF05, 0x54FF, 0x2DA9, 0x1A3E, 0x6368, 0xE892, 0x91C4,
0522 0xC462, 0xBD34, 0x36CE, 0x4F98, 0x780F, 0x0159, 0x8AA3, 0xF3F5,
0523 0xE58D, 0x9CDB, 0x1721, 0x6E77, 0x59E0, 0x20B6, 0xAB4C, 0xD21A,
0524 0x564D, 0x2F1B, 0xA4E1, 0xDDB7, 0xEA20, 0x9376, 0x188C, 0x61DA,
0525 0x77A2, 0x0EF4, 0x850E, 0xFC58, 0xCBCF, 0xB299, 0x3963, 0x4035,
0526 0x1593, 0x6CC5, 0xE73F, 0x9E69, 0xA9FE, 0xD0A8, 0x5B52, 0x2204,
0527 0x347C, 0x4D2A, 0xC6D0, 0xBF86, 0x8811, 0xF147, 0x7ABD, 0x03EB,
0528 0xD1F1, 0xA8A7, 0x235D, 0x5A0B, 0x6D9C, 0x14CA, 0x9F30, 0xE666,
0529 0xF01E, 0x8948, 0x02B2, 0x7BE4, 0x4C73, 0x3525, 0xBEDF, 0xC789,
0530 0x922F, 0xEB79, 0x6083, 0x19D5, 0x2E42, 0x5714, 0xDCEE, 0xA5B8,
0531 0xB3C0, 0xCA96, 0x416C, 0x383A, 0x0FAD, 0x76FB, 0xFD01, 0x8457,
0532 0xAC9A, 0xD5CC, 0x5E36, 0x2760, 0x10F7, 0x69A1, 0xE25B, 0x9B0D,
0533 0x8D75, 0xF423, 0x7FD9, 0x068F, 0x3118, 0x484E, 0xC3B4, 0xBAE2,
0534 0xEF44, 0x9612, 0x1DE8, 0x64BE, 0x5329, 0x2A7F, 0xA185, 0xD8D3,
0535 0xCEAB, 0xB7FD, 0x3C07, 0x4551, 0x72C6, 0x0B90, 0x806A, 0xF93C,
0536 0x2B26, 0x5270, 0xD98A, 0xA0DC, 0x974B, 0xEE1D, 0x65E7, 0x1CB1,
0537 0x0AC9, 0x739F, 0xF865, 0x8133, 0xB6A4, 0xCFF2, 0x4408, 0x3D5E,
0538 0x68F8, 0x11AE, 0x9A54, 0xE302, 0xD495, 0xADC3, 0x2639, 0x5F6F,
0539 0x4917, 0x3041, 0xBBBB, 0xC2ED, 0xF57A, 0x8C2C, 0x07D6, 0x7E80,
0540 0xFAD7, 0x8381, 0x087B, 0x712D, 0x46BA, 0x3FEC, 0xB416, 0xCD40,
0541 0xDB38, 0xA26E, 0x2994, 0x50C2, 0x6755, 0x1E03, 0x95F9, 0xECAF,
0542 0xB909, 0xC05F, 0x4BA5, 0x32F3, 0x0564, 0x7C32, 0xF7C8, 0x8E9E,
0543 0x98E6, 0xE1B0, 0x6A4A, 0x131C, 0x248B, 0x5DDD, 0xD627, 0xAF71,
0544 0x7D6B, 0x043D, 0x8FC7, 0xF691, 0xC106, 0xB850, 0x33AA, 0x4AFC,
0545 0x5C84, 0x25D2, 0xAE28, 0xD77E, 0xE0E9, 0x99BF, 0x1245, 0x6B13,
0546 0x3EB5, 0x47E3, 0xCC19, 0xB54F, 0x82D8, 0xFB8E, 0x7074, 0x0922,
0547 0x1F5A, 0x660C, 0xEDF6, 0x94A0, 0xA337, 0xDA61, 0x519B, 0x28CD };
0548
0549
0550
0551
0552
0553
0554
0555
0556
0557
0558
0559
0560 static u16 fm10k_crc_16b(const u32 *data, u16 seed, u16 len)
0561 {
0562 u32 result = seed;
0563
0564 while (len--) {
0565 result ^= *(data++);
0566 result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
0567 result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
0568
0569 if (!(len--))
0570 break;
0571
0572 result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
0573 result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
0574 }
0575
0576 return (u16)result;
0577 }
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588 static u16 fm10k_fifo_crc(struct fm10k_mbx_fifo *fifo, u16 offset,
0589 u16 len, u16 seed)
0590 {
0591 u32 *data = fifo->buffer + offset;
0592
0593
0594 offset = fifo->size - offset;
0595
0596
0597 if (offset < len) {
0598 seed = fm10k_crc_16b(data, seed, offset * 2);
0599 data = fifo->buffer;
0600 len -= offset;
0601 }
0602
0603
0604 return fm10k_crc_16b(data, seed, len * 2);
0605 }
0606
0607
0608
0609
0610
0611
0612
0613
0614
0615
0616
0617 static void fm10k_mbx_update_local_crc(struct fm10k_mbx_info *mbx, u16 head)
0618 {
0619 u16 len = mbx->tail_len - fm10k_mbx_index_len(mbx, head, mbx->tail);
0620
0621
0622 head = fm10k_fifo_head_offset(&mbx->tx, mbx->pulled);
0623
0624
0625 mbx->local = fm10k_fifo_crc(&mbx->tx, head, len, mbx->local);
0626 }
0627
0628
0629
0630
0631
0632
0633
0634
0635
0636
0637
0638 static s32 fm10k_mbx_verify_remote_crc(struct fm10k_mbx_info *mbx)
0639 {
0640 struct fm10k_mbx_fifo *fifo = &mbx->rx;
0641 u16 len = mbx->head_len;
0642 u16 offset = fm10k_fifo_tail_offset(fifo, mbx->pushed) - len;
0643 u16 crc;
0644
0645
0646 if (len)
0647 mbx->remote = fm10k_fifo_crc(fifo, offset, len, mbx->remote);
0648
0649
0650 crc = fm10k_crc_16b(&mbx->mbx_hdr, mbx->remote, 1);
0651
0652
0653 return crc ? FM10K_MBX_ERR_CRC : 0;
0654 }
0655
0656
0657
0658
0659
0660
0661
0662 static bool fm10k_mbx_rx_ready(struct fm10k_mbx_info *mbx)
0663 {
0664 u16 msg_size = fm10k_fifo_head_len(&mbx->rx);
0665
0666 return msg_size && (fm10k_fifo_used(&mbx->rx) >= msg_size);
0667 }
0668
0669
0670
0671
0672
0673
0674
0675
0676 static bool fm10k_mbx_tx_ready(struct fm10k_mbx_info *mbx, u16 len)
0677 {
0678 u16 fifo_unused = fm10k_fifo_unused(&mbx->tx);
0679
0680 return (mbx->state == FM10K_STATE_OPEN) && (fifo_unused >= len);
0681 }
0682
0683
0684
0685
0686
0687
0688
0689 static bool fm10k_mbx_tx_complete(struct fm10k_mbx_info *mbx)
0690 {
0691 return fm10k_fifo_empty(&mbx->tx);
0692 }
0693
0694
0695
0696
0697
0698
0699
0700
0701
0702 static u16 fm10k_mbx_dequeue_rx(struct fm10k_hw *hw,
0703 struct fm10k_mbx_info *mbx)
0704 {
0705 struct fm10k_mbx_fifo *fifo = &mbx->rx;
0706 s32 err;
0707 u16 cnt;
0708
0709
0710 for (cnt = 0; !fm10k_fifo_empty(fifo); cnt++) {
0711 err = fm10k_tlv_msg_parse(hw, fifo->buffer + fifo->head,
0712 mbx, mbx->msg_data);
0713 if (err < 0)
0714 mbx->rx_parse_err++;
0715
0716 fm10k_fifo_head_drop(fifo);
0717 }
0718
0719
0720 memmove(fifo->buffer, fifo->buffer + fifo->tail, mbx->pushed << 2);
0721
0722
0723 fifo->tail -= fifo->head;
0724 fifo->head = 0;
0725
0726 return cnt;
0727 }
0728
0729
0730
0731
0732
0733
0734
0735
0736
0737
0738
0739 static s32 fm10k_mbx_enqueue_tx(struct fm10k_hw *hw,
0740 struct fm10k_mbx_info *mbx, const u32 *msg)
0741 {
0742 u32 countdown = mbx->timeout;
0743 s32 err;
0744
0745 switch (mbx->state) {
0746 case FM10K_STATE_CLOSED:
0747 case FM10K_STATE_DISCONNECT:
0748 return FM10K_MBX_ERR_NO_MBX;
0749 default:
0750 break;
0751 }
0752
0753
0754 err = fm10k_fifo_enqueue(&mbx->tx, msg);
0755
0756
0757 while (err && countdown) {
0758 countdown--;
0759 udelay(mbx->udelay);
0760 mbx->ops.process(hw, mbx);
0761 err = fm10k_fifo_enqueue(&mbx->tx, msg);
0762 }
0763
0764
0765 if (err) {
0766 mbx->timeout = 0;
0767 mbx->tx_busy++;
0768 }
0769
0770
0771
0772
0773
0774 if (!mbx->tail_len)
0775 mbx->ops.process(hw, mbx);
0776
0777 return 0;
0778 }
0779
0780
0781
0782
0783
0784
0785
0786
0787 static s32 fm10k_mbx_read(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
0788 {
0789
0790 if (mbx->mbx_hdr)
0791 return FM10K_MBX_ERR_BUSY;
0792
0793
0794 if (fm10k_read_reg(hw, mbx->mbx_reg) & FM10K_MBX_REQ_INTERRUPT)
0795 mbx->mbx_lock = FM10K_MBX_ACK;
0796
0797
0798 fm10k_write_reg(hw, mbx->mbx_reg,
0799 FM10K_MBX_REQ_INTERRUPT | FM10K_MBX_ACK_INTERRUPT);
0800
0801
0802 mbx->mbx_hdr = fm10k_read_reg(hw, mbx->mbmem_reg ^ mbx->mbmem_len);
0803
0804 return 0;
0805 }
0806
0807
0808
0809
0810
0811
0812
0813
0814 static void fm10k_mbx_write(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
0815 {
0816 u32 mbmem = mbx->mbmem_reg;
0817
0818
0819 fm10k_write_reg(hw, mbmem, mbx->mbx_hdr);
0820
0821
0822 if (mbx->mbx_lock)
0823 fm10k_write_reg(hw, mbx->mbx_reg, mbx->mbx_lock);
0824
0825
0826 mbx->mbx_hdr = 0;
0827 mbx->mbx_lock = 0;
0828 }
0829
0830
0831
0832
0833
0834
0835
0836 static void fm10k_mbx_create_connect_hdr(struct fm10k_mbx_info *mbx)
0837 {
0838 mbx->mbx_lock |= FM10K_MBX_REQ;
0839
0840 mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_CONNECT, TYPE) |
0841 FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD) |
0842 FM10K_MSG_HDR_FIELD_SET(mbx->rx.size - 1, CONNECT_SIZE);
0843 }
0844
0845
0846
0847
0848
0849
0850
0851 static void fm10k_mbx_create_data_hdr(struct fm10k_mbx_info *mbx)
0852 {
0853 u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DATA, TYPE) |
0854 FM10K_MSG_HDR_FIELD_SET(mbx->tail, TAIL) |
0855 FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD);
0856 struct fm10k_mbx_fifo *fifo = &mbx->tx;
0857 u16 crc;
0858
0859 if (mbx->tail_len)
0860 mbx->mbx_lock |= FM10K_MBX_REQ;
0861
0862
0863 crc = fm10k_fifo_crc(fifo, fm10k_fifo_head_offset(fifo, mbx->pulled),
0864 mbx->tail_len, mbx->local);
0865 crc = fm10k_crc_16b(&hdr, crc, 1);
0866
0867
0868 mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
0869 }
0870
0871
0872
0873
0874
0875
0876
0877 static void fm10k_mbx_create_disconnect_hdr(struct fm10k_mbx_info *mbx)
0878 {
0879 u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DISCONNECT, TYPE) |
0880 FM10K_MSG_HDR_FIELD_SET(mbx->tail, TAIL) |
0881 FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD);
0882 u16 crc = fm10k_crc_16b(&hdr, mbx->local, 1);
0883
0884 mbx->mbx_lock |= FM10K_MBX_ACK;
0885
0886
0887 mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
0888 }
0889
0890
0891
0892
0893
0894
0895
0896
0897
0898 static void fm10k_mbx_create_fake_disconnect_hdr(struct fm10k_mbx_info *mbx)
0899 {
0900 u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DISCONNECT, TYPE) |
0901 FM10K_MSG_HDR_FIELD_SET(mbx->head, TAIL) |
0902 FM10K_MSG_HDR_FIELD_SET(mbx->tail, HEAD);
0903 u16 crc = fm10k_crc_16b(&hdr, mbx->local, 1);
0904
0905 mbx->mbx_lock |= FM10K_MBX_ACK;
0906
0907
0908 mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
0909 }
0910
0911
0912
0913
0914
0915
0916
0917
0918
0919
0920 static void fm10k_mbx_create_error_msg(struct fm10k_mbx_info *mbx, s32 err)
0921 {
0922
0923 switch (err) {
0924 case FM10K_MBX_ERR_TAIL:
0925 case FM10K_MBX_ERR_HEAD:
0926 case FM10K_MBX_ERR_TYPE:
0927 case FM10K_MBX_ERR_SIZE:
0928 case FM10K_MBX_ERR_RSVD0:
0929 case FM10K_MBX_ERR_CRC:
0930 break;
0931 default:
0932 return;
0933 }
0934
0935 mbx->mbx_lock |= FM10K_MBX_REQ;
0936
0937 mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_ERROR, TYPE) |
0938 FM10K_MSG_HDR_FIELD_SET(err, ERR_NO) |
0939 FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD);
0940 }
0941
0942
0943
0944
0945
0946
0947
0948
0949
0950 static s32 fm10k_mbx_validate_msg_hdr(struct fm10k_mbx_info *mbx)
0951 {
0952 u16 type, rsvd0, head, tail, size;
0953 const u32 *hdr = &mbx->mbx_hdr;
0954
0955 type = FM10K_MSG_HDR_FIELD_GET(*hdr, TYPE);
0956 rsvd0 = FM10K_MSG_HDR_FIELD_GET(*hdr, RSVD0);
0957 tail = FM10K_MSG_HDR_FIELD_GET(*hdr, TAIL);
0958 head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
0959 size = FM10K_MSG_HDR_FIELD_GET(*hdr, CONNECT_SIZE);
0960
0961 if (rsvd0)
0962 return FM10K_MBX_ERR_RSVD0;
0963
0964 switch (type) {
0965 case FM10K_MSG_DISCONNECT:
0966
0967 if (tail != mbx->head)
0968 return FM10K_MBX_ERR_TAIL;
0969
0970 fallthrough;
0971 case FM10K_MSG_DATA:
0972
0973 if (!head || (head == FM10K_MSG_HDR_MASK(HEAD)))
0974 return FM10K_MBX_ERR_HEAD;
0975 if (fm10k_mbx_index_len(mbx, head, mbx->tail) > mbx->tail_len)
0976 return FM10K_MBX_ERR_HEAD;
0977
0978
0979 if (!tail || (tail == FM10K_MSG_HDR_MASK(TAIL)))
0980 return FM10K_MBX_ERR_TAIL;
0981 if (fm10k_mbx_index_len(mbx, mbx->head, tail) < mbx->mbmem_len)
0982 break;
0983
0984 return FM10K_MBX_ERR_TAIL;
0985 case FM10K_MSG_CONNECT:
0986
0987 if ((size < FM10K_VFMBX_MSG_MTU) || (size & (size + 1)))
0988 return FM10K_MBX_ERR_SIZE;
0989
0990 fallthrough;
0991 case FM10K_MSG_ERROR:
0992 if (!head || (head == FM10K_MSG_HDR_MASK(HEAD)))
0993 return FM10K_MBX_ERR_HEAD;
0994
0995 if (tail)
0996 return FM10K_MBX_ERR_TAIL;
0997
0998 break;
0999 default:
1000 return FM10K_MBX_ERR_TYPE;
1001 }
1002
1003 return 0;
1004 }
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017 static s32 fm10k_mbx_create_reply(struct fm10k_hw *hw,
1018 struct fm10k_mbx_info *mbx, u16 head)
1019 {
1020 switch (mbx->state) {
1021 case FM10K_STATE_OPEN:
1022 case FM10K_STATE_DISCONNECT:
1023
1024 fm10k_mbx_update_local_crc(mbx, head);
1025
1026
1027 fm10k_mbx_pull_head(hw, mbx, head);
1028
1029
1030 if (mbx->tail_len || (mbx->state == FM10K_STATE_OPEN))
1031 fm10k_mbx_create_data_hdr(mbx);
1032 else
1033 fm10k_mbx_create_disconnect_hdr(mbx);
1034 break;
1035 case FM10K_STATE_CONNECT:
1036
1037 fm10k_mbx_create_connect_hdr(mbx);
1038 break;
1039 case FM10K_STATE_CLOSED:
1040
1041 fm10k_mbx_create_disconnect_hdr(mbx);
1042 break;
1043 default:
1044 break;
1045 }
1046
1047 return 0;
1048 }
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058 static void fm10k_mbx_reset_work(struct fm10k_mbx_info *mbx)
1059 {
1060 u16 len, head, ack;
1061
1062
1063 mbx->max_size = mbx->rx.size - 1;
1064
1065
1066 head = FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, HEAD);
1067 ack = fm10k_mbx_index_len(mbx, head, mbx->tail);
1068 mbx->pulled += mbx->tail_len - ack;
1069
1070
1071 while (fm10k_fifo_head_len(&mbx->tx) && mbx->pulled) {
1072 len = fm10k_fifo_head_drop(&mbx->tx);
1073 mbx->tx_dropped++;
1074 if (mbx->pulled >= len)
1075 mbx->pulled -= len;
1076 else
1077 mbx->pulled = 0;
1078 }
1079
1080
1081 mbx->pushed = 0;
1082 mbx->pulled = 0;
1083 mbx->tail_len = 0;
1084 mbx->head_len = 0;
1085 mbx->rx.tail = 0;
1086 mbx->rx.head = 0;
1087 }
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100 static void fm10k_mbx_update_max_size(struct fm10k_mbx_info *mbx, u16 size)
1101 {
1102 u16 len;
1103
1104 mbx->max_size = size;
1105
1106
1107 for (len = fm10k_fifo_head_len(&mbx->tx);
1108 len > size;
1109 len = fm10k_fifo_head_len(&mbx->tx)) {
1110 fm10k_fifo_head_drop(&mbx->tx);
1111 mbx->tx_dropped++;
1112 }
1113 }
1114
1115
1116
1117
1118
1119
1120
1121
1122 static void fm10k_mbx_connect_reset(struct fm10k_mbx_info *mbx)
1123 {
1124
1125 fm10k_mbx_reset_work(mbx);
1126
1127
1128 mbx->local = FM10K_MBX_CRC_SEED;
1129 mbx->remote = FM10K_MBX_CRC_SEED;
1130
1131
1132 if (mbx->state == FM10K_STATE_OPEN)
1133 mbx->state = FM10K_STATE_CONNECT;
1134 else
1135 mbx->state = FM10K_STATE_CLOSED;
1136 }
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147 static s32 fm10k_mbx_process_connect(struct fm10k_hw *hw,
1148 struct fm10k_mbx_info *mbx)
1149 {
1150 const enum fm10k_mbx_state state = mbx->state;
1151 const u32 *hdr = &mbx->mbx_hdr;
1152 u16 size, head;
1153
1154
1155 size = FM10K_MSG_HDR_FIELD_GET(*hdr, CONNECT_SIZE);
1156 head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
1157
1158 switch (state) {
1159 case FM10K_STATE_DISCONNECT:
1160 case FM10K_STATE_OPEN:
1161
1162 fm10k_mbx_connect_reset(mbx);
1163 break;
1164 case FM10K_STATE_CONNECT:
1165
1166 if (size > mbx->rx.size) {
1167 mbx->max_size = mbx->rx.size - 1;
1168 } else {
1169
1170 mbx->state = FM10K_STATE_OPEN;
1171
1172 fm10k_mbx_update_max_size(mbx, size);
1173 }
1174 break;
1175 default:
1176 break;
1177 }
1178
1179
1180 mbx->tail = head;
1181
1182 return fm10k_mbx_create_reply(hw, mbx, head);
1183 }
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194 static s32 fm10k_mbx_process_data(struct fm10k_hw *hw,
1195 struct fm10k_mbx_info *mbx)
1196 {
1197 const u32 *hdr = &mbx->mbx_hdr;
1198 u16 head, tail;
1199 s32 err;
1200
1201
1202 head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
1203 tail = FM10K_MSG_HDR_FIELD_GET(*hdr, TAIL);
1204
1205
1206 if (mbx->state == FM10K_STATE_CONNECT) {
1207 mbx->tail = head;
1208 mbx->state = FM10K_STATE_OPEN;
1209 }
1210
1211
1212 err = fm10k_mbx_push_tail(hw, mbx, tail);
1213 if (err < 0)
1214 return err;
1215
1216
1217 err = fm10k_mbx_verify_remote_crc(mbx);
1218 if (err)
1219 return err;
1220
1221
1222 fm10k_mbx_dequeue_rx(hw, mbx);
1223
1224 return fm10k_mbx_create_reply(hw, mbx, head);
1225 }
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236 static s32 fm10k_mbx_process_disconnect(struct fm10k_hw *hw,
1237 struct fm10k_mbx_info *mbx)
1238 {
1239 const enum fm10k_mbx_state state = mbx->state;
1240 const u32 *hdr = &mbx->mbx_hdr;
1241 u16 head;
1242 s32 err;
1243
1244
1245 head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
1246
1247
1248 if (mbx->pushed)
1249 return FM10K_MBX_ERR_TAIL;
1250
1251
1252 mbx->head_len = 0;
1253
1254
1255 err = fm10k_mbx_verify_remote_crc(mbx);
1256 if (err)
1257 return err;
1258
1259 switch (state) {
1260 case FM10K_STATE_DISCONNECT:
1261 case FM10K_STATE_OPEN:
1262
1263 if (!fm10k_mbx_tx_complete(mbx))
1264 break;
1265
1266
1267 if (head != mbx->tail)
1268 return FM10K_MBX_ERR_HEAD;
1269
1270
1271 fm10k_mbx_connect_reset(mbx);
1272 break;
1273 default:
1274 break;
1275 }
1276
1277 return fm10k_mbx_create_reply(hw, mbx, head);
1278 }
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289 static s32 fm10k_mbx_process_error(struct fm10k_hw *hw,
1290 struct fm10k_mbx_info *mbx)
1291 {
1292 const u32 *hdr = &mbx->mbx_hdr;
1293 u16 head;
1294
1295
1296 head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
1297
1298 switch (mbx->state) {
1299 case FM10K_STATE_OPEN:
1300 case FM10K_STATE_DISCONNECT:
1301
1302 fm10k_mbx_reset_work(mbx);
1303
1304
1305 mbx->local = FM10K_MBX_CRC_SEED;
1306 mbx->remote = FM10K_MBX_CRC_SEED;
1307
1308
1309 mbx->tail = head;
1310
1311
1312 if (mbx->state == FM10K_STATE_OPEN) {
1313 mbx->state = FM10K_STATE_CONNECT;
1314 break;
1315 }
1316
1317
1318 fm10k_mbx_create_connect_hdr(mbx);
1319 return 0;
1320 default:
1321 break;
1322 }
1323
1324 return fm10k_mbx_create_reply(hw, mbx, mbx->tail);
1325 }
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336 static s32 fm10k_mbx_process(struct fm10k_hw *hw,
1337 struct fm10k_mbx_info *mbx)
1338 {
1339 s32 err;
1340
1341
1342 if (mbx->state == FM10K_STATE_CLOSED)
1343 return 0;
1344
1345
1346 err = fm10k_mbx_read(hw, mbx);
1347 if (err)
1348 return err;
1349
1350
1351 err = fm10k_mbx_validate_msg_hdr(mbx);
1352 if (err < 0)
1353 goto msg_err;
1354
1355 switch (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, TYPE)) {
1356 case FM10K_MSG_CONNECT:
1357 err = fm10k_mbx_process_connect(hw, mbx);
1358 break;
1359 case FM10K_MSG_DATA:
1360 err = fm10k_mbx_process_data(hw, mbx);
1361 break;
1362 case FM10K_MSG_DISCONNECT:
1363 err = fm10k_mbx_process_disconnect(hw, mbx);
1364 break;
1365 case FM10K_MSG_ERROR:
1366 err = fm10k_mbx_process_error(hw, mbx);
1367 break;
1368 default:
1369 err = FM10K_MBX_ERR_TYPE;
1370 break;
1371 }
1372
1373 msg_err:
1374
1375 if (err < 0)
1376 fm10k_mbx_create_error_msg(mbx, err);
1377
1378
1379 fm10k_mbx_write(hw, mbx);
1380
1381 return err;
1382 }
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397 static void fm10k_mbx_disconnect(struct fm10k_hw *hw,
1398 struct fm10k_mbx_info *mbx)
1399 {
1400 int timeout = mbx->timeout ? FM10K_MBX_DISCONNECT_TIMEOUT : 0;
1401
1402
1403 mbx->state = FM10K_STATE_DISCONNECT;
1404
1405
1406 fm10k_write_reg(hw, mbx->mbx_reg, FM10K_MBX_REQ |
1407 FM10K_MBX_INTERRUPT_DISABLE);
1408 do {
1409 udelay(FM10K_MBX_POLL_DELAY);
1410 mbx->ops.process(hw, mbx);
1411 timeout -= FM10K_MBX_POLL_DELAY;
1412 } while ((timeout > 0) && (mbx->state != FM10K_STATE_CLOSED));
1413
1414
1415
1416
1417 fm10k_mbx_connect_reset(mbx);
1418 fm10k_fifo_drop_all(&mbx->tx);
1419
1420 fm10k_write_reg(hw, mbx->mbmem_reg, 0);
1421 }
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436 static s32 fm10k_mbx_connect(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
1437 {
1438
1439 if (!mbx->rx.buffer)
1440 return FM10K_MBX_ERR_NO_SPACE;
1441
1442
1443 if (mbx->state != FM10K_STATE_CLOSED)
1444 return FM10K_MBX_ERR_BUSY;
1445
1446
1447 mbx->timeout = FM10K_MBX_INIT_TIMEOUT;
1448
1449
1450 mbx->state = FM10K_STATE_CONNECT;
1451
1452 fm10k_mbx_reset_work(mbx);
1453
1454
1455 fm10k_mbx_create_fake_disconnect_hdr(mbx);
1456 fm10k_write_reg(hw, mbx->mbmem_reg ^ mbx->mbmem_len, mbx->mbx_hdr);
1457
1458
1459 mbx->mbx_lock = FM10K_MBX_REQ_INTERRUPT | FM10K_MBX_ACK_INTERRUPT |
1460 FM10K_MBX_INTERRUPT_ENABLE;
1461
1462
1463 fm10k_mbx_create_connect_hdr(mbx);
1464 fm10k_mbx_write(hw, mbx);
1465
1466 return 0;
1467 }
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477 static s32 fm10k_mbx_validate_handlers(const struct fm10k_msg_data *msg_data)
1478 {
1479 const struct fm10k_tlv_attr *attr;
1480 unsigned int id;
1481
1482
1483 if (!msg_data)
1484 return 0;
1485
1486 while (msg_data->id != FM10K_TLV_ERROR) {
1487
1488 if (!msg_data->func)
1489 return FM10K_ERR_PARAM;
1490
1491
1492 attr = msg_data->attr;
1493 if (attr) {
1494 while (attr->id != FM10K_TLV_ERROR) {
1495 id = attr->id;
1496 attr++;
1497
1498 if (id >= attr->id)
1499 return FM10K_ERR_PARAM;
1500
1501 if (id >= FM10K_TLV_RESULTS_MAX)
1502 return FM10K_ERR_PARAM;
1503 }
1504
1505
1506 if (attr->id != FM10K_TLV_ERROR)
1507 return FM10K_ERR_PARAM;
1508 }
1509
1510 id = msg_data->id;
1511 msg_data++;
1512
1513 if (id >= msg_data->id)
1514 return FM10K_ERR_PARAM;
1515 }
1516
1517
1518 if ((msg_data->id != FM10K_TLV_ERROR) || !msg_data->func)
1519 return FM10K_ERR_PARAM;
1520
1521 return 0;
1522 }
1523
1524
1525
1526
1527
1528
1529
1530
1531 static s32 fm10k_mbx_register_handlers(struct fm10k_mbx_info *mbx,
1532 const struct fm10k_msg_data *msg_data)
1533 {
1534
1535 if (fm10k_mbx_validate_handlers(msg_data))
1536 return FM10K_ERR_PARAM;
1537
1538
1539 mbx->msg_data = msg_data;
1540
1541 return 0;
1542 }
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558 s32 fm10k_pfvf_mbx_init(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx,
1559 const struct fm10k_msg_data *msg_data, u8 id)
1560 {
1561
1562 switch (hw->mac.type) {
1563 case fm10k_mac_vf:
1564 mbx->mbx_reg = FM10K_VFMBX;
1565 mbx->mbmem_reg = FM10K_VFMBMEM(FM10K_VFMBMEM_VF_XOR);
1566 break;
1567 case fm10k_mac_pf:
1568
1569 if (id < 64) {
1570 mbx->mbx_reg = FM10K_MBX(id);
1571 mbx->mbmem_reg = FM10K_MBMEM_VF(id, 0);
1572 break;
1573 }
1574 fallthrough;
1575 default:
1576 return FM10K_MBX_ERR_NO_MBX;
1577 }
1578
1579
1580 mbx->state = FM10K_STATE_CLOSED;
1581
1582
1583 if (fm10k_mbx_validate_handlers(msg_data))
1584 return FM10K_ERR_PARAM;
1585
1586
1587 mbx->msg_data = msg_data;
1588
1589
1590
1591
1592 mbx->timeout = 0;
1593 mbx->udelay = FM10K_MBX_INIT_DELAY;
1594
1595
1596 mbx->tail = 1;
1597 mbx->head = 1;
1598
1599
1600 mbx->local = FM10K_MBX_CRC_SEED;
1601 mbx->remote = FM10K_MBX_CRC_SEED;
1602
1603
1604 mbx->max_size = FM10K_MBX_MSG_MAX_SIZE;
1605 mbx->mbmem_len = FM10K_VFMBMEM_VF_XOR;
1606
1607
1608 fm10k_fifo_init(&mbx->tx, mbx->buffer, FM10K_MBX_TX_BUFFER_SIZE);
1609 fm10k_fifo_init(&mbx->rx, &mbx->buffer[FM10K_MBX_TX_BUFFER_SIZE],
1610 FM10K_MBX_RX_BUFFER_SIZE);
1611
1612
1613 mbx->ops.connect = fm10k_mbx_connect;
1614 mbx->ops.disconnect = fm10k_mbx_disconnect;
1615 mbx->ops.rx_ready = fm10k_mbx_rx_ready;
1616 mbx->ops.tx_ready = fm10k_mbx_tx_ready;
1617 mbx->ops.tx_complete = fm10k_mbx_tx_complete;
1618 mbx->ops.enqueue_tx = fm10k_mbx_enqueue_tx;
1619 mbx->ops.process = fm10k_mbx_process;
1620 mbx->ops.register_handlers = fm10k_mbx_register_handlers;
1621
1622 return 0;
1623 }
1624
1625
1626
1627
1628
1629
1630
1631 static void fm10k_sm_mbx_create_data_hdr(struct fm10k_mbx_info *mbx)
1632 {
1633 if (mbx->tail_len)
1634 mbx->mbx_lock |= FM10K_MBX_REQ;
1635
1636 mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(mbx->tail, SM_TAIL) |
1637 FM10K_MSG_HDR_FIELD_SET(mbx->remote, SM_VER) |
1638 FM10K_MSG_HDR_FIELD_SET(mbx->head, SM_HEAD);
1639 }
1640
1641
1642
1643
1644
1645
1646
1647
1648 static void fm10k_sm_mbx_create_connect_hdr(struct fm10k_mbx_info *mbx, u8 err)
1649 {
1650 if (mbx->local)
1651 mbx->mbx_lock |= FM10K_MBX_REQ;
1652
1653 mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(mbx->tail, SM_TAIL) |
1654 FM10K_MSG_HDR_FIELD_SET(mbx->remote, SM_VER) |
1655 FM10K_MSG_HDR_FIELD_SET(mbx->head, SM_HEAD) |
1656 FM10K_MSG_HDR_FIELD_SET(err, SM_ERR);
1657 }
1658
1659
1660
1661
1662
1663
1664
1665 static void fm10k_sm_mbx_connect_reset(struct fm10k_mbx_info *mbx)
1666 {
1667
1668 fm10k_mbx_reset_work(mbx);
1669
1670
1671 mbx->local = FM10K_SM_MBX_VERSION;
1672 mbx->remote = 0;
1673
1674
1675 mbx->tail = 1;
1676 mbx->head = 1;
1677
1678
1679 mbx->state = FM10K_STATE_CONNECT;
1680 }
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694 static s32 fm10k_sm_mbx_connect(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
1695 {
1696
1697 if (!mbx->rx.buffer)
1698 return FM10K_MBX_ERR_NO_SPACE;
1699
1700
1701 if (mbx->state != FM10K_STATE_CLOSED)
1702 return FM10K_MBX_ERR_BUSY;
1703
1704
1705 mbx->timeout = FM10K_MBX_INIT_TIMEOUT;
1706
1707
1708 mbx->state = FM10K_STATE_CONNECT;
1709 mbx->max_size = FM10K_MBX_MSG_MAX_SIZE;
1710
1711
1712 fm10k_sm_mbx_connect_reset(mbx);
1713
1714
1715 mbx->mbx_lock = FM10K_MBX_REQ_INTERRUPT | FM10K_MBX_ACK_INTERRUPT |
1716 FM10K_MBX_INTERRUPT_ENABLE;
1717
1718
1719 fm10k_sm_mbx_create_connect_hdr(mbx, 0);
1720 fm10k_mbx_write(hw, mbx);
1721
1722 return 0;
1723 }
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738 static void fm10k_sm_mbx_disconnect(struct fm10k_hw *hw,
1739 struct fm10k_mbx_info *mbx)
1740 {
1741 int timeout = mbx->timeout ? FM10K_MBX_DISCONNECT_TIMEOUT : 0;
1742
1743
1744 mbx->state = FM10K_STATE_DISCONNECT;
1745
1746
1747 fm10k_write_reg(hw, mbx->mbx_reg, FM10K_MBX_REQ |
1748 FM10K_MBX_INTERRUPT_DISABLE);
1749 do {
1750 udelay(FM10K_MBX_POLL_DELAY);
1751 mbx->ops.process(hw, mbx);
1752 timeout -= FM10K_MBX_POLL_DELAY;
1753 } while ((timeout > 0) && (mbx->state != FM10K_STATE_CLOSED));
1754
1755
1756 mbx->state = FM10K_STATE_CLOSED;
1757 mbx->remote = 0;
1758 fm10k_mbx_reset_work(mbx);
1759 fm10k_fifo_drop_all(&mbx->tx);
1760
1761 fm10k_write_reg(hw, mbx->mbmem_reg, 0);
1762 }
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772 static s32 fm10k_sm_mbx_validate_fifo_hdr(struct fm10k_mbx_info *mbx)
1773 {
1774 const u32 *hdr = &mbx->mbx_hdr;
1775 u16 tail, head, ver;
1776
1777 tail = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_TAIL);
1778 ver = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_VER);
1779 head = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_HEAD);
1780
1781 switch (ver) {
1782 case 0:
1783 break;
1784 case FM10K_SM_MBX_VERSION:
1785 if (!head || head > FM10K_SM_MBX_FIFO_LEN)
1786 return FM10K_MBX_ERR_HEAD;
1787 if (!tail || tail > FM10K_SM_MBX_FIFO_LEN)
1788 return FM10K_MBX_ERR_TAIL;
1789 if (mbx->tail < head)
1790 head += mbx->mbmem_len - 1;
1791 if (tail < mbx->head)
1792 tail += mbx->mbmem_len - 1;
1793 if (fm10k_mbx_index_len(mbx, head, mbx->tail) > mbx->tail_len)
1794 return FM10K_MBX_ERR_HEAD;
1795 if (fm10k_mbx_index_len(mbx, mbx->head, tail) < mbx->mbmem_len)
1796 break;
1797 return FM10K_MBX_ERR_TAIL;
1798 default:
1799 return FM10K_MBX_ERR_SRC;
1800 }
1801
1802 return 0;
1803 }
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814 static void fm10k_sm_mbx_process_error(struct fm10k_mbx_info *mbx)
1815 {
1816 const enum fm10k_mbx_state state = mbx->state;
1817
1818 switch (state) {
1819 case FM10K_STATE_DISCONNECT:
1820
1821 mbx->remote = 0;
1822 break;
1823 case FM10K_STATE_OPEN:
1824
1825 fm10k_sm_mbx_connect_reset(mbx);
1826 break;
1827 case FM10K_STATE_CONNECT:
1828
1829 if (mbx->remote) {
1830 while (mbx->local > 1)
1831 mbx->local--;
1832 mbx->remote = 0;
1833 }
1834 break;
1835 default:
1836 break;
1837 }
1838
1839 fm10k_sm_mbx_create_connect_hdr(mbx, 0);
1840 }
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850 static void fm10k_sm_mbx_create_error_msg(struct fm10k_mbx_info *mbx, s32 err)
1851 {
1852
1853 switch (err) {
1854 case FM10K_MBX_ERR_TAIL:
1855 case FM10K_MBX_ERR_HEAD:
1856 case FM10K_MBX_ERR_SRC:
1857 case FM10K_MBX_ERR_SIZE:
1858 case FM10K_MBX_ERR_RSVD0:
1859 break;
1860 default:
1861 return;
1862 }
1863
1864
1865 fm10k_sm_mbx_process_error(mbx);
1866 fm10k_sm_mbx_create_connect_hdr(mbx, 1);
1867 }
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878 static s32 fm10k_sm_mbx_receive(struct fm10k_hw *hw,
1879 struct fm10k_mbx_info *mbx,
1880 u16 tail)
1881 {
1882
1883 u16 mbmem_len = mbx->mbmem_len - 1;
1884 s32 err;
1885
1886
1887 if (tail < mbx->head)
1888 tail += mbmem_len;
1889
1890
1891 err = fm10k_mbx_push_tail(hw, mbx, tail);
1892 if (err < 0)
1893 return err;
1894
1895
1896 fm10k_mbx_dequeue_rx(hw, mbx);
1897
1898
1899 mbx->head = fm10k_mbx_head_sub(mbx, mbx->pushed);
1900 mbx->pushed = 0;
1901
1902
1903 if (mbx->head > mbmem_len)
1904 mbx->head -= mbmem_len;
1905
1906 return err;
1907 }
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918 static void fm10k_sm_mbx_transmit(struct fm10k_hw *hw,
1919 struct fm10k_mbx_info *mbx, u16 head)
1920 {
1921 struct fm10k_mbx_fifo *fifo = &mbx->tx;
1922
1923 u16 mbmem_len = mbx->mbmem_len - 1;
1924 u16 tail_len, len = 0;
1925
1926
1927 if (mbx->tail < head)
1928 head += mbmem_len;
1929
1930 fm10k_mbx_pull_head(hw, mbx, head);
1931
1932
1933 do {
1934 u32 *msg;
1935
1936 msg = fifo->buffer + fm10k_fifo_head_offset(fifo, len);
1937 tail_len = len;
1938 len += FM10K_TLV_DWORD_LEN(*msg);
1939 } while ((len <= mbx->tail_len) && (len < mbmem_len));
1940
1941
1942 if (mbx->tail_len > tail_len) {
1943 mbx->tail = fm10k_mbx_tail_sub(mbx, mbx->tail_len - tail_len);
1944 mbx->tail_len = tail_len;
1945 }
1946
1947
1948 if (mbx->tail > mbmem_len)
1949 mbx->tail -= mbmem_len;
1950 }
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963 static void fm10k_sm_mbx_create_reply(struct fm10k_hw *hw,
1964 struct fm10k_mbx_info *mbx, u16 head)
1965 {
1966 switch (mbx->state) {
1967 case FM10K_STATE_OPEN:
1968 case FM10K_STATE_DISCONNECT:
1969
1970 fm10k_sm_mbx_transmit(hw, mbx, head);
1971
1972
1973 if (mbx->tail_len || (mbx->state == FM10K_STATE_OPEN)) {
1974 fm10k_sm_mbx_create_data_hdr(mbx);
1975 } else {
1976 mbx->remote = 0;
1977 fm10k_sm_mbx_create_connect_hdr(mbx, 0);
1978 }
1979 break;
1980 case FM10K_STATE_CONNECT:
1981 case FM10K_STATE_CLOSED:
1982 fm10k_sm_mbx_create_connect_hdr(mbx, 0);
1983 break;
1984 default:
1985 break;
1986 }
1987 }
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000 static s32 fm10k_sm_mbx_process_reset(struct fm10k_hw *hw,
2001 struct fm10k_mbx_info *mbx)
2002 {
2003 s32 err = 0;
2004 const enum fm10k_mbx_state state = mbx->state;
2005
2006 switch (state) {
2007 case FM10K_STATE_DISCONNECT:
2008
2009 mbx->state = FM10K_STATE_CLOSED;
2010 mbx->remote = 0;
2011 mbx->local = 0;
2012 break;
2013 case FM10K_STATE_OPEN:
2014
2015 fm10k_sm_mbx_connect_reset(mbx);
2016 err = FM10K_ERR_RESET_REQUESTED;
2017 break;
2018 case FM10K_STATE_CONNECT:
2019
2020 mbx->remote = mbx->local;
2021 break;
2022 default:
2023 break;
2024 }
2025
2026 fm10k_sm_mbx_create_reply(hw, mbx, mbx->tail);
2027
2028 return err;
2029 }
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039 static s32 fm10k_sm_mbx_process_version_1(struct fm10k_hw *hw,
2040 struct fm10k_mbx_info *mbx)
2041 {
2042 const u32 *hdr = &mbx->mbx_hdr;
2043 u16 head, tail;
2044 s32 len;
2045
2046
2047 tail = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_TAIL);
2048 head = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_HEAD);
2049
2050
2051 if (mbx->state == FM10K_STATE_CONNECT) {
2052 if (!mbx->remote)
2053 goto send_reply;
2054 if (mbx->remote != 1)
2055 return FM10K_MBX_ERR_SRC;
2056
2057 mbx->state = FM10K_STATE_OPEN;
2058 }
2059
2060 do {
2061
2062 len = fm10k_sm_mbx_receive(hw, mbx, tail);
2063 if (len < 0)
2064 return len;
2065
2066
2067 } while (len);
2068
2069 send_reply:
2070 fm10k_sm_mbx_create_reply(hw, mbx, head);
2071
2072 return 0;
2073 }
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084 static s32 fm10k_sm_mbx_process(struct fm10k_hw *hw,
2085 struct fm10k_mbx_info *mbx)
2086 {
2087 s32 err;
2088
2089
2090 if (mbx->state == FM10K_STATE_CLOSED)
2091 return 0;
2092
2093
2094 err = fm10k_mbx_read(hw, mbx);
2095 if (err)
2096 return err;
2097
2098 err = fm10k_sm_mbx_validate_fifo_hdr(mbx);
2099 if (err < 0)
2100 goto fifo_err;
2101
2102 if (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, SM_ERR)) {
2103 fm10k_sm_mbx_process_error(mbx);
2104 goto fifo_err;
2105 }
2106
2107 switch (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, SM_VER)) {
2108 case 0:
2109 err = fm10k_sm_mbx_process_reset(hw, mbx);
2110 break;
2111 case FM10K_SM_MBX_VERSION:
2112 err = fm10k_sm_mbx_process_version_1(hw, mbx);
2113 break;
2114 }
2115
2116 fifo_err:
2117 if (err < 0)
2118 fm10k_sm_mbx_create_error_msg(mbx, err);
2119
2120
2121 fm10k_mbx_write(hw, mbx);
2122
2123 return err;
2124 }
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139 s32 fm10k_sm_mbx_init(struct fm10k_hw __always_unused *hw,
2140 struct fm10k_mbx_info *mbx,
2141 const struct fm10k_msg_data *msg_data)
2142 {
2143 mbx->mbx_reg = FM10K_GMBX;
2144 mbx->mbmem_reg = FM10K_MBMEM_PF(0);
2145
2146
2147 mbx->state = FM10K_STATE_CLOSED;
2148
2149
2150 if (fm10k_mbx_validate_handlers(msg_data))
2151 return FM10K_ERR_PARAM;
2152
2153
2154 mbx->msg_data = msg_data;
2155
2156
2157
2158
2159 mbx->timeout = 0;
2160 mbx->udelay = FM10K_MBX_INIT_DELAY;
2161
2162
2163 mbx->max_size = FM10K_MBX_MSG_MAX_SIZE;
2164 mbx->mbmem_len = FM10K_MBMEM_PF_XOR;
2165
2166
2167 fm10k_fifo_init(&mbx->tx, mbx->buffer, FM10K_MBX_TX_BUFFER_SIZE);
2168 fm10k_fifo_init(&mbx->rx, &mbx->buffer[FM10K_MBX_TX_BUFFER_SIZE],
2169 FM10K_MBX_RX_BUFFER_SIZE);
2170
2171
2172 mbx->ops.connect = fm10k_sm_mbx_connect;
2173 mbx->ops.disconnect = fm10k_sm_mbx_disconnect;
2174 mbx->ops.rx_ready = fm10k_mbx_rx_ready;
2175 mbx->ops.tx_ready = fm10k_mbx_tx_ready;
2176 mbx->ops.tx_complete = fm10k_mbx_tx_complete;
2177 mbx->ops.enqueue_tx = fm10k_mbx_enqueue_tx;
2178 mbx->ops.process = fm10k_sm_mbx_process;
2179 mbx->ops.register_handlers = fm10k_mbx_register_handlers;
2180
2181 return 0;
2182 }